mirror of
https://github.com/OpenEPaperLink/OpenEPaperLink.git
synced 2026-03-21 08:06:46 +01:00
Compare commits
22 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9c06cdf2d7 | ||
|
|
7a0ca319e7 | ||
|
|
c095f4c881 | ||
|
|
c586c9f541 | ||
|
|
6c4f8ef35b | ||
|
|
c403c06b09 | ||
|
|
ddd043f44f | ||
|
|
81cc5ccc9a | ||
|
|
be325b0e62 | ||
|
|
3621c84cc4 | ||
|
|
ed82795e5f | ||
|
|
5b9f8b324e | ||
|
|
db80d23b52 | ||
|
|
125922f8e7 | ||
|
|
aa484575b8 | ||
|
|
fa97daef3c | ||
|
|
0c591660bc | ||
|
|
c8fb0ca4de | ||
|
|
87ce823776 | ||
|
|
7fe4a1e6ad | ||
|
|
29b8c9bc21 | ||
|
|
2e44889b19 |
40
.github/workflows/release.yml
vendored
40
.github/workflows/release.yml
vendored
@@ -39,18 +39,18 @@ jobs:
|
||||
- name: Install intelhex
|
||||
run: pip install --upgrade intelhex
|
||||
|
||||
- name: Build NRF firmware
|
||||
run: |
|
||||
cd ARM_Tag_FW/Newton_M3_nRF52811
|
||||
pio run --environment Newton_M3_22_BWR
|
||||
pio run --environment Newton_M3_29_BWR
|
||||
pio run --environment Newton_M3_75_BWR
|
||||
cp Newton_M3_22_BWR-ota.bin /home/runner/work/OpenEPaperLink/OpenEPaperLink/binaries/Newton_M3_22_BWR-ota.bin
|
||||
cp Newton_M3_22_BWR-full-flash.bin /home/runner/work/OpenEPaperLink/OpenEPaperLink/binaries/Newton_M3_22_BWR-full-flash.bin
|
||||
cp Newton_M3_29_BWR-ota.bin /home/runner/work/OpenEPaperLink/OpenEPaperLink/binaries/Newton_M3_29_BWR-ota.bin
|
||||
cp Newton_M3_29_BWR-full-flash.bin /home/runner/work/OpenEPaperLink/OpenEPaperLink/binaries/Newton_M3_29_BWR-full-flash.bin
|
||||
cp Newton_M3_75_BWR-ota.bin /home/runner/work/OpenEPaperLink/OpenEPaperLink/binaries/Newton_M3_75_BWR-ota.bin
|
||||
cp Newton_M3_75_BWR-full-flash.bin /home/runner/work/OpenEPaperLink/OpenEPaperLink/binaries/Newton_M3_75_BWR-full-flash.bin
|
||||
# - name: Build NRF firmware
|
||||
# run: |
|
||||
# cd ARM_Tag_FW/Newton_M3_nRF52811
|
||||
# pio run --environment Newton_M3_22_BWR
|
||||
# pio run --environment Newton_M3_29_BWR
|
||||
# pio run --environment Newton_M3_75_BWR
|
||||
# cp Newton_M3_22_BWR-ota.bin /home/runner/work/OpenEPaperLink/OpenEPaperLink/binaries/Newton_M3_22_BWR-ota.bin
|
||||
# cp Newton_M3_22_BWR-full-flash.bin /home/runner/work/OpenEPaperLink/OpenEPaperLink/binaries/Newton_M3_22_BWR-full-flash.bin
|
||||
# cp Newton_M3_29_BWR-ota.bin /home/runner/work/OpenEPaperLink/OpenEPaperLink/binaries/Newton_M3_29_BWR-ota.bin
|
||||
# cp Newton_M3_29_BWR-full-flash.bin /home/runner/work/OpenEPaperLink/OpenEPaperLink/binaries/Newton_M3_29_BWR-full-flash.bin
|
||||
# cp Newton_M3_75_BWR-ota.bin /home/runner/work/OpenEPaperLink/OpenEPaperLink/binaries/Newton_M3_75_BWR-ota.bin
|
||||
# cp Newton_M3_75_BWR-full-flash.bin /home/runner/work/OpenEPaperLink/OpenEPaperLink/binaries/Newton_M3_75_BWR-full-flash.bin
|
||||
|
||||
- name: Install esptool
|
||||
run: pip install esptool
|
||||
@@ -199,14 +199,14 @@ jobs:
|
||||
file_glob: true
|
||||
overwrite: true
|
||||
|
||||
- name: Add tag bins to release
|
||||
uses: svenstaro/upload-release-action@v2
|
||||
with:
|
||||
repo_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
file: binaries/*
|
||||
tag: ${{ github.ref }}
|
||||
file_glob: true
|
||||
overwrite: true
|
||||
# - name: Add tag bins to release
|
||||
# uses: svenstaro/upload-release-action@v2
|
||||
# with:
|
||||
# repo_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
# file: binaries/*
|
||||
# tag: ${{ github.ref }}
|
||||
# file_glob: true
|
||||
# overwrite: true
|
||||
|
||||
# this is down here intentionally to be able to modify the binary folder before adding it to the Tag_Flasher later (ota binaries can be removed)
|
||||
|
||||
|
||||
@@ -2,3 +2,7 @@ build
|
||||
*.axf
|
||||
# Allow
|
||||
!*.bin
|
||||
|
||||
.vscode
|
||||
sdkconfig
|
||||
sdkconfig.old
|
||||
|
||||
28
ARM_Tag_FW/OpenEPaperLink_esp32_C6_AP/main/Kconfig.projbuild
Normal file
28
ARM_Tag_FW/OpenEPaperLink_esp32_C6_AP/main/Kconfig.projbuild
Normal file
@@ -0,0 +1,28 @@
|
||||
menu "OEPL Hardware config"
|
||||
|
||||
choice OEPL_HARDWARE_PROFILE
|
||||
prompt "Hardware profile"
|
||||
default OEPL_HARDWARE_PROFILE_DEFAULT
|
||||
|
||||
config OEPL_HARDWARE_PROFILE_DEFAULT
|
||||
bool "Default"
|
||||
|
||||
config OEPL_HARDWARE_PROFILE_POE_AP
|
||||
bool "PoE-AP"
|
||||
|
||||
config OEPL_HARDWARE_PROFILE_CUSTOM
|
||||
bool "Custom"
|
||||
|
||||
endchoice
|
||||
|
||||
config OEPL_HARDWARE_UART_TX
|
||||
depends on OEPL_HARDWARE_PROFILE_CUSTOM
|
||||
int "GPIO - UART TX"
|
||||
default 3
|
||||
|
||||
config OEPL_HARDWARE_UART_RX
|
||||
depends on OEPL_HARDWARE_PROFILE_CUSTOM
|
||||
int "GPIO - UART RX"
|
||||
default 2
|
||||
|
||||
endmenu
|
||||
@@ -326,15 +326,15 @@ void processSerial(uint8_t lastchar) {
|
||||
}
|
||||
goto SCPfailed;
|
||||
SCPchannelFound:
|
||||
pr("ACK>");
|
||||
if (curChannel != scp->channel) {
|
||||
radioSetChannel(scp->channel);
|
||||
curChannel = scp->channel;
|
||||
}
|
||||
curPower = scp->power;
|
||||
pr("ACK>");
|
||||
if (curChannel != scp->channel) {
|
||||
radioSetChannel(scp->channel);
|
||||
curChannel = scp->channel;
|
||||
}
|
||||
curPower = scp->power;
|
||||
radioSetTxPower(scp->power);
|
||||
ESP_LOGI(TAG, "Set channel: %d power: %d", curChannel, curPower);
|
||||
} else {
|
||||
} else {
|
||||
SCPfailed:
|
||||
pr("NOK>");
|
||||
}
|
||||
@@ -412,27 +412,27 @@ void espNotifyAPInfo() {
|
||||
}
|
||||
|
||||
void espNotifyTagReturnData(uint8_t *src, uint8_t len) {
|
||||
struct tagReturnData *trd = (struct tagReturnData *)(radiorxbuffer + sizeof(struct MacFrameBcast) + 1); // oh how I'd love to pass this as an argument, but sdcc won't let me
|
||||
struct espTagReturnData *etrd = (struct espTagReturnData *)radiotxbuffer;
|
||||
struct tagReturnData *trd = (struct tagReturnData *)(radiorxbuffer + sizeof(struct MacFrameBcast) + 1); // oh how I'd love to pass this as an argument, but sdcc won't let me
|
||||
struct espTagReturnData *etrd = (struct espTagReturnData *)radiotxbuffer;
|
||||
|
||||
if (memcmp((void *) & trd->dataVer, lastTagReturn, 8) == 0) {
|
||||
return;
|
||||
} else {
|
||||
memcpy(lastTagReturn, &trd->dataVer, 8);
|
||||
}
|
||||
if (memcmp((void *) & trd->dataVer, lastTagReturn, 8) == 0) {
|
||||
return;
|
||||
} else {
|
||||
memcpy(lastTagReturn, &trd->dataVer, 8);
|
||||
}
|
||||
|
||||
memcpy(etrd->src, src, 8);
|
||||
etrd->len = len;
|
||||
memcpy(&etrd->returnData, trd, len);
|
||||
addCRC(etrd, len + 10);
|
||||
memcpy(etrd->src, src, 8);
|
||||
etrd->len = len;
|
||||
memcpy(&etrd->returnData, trd, len);
|
||||
addCRC(etrd, len + 10);
|
||||
|
||||
uartTx('T');
|
||||
uartTx('R');
|
||||
uartTx('D');
|
||||
uartTx('>');
|
||||
for (uint8_t c = 0; c < len + 10; c++) {
|
||||
uartTx(((uint8_t *)etrd)[c]);
|
||||
}
|
||||
uartTx('T');
|
||||
uartTx('R');
|
||||
uartTx('D');
|
||||
uartTx('>');
|
||||
for (uint8_t c = 0; c < len + 10; c++) {
|
||||
uartTx(((uint8_t *)etrd)[c]);
|
||||
}
|
||||
}
|
||||
|
||||
// process data from tag
|
||||
@@ -492,7 +492,7 @@ void processBlockRequest(const uint8_t *buffer, uint8_t forceBlockDownload) {
|
||||
if (blockStartTimer == 0) {
|
||||
if (requestDataDownload) {
|
||||
if (highspeedSerial == true) {
|
||||
blockRequestAck->pleaseWaitMs = 220;
|
||||
blockRequestAck->pleaseWaitMs = 140;
|
||||
} else {
|
||||
blockRequestAck->pleaseWaitMs = 550;
|
||||
}
|
||||
@@ -583,23 +583,23 @@ void processXferComplete(uint8_t *buffer) {
|
||||
}
|
||||
|
||||
void processTagReturnData(uint8_t *buffer, uint8_t len) {
|
||||
struct MacFrameBcast *rxframe = (struct MacFrameBcast *)buffer;
|
||||
struct MacFrameNormal *frameHeader = (struct MacFrameNormal *)(radiotxbuffer + 1);
|
||||
struct MacFrameBcast *rxframe = (struct MacFrameBcast *)buffer;
|
||||
struct MacFrameNormal *frameHeader = (struct MacFrameNormal *)(radiotxbuffer + 1);
|
||||
|
||||
if (!checkCRC((buffer + sizeof(struct MacFrameBcast) + 1), len - (sizeof(struct MacFrameBcast) + 1))) {
|
||||
return;
|
||||
}
|
||||
radiotxbuffer[sizeof(struct MacFrameNormal) + 1] = PKT_TAG_RETURN_DATA_ACK;
|
||||
radiotxbuffer[0] = sizeof(struct MacFrameNormal) + 1 + RAW_PKT_PADDING;
|
||||
memcpy(frameHeader->src, mSelfMac, 8);
|
||||
memcpy(frameHeader->dst, rxframe->src, 8);
|
||||
radiotxbuffer[1] = 0x41; // fast way to set the appropriate bits
|
||||
radiotxbuffer[2] = 0xCC; // normal frame
|
||||
frameHeader->seq = seq++;
|
||||
frameHeader->pan = rxframe->srcPan;
|
||||
radioTx(radiotxbuffer);
|
||||
if (!checkCRC((buffer + sizeof(struct MacFrameBcast) + 1), len - (sizeof(struct MacFrameBcast) + 1))) {
|
||||
return;
|
||||
}
|
||||
radiotxbuffer[sizeof(struct MacFrameNormal) + 1] = PKT_TAG_RETURN_DATA_ACK;
|
||||
radiotxbuffer[0] = sizeof(struct MacFrameNormal) + 1 + RAW_PKT_PADDING;
|
||||
memcpy(frameHeader->src, mSelfMac, 8);
|
||||
memcpy(frameHeader->dst, rxframe->src, 8);
|
||||
radiotxbuffer[1] = 0x41; // fast way to set the appropriate bits
|
||||
radiotxbuffer[2] = 0xCC; // normal frame
|
||||
frameHeader->seq = seq++;
|
||||
frameHeader->pan = rxframe->srcPan;
|
||||
radioTx(radiotxbuffer);
|
||||
|
||||
espNotifyTagReturnData(rxframe->src, len - (sizeof(struct MacFrameBcast) + 1));
|
||||
espNotifyTagReturnData(rxframe->src, len - (sizeof(struct MacFrameBcast) + 1));
|
||||
}
|
||||
|
||||
// send block data to the tag
|
||||
@@ -628,6 +628,18 @@ void sendBlockData() {
|
||||
pr("Invalid block request received, 0 parts..\n");
|
||||
requestedData.requestedParts[0] |= 0x01;
|
||||
}
|
||||
|
||||
pr("Sending parts:");
|
||||
for (uint8_t c = 0; (c < BLOCK_MAX_PARTS); c++) {
|
||||
if (c % 10 == 0) pr(" ");
|
||||
if (requestedData.requestedParts[c / 8] & (1 << (c % 8))) {
|
||||
pr("X");
|
||||
} else {
|
||||
pr(".");
|
||||
}
|
||||
}
|
||||
pr("\n");
|
||||
|
||||
uint8_t partNo = 0;
|
||||
while (partNo < BLOCK_MAX_PARTS) {
|
||||
for (uint8_t c = 0; (c < BLOCK_MAX_PARTS) && (partNo < BLOCK_MAX_PARTS); c++) {
|
||||
@@ -684,24 +696,24 @@ void sendPong(void *buf) {
|
||||
}
|
||||
|
||||
void app_main(void) {
|
||||
esp_event_loop_create_default();
|
||||
|
||||
esp_event_loop_create_default();
|
||||
|
||||
init_nvs();
|
||||
init_led();
|
||||
init_led();
|
||||
init_second_uart();
|
||||
|
||||
requestedData.blockId = 0xFF;
|
||||
// clear the array with pending information
|
||||
memset(pendingDataArr, 0, sizeof(pendingDataArr));
|
||||
|
||||
radio_init(curChannel);
|
||||
radio_init(curChannel);
|
||||
radioSetTxPower(10);
|
||||
|
||||
pr("RES>");
|
||||
pr("RDY>");
|
||||
ESP_LOGI(TAG, "C6 ready!");
|
||||
ESP_LOGI(TAG, "C6 ready!");
|
||||
|
||||
housekeepingTimer = getMillis();
|
||||
housekeepingTimer = getMillis();
|
||||
while (1) {
|
||||
while ((getMillis() - housekeepingTimer) < ((1000 * HOUSEKEEPING_INTERVAL) - 100)) {
|
||||
int8_t ret = commsRxUnencrypted(radiorxbuffer);
|
||||
@@ -741,11 +753,11 @@ void app_main(void) {
|
||||
processAvailDataReq(radiorxbuffer);
|
||||
}
|
||||
break;
|
||||
case PKT_TAG_RETURN_DATA:
|
||||
processTagReturnData(radiorxbuffer, ret);
|
||||
break;
|
||||
default:
|
||||
ESP_LOGI(TAG, "t=%02X" , getPacketType(radiorxbuffer));
|
||||
case PKT_TAG_RETURN_DATA:
|
||||
processTagReturnData(radiorxbuffer, ret);
|
||||
break;
|
||||
default:
|
||||
ESP_LOGI(TAG, "t=%02X" , getPacketType(radiorxbuffer));
|
||||
break;
|
||||
}
|
||||
} else if (blockStartTimer == 0) {
|
||||
@@ -763,8 +775,8 @@ void app_main(void) {
|
||||
}
|
||||
}
|
||||
|
||||
memset(&lastTagReturn, 0, 8);
|
||||
for (uint8_t cCount = 0; cCount < MAX_PENDING_MACS; cCount++) {
|
||||
memset(&lastTagReturn, 0, 8);
|
||||
for (uint8_t cCount = 0; cCount < MAX_PENDING_MACS; cCount++) {
|
||||
if (pendingDataArr[cCount].attemptsLeft == 1) {
|
||||
if (pendingDataArr[cCount].availdatainfo.dataType != DATATYPE_NOUPDATE) {
|
||||
espNotifyTimeOut(pendingDataArr[cCount].targetMac);
|
||||
|
||||
@@ -14,6 +14,8 @@
|
||||
#include "main.h"
|
||||
#include "proto.h"
|
||||
#include "sdkconfig.h"
|
||||
// if you get an error about soc/lp_uart_reg.h not being found,
|
||||
// you didn't choose the right build target. :-)
|
||||
#include "soc/lp_uart_reg.h"
|
||||
#include "soc/uart_struct.h"
|
||||
#include "utils.h"
|
||||
@@ -48,62 +50,62 @@ void esp_ieee802154_transmit_done(const uint8_t *frame, const uint8_t *ack, esp_
|
||||
}
|
||||
|
||||
void radio_init(uint8_t ch) {
|
||||
if (packet_buffer == NULL) packet_buffer = xQueueCreate(32, 130);
|
||||
if (packet_buffer == NULL) packet_buffer = xQueueCreate(32, 130);
|
||||
|
||||
// this will trigger a "IEEE802154 MAC sleep init failed" when called a second time, but it works
|
||||
esp_ieee802154_enable();
|
||||
esp_ieee802154_set_channel(ch);
|
||||
// esp_ieee802154_set_txpower(int8_t power);
|
||||
esp_ieee802154_set_panid(PROTO_PAN_ID);
|
||||
// this will trigger a "IEEE802154 MAC sleep init failed" when called a second time, but it works
|
||||
esp_ieee802154_enable();
|
||||
esp_ieee802154_set_channel(ch);
|
||||
// esp_ieee802154_set_txpower(int8_t power);
|
||||
esp_ieee802154_set_panid(PROTO_PAN_ID);
|
||||
esp_ieee802154_set_promiscuous(false);
|
||||
esp_ieee802154_set_coordinator(false);
|
||||
esp_ieee802154_set_pending_mode(ESP_IEEE802154_AUTO_PENDING_ZIGBEE);
|
||||
|
||||
// esp_ieee802154_set_extended_address needs the MAC in reversed byte order
|
||||
esp_read_mac(mSelfMac, ESP_MAC_IEEE802154);
|
||||
uint8_t eui64_rev[8] = {0};
|
||||
for (int i = 0; i < 8; i++) {
|
||||
eui64_rev[7 - i] = mSelfMac[i];
|
||||
}
|
||||
esp_ieee802154_set_extended_address(eui64_rev);
|
||||
esp_ieee802154_get_extended_address(mSelfMac);
|
||||
// esp_ieee802154_set_extended_address needs the MAC in reversed byte order
|
||||
esp_read_mac(mSelfMac, ESP_MAC_IEEE802154);
|
||||
uint8_t eui64_rev[8] = {0};
|
||||
for (int i = 0; i < 8; i++) {
|
||||
eui64_rev[7 - i] = mSelfMac[i];
|
||||
}
|
||||
esp_ieee802154_set_extended_address(eui64_rev);
|
||||
esp_ieee802154_get_extended_address(mSelfMac);
|
||||
|
||||
esp_ieee802154_set_short_address(0xFFFE);
|
||||
esp_ieee802154_set_short_address(0xFFFE);
|
||||
esp_ieee802154_set_rx_when_idle(true);
|
||||
esp_ieee802154_receive();
|
||||
|
||||
led_flash(1);
|
||||
vTaskDelay(100 / portTICK_PERIOD_MS);
|
||||
led_flash(0);
|
||||
vTaskDelay(100 / portTICK_PERIOD_MS);
|
||||
led_flash(1);
|
||||
vTaskDelay(100 / portTICK_PERIOD_MS);
|
||||
led_flash(0);
|
||||
led_flash(1);
|
||||
vTaskDelay(100 / portTICK_PERIOD_MS);
|
||||
led_flash(0);
|
||||
vTaskDelay(100 / portTICK_PERIOD_MS);
|
||||
led_flash(1);
|
||||
vTaskDelay(100 / portTICK_PERIOD_MS);
|
||||
led_flash(0);
|
||||
|
||||
ESP_LOGI(TAG, "Receiver ready, panId=0x%04x, channel=%d, long=%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x, short=%04x",
|
||||
esp_ieee802154_get_panid(), esp_ieee802154_get_channel(),
|
||||
mSelfMac[0], mSelfMac[1], mSelfMac[2], mSelfMac[3],
|
||||
mSelfMac[4], mSelfMac[5], mSelfMac[6], mSelfMac[7],
|
||||
esp_ieee802154_get_short_address());
|
||||
ESP_LOGI(TAG, "Receiver ready, panId=0x%04x, channel=%d, long=%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x, short=%04x",
|
||||
esp_ieee802154_get_panid(), esp_ieee802154_get_channel(),
|
||||
mSelfMac[0], mSelfMac[1], mSelfMac[2], mSelfMac[3],
|
||||
mSelfMac[4], mSelfMac[5], mSelfMac[6], mSelfMac[7],
|
||||
esp_ieee802154_get_short_address());
|
||||
}
|
||||
|
||||
uint32_t lastZbTx = 0;
|
||||
// uint32_t lastZbTx = 0;
|
||||
bool radioTx(uint8_t *packet) {
|
||||
static uint8_t txPKT[130];
|
||||
while (isInTransmit) {
|
||||
}
|
||||
while (getMillis() - lastZbTx < 6) {
|
||||
}
|
||||
led_flash(1);
|
||||
memcpy(txPKT, packet, packet[0]);
|
||||
isInTransmit = 1;
|
||||
lastZbTx = getMillis();
|
||||
esp_ieee802154_transmit(txPKT, false);
|
||||
return true;
|
||||
while (isInTransmit) {
|
||||
}
|
||||
// while (getMillis() - lastZbTx < 6) {
|
||||
// }
|
||||
// lastZbTx = getMillis();
|
||||
memcpy(txPKT, packet, packet[0]);
|
||||
isInTransmit = 1;
|
||||
esp_ieee802154_transmit(txPKT, false);
|
||||
return true;
|
||||
}
|
||||
|
||||
void radioSetChannel(uint8_t ch) {
|
||||
radio_init(ch);
|
||||
radio_init(ch);
|
||||
}
|
||||
|
||||
void radioSetTxPower(uint8_t power) {}
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
#include "sdkconfig.h"
|
||||
#include "soc/uart_struct.h"
|
||||
#include "soc/lp_uart_reg.h"
|
||||
#include "second_uart.h"
|
||||
|
||||
static const char *TAG = "SECOND_UART";
|
||||
|
||||
@@ -32,9 +33,6 @@ volatile int curr_buff_pos = 0;
|
||||
volatile int worked_buff_pos = 0;
|
||||
volatile uint8_t buff_pos[MAX_BUFF_POS + 5];
|
||||
|
||||
#define S3_TX_PIN 3
|
||||
#define S3_RX_PIN 2
|
||||
|
||||
static void uart_event_task(void *pvParameters);
|
||||
void init_second_uart() {
|
||||
uart_config_t uart_config = {
|
||||
@@ -47,7 +45,7 @@ void init_second_uart() {
|
||||
};
|
||||
ESP_ERROR_CHECK(uart_driver_install(1, BUF_SIZE * 2, BUF_SIZE * 2, 20, &uart0_queue, 0));
|
||||
ESP_ERROR_CHECK(uart_param_config(1, &uart_config));
|
||||
ESP_ERROR_CHECK(uart_set_pin(1, S3_TX_PIN, S3_RX_PIN, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE));
|
||||
ESP_ERROR_CHECK(uart_set_pin(1, CONFIG_OEPL_HARDWARE_UART_TX, CONFIG_OEPL_HARDWARE_UART_RX, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE));
|
||||
|
||||
xTaskCreate(uart_event_task, "uart_event_task", 16384, NULL, 12, NULL);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <inttypes.h>
|
||||
|
||||
void init_second_uart();
|
||||
void uart_switch_speed(int baudrate);
|
||||
|
||||
@@ -9,3 +11,15 @@ bool getRxCharSecond(uint8_t *newChar);
|
||||
void uart_printf(const char *format, ...);
|
||||
|
||||
#define pr uart_printf
|
||||
|
||||
#if defined(CONFIG_OEPL_HARDWARE_PROFILE_DEFAULT)
|
||||
#define CONFIG_OEPL_HARDWARE_UART_TX 3
|
||||
#define CONFIG_OEPL_HARDWARE_UART_RX 2
|
||||
#elif defined(CONFIG_OEPL_HARDWARE_PROFILE_POE_AP)
|
||||
#define CONFIG_OEPL_HARDWARE_UART_TX 5
|
||||
#define CONFIG_OEPL_HARDWARE_UART_RX 18
|
||||
#elif defined(CONFIG_OEPL_HARDWARE_PROFILE_CUSTOM)
|
||||
#if !defined(CONFIG_OEPL_HARDWARE_UART_TX) || !defined(CONFIG_OEPL_HARDWARE_UART_RX)
|
||||
#error "No UART TX / RX pins defined. Please check menuconfig"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
8
ARM_Tag_FW/OpenEPaperLink_esp32_C6_AP/sdkconfig.defaults
Normal file
8
ARM_Tag_FW/OpenEPaperLink_esp32_C6_AP/sdkconfig.defaults
Normal file
@@ -0,0 +1,8 @@
|
||||
# This file was generated using idf.py save-defconfig. It can be edited manually.
|
||||
# Espressif IoT Development Framework (ESP-IDF) Project Minimal Configuration
|
||||
#
|
||||
CONFIG_IDF_TARGET="esp32c6"
|
||||
CONFIG_ESPTOOLPY_FLASHMODE_QIO=y
|
||||
CONFIG_ESPTOOLPY_FLASHSIZE_4MB=y
|
||||
CONFIG_ESPTOOLPY_HEADER_FLASHSIZE_UPDATE=y
|
||||
CONFIG_PARTITION_TABLE_CUSTOM=y
|
||||
4
ESP32_AP-Flasher/.vscode/settings.json
vendored
4
ESP32_AP-Flasher/.vscode/settings.json
vendored
@@ -50,6 +50,8 @@
|
||||
"stdexcept": "cpp",
|
||||
"streambuf": "cpp",
|
||||
"cinttypes": "cpp",
|
||||
"typeinfo": "cpp"
|
||||
"typeinfo": "cpp",
|
||||
"chrono": "cpp",
|
||||
"ratio": "cpp"
|
||||
}
|
||||
}
|
||||
8
ESP32_AP-Flasher/16MB_partition table.csv
Normal file
8
ESP32_AP-Flasher/16MB_partition table.csv
Normal file
@@ -0,0 +1,8 @@
|
||||
# Name, Type, SubType, Offset, Size, Flags
|
||||
nvs, data, nvs, 0x9000, 0x4000
|
||||
otadata, data, ota, 0xD000, 0x2000
|
||||
phy_init, data, phy, 0xF000, 0x1000
|
||||
app0, app, ota_0, 0x10000, 0x200000
|
||||
app1, app, ota_1, 0x210000, 0x200000
|
||||
spiffs, data, spiffs, 0x410000, 0xBE0000
|
||||
coredump, data, coredump, 0xFF0000, 0x10000
|
||||
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -19,6 +19,7 @@ class SPIFFSEditor: public AsyncWebHandler {
|
||||
virtual void handleRequest(AsyncWebServerRequest *request) override final;
|
||||
virtual void handleUpload(AsyncWebServerRequest *request, const String& filename, size_t index, uint8_t *data, size_t len, bool final) override final;
|
||||
virtual bool isRequestHandlerTrivial() override final {return false;}
|
||||
virtual String listFilesRecursively(String path, bool recursive = false);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -28,6 +28,8 @@ void setBrightness(int brightness);
|
||||
void updateBrightnessFromConfig();
|
||||
|
||||
#ifdef HAS_RGB_LED
|
||||
extern CRGB rgbIdleColor;
|
||||
extern uint16_t rgbIdlePeriod;
|
||||
void shortBlink(CRGB cname);
|
||||
void showColorPattern(CRGB colorone, CRGB colortwo, CRGB colorthree);
|
||||
void rgbIdle();
|
||||
|
||||
@@ -24,10 +24,14 @@ struct imgParam {
|
||||
|
||||
char segments[12];
|
||||
uint16_t symbols;
|
||||
bool invert;
|
||||
uint8_t invert;
|
||||
|
||||
uint8_t lut;
|
||||
uint8_t shortlut;
|
||||
|
||||
bool preload;
|
||||
uint8_t preloadtype;
|
||||
uint8_t preloadlut;
|
||||
};
|
||||
|
||||
void spr2buffer(TFT_eSprite &spr, String &fileout, imgParam &imageParams);
|
||||
|
||||
@@ -33,4 +33,5 @@ void APEnterEarlyReset();
|
||||
bool sendChannelPower(struct espSetChannelPower* scp);
|
||||
void rxSerialTask2(void* parameter);
|
||||
void APTagReset();
|
||||
bool bringAPOnline();
|
||||
bool bringAPOnline();
|
||||
void setAPstate(bool isOnline, uint8_t state);
|
||||
@@ -27,7 +27,7 @@ class DynStorage {
|
||||
void begin();
|
||||
void end();
|
||||
void listFiles();
|
||||
size_t freeSpace();
|
||||
uint64_t freeSpace();
|
||||
|
||||
private:
|
||||
bool isInited;
|
||||
|
||||
@@ -12,5 +12,5 @@
|
||||
|
||||
void initTime(void* parameter);
|
||||
void logLine(const char* buffer);
|
||||
void logLine(String text);
|
||||
void logLine(const String& text);
|
||||
void logStartUp();
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
|
||||
class tagRecord {
|
||||
public:
|
||||
tagRecord() : mac{0}, alias(""), lastseen(0), nextupdate(0), contentMode(0), pending(false), md5{0}, md5pending{0}, expectedNextCheckin(0), modeConfigJson(""), LQI(0), RSSI(0), temperature(0), batteryMv(0), hwType(0), wakeupReason(0), capabilities(0), lastfullupdate(0), isExternal(false), apIp(IPAddress(0, 0, 0, 0)), pendingIdle(0), hasCustomLUT(false), rotate(0), lut(0), tagSoftwareVersion(0), currentChannel(0), dataType(0), filename(""), data(nullptr), len(0) {}
|
||||
tagRecord() : mac{0}, alias(""), lastseen(0), nextupdate(0), contentMode(0), pending(false), md5{0}, md5pending{0}, expectedNextCheckin(0), modeConfigJson(""), LQI(0), RSSI(0), temperature(0), batteryMv(0), hwType(0), wakeupReason(0), capabilities(0), lastfullupdate(0), isExternal(false), apIp(IPAddress(0, 0, 0, 0)), pendingIdle(0), hasCustomLUT(false), rotate(0), lut(0), tagSoftwareVersion(0), currentChannel(0), dataType(0), filename(""), data(nullptr), len(0), invert(0) {}
|
||||
|
||||
uint8_t mac[8];
|
||||
String alias;
|
||||
@@ -49,6 +49,7 @@ class tagRecord {
|
||||
uint8_t lut;
|
||||
uint16_t tagSoftwareVersion;
|
||||
uint8_t currentChannel;
|
||||
uint8_t invert;
|
||||
|
||||
uint8_t dataType;
|
||||
String filename;
|
||||
@@ -62,6 +63,7 @@ struct Config {
|
||||
uint8_t channel;
|
||||
char alias[32];
|
||||
int16_t led;
|
||||
uint8_t tft;
|
||||
uint8_t language;
|
||||
uint8_t maxsleep;
|
||||
uint8_t stopsleep;
|
||||
@@ -71,6 +73,8 @@ struct Config {
|
||||
char timeZone[52];
|
||||
uint8_t sleepTime1;
|
||||
uint8_t sleepTime2;
|
||||
String repo;
|
||||
String env;
|
||||
};
|
||||
|
||||
struct HwType {
|
||||
@@ -90,7 +94,6 @@ extern Config config;
|
||||
extern std::vector<tagRecord*> tagDB;
|
||||
extern std::unordered_map<int, HwType> hwtype;
|
||||
extern std::unordered_map<std::string, varStruct> varDB;
|
||||
extern DynamicJsonDocument APconfig;
|
||||
extern String tagDBtoJson(const uint8_t mac[8] = nullptr, uint8_t startPos = 0);
|
||||
extern bool deleteRecord(const uint8_t mac[8]);
|
||||
extern void fillNode(JsonObject& tag, const tagRecord* taginfo);
|
||||
@@ -105,7 +108,14 @@ extern void clearPending(tagRecord* taginfo);
|
||||
extern void initAPconfig();
|
||||
extern void saveAPconfig();
|
||||
extern HwType getHwType(const uint8_t id);
|
||||
extern bool setVarDB(const std::string& key, const String& value);
|
||||
/// @brief Update a variable with the given key and value
|
||||
///
|
||||
/// @param key Variable key
|
||||
/// @param value Variable value
|
||||
/// @param notify Should the change be notified (true, default) or not (false)
|
||||
/// @return true If variable was created/updated
|
||||
/// @return false If not
|
||||
extern bool setVarDB(const std::string& key, const String& value, const bool notify = true);
|
||||
extern void cleanupCurrent();
|
||||
|
||||
#pragma pack(pop)
|
||||
|
||||
140
ESP32_AP-Flasher/include/tagdata.h
Normal file
140
ESP32_AP-Flasher/include/tagdata.h
Normal file
@@ -0,0 +1,140 @@
|
||||
/// @file tagdata.h
|
||||
/// @author Moritz Wirger (contact@wirmo.de)
|
||||
/// @brief Custom tag data parser and helpers
|
||||
#pragma once
|
||||
|
||||
#include <Arduino.h>
|
||||
#include <ArduinoJson.h>
|
||||
|
||||
#include <optional>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
#include "storage.h"
|
||||
#include "system.h"
|
||||
#include "web.h"
|
||||
|
||||
/// @brief Functions for custom tag data parser
|
||||
namespace TagData {
|
||||
|
||||
/// @brief All available data types
|
||||
enum class Type {
|
||||
/// @brief Signed integer type
|
||||
INT,
|
||||
/// @brief Unsigned integer type
|
||||
UINT,
|
||||
/// @brief Float type
|
||||
FLOAT,
|
||||
/// @brief String type
|
||||
STRING,
|
||||
|
||||
/// @brief Not a type, just a helper to determine max type
|
||||
MAX,
|
||||
};
|
||||
|
||||
/// @brief Field that can be parsed
|
||||
struct Field {
|
||||
/// @brief Field name
|
||||
String name;
|
||||
/// @brief Field type
|
||||
Type type;
|
||||
/// @brief Field byte length
|
||||
uint8_t length;
|
||||
/// @brief Number of decimals numeric types
|
||||
uint8_t decimals;
|
||||
/// @brief Optional multiplication
|
||||
std::optional<double> mult;
|
||||
|
||||
Field(const String &name, const Type type, const uint8_t length, uint8_t decimals = 0, std::optional<double> mult = std::nullopt)
|
||||
: name(name), type(type), length(length), decimals(decimals), mult(mult) {}
|
||||
};
|
||||
|
||||
/// @brief Parser for parsing custom tag data
|
||||
struct Parser {
|
||||
/// @brief Parser name
|
||||
String name;
|
||||
/// @brief Parsed fields
|
||||
std::vector<Field> fields = {};
|
||||
};
|
||||
|
||||
/// @brief Maps parser id to parser
|
||||
extern std::unordered_map<size_t, Parser> parsers;
|
||||
|
||||
/// @brief Load all parsers from the given json file
|
||||
/// @param filename File name
|
||||
extern void loadParsers(const String &filename);
|
||||
|
||||
/// @brief Parse the incoming custom message
|
||||
/// @param src Source mac address
|
||||
/// @param id Message identifier
|
||||
/// @param data Payload
|
||||
/// @param len Payload length
|
||||
extern void parse(const uint8_t src[8], const size_t id, const uint8_t *data, const uint8_t len);
|
||||
|
||||
/// @brief Convert the given byte array @ref data with given @ref length to an unsigned integer
|
||||
///
|
||||
/// Will also convert non standard integer sizes (e.g. 3, 5, 6, and 7 bytes)
|
||||
/// @tparam T Unsigned integer type
|
||||
/// @param data Byte array
|
||||
/// @param length Length of byte array
|
||||
/// @return Unsigned integer
|
||||
template <typename T, std::enable_if_t<std::is_unsigned_v<T> && std::is_integral_v<T>, bool> = true>
|
||||
inline T bytesTo(const uint8_t *data, const uint8_t length) {
|
||||
T value = 0;
|
||||
for (int i = 0; i < length; i++) {
|
||||
value |= (data[i] & 0xFF) << (8 * i);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
/// @brief Convert the given byte array @ref data with given @ref length to a signed integer
|
||||
///
|
||||
/// Will also convert non standard integer sizes (e.g. 3, 5, 6, and 7 bytes)
|
||||
/// @tparam T Signed integer type
|
||||
/// @param data Byte array
|
||||
/// @param length Length of byte array
|
||||
/// @return Signed integer
|
||||
template <typename T, std::enable_if_t<std::is_signed_v<T> && std::is_integral_v<T>, bool> = true>
|
||||
inline T bytesTo(const uint8_t *data, const uint8_t length) {
|
||||
T value = 0;
|
||||
for (int i = 0; i < length; ++i) {
|
||||
value |= (data[i] & 0xFF) << (8 * i);
|
||||
}
|
||||
|
||||
// If data is smaller than T and last byte is negative set all upper bytes negative
|
||||
if (length < sizeof(T) && (data[length - 1] & 0x80) != 0) {
|
||||
value |= ~((1 << (length * 8)) - 1);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
/// @brief Convert the given byte array to a float/double
|
||||
/// @param data Byte array, should be at least 4/8 bytes long
|
||||
/// @param length Length of byte array
|
||||
/// @return float/double
|
||||
template <typename T, std::enable_if_t<std::is_floating_point_v<T>, bool> = true>
|
||||
inline T bytesTo(const uint8_t *data, const uint8_t length) {
|
||||
const size_t len = sizeof(T) < length ? sizeof(T) : length;
|
||||
T value;
|
||||
memcpy(&value, data, len);
|
||||
return value;
|
||||
}
|
||||
|
||||
/// @brief Convert the given byte array to a string
|
||||
/// @param data Byte array representing a string
|
||||
/// @param length Length of byte array
|
||||
/// @return String
|
||||
template <typename T, std::enable_if_t<std::is_same_v<T, String>, bool> = true>
|
||||
inline T bytesTo(const uint8_t *data, int length) {
|
||||
return T(data, length);
|
||||
}
|
||||
|
||||
/// @brief Convert the given byte array to a string
|
||||
/// @param data Byte array representing a string
|
||||
/// @param length Length of byte array
|
||||
/// @return std::string
|
||||
template <typename T, std::enable_if_t<std::is_same_v<T, std::string>, bool> = true>
|
||||
inline T bytesTo(const uint8_t *data, int length) {
|
||||
return T(data, data + length);
|
||||
}
|
||||
} // namespace TagData
|
||||
@@ -4,8 +4,10 @@
|
||||
#include <ArduinoJson.h>
|
||||
#include <HTTPClient.h>
|
||||
|
||||
#include "system.h"
|
||||
#include "web.h"
|
||||
|
||||
/// @brief Different utility functions
|
||||
namespace util {
|
||||
|
||||
/// @brief Can be used to wrap a stream and see what's going on
|
||||
@@ -72,6 +74,7 @@ static void printLargestFreeBlock() {
|
||||
static bool httpGetJson(String &url, JsonDocument &json, const uint16_t timeout, JsonDocument *filter = nullptr) //, const followRedirects_t redirects = followRedirects_t::HTTPC_DISABLE_FOLLOW_REDIRECTS)
|
||||
{
|
||||
HTTPClient http;
|
||||
logLine("http httpGetJson " + url);
|
||||
http.begin(url);
|
||||
http.setTimeout(timeout);
|
||||
// http.setFollowRedirects(redirects);
|
||||
@@ -100,7 +103,7 @@ static bool httpGetJson(String &url, JsonDocument &json, const uint16_t timeout,
|
||||
///
|
||||
/// @param str String to check
|
||||
/// @return True if empty or null, false if not
|
||||
static inline bool isEmptyOrNull(const String &str) {
|
||||
inline bool isEmptyOrNull(const String &str) {
|
||||
return str.isEmpty() || str == "null";
|
||||
}
|
||||
|
||||
@@ -123,26 +126,68 @@ static bool isSleeping(int sleeptime1, int sleeptime2) {
|
||||
}
|
||||
}
|
||||
|
||||
/// @brief Get the time_t for midnight
|
||||
/// @return time_t for midnight
|
||||
inline time_t getMidnightTime() {
|
||||
struct tm time_info;
|
||||
getLocalTime(&time_info);
|
||||
time_info.tm_hour = time_info.tm_min = time_info.tm_sec = 0;
|
||||
time_info.tm_mday++;
|
||||
return mktime(&time_info);
|
||||
}
|
||||
|
||||
/// @brief Timer for kind of scheduling things
|
||||
class Timer {
|
||||
public:
|
||||
Timer(unsigned long interval) : interval_(interval), previousMillis_(0) {}
|
||||
/// @brief Construct a timer
|
||||
/// @param interval Interval in ms at which @ref doRun() returns true
|
||||
/// @param delay Delay in ms until first execution to defer start
|
||||
Timer(const unsigned long interval, const unsigned long delay = 0) : m_interval(interval), m_nextMillis(millis() + delay) {}
|
||||
|
||||
void setInterval(unsigned long interval) {
|
||||
interval_ = interval;
|
||||
/// @brief Change the interval
|
||||
/// @param interval New interval in ms
|
||||
void setInterval(const unsigned long interval) {
|
||||
m_interval = interval;
|
||||
}
|
||||
|
||||
bool doRun() {
|
||||
unsigned long currentMillis = millis();
|
||||
if (currentMillis - previousMillis_ >= interval_) {
|
||||
previousMillis_ = currentMillis;
|
||||
/// @brief Check if interval is met
|
||||
/// @param currentMillis Optionally provide the current time in millis
|
||||
/// @return True if interval is met, false if not
|
||||
bool doRun(const unsigned long currentMillis = millis()) {
|
||||
if (currentMillis >= m_nextMillis) {
|
||||
m_nextMillis = currentMillis + m_interval;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private:
|
||||
unsigned long interval_;
|
||||
unsigned long previousMillis_;
|
||||
/// @brief Timer interval in ms
|
||||
unsigned long m_interval;
|
||||
/// @brief Next timeer interval in ms
|
||||
unsigned long m_nextMillis;
|
||||
};
|
||||
|
||||
/// @brief Create a String from format
|
||||
/// @param buffer Buffer to use for sprintf
|
||||
/// @param format String format
|
||||
/// @return String
|
||||
template <size_t bufSize>
|
||||
inline String formatString(char buffer[bufSize], const char *format, ...) {
|
||||
va_list args;
|
||||
|
||||
va_start(args, format);
|
||||
const size_t size = vsnprintf(buffer, bufSize, format, args);
|
||||
va_end(args);
|
||||
|
||||
return String(buffer, size);
|
||||
}
|
||||
|
||||
} // namespace util
|
||||
|
||||
/// @brief Converts seconds to milliseconds
|
||||
#define seconds(s) s * 1000
|
||||
/// @brief Converts minutes to milliseconds
|
||||
#define minutes(m) seconds(m * 60)
|
||||
/// @brief Converts hours to milliseconds
|
||||
#define hours(m) minutes(m * 60)
|
||||
|
||||
@@ -6,12 +6,12 @@
|
||||
void init_web();
|
||||
void doImageUpload(AsyncWebServerRequest *request, String filename, size_t index, uint8_t *data, size_t len, bool final);
|
||||
void doJsonUpload(AsyncWebServerRequest *request);
|
||||
void wsLog(String text);
|
||||
void wsErr(String text);
|
||||
void wsLog(const String &text);
|
||||
void wsErr(const String &text);
|
||||
void wsSendTaginfo(const uint8_t *mac, uint8_t syncMode);
|
||||
void wsSendSysteminfo();
|
||||
void wsSendAPitem(struct APlist *apitem);
|
||||
void wsSerial(String text);
|
||||
void wsSerial(const String &text);
|
||||
uint8_t wsClientCount();
|
||||
|
||||
extern AsyncWebSocket ws;
|
||||
|
||||
@@ -26,7 +26,10 @@ board_build.filesystem = littlefs
|
||||
monitor_filters = esp32_exception_decoder
|
||||
monitor_speed = 115200
|
||||
board_build.f_cpu = 240000000L
|
||||
build_unflags =
|
||||
-std=gnu++11
|
||||
build_flags =
|
||||
-std=gnu++17
|
||||
-D BUILD_ENV_NAME=$PIOENV
|
||||
-D BUILD_TIME=$UNIX_TIME
|
||||
-D USER_SETUP_LOADED
|
||||
@@ -42,8 +45,10 @@ platform = https://github.com/platformio/platform-espressif32.git
|
||||
board=lolin_s2_mini
|
||||
board_build.partitions = default.csv
|
||||
build_unflags =
|
||||
-D CONFIG_MBEDTLS_INTERNAL_MEM_ALLOC=y
|
||||
-std=gnu++11
|
||||
-D CONFIG_MBEDTLS_INTERNAL_MEM_ALLOC=y
|
||||
build_flags =
|
||||
-std=gnu++17
|
||||
${env.build_flags}
|
||||
-D OPENEPAPERLINK_MINI_AP_PCB
|
||||
-D ARDUINO_USB_MODE=0
|
||||
@@ -64,7 +69,7 @@ build_flags =
|
||||
-D FLASHER_LED=15
|
||||
-D FLASHER_RGB_LED=33
|
||||
build_src_filter =
|
||||
+<*>-<usbflasher.cpp>-<swd.cpp>-<espflasher.cpp>
|
||||
+<*>-<usbflasher.cpp>-<swd.cpp>-<espflasher.cpp>
|
||||
board_build.psram_type=qspi_opi
|
||||
board_upload.maximum_size = 4194304
|
||||
board_upload.maximum_ram_size = 327680
|
||||
@@ -79,8 +84,10 @@ platform = https://github.com/platformio/platform-espressif32.git
|
||||
board=lolin_s2_mini
|
||||
board_build.partitions = default.csv
|
||||
build_unflags =
|
||||
-D CONFIG_MBEDTLS_INTERNAL_MEM_ALLOC=y
|
||||
-std=gnu++11
|
||||
-D CONFIG_MBEDTLS_INTERNAL_MEM_ALLOC=y
|
||||
build_flags =
|
||||
-std=gnu++17
|
||||
${env.build_flags}
|
||||
-D OPENEPAPERLINK_NANO_AP_PCB
|
||||
-D ARDUINO_USB_MODE=0
|
||||
@@ -99,7 +106,7 @@ build_flags =
|
||||
-D FLASHER_LED=15
|
||||
-D FLASHER_RGB_LED=-1
|
||||
build_src_filter =
|
||||
+<*>-<usbflasher.cpp>-<swd.cpp>-<espflasher.cpp>
|
||||
+<*>-<usbflasher.cpp>-<swd.cpp>-<espflasher.cpp>
|
||||
board_build.psram_type=qspi_opi
|
||||
board_upload.maximum_size = 4194304
|
||||
board_upload.maximum_ram_size = 327680
|
||||
@@ -114,9 +121,11 @@ platform = https://github.com/platformio/platform-espressif32.git
|
||||
board = esp32-s3-devkitc-1
|
||||
board_build.partitions = default_16MB.csv
|
||||
build_unflags =
|
||||
-D ARDUINO_USB_MODE=1
|
||||
-D CONFIG_MBEDTLS_INTERNAL_MEM_ALLOC=y
|
||||
-std=gnu++11
|
||||
-D ARDUINO_USB_MODE=1
|
||||
-D CONFIG_MBEDTLS_INTERNAL_MEM_ALLOC=y
|
||||
build_flags =
|
||||
-std=gnu++17
|
||||
${env.build_flags}
|
||||
-D OPENEPAPERLINK_PCB
|
||||
-D ARDUINO_USB_MODE=0
|
||||
@@ -158,7 +167,7 @@ build_flags =
|
||||
-D FLASHER_LED=21
|
||||
-D FLASHER_RGB_LED=48
|
||||
build_src_filter =
|
||||
+<*>-<espflasher.cpp>
|
||||
+<*>-<espflasher.cpp>
|
||||
board_build.flash_mode=qio
|
||||
board_build.arduino.memory_type = qio_opi
|
||||
board_build.psram_type=qspi_opi
|
||||
@@ -173,7 +182,10 @@ board_upload.flash_size = 16MB
|
||||
[env:Simple_AP]
|
||||
board = esp32dev
|
||||
board_build.partitions = default.csv
|
||||
build_unflags =
|
||||
-std=gnu++11
|
||||
build_flags =
|
||||
-std=gnu++17
|
||||
${env.build_flags}
|
||||
-D CORE_DEBUG_LEVEL=0
|
||||
-D SIMPLE_AP
|
||||
@@ -188,7 +200,7 @@ build_flags =
|
||||
-D FLASHER_AP_RXD=16
|
||||
-D FLASHER_LED=22
|
||||
build_src_filter =
|
||||
+<*>-<usbflasher.cpp>-<swd.cpp>-<espflasher.cpp>
|
||||
+<*>-<usbflasher.cpp>-<swd.cpp>-<espflasher.cpp>
|
||||
|
||||
; ----------------------------------------------------------------------------------------
|
||||
; !!! this configuration expects an wemos_d1_mini32
|
||||
@@ -197,7 +209,10 @@ build_src_filter =
|
||||
[env:Wemos_d1_mini32_AP]
|
||||
board = wemos_d1_mini32
|
||||
board_build.partitions = default.csv
|
||||
build_unflags =
|
||||
-std=gnu++11
|
||||
build_flags =
|
||||
-std=gnu++17
|
||||
${env.build_flags}
|
||||
-D CORE_DEBUG_LEVEL=0
|
||||
|
||||
@@ -214,7 +229,7 @@ build_flags =
|
||||
-D FLASHER_AP_RXD=17
|
||||
-D FLASHER_LED=22
|
||||
build_src_filter =
|
||||
+<*>-<usbflasher.cpp>-<swd.cpp>-<espflasher.cpp>
|
||||
+<*>-<usbflasher.cpp>-<swd.cpp>-<espflasher.cpp>
|
||||
|
||||
; ----------------------------------------------------------------------------------------
|
||||
; !!! this configuration expects an m5stack esp32
|
||||
@@ -224,7 +239,10 @@ build_src_filter =
|
||||
platform = espressif32
|
||||
board = m5stack-core-esp32
|
||||
board_build.partitions = esp32_sdcard.csv
|
||||
build_unflags =
|
||||
-std=gnu++11
|
||||
build_flags =
|
||||
-std=gnu++17
|
||||
${env.build_flags}
|
||||
-D CORE_DEBUG_LEVEL=0
|
||||
|
||||
@@ -251,7 +269,7 @@ build_flags =
|
||||
-D ILI9341_DRIVER
|
||||
-D SMOOTH_FONT
|
||||
build_src_filter =
|
||||
+<*>-<usbflasher.cpp>-<swd.cpp>-<espflasher.cpp>
|
||||
+<*>-<usbflasher.cpp>-<swd.cpp>-<espflasher.cpp>
|
||||
; ----------------------------------------------------------------------------------------
|
||||
; !!! this configuration expects an ESP32-S3 16MB Flash 8MB RAM
|
||||
;
|
||||
@@ -260,12 +278,14 @@ build_src_filter =
|
||||
board = esp32-s3-devkitc-1
|
||||
board_build.partitions = large_spiffs_16MB.csv
|
||||
build_unflags =
|
||||
-std=gnu++11
|
||||
-D ARDUINO_USB_MODE=1
|
||||
-D CONFIG_MBEDTLS_INTERNAL_MEM_ALLOC=y
|
||||
-D ILI9341_DRIVER
|
||||
lib_deps =
|
||||
${env.lib_deps}
|
||||
build_flags =
|
||||
-std=gnu++17
|
||||
${env.build_flags}
|
||||
-D YELLOW_IPS_AP
|
||||
-D CORE_DEBUG_LEVEL=0
|
||||
@@ -307,7 +327,7 @@ build_flags =
|
||||
-D SERIAL_FLASHER_BOOT_HOLD_TIME_MS=50
|
||||
-D SERIAL_FLASHER_RESET_HOLD_TIME_MS=100
|
||||
build_src_filter =
|
||||
+<*>-<usbflasher.cpp>-<swd.cpp>
|
||||
+<*>-<usbflasher.cpp>-<swd.cpp>
|
||||
board_build.flash_mode=qio
|
||||
board_build.arduino.memory_type = qio_opi
|
||||
board_build.psram_type=qspi_opi
|
||||
@@ -321,7 +341,10 @@ board_upload.flash_size = 16MB
|
||||
[env:Sonoff_zb_bridge_P_AP]
|
||||
board = esp32dev
|
||||
board_build.partitions = default.csv
|
||||
build_unflags =
|
||||
-std=gnu++11
|
||||
build_flags =
|
||||
-std=gnu++17
|
||||
${env.build_flags}
|
||||
-D CORE_DEBUG_LEVEL=0
|
||||
|
||||
@@ -340,7 +363,7 @@ build_flags =
|
||||
-D FLASHER_AP_RXD=23
|
||||
-D FLASHER_LED=2
|
||||
build_src_filter =
|
||||
+<*>-<usbflasher.cpp>-<swd.cpp>-<espflasher.cpp>
|
||||
+<*>-<usbflasher.cpp>-<swd.cpp>-<espflasher.cpp>
|
||||
board_build.psram_type=qspi_opi
|
||||
board_upload.maximum_size = 4194304
|
||||
board_upload.maximum_ram_size = 327680
|
||||
@@ -354,8 +377,10 @@ platform = https://github.com/platformio/platform-espressif32.git
|
||||
board=lolin_s2_mini
|
||||
board_build.partitions = default.csv
|
||||
build_unflags =
|
||||
-D CONFIG_MBEDTLS_INTERNAL_MEM_ALLOC=y
|
||||
-std=gnu++11
|
||||
-D CONFIG_MBEDTLS_INTERNAL_MEM_ALLOC=y
|
||||
build_flags =
|
||||
-std=gnu++17
|
||||
${env.build_flags}
|
||||
-D OPENEPAPERLINK_MINI_AP_PCB
|
||||
-D ARDUINO_USB_MODE=0
|
||||
@@ -375,7 +400,7 @@ build_flags =
|
||||
-D FLASHER_LED=2
|
||||
-D FLASHER_RGB_LED=-1
|
||||
build_src_filter =
|
||||
+<*>-<usbflasher.cpp>-<swd.cpp>-<espflasher.cpp>
|
||||
+<*>-<usbflasher.cpp>-<swd.cpp>-<espflasher.cpp>
|
||||
board_build.psram_type=qspi_opi
|
||||
board_upload.maximum_size = 4194304
|
||||
board_upload.maximum_ram_size = 327680
|
||||
@@ -389,9 +414,11 @@ board_upload.flash_size = 4MB
|
||||
board = esp32-s3-devkitc-1
|
||||
board_build.partitions = 32MB_partition table.csv
|
||||
build_unflags =
|
||||
-D ARDUINO_USB_MODE=1
|
||||
-D CONFIG_MBEDTLS_INTERNAL_MEM_ALLOC=y
|
||||
-std=gnu++11
|
||||
-D ARDUINO_USB_MODE=1
|
||||
-D CONFIG_MBEDTLS_INTERNAL_MEM_ALLOC=y
|
||||
build_flags =
|
||||
-std=gnu++17
|
||||
${env.build_flags}
|
||||
-D OutdoorAP
|
||||
-D HAS_RGB_LED
|
||||
@@ -414,7 +441,7 @@ build_flags =
|
||||
-D FLASHER_LED=21
|
||||
-D FLASHER_RGB_LED=38
|
||||
build_src_filter =
|
||||
+<*>-<usbflasher.cpp>-<swd.cpp>-<espflasher.cpp>
|
||||
+<*>-<usbflasher.cpp>-<swd.cpp>-<espflasher.cpp>
|
||||
board_build.flash_mode=opi
|
||||
board_build.arduino.memory_type = opi_opi
|
||||
board_build.psram_type=qspi_opi
|
||||
@@ -422,3 +449,53 @@ board_upload.maximum_size = 16777216
|
||||
board_upload.maximum_ram_size = 327680
|
||||
board_upload.flash_size = 32MB
|
||||
#upload_flags = --no-stub
|
||||
|
||||
|
||||
; ----------------------------------------------------------------------------------------
|
||||
; !!! this configuration expects the PoE-AP and is work in progress right now !!!
|
||||
; ----------------------------------------------------------------------------------------
|
||||
|
||||
[env:OpenEPaperLink_PoE_AP]
|
||||
platform = https://github.com/platformio/platform-espressif32.git
|
||||
board=esp32dev
|
||||
board_build.partitions = 16MB_partition table.csv
|
||||
build_unflags =
|
||||
-D CONFIG_MBEDTLS_INTERNAL_MEM_ALLOC=y
|
||||
-std=gnu++11
|
||||
lib_deps =
|
||||
${env.lib_deps}
|
||||
build_flags =
|
||||
-std=gnu++17
|
||||
${env.build_flags}
|
||||
; -D CORE_DEBUG_LEVEL=5
|
||||
-D OPENEPAPERLINK_POE_AP_PCB
|
||||
-D CONFIG_SPIRAM_USE_MALLOC=1
|
||||
-D CONFIG_MBEDTLS_EXTERNAL_MEM_ALLOC=y
|
||||
-D HAS_RGB_LED
|
||||
-D BOARD_HAS_PSRAM
|
||||
-mfix-esp32-psram-cache-issue
|
||||
-D HAS_SDCARD
|
||||
-D POWER_NO_SOFT_POWER
|
||||
-D FLASHER_AP_SS=-1
|
||||
-D FLASHER_AP_CLK=-1
|
||||
-D FLASHER_AP_MOSI=-1
|
||||
-D FLASHER_AP_MISO=-1
|
||||
-D FLASHER_AP_RESET=-1
|
||||
-D FLASHER_AP_POWER={-1} ;this board has no soft power control
|
||||
-D FLASHER_AP_TXD=15
|
||||
-D FLASHER_AP_RXD=4
|
||||
-D FLASHER_AP_TEST=-1
|
||||
-D FLASHER_LED=-1
|
||||
-D FLASHER_RGB_LED=5
|
||||
-D SD_CARD_CLK=13
|
||||
-D SD_CARD_MISO=36
|
||||
-D SD_CARD_MOSI=14
|
||||
-D SD_CARD_SS=12
|
||||
build_src_filter =
|
||||
+<*>-<usbflasher.cpp>-<swd.cpp>-<espflasher.cpp>
|
||||
|
||||
board_build.flash_mode=qio
|
||||
|
||||
board_upload.maximum_size = 16777216
|
||||
board_upload.maximum_ram_size = 327680
|
||||
board_upload.flash_size = 16MB
|
||||
|
||||
@@ -43,6 +43,37 @@ bool SPIFFSEditor::canHandle(AsyncWebServerRequest *request) {
|
||||
return false;
|
||||
}
|
||||
|
||||
String SPIFFSEditor::listFilesRecursively(String path, bool recursive) {
|
||||
if (recursive && (path == "//www" || path == "//tagtypes" || path == "//current")) return "";
|
||||
|
||||
File dir = _fs.open(path);
|
||||
String output = "";
|
||||
|
||||
File file = dir.openNextFile();
|
||||
bool isFirstFile = true;
|
||||
|
||||
while (file) {
|
||||
if (file.isDirectory()) {
|
||||
if (recursive) {
|
||||
String subDirPath = String(path + "/" + file.name());
|
||||
String subDirOutput = listFilesRecursively(subDirPath, true);
|
||||
output += subDirOutput;
|
||||
} else {
|
||||
output += ",{\"type\":\"dir\",\"name\":\"" + String(file.name()) + "\"}";
|
||||
}
|
||||
} else {
|
||||
if (recursive) {
|
||||
output += ",{\"type\":\"file\",\"name\":\"" + path.substring(2) + "/" + String(file.name()) + "\",\"size\":" + file.size() + "}";
|
||||
} else {
|
||||
output += ",{\"type\":\"file\",\"name\":\"" + String(file.name()) + "\",\"size\":" + file.size() + "}";
|
||||
}
|
||||
}
|
||||
file = dir.openNextFile();
|
||||
}
|
||||
dir.close();
|
||||
return output;
|
||||
}
|
||||
|
||||
void SPIFFSEditor::handleRequest(AsyncWebServerRequest *request) {
|
||||
if (_username.length() && _password.length() && !request->authenticate(_username.c_str(), _password.c_str())) {
|
||||
return request->requestAuthentication();
|
||||
@@ -51,23 +82,7 @@ void SPIFFSEditor::handleRequest(AsyncWebServerRequest *request) {
|
||||
if (request->method() == HTTP_GET) {
|
||||
if (request->hasParam("list")) {
|
||||
const String path = request->getParam("list")->value();
|
||||
|
||||
File dir = _fs.open(path);
|
||||
String output = "[";
|
||||
File file = dir.openNextFile();
|
||||
while (file) {
|
||||
if (output != "[") {
|
||||
output += ',';
|
||||
}
|
||||
if (file.isDirectory()) {
|
||||
output += "{\"type\":\"dir\",\"name\":\"" + String(file.name()) + "\",\"size\":" + file.size() + "}";
|
||||
} else {
|
||||
output += "{\"type\":\"file\",\"name\":\"" + String(file.name()) + "\",\"size\":" + file.size() + "}";
|
||||
}
|
||||
file = dir.openNextFile();
|
||||
}
|
||||
dir.close();
|
||||
output += "]";
|
||||
String output = "[" + listFilesRecursively(path, request->hasParam("recursive")).substring(1) + "]";
|
||||
request->send(200, "application/json", output);
|
||||
} else if (request->hasParam("edit") || request->hasParam("download")) {
|
||||
request->send(request->_tempFile, request->_tempFile.name(), String(), request->hasParam("download"));
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
#endif
|
||||
#include "language.h"
|
||||
#include "settings.h"
|
||||
#include "system.h"
|
||||
#include "tag_db.h"
|
||||
#include "truetype.h"
|
||||
#include "util.h"
|
||||
@@ -177,12 +178,6 @@ void drawNew(const uint8_t mac[8], const bool buttonPressed, tagRecord *&taginfo
|
||||
}
|
||||
#endif
|
||||
|
||||
struct tm time_info;
|
||||
getLocalTime(&time_info);
|
||||
time_info.tm_hour = time_info.tm_min = time_info.tm_sec = 0;
|
||||
time_info.tm_mday++;
|
||||
const time_t midnight = mktime(&time_info);
|
||||
|
||||
DynamicJsonDocument doc(500);
|
||||
deserializeJson(doc, taginfo->modeConfigJson);
|
||||
JsonObject cfgobj = doc.as<JsonObject>();
|
||||
@@ -192,7 +187,6 @@ void drawNew(const uint8_t mac[8], const bool buttonPressed, tagRecord *&taginfo
|
||||
taginfo->nextupdate = now + 60;
|
||||
|
||||
imgParam imageParams;
|
||||
|
||||
imageParams.width = hwdata.width;
|
||||
imageParams.height = hwdata.height;
|
||||
imageParams.bpp = hwdata.bpp;
|
||||
@@ -203,7 +197,7 @@ void drawNew(const uint8_t mac[8], const bool buttonPressed, tagRecord *&taginfo
|
||||
imageParams.dither = false;
|
||||
if (taginfo->hasCustomLUT && taginfo->lut != 1) imageParams.grayLut = true;
|
||||
|
||||
imageParams.invert = false;
|
||||
imageParams.invert = taginfo->invert;
|
||||
imageParams.symbols = 0;
|
||||
imageParams.rotate = taginfo->rotate;
|
||||
|
||||
@@ -230,12 +224,20 @@ void drawNew(const uint8_t mac[8], const bool buttonPressed, tagRecord *&taginfo
|
||||
}
|
||||
if (contentFS->exists(configFilename)) {
|
||||
imageParams.dither = cfgobj["dither"] && cfgobj["dither"] == "1";
|
||||
|
||||
imageParams.preload = cfgobj["preload"] && cfgobj["preload"] == "1";
|
||||
imageParams.preloadlut = cfgobj["preload_lut"];
|
||||
imageParams.preloadtype = cfgobj["preload_type"];
|
||||
|
||||
jpg2buffer(configFilename, filename, imageParams);
|
||||
} else {
|
||||
filename = "/current/" + String(hexmac) + ".raw";
|
||||
filename = "/current/" + String(hexmac) + ".pending";
|
||||
if (!contentFS->exists(filename)) {
|
||||
filename = "/current/" + String(hexmac) + ".raw";
|
||||
}
|
||||
if (contentFS->exists(filename)) {
|
||||
prepareDataAvail(filename, imageParams.dataType, imageParams.lut, mac, cfgobj["timetolive"].as<int>(), true);
|
||||
wsLog("File " + configFilename + " not found, resending image " + filename);
|
||||
wsLog("Resending image " + filename);
|
||||
} else {
|
||||
wsErr("File " + configFilename + " not found");
|
||||
}
|
||||
@@ -246,7 +248,18 @@ void drawNew(const uint8_t mac[8], const bool buttonPressed, tagRecord *&taginfo
|
||||
imageParams.dataType = DATATYPE_IMG_RAW_2BPP;
|
||||
if (imageParams.lut = EPD_LUT_NO_REPEATS && imageParams.shortlut == SHORTLUT_ONLY_BLACK) imageParams.lut = EPD_LUT_DEFAULT;
|
||||
}
|
||||
if (prepareDataAvail(filename, imageParams.dataType, imageParams.lut, mac, cfgobj["timetolive"].as<int>())) {
|
||||
|
||||
struct imageDataTypeArgStruct arg = {0};
|
||||
// load parameters in case we do need to preload an image
|
||||
if (imageParams.preload) {
|
||||
arg.preloadImage = 1;
|
||||
arg.specialType = imageParams.preloadtype;
|
||||
arg.lut = imageParams.preloadlut;
|
||||
} else {
|
||||
arg.lut = imageParams.lut & 0x03;
|
||||
}
|
||||
|
||||
if (prepareDataAvail(filename, imageParams.dataType, *((uint8_t *)&arg), mac, cfgobj["timetolive"].as<int>())) {
|
||||
if (cfgobj["delete"].as<String>() == "1") {
|
||||
contentFS->remove("/" + configFilename);
|
||||
}
|
||||
@@ -260,12 +273,12 @@ void drawNew(const uint8_t mac[8], const bool buttonPressed, tagRecord *&taginfo
|
||||
case 1: // Today
|
||||
|
||||
drawDate(filename, taginfo, imageParams);
|
||||
taginfo->nextupdate = midnight;
|
||||
updateTagImage(filename, mac, (midnight - now) / 60 - 10, taginfo, imageParams);
|
||||
taginfo->nextupdate = util::getMidnightTime();
|
||||
updateTagImage(filename, mac, (taginfo->nextupdate - now) / 60 - 10, taginfo, imageParams);
|
||||
break;
|
||||
|
||||
case 2: // CountDays
|
||||
drawCounter(mac, buttonPressed, taginfo, cfgobj, filename, imageParams, midnight, 15);
|
||||
drawCounter(mac, buttonPressed, taginfo, cfgobj, filename, imageParams, util::getMidnightTime(), 15);
|
||||
break;
|
||||
|
||||
case 3: // CountHours
|
||||
@@ -462,7 +475,7 @@ void drawNew(const uint8_t mac[8], const bool buttonPressed, tagRecord *&taginfo
|
||||
|
||||
bool updateTagImage(String &filename, const uint8_t *dst, uint16_t nextCheckin, tagRecord *&taginfo, imgParam &imageParams) {
|
||||
if (taginfo->hwType == SOLUM_SEG_UK) {
|
||||
sendAPSegmentedData(dst, (String)imageParams.segments, imageParams.symbols, imageParams.invert, (taginfo->isExternal == false));
|
||||
sendAPSegmentedData(dst, (String)imageParams.segments, imageParams.symbols, (imageParams.invert == 1), (taginfo->isExternal == false));
|
||||
} else {
|
||||
if (imageParams.hasRed) {
|
||||
imageParams.dataType = DATATYPE_IMG_RAW_2BPP;
|
||||
@@ -489,11 +502,19 @@ void replaceVariables(String &format) {
|
||||
size_t startIndex = 0;
|
||||
size_t openBraceIndex, closeBraceIndex;
|
||||
|
||||
time_t now;
|
||||
time(&now);
|
||||
struct tm timedef;
|
||||
localtime_r(&now, &timedef);
|
||||
char timeBuffer[80];
|
||||
strftime(timeBuffer, sizeof(timeBuffer), "%H:%M:%S", &timedef);
|
||||
setVarDB("ap_time", timeBuffer, false);
|
||||
|
||||
while ((openBraceIndex = format.indexOf('{', startIndex)) != -1 &&
|
||||
(closeBraceIndex = format.indexOf('}', openBraceIndex + 1)) != -1) {
|
||||
const std::string variableName = format.substring(openBraceIndex + 1, closeBraceIndex).c_str();
|
||||
const std::string varKey = "{" + variableName + "}";
|
||||
auto var = varDB.find(variableName);
|
||||
const auto var = varDB.find(variableName);
|
||||
if (var != varDB.end()) {
|
||||
format.replace(varKey.c_str(), var->second.value);
|
||||
}
|
||||
@@ -671,7 +692,7 @@ const String getWeatherIcon(const uint8_t id, const bool isNight = false) {
|
||||
"\uf01b", "", "\uf01b", "", "\uf01b", "", "\uf076", "", "", "\uf01a",
|
||||
"\uf01a", "\uf01a", "", "", "\uf064", "\uf064", "", "", "", "",
|
||||
"", "", "", "", "\uf01e", "\uf01d", "", "", "\uf01e"};
|
||||
if (isNight && id <= 3) {
|
||||
if (isNight && id <= 2) {
|
||||
const String nightIcons[] = {"\uf02e", "\uf083", "\uf086"};
|
||||
return nightIcons[id];
|
||||
}
|
||||
@@ -851,6 +872,7 @@ int getImgURL(String &filename, String URL, time_t fetched, imgParam &imageParam
|
||||
Storage.begin();
|
||||
|
||||
HTTPClient http;
|
||||
logLine("http getImgURL " + URL);
|
||||
http.begin(URL);
|
||||
http.addHeader("If-Modified-Since", formatHttpDate(fetched));
|
||||
http.addHeader("X-ESL-MAC", MAC);
|
||||
@@ -956,6 +978,7 @@ bool getCalFeed(String &filename, String URL, String title, tagRecord *&taginfo,
|
||||
strftime(dateString, sizeof(dateString), "%d.%m.%Y", &timeinfo);
|
||||
|
||||
HTTPClient http;
|
||||
logLine("http getCalFeed " + URL);
|
||||
http.begin(URL);
|
||||
http.setTimeout(10000);
|
||||
http.setFollowRedirects(HTTPC_STRICT_FOLLOW_REDIRECTS);
|
||||
@@ -1058,6 +1081,7 @@ uint8_t drawBuienradar(String &filename, JsonObject &cfgobj, tagRecord *&taginfo
|
||||
|
||||
String lat = cfgobj["#lat"];
|
||||
String lon = cfgobj["#lon"];
|
||||
logLine("http drawBuienradar");
|
||||
http.begin("https://gps.buienradar.nl/getrr.php?lat=" + lat + "&lon=" + lon);
|
||||
http.setFollowRedirects(HTTPC_STRICT_FOLLOW_REDIRECTS);
|
||||
http.setTimeout(5000);
|
||||
@@ -1319,6 +1343,7 @@ bool getJsonTemplateFileExtractVariables(String &filename, String jsonfile, Json
|
||||
int getJsonTemplateUrl(String &filename, String URL, time_t fetched, String MAC, tagRecord *&taginfo, imgParam &imageParams) {
|
||||
HTTPClient http;
|
||||
http.useHTTP10(true);
|
||||
logLine("http getJsonTemplateUrl " + URL);
|
||||
http.begin(URL);
|
||||
http.addHeader("If-Modified-Since", formatHttpDate(fetched));
|
||||
http.addHeader("X-ESL-MAC", MAC);
|
||||
@@ -1339,7 +1364,7 @@ int getJsonTemplateUrl(String &filename, String URL, time_t fetched, String MAC,
|
||||
void drawJsonStream(Stream &stream, String &filename, tagRecord *&taginfo, imgParam &imageParams) {
|
||||
TFT_eSprite spr = TFT_eSprite(&tft);
|
||||
initSprite(spr, imageParams.width, imageParams.height, imageParams);
|
||||
DynamicJsonDocument doc(300);
|
||||
DynamicJsonDocument doc(500);
|
||||
if (stream.find("[")) {
|
||||
do {
|
||||
DeserializationError error = deserializeJson(doc, stream);
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
#include "esp32_port.h"
|
||||
#include "esp_littlefs.h"
|
||||
#include "storage.h"
|
||||
#include "tag_db.h"
|
||||
#include "web.h"
|
||||
|
||||
esp_loader_error_t connect_to_target(uint32_t higher_transmission_rate) {
|
||||
@@ -125,18 +126,22 @@ bool downloadAndWriteBinary(String &filename, const char *url) {
|
||||
int binaryResponseCode = binaryHttp.GET();
|
||||
Serial.println(binaryResponseCode);
|
||||
if (binaryResponseCode == HTTP_CODE_OK) {
|
||||
int contentLength = binaryHttp.getSize();
|
||||
Serial.println(contentLength);
|
||||
xSemaphoreTake(fsMutex, portMAX_DELAY);
|
||||
File file = contentFS->open(filename, "wb");
|
||||
if (file) {
|
||||
wsSerial("downloading " + String(filename));
|
||||
WiFiClient *stream = binaryHttp.getStreamPtr();
|
||||
uint8_t buffer[256];
|
||||
uint8_t buffer[1024];
|
||||
size_t totalBytesRead = 0;
|
||||
while (stream->available()) {
|
||||
time_t timeOut = millis() + 5000;
|
||||
// while (stream->available()) {
|
||||
while (millis() < timeOut) {
|
||||
size_t bytesRead = stream->readBytes(buffer, sizeof(buffer));
|
||||
file.write(buffer, bytesRead);
|
||||
totalBytesRead += bytesRead;
|
||||
vTaskDelay(1 / portTICK_PERIOD_MS);
|
||||
if (totalBytesRead == contentLength) break;
|
||||
}
|
||||
file.close();
|
||||
xSemaphoreGive(fsMutex);
|
||||
@@ -144,7 +149,7 @@ bool downloadAndWriteBinary(String &filename, const char *url) {
|
||||
|
||||
file = contentFS->open(filename, "r");
|
||||
if (file) {
|
||||
if (totalBytesRead == file.size() && file.size() > 0) {
|
||||
if (totalBytesRead == contentLength || (contentLength == 0 && file.size() > 0)) {
|
||||
file.close();
|
||||
return true;
|
||||
}
|
||||
@@ -163,8 +168,7 @@ bool downloadAndWriteBinary(String &filename, const char *url) {
|
||||
}
|
||||
|
||||
bool doC6flash(uint8_t doDownload) {
|
||||
const char *githubUrl = "https://raw.githubusercontent.com/jjwbruijn/OpenEPaperLink/master/binaries/ESP32-C6/firmware.json";
|
||||
|
||||
const String githubUrl = "https://raw.githubusercontent.com/" + config.repo + "/master/binaries/ESP32-C6/firmware.json";
|
||||
HTTPClient http;
|
||||
Serial.println(githubUrl);
|
||||
http.begin(githubUrl);
|
||||
@@ -181,7 +185,8 @@ bool doC6flash(uint8_t doDownload) {
|
||||
JsonArray jsonArray = jsonDoc.as<JsonArray>();
|
||||
for (JsonObject obj : jsonArray) {
|
||||
String filename = "/" + obj["filename"].as<String>();
|
||||
String binaryUrl = "https://raw.githubusercontent.com/jjwbruijn/OpenEPaperLink/master/binaries/ESP32-C6" + String(filename);
|
||||
// String binaryUrl = "https://raw.githubusercontent.com/" + config.repo + "/master/binaries/ESP32-C6" + String(filename);
|
||||
String binaryUrl = "http://www.openepaperlink.eu/binaries/ESP32-C6" + String(filename);
|
||||
for (int retry = 0; retry < 10; retry++) {
|
||||
if (downloadAndWriteBinary(filename, binaryUrl.c_str())) {
|
||||
break;
|
||||
|
||||
@@ -176,7 +176,6 @@ bool flasher::getInfoBlockType() {
|
||||
|
||||
bool flasher::findTagByMD5() {
|
||||
DynamicJsonDocument doc(3000);
|
||||
DynamicJsonDocument APconfig(600);
|
||||
fs::File readfile = contentFS->open("/tag_md5_db.json", "r");
|
||||
DeserializationError err = deserializeJson(doc, readfile);
|
||||
if (!err) {
|
||||
@@ -206,7 +205,6 @@ bool flasher::findTagByMD5() {
|
||||
|
||||
bool flasher::findTagByType(uint8_t type) {
|
||||
DynamicJsonDocument doc(3000);
|
||||
DynamicJsonDocument APconfig(600);
|
||||
fs::File readfile = contentFS->open("/tag_md5_db.json", "r");
|
||||
DeserializationError err = deserializeJson(doc, readfile);
|
||||
if (!err) {
|
||||
@@ -445,8 +443,7 @@ bool flasher::writeFlashFromPackOffset(fs::File *file, uint16_t length) {
|
||||
}
|
||||
|
||||
bool flasher::writeFlashFromPack(String filename, uint8_t type) {
|
||||
StaticJsonDocument<512> doc;
|
||||
DynamicJsonDocument APconfig(512);
|
||||
DynamicJsonDocument doc(1024);
|
||||
fs::File readfile = contentFS->open(filename, "r");
|
||||
DeserializationError err = deserializeJson(doc, readfile);
|
||||
if (!err) {
|
||||
@@ -469,6 +466,7 @@ bool flasher::writeFlashFromPack(String filename, uint8_t type) {
|
||||
}
|
||||
Serial.print("Failed to find this tag's type in the FW pack database.\n");
|
||||
} else {
|
||||
Serial.println(err.c_str());
|
||||
Serial.print("Failed to read json header from FW pack\n");
|
||||
}
|
||||
readfile.close();
|
||||
@@ -505,7 +503,6 @@ bool flasher::writeBlock(uint16_t offset, uint8_t *data, uint16_t len, bool info
|
||||
|
||||
uint16_t getAPUpdateVersion(uint8_t type) {
|
||||
StaticJsonDocument<512> doc;
|
||||
DynamicJsonDocument APconfig(512);
|
||||
fs::File readfile = contentFS->open("/AP_FW_Pack.bin", "r");
|
||||
DeserializationError err = deserializeJson(doc, readfile);
|
||||
if (!err) {
|
||||
|
||||
@@ -84,7 +84,7 @@ void yellow_ap_display_init(void) {
|
||||
|
||||
ledcSetup(6, 5000, 8);
|
||||
ledcAttachPin(TFT_BACKLIGHT, 6);
|
||||
ledcWrite(6, 255); // config.led
|
||||
ledcWrite(6, config.tft);
|
||||
|
||||
tft2.init();
|
||||
tft2.setRotation(YellowSense == 1 ? 1 : 3);
|
||||
|
||||
@@ -14,6 +14,8 @@ int maxledbrightness = 255;
|
||||
|
||||
#ifdef HAS_RGB_LED
|
||||
QueueHandle_t rgbLedQueue;
|
||||
CRGB rgbIdleColor = CRGB::Green;
|
||||
uint16_t rgbIdlePeriod = 511;
|
||||
|
||||
struct ledInstructionRGB {
|
||||
CRGB ledColor;
|
||||
@@ -56,6 +58,7 @@ void addFadeColor(CRGB cname) {
|
||||
}
|
||||
|
||||
void shortBlink(CRGB cname) {
|
||||
#ifndef YELLOW_IPS_AP
|
||||
struct ledInstructionRGB* rgb = new struct ledInstructionRGB;
|
||||
rgb->ledColor = CRGB::Black;
|
||||
rgb->fadeTime = 0;
|
||||
@@ -72,6 +75,7 @@ void shortBlink(CRGB cname) {
|
||||
rgb->fadeTime = 0;
|
||||
rgb->length = 3;
|
||||
addToRGBQueue(rgb, false);
|
||||
#endif
|
||||
}
|
||||
|
||||
void flushRGBQueue() {
|
||||
@@ -119,9 +123,6 @@ void showRGB() {
|
||||
FastLED.show();
|
||||
}
|
||||
|
||||
volatile CRGB rgbIdleColor = CRGB::Green;
|
||||
volatile uint16_t rgbIdlePeriod = 800;
|
||||
|
||||
void rgbIdleStep() {
|
||||
static bool dirUp = true;
|
||||
static uint16_t step = 0;
|
||||
@@ -129,7 +130,7 @@ void rgbIdleStep() {
|
||||
if (dirUp) {
|
||||
// up
|
||||
step++;
|
||||
if (step == rgbIdlePeriod) {
|
||||
if (step >= rgbIdlePeriod) {
|
||||
dirUp = false;
|
||||
}
|
||||
} else {
|
||||
@@ -139,7 +140,7 @@ void rgbIdleStep() {
|
||||
dirUp = true;
|
||||
}
|
||||
}
|
||||
CRGB newvalue = blend(CRGB::Black, (const CRGB&)rgbIdleColor, gamma8[map(step, 0, rgbIdlePeriod, 0, 255)]);
|
||||
CRGB newvalue = blend(CRGB::Black, (const CRGB&)rgbIdleColor, map(step, 0, rgbIdlePeriod, 0, 255));
|
||||
if (newvalue != leds[0]) {
|
||||
leds[0] = newvalue;
|
||||
showRGB();
|
||||
@@ -150,7 +151,7 @@ void rgbIdleStep() {
|
||||
void setBrightness(int brightness) {
|
||||
maxledbrightness = brightness;
|
||||
#ifdef YELLOW_IPS_AP
|
||||
// ledcWrite(6, config.led);
|
||||
ledcWrite(6, config.tft);
|
||||
#endif
|
||||
#ifdef HAS_RGB_LED
|
||||
FastLED.setBrightness(maxledbrightness);
|
||||
@@ -165,6 +166,7 @@ void updateBrightnessFromConfig() {
|
||||
setBrightness(newbrightness);
|
||||
}
|
||||
}
|
||||
ledcWrite(6, config.tft);
|
||||
}
|
||||
|
||||
void addToMonoQueue(struct ledInstruction* mono) {
|
||||
@@ -193,7 +195,11 @@ void showMono(uint8_t brightness) {
|
||||
void quickBlink(uint8_t repeat) {
|
||||
for (int i = 0; i < repeat; i++) {
|
||||
struct ledInstruction* mono = new struct ledInstruction;
|
||||
#ifdef YELLOW_IPS_AP
|
||||
mono->value = 255;
|
||||
#else
|
||||
mono->value = maxledbrightness;
|
||||
#endif
|
||||
mono->fadeTime = 120 / repeat;
|
||||
mono->length = 0;
|
||||
addToMonoQueue(mono);
|
||||
@@ -207,31 +213,6 @@ void quickBlink(uint8_t repeat) {
|
||||
|
||||
volatile uint16_t monoIdlePeriod = 900;
|
||||
|
||||
uint8_t monoValue = 0;
|
||||
|
||||
void monoIdleStep() {
|
||||
static bool dirUp = true;
|
||||
static uint16_t step = 0;
|
||||
if (dirUp) {
|
||||
// up
|
||||
step++;
|
||||
if (step == monoIdlePeriod) {
|
||||
dirUp = false;
|
||||
}
|
||||
} else {
|
||||
// down
|
||||
step--;
|
||||
if (step == 0) {
|
||||
dirUp = true;
|
||||
}
|
||||
}
|
||||
uint8_t newvalue = map(step, 0, monoIdlePeriod, 0, maxledbrightness);
|
||||
if (newvalue != monoValue) {
|
||||
monoValue = newvalue;
|
||||
showMono(newvalue);
|
||||
}
|
||||
}
|
||||
|
||||
void ledTask(void* parameter) {
|
||||
#ifdef HAS_RGB_LED
|
||||
FastLED.addLeds<WS2812B, FLASHER_RGB_LED, GRB>(leds, 1); // GRB ordering is typical
|
||||
@@ -244,9 +225,6 @@ void ledTask(void* parameter) {
|
||||
addFadeColor(CRGB::Red);
|
||||
addFadeColor(CRGB::Green);
|
||||
addFadeColor(CRGB::Blue);
|
||||
addFadeColor(CRGB::Red);
|
||||
addFadeColor(CRGB::Green);
|
||||
addFadeColor(CRGB::Blue);
|
||||
CRGB oldColor = CRGB::Black;
|
||||
uint16_t rgbInstructionFadeTime = 0;
|
||||
#endif
|
||||
@@ -263,7 +241,11 @@ void ledTask(void* parameter) {
|
||||
struct ledInstruction* monoled = nullptr;
|
||||
|
||||
addFadeMono(0);
|
||||
#ifdef YELLOW_IPS_AP
|
||||
addFadeMono(255);
|
||||
#else
|
||||
addFadeMono(maxledbrightness);
|
||||
#endif
|
||||
addFadeMono(0);
|
||||
|
||||
uint8_t oldBrightness = 0;
|
||||
@@ -324,9 +306,7 @@ void ledTask(void* parameter) {
|
||||
if (monoled->fadeTime <= 1) {
|
||||
showMono(monoled->value);
|
||||
}
|
||||
} else {
|
||||
// monoIdleStep();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (monoled->fadeTime) {
|
||||
monoled->fadeTime--;
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
#include "storage.h"
|
||||
#include "system.h"
|
||||
#include "tag_db.h"
|
||||
#include "tagdata.h"
|
||||
#include "wifimanager.h"
|
||||
|
||||
#ifdef HAS_USB
|
||||
@@ -22,10 +23,15 @@
|
||||
#include "util.h"
|
||||
#include "web.h"
|
||||
|
||||
util::Timer intervalSysinfo(3000);
|
||||
util::Timer intervalVars(10000);
|
||||
util::Timer intervalSaveDB(300000);
|
||||
util::Timer intervalContentRunner(1000);
|
||||
util::Timer intervalContentRunner(seconds(1));
|
||||
util::Timer intervalSysinfo(seconds(3));
|
||||
util::Timer intervalVars(seconds(10));
|
||||
util::Timer intervalSaveDB(minutes(5));
|
||||
util::Timer intervalCheckDate(minutes(5));
|
||||
|
||||
#ifdef OPENEPAPERLINK_PCB
|
||||
util::Timer tagConnectTimer(seconds(1));
|
||||
#endif
|
||||
|
||||
SET_LOOP_TASK_STACK_SIZE(16 * 1024);
|
||||
|
||||
@@ -52,11 +58,6 @@ void setup() {
|
||||
xTaskCreate(ledTask, "ledhandler", 2000, NULL, 2, NULL);
|
||||
vTaskDelay(10 / portTICK_PERIOD_MS);
|
||||
|
||||
#ifdef HAS_RGB_LED
|
||||
// show a nice pattern to indicate the AP is booting / waiting for WiFi setup
|
||||
showColorPattern(CRGB::Aqua, CRGB::Green, CRGB::Blue);
|
||||
#endif
|
||||
|
||||
#if defined(OPENEPAPERLINK_MINI_AP_PCB) || defined(OPENEPAPERLINK_NANO_AP_PCB)
|
||||
APEnterEarlyReset();
|
||||
// this allows us to view the booting process. After the device showing up, you have 3 seconds to open a terminal on the COM port
|
||||
@@ -118,6 +119,7 @@ void setup() {
|
||||
|
||||
initAPconfig();
|
||||
|
||||
xTaskCreate(initTime, "init time", 5000, NULL, 2, NULL);
|
||||
updateLanguageFromConfig();
|
||||
updateBrightnessFromConfig();
|
||||
|
||||
@@ -126,6 +128,7 @@ void setup() {
|
||||
#ifdef HAS_RGB_LED
|
||||
rgbIdle();
|
||||
#endif
|
||||
TagData::loadParsers("/parsers.json");
|
||||
loadDB("/current/tagDB.json");
|
||||
cleanupCurrent();
|
||||
xTaskCreate(APTask, "AP Process", 6000, NULL, 2, NULL);
|
||||
@@ -138,7 +141,6 @@ void setup() {
|
||||
config.runStatus = RUNSTATUS_PAUSE;
|
||||
}
|
||||
|
||||
xTaskCreate(initTime, "init time", 5000, NULL, 2, NULL);
|
||||
xTaskCreate(delayedStart, "delaystart", 2000, NULL, 2, NULL);
|
||||
|
||||
wsSendSysteminfo();
|
||||
@@ -161,6 +163,21 @@ void loop() {
|
||||
if (intervalContentRunner.doRun() && apInfo.state == AP_STATE_ONLINE) {
|
||||
contentRunner();
|
||||
}
|
||||
if (intervalCheckDate.doRun() && config.runStatus == RUNSTATUS_RUN) {
|
||||
static uint8_t day = 0;
|
||||
|
||||
time_t now;
|
||||
time(&now);
|
||||
struct tm timedef;
|
||||
localtime_r(&now, &timedef);
|
||||
|
||||
if (day != timedef.tm_mday) {
|
||||
day = timedef.tm_mday;
|
||||
char timeBuffer[80];
|
||||
strftime(timeBuffer, sizeof(timeBuffer), "%d-%m-%Y", &timedef);
|
||||
setVarDB("ap_date", timeBuffer);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef YELLOW_IPS_AP
|
||||
extern void yellow_ap_display_loop(void);
|
||||
@@ -168,21 +185,17 @@ void loop() {
|
||||
#endif
|
||||
|
||||
#ifdef OPENEPAPERLINK_PCB
|
||||
time_t tagConnectTimer = 0;
|
||||
if (millis() - tagConnectTimer > 1000) {
|
||||
tagConnectTimer = millis();
|
||||
if (extTagConnected()) {
|
||||
flashCountDown(3);
|
||||
if (tagConnectTimer.doRun() && extTagConnected()) {
|
||||
flashCountDown(3);
|
||||
|
||||
pinMode(FLASHER_EXT_TEST, OUTPUT);
|
||||
digitalWrite(FLASHER_EXT_TEST, LOW);
|
||||
pinMode(FLASHER_EXT_TEST, OUTPUT);
|
||||
digitalWrite(FLASHER_EXT_TEST, LOW);
|
||||
|
||||
doTagFlash();
|
||||
doTagFlash();
|
||||
|
||||
vTaskDelay(10000 / portTICK_PERIOD_MS);
|
||||
pinMode(FLASHER_EXT_TEST, INPUT);
|
||||
vTaskDelay(1000 / portTICK_PERIOD_MS);
|
||||
}
|
||||
vTaskDelay(10000 / portTICK_PERIOD_MS);
|
||||
pinMode(FLASHER_EXT_TEST, INPUT);
|
||||
vTaskDelay(1000 / portTICK_PERIOD_MS);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
@@ -97,6 +97,9 @@ void spr2color(TFT_eSprite &spr, imgParam &imageParams, uint8_t *buffer, size_t
|
||||
{0, 0, 0}, // Black
|
||||
{255, 0, 0} // Red
|
||||
};
|
||||
if (imageParams.invert == 1) {
|
||||
std::swap(palette[0], palette[1]);
|
||||
}
|
||||
if (imageParams.grayLut) {
|
||||
Color newColor = {160, 160, 160};
|
||||
palette.push_back(newColor);
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
#include "storage.h"
|
||||
#include "system.h"
|
||||
#include "tag_db.h"
|
||||
#include "tagdata.h"
|
||||
#include "udp.h"
|
||||
#include "util.h"
|
||||
#include "web.h"
|
||||
@@ -238,6 +239,7 @@ void prepareExternalDataAvail(struct pendingData* pending, IPAddress remoteIP) {
|
||||
String imageUrl = "http://" + remoteIP.toString() + filename;
|
||||
wsLog("GET " + imageUrl);
|
||||
HTTPClient http;
|
||||
logLine("http prepareExternalDataAvail " + imageUrl);
|
||||
http.begin(imageUrl);
|
||||
int httpCode = http.GET();
|
||||
if (httpCode == 200) {
|
||||
@@ -249,6 +251,7 @@ void prepareExternalDataAvail(struct pendingData* pending, IPAddress remoteIP) {
|
||||
} else if (httpCode == 404) {
|
||||
imageUrl = "http://" + remoteIP.toString() + "/current/" + String(hexmac) + ".raw";
|
||||
http.end();
|
||||
logLine("http prepareExternalDataAvail " + imageUrl);
|
||||
http.begin(imageUrl);
|
||||
httpCode = http.GET();
|
||||
if (httpCode == 200) {
|
||||
@@ -295,6 +298,7 @@ void prepareExternalDataAvail(struct pendingData* pending, IPAddress remoteIP) {
|
||||
String dataUrl = "http://" + remoteIP.toString() + "/getdata?mac=" + String(hexmac);
|
||||
wsLog("GET " + dataUrl);
|
||||
HTTPClient http;
|
||||
logLine("http DATATYPE_CUSTOM_LUT_OTA " + dataUrl);
|
||||
http.begin(dataUrl);
|
||||
int httpCode = http.GET();
|
||||
if (httpCode == 200) {
|
||||
@@ -326,7 +330,9 @@ void prepareExternalDataAvail(struct pendingData* pending, IPAddress remoteIP) {
|
||||
}
|
||||
|
||||
void processBlockRequest(struct espBlockRequest* br) {
|
||||
if (config.runStatus == RUNSTATUS_STOP) return;
|
||||
if (config.runStatus == RUNSTATUS_STOP) {
|
||||
return;
|
||||
}
|
||||
if (!checkCRC(br, sizeof(struct espBlockRequest))) {
|
||||
Serial.print("Failed CRC on a blockrequest received by the AP");
|
||||
return;
|
||||
@@ -368,7 +374,9 @@ void processBlockRequest(struct espBlockRequest* br) {
|
||||
}
|
||||
|
||||
void processXferComplete(struct espXferComplete* xfc, bool local) {
|
||||
if (config.runStatus == RUNSTATUS_STOP) return;
|
||||
if (config.runStatus == RUNSTATUS_STOP) {
|
||||
return;
|
||||
}
|
||||
char buffer[64];
|
||||
sprintf(buffer, "< %02X%02X%02X%02X%02X%02X%02X%02X reports xfer complete\n\0", xfc->src[7], xfc->src[6], xfc->src[5], xfc->src[4], xfc->src[3], xfc->src[2], xfc->src[1], xfc->src[0]);
|
||||
wsLog((String)buffer);
|
||||
@@ -412,7 +420,9 @@ void processXferComplete(struct espXferComplete* xfc, bool local) {
|
||||
}
|
||||
|
||||
void processXferTimeout(struct espXferComplete* xfc, bool local) {
|
||||
if (config.runStatus == RUNSTATUS_STOP) return;
|
||||
if (config.runStatus == RUNSTATUS_STOP) {
|
||||
return;
|
||||
}
|
||||
char buffer[64];
|
||||
sprintf(buffer, "< %02X%02X%02X%02X%02X%02X%02X%02X xfer timeout\n\0", xfc->src[7], xfc->src[6], xfc->src[5], xfc->src[4], xfc->src[3], xfc->src[2], xfc->src[1], xfc->src[0]);
|
||||
wsErr((String)buffer);
|
||||
@@ -436,7 +446,9 @@ void processXferTimeout(struct espXferComplete* xfc, bool local) {
|
||||
}
|
||||
|
||||
void processDataReq(struct espAvailDataReq* eadr, bool local, IPAddress remoteIP) {
|
||||
if (config.runStatus == RUNSTATUS_STOP) return;
|
||||
if (config.runStatus == RUNSTATUS_STOP) {
|
||||
return;
|
||||
}
|
||||
char buffer[64];
|
||||
|
||||
tagRecord* taginfo = tagRecord::findByMAC(eadr->src);
|
||||
@@ -527,16 +539,17 @@ void processTagReturnData(struct espTagReturnData* trd, uint8_t len, bool local)
|
||||
if (!checkCRC(trd, len)) {
|
||||
return;
|
||||
}
|
||||
char buffer[64];
|
||||
|
||||
const uint8_t payloadLength = trd->len - 11;
|
||||
|
||||
// Replace this stuff with something that handles the data coming from the tag. This is here for demo purposes!
|
||||
char buffer[64];
|
||||
sprintf(buffer, "<TRD %02X%02X%02X%02X%02X%02X%02X%02X\n", trd->src[7], trd->src[6], trd->src[5], trd->src[4], trd->src[3], trd->src[2], trd->src[1], trd->src[0]);
|
||||
wsLog((String)buffer);
|
||||
sprintf(buffer, "TRD Data: len=%d, type=%d, ver=0x%08X\n", trd->len - 11, trd->returnData.dataType, trd->returnData.dataVer);
|
||||
sprintf(buffer, "TRD Data: len=%d, type=%d, ver=0x%08X\n", payloadLength, trd->returnData.dataType, trd->returnData.dataVer);
|
||||
wsLog((String)buffer);
|
||||
|
||||
uint8_t actualPayloadLength = trd->len - 11;
|
||||
uint8_t* actualPayload = (uint8_t*)calloc(actualPayloadLength, 1);
|
||||
memcpy(actualPayload, trd->returnData.data, actualPayloadLength);
|
||||
TagData::parse(trd->src, trd->returnData.dataType, trd->returnData.data, payloadLength);
|
||||
}
|
||||
|
||||
void refreshAllPending() {
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
#include <Update.h>
|
||||
|
||||
#include "espflasher.h"
|
||||
#include "leds.h"
|
||||
#include "serialap.h"
|
||||
#include "storage.h"
|
||||
#include "tag_db.h"
|
||||
@@ -240,8 +241,7 @@ void C6firmwareUpdateTask(void* parameter) {
|
||||
uint8_t doDownload = *((uint8_t*)parameter);
|
||||
wsSerial("Stopping AP service");
|
||||
|
||||
apInfo.isOnline = false;
|
||||
apInfo.state = AP_STATE_FLASHING;
|
||||
setAPstate(false, AP_STATE_FLASHING);
|
||||
config.runStatus = RUNSTATUS_STOP;
|
||||
extern bool rxSerialStopTask2;
|
||||
rxSerialStopTask2 = true;
|
||||
@@ -255,8 +255,8 @@ void C6firmwareUpdateTask(void* parameter) {
|
||||
wsSerial("C6 flash end");
|
||||
|
||||
if (result) {
|
||||
apInfo.state = AP_STATE_OFFLINE;
|
||||
|
||||
setAPstate(false, AP_STATE_OFFLINE);
|
||||
|
||||
wsSerial("Finishing config...");
|
||||
vTaskDelay(3000 / portTICK_PERIOD_MS);
|
||||
|
||||
|
||||
@@ -137,6 +137,24 @@ void APEnterEarlyReset() {
|
||||
digitalWrite(AP_RESET_PIN, LOW);
|
||||
}
|
||||
|
||||
void setAPstate(bool isOnline, uint8_t state) {
|
||||
apInfo.isOnline = isOnline;
|
||||
apInfo.state = state;
|
||||
#ifdef HAS_RGB_LED
|
||||
CRGB colorMap[7] = {
|
||||
CRGB::Orange,
|
||||
CRGB::Green,
|
||||
CRGB::Blue,
|
||||
CRGB::Yellow,
|
||||
CRGB::Aqua,
|
||||
CRGB::Red,
|
||||
CRGB::YellowGreen
|
||||
};
|
||||
rgbIdleColor = colorMap[state];
|
||||
rgbIdlePeriod = (isOnline ? 767 : 255);
|
||||
#endif
|
||||
}
|
||||
|
||||
// Reset the tag
|
||||
void APTagReset() {
|
||||
Serial.println("Resetting tag");
|
||||
@@ -270,7 +288,7 @@ bool sendPing() {
|
||||
Serial.print("ping");
|
||||
int t = millis();
|
||||
if (!txStart()) return false;
|
||||
for (uint8_t attempt = 0; attempt < 5; attempt++) {
|
||||
for (uint8_t attempt = 0; attempt < 3; attempt++) {
|
||||
cmdReplyValue = CMD_REPLY_WAIT;
|
||||
AP_SERIAL_PORT.print("RDY?");
|
||||
if (waitCmdReply()) {
|
||||
@@ -632,8 +650,7 @@ void notifySegmentedFlash() {
|
||||
void checkWaitPowerCycle() {
|
||||
// check if we should wait for a power cycle. If we do, try to inform the user the best we can, and hang.
|
||||
#ifdef POWER_NO_SOFT_POWER
|
||||
apInfo.isOnline = false;
|
||||
apInfo.state = AP_STATE_REQUIRED_POWER_CYCLE;
|
||||
setAPstate(false, AP_STATE_REQUIRED_POWER_CYCLE);
|
||||
// If we have no soft power control, we'll now wait until the device is power-cycled
|
||||
Serial.printf("Please power-cycle your AP/device\n");
|
||||
#ifdef HAS_RGB_LED
|
||||
@@ -660,16 +677,11 @@ void segmentedShowIp() {
|
||||
|
||||
bool bringAPOnline() {
|
||||
if (apInfo.state == AP_STATE_FLASHING) return false;
|
||||
apInfo.isOnline = false;
|
||||
apInfo.state = AP_STATE_OFFLINE;
|
||||
setAPstate(false, AP_STATE_OFFLINE);
|
||||
// try without rebooting
|
||||
AP_SERIAL_PORT.updateBaudRate(115200);
|
||||
uint32_t bootTimeout = millis();
|
||||
bool APrdy = false;
|
||||
while ((!APrdy) && (millis() - bootTimeout < 3 * 1000)) {
|
||||
APrdy = sendPing();
|
||||
vTaskDelay(300 / portTICK_PERIOD_MS);
|
||||
}
|
||||
bool APrdy = sendPing();
|
||||
if (!APrdy) {
|
||||
if (apInfo.state == AP_STATE_FLASHING) return false;
|
||||
APTagReset();
|
||||
@@ -684,11 +696,11 @@ bool bringAPOnline() {
|
||||
if (!APrdy) {
|
||||
return false;
|
||||
} else {
|
||||
apInfo.state = AP_STATE_COMING_ONLINE;
|
||||
setAPstate(false, AP_STATE_COMING_ONLINE);
|
||||
sendChannelPower(&curChannel);
|
||||
vTaskDelay(200 / portTICK_PERIOD_MS);
|
||||
if (!sendGetInfo()) {
|
||||
apInfo.state = AP_STATE_OFFLINE;
|
||||
setAPstate(false, AP_STATE_OFFLINE);
|
||||
return false;
|
||||
}
|
||||
if (apInfo.type == ESP32_C6) {
|
||||
@@ -701,8 +713,7 @@ bool bringAPOnline() {
|
||||
}
|
||||
|
||||
vTaskDelay(200 / portTICK_PERIOD_MS);
|
||||
apInfo.isOnline = true;
|
||||
apInfo.state = AP_STATE_ONLINE;
|
||||
setAPstate(true, AP_STATE_ONLINE);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -735,8 +746,7 @@ void APTask(void* parameter) {
|
||||
Serial.printf("We're going to try to perform an 'AP forced flash' in\n");
|
||||
flashCountDown(10);
|
||||
Serial.printf("\nPerforming force flash of the AP\n");
|
||||
apInfo.isOnline = false;
|
||||
apInfo.state = AP_STATE_FLASHING;
|
||||
setAPstate(false, AP_STATE_FLASHING);
|
||||
doForcedAPFlash();
|
||||
checkWaitPowerCycle();
|
||||
bringAPOnline();
|
||||
@@ -747,10 +757,10 @@ void APTask(void* parameter) {
|
||||
ShowAPInfo();
|
||||
|
||||
if (apInfo.type == SOLUM_SEG_UK) {
|
||||
apInfo.state = AP_STATE_COMING_ONLINE;
|
||||
setAPstate(true, AP_STATE_COMING_ONLINE);
|
||||
segmentedShowIp();
|
||||
showAPSegmentedInfo(apInfo.mac, true);
|
||||
apInfo.state = AP_STATE_ONLINE;
|
||||
setAPstate(true, AP_STATE_ONLINE);
|
||||
updateContent(apInfo.mac);
|
||||
}
|
||||
|
||||
@@ -765,8 +775,7 @@ void APTask(void* parameter) {
|
||||
flashCountDown(30);
|
||||
Serial.printf("\n");
|
||||
notifySegmentedFlash();
|
||||
apInfo.isOnline = false;
|
||||
apInfo.state = AP_STATE_FLASHING;
|
||||
setAPstate(false, AP_STATE_FLASHING);
|
||||
if (doAPUpdate(apInfo.type)) {
|
||||
checkWaitPowerCycle();
|
||||
Serial.printf("Flash completed, let's try to boot the AP!\n");
|
||||
@@ -777,18 +786,18 @@ void APTask(void* parameter) {
|
||||
} else {
|
||||
Serial.printf("Failed to bring up the AP after flashing seemed successful... That's not supposed to happen!\n");
|
||||
Serial.printf("This can be caused by a bad AP firmware, failed or failing hardware, or the inability to fully power-cycle the AP\n");
|
||||
apInfo.state = AP_STATE_FAILED;
|
||||
#ifdef HAS_RGB_LED
|
||||
setAPstate(false, AP_STATE_FAILED);
|
||||
#ifdef HAS_RGB_LED
|
||||
showColorPattern(CRGB::Red, CRGB::Yellow, CRGB::Red);
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
} else {
|
||||
apInfo.state = AP_STATE_FAILED;
|
||||
setAPstate(false, AP_STATE_FAILED);
|
||||
checkWaitPowerCycle();
|
||||
Serial.println("Failed to update version on the AP :(\n");
|
||||
#ifdef HAS_RGB_LED
|
||||
#ifdef HAS_RGB_LED
|
||||
showColorPattern(CRGB::Red, CRGB::Red, CRGB::Red);
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -804,12 +813,10 @@ void APTask(void* parameter) {
|
||||
#ifdef HAS_RGB_LED
|
||||
showColorPattern(CRGB::Red, CRGB::Yellow, CRGB::Red);
|
||||
#endif
|
||||
apInfo.isOnline = false;
|
||||
apInfo.state = AP_STATE_FAILED;
|
||||
setAPstate(false, AP_STATE_FAILED);
|
||||
} else {
|
||||
// AP unavailable, maybe time to flash?
|
||||
apInfo.isOnline = false;
|
||||
apInfo.state = AP_STATE_OFFLINE;
|
||||
setAPstate(false, AP_STATE_OFFLINE);
|
||||
|
||||
Serial.printf("I wasn't able to connect to a ZBS (AP) tag.\n");
|
||||
Serial.printf("This could be the first time this AP is booted and the AP-tag may be unflashed.\n");
|
||||
@@ -840,16 +847,14 @@ void APTask(void* parameter) {
|
||||
#ifdef HAS_RGB_LED
|
||||
showColorPattern(CRGB::Red, CRGB::Yellow, CRGB::Red);
|
||||
#endif
|
||||
apInfo.isOnline = false;
|
||||
apInfo.state = AP_STATE_FAILED;
|
||||
setAPstate(false, AP_STATE_FAILED);
|
||||
}
|
||||
} else {
|
||||
// failed to flash
|
||||
#ifdef HAS_RGB_LED
|
||||
showColorPattern(CRGB::Red, CRGB::Red, CRGB::Red);
|
||||
#endif
|
||||
apInfo.isOnline = false;
|
||||
apInfo.state = AP_STATE_FAILED;
|
||||
setAPstate(false, AP_STATE_FAILED);
|
||||
Serial.println("Failed to flash the AP :(");
|
||||
Serial.println("Seems like you're running into some issues with the wiring, or (very small chance) the tag itself");
|
||||
Serial.println("This ESP32-build expects the following pins connected to the ZBS243:");
|
||||
@@ -890,17 +895,15 @@ void APTask(void* parameter) {
|
||||
attempts = 0;
|
||||
}
|
||||
if (attempts > 5) {
|
||||
apInfo.state = AP_STATE_WAIT_RESET;
|
||||
apInfo.isOnline = false;
|
||||
setAPstate(false, AP_STATE_WAIT_RESET);
|
||||
if (!bringAPOnline()) {
|
||||
// tried to reset the AP, but we failed... Maybe the AP-Tag died?
|
||||
apInfo.state = AP_STATE_FAILED;
|
||||
setAPstate(false, AP_STATE_FAILED);
|
||||
#ifdef HAS_RGB_LED
|
||||
showColorPattern(CRGB::Yellow, CRGB::Yellow, CRGB::Red);
|
||||
#endif
|
||||
} else {
|
||||
apInfo.state = AP_STATE_ONLINE;
|
||||
apInfo.isOnline = true;
|
||||
setAPstate(true, AP_STATE_ONLINE);
|
||||
attempts = 0;
|
||||
refreshAllPending();
|
||||
}
|
||||
|
||||
@@ -46,7 +46,7 @@ static void initSDCard() {
|
||||
}
|
||||
#endif
|
||||
|
||||
size_t DynStorage::freeSpace(){
|
||||
uint64_t DynStorage::freeSpace(){
|
||||
this->begin();
|
||||
#ifdef HAS_SDCARD
|
||||
return SD.totalBytes() - SD.usedBytes();
|
||||
|
||||
@@ -16,6 +16,7 @@ void initTime(void* parameter) {
|
||||
sntp_set_time_sync_notification_cb(timeSyncCallback);
|
||||
sntp_set_sync_interval(300 * 1000);
|
||||
configTzTime(config.timeZone, "nl.pool.ntp.org", "europe.pool.ntp.org", "time.nist.gov");
|
||||
logStartUp();
|
||||
struct tm timeinfo;
|
||||
while (millis() < 30000) {
|
||||
if (!getLocalTime(&timeinfo)) {
|
||||
@@ -25,8 +26,9 @@ void initTime(void* parameter) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
logStartUp();
|
||||
if (config.runStatus = RUNSTATUS_INIT) config.runStatus = RUNSTATUS_RUN;
|
||||
if (config.runStatus == RUNSTATUS_INIT) {
|
||||
config.runStatus = RUNSTATUS_RUN;
|
||||
}
|
||||
vTaskDelay(10 / portTICK_PERIOD_MS);
|
||||
vTaskDelete(NULL);
|
||||
}
|
||||
@@ -35,7 +37,7 @@ void logLine(const char* buffer) {
|
||||
logLine(String(buffer));
|
||||
}
|
||||
|
||||
void logLine(String text) {
|
||||
void logLine(const String& text) {
|
||||
time_t now;
|
||||
time(&now);
|
||||
|
||||
@@ -43,6 +45,7 @@ void logLine(String text) {
|
||||
const char* format = (now < (time_t)1672531200) ? " %H:%M:%S " : "%Y-%m-%d %H:%M:%S ";
|
||||
strftime(timeStr, sizeof(timeStr), format, localtime(&now));
|
||||
|
||||
xSemaphoreTake(fsMutex, portMAX_DELAY);
|
||||
File logFile = contentFS->open("/log.txt", "a");
|
||||
if (logFile) {
|
||||
if (logFile.size() >= 10 * 1024) {
|
||||
@@ -57,6 +60,7 @@ void logLine(String text) {
|
||||
logFile.println(text);
|
||||
logFile.close();
|
||||
}
|
||||
xSemaphoreGive(fsMutex);
|
||||
}
|
||||
|
||||
void logStartUp() {
|
||||
|
||||
@@ -11,6 +11,9 @@
|
||||
#include "storage.h"
|
||||
#include "util.h"
|
||||
|
||||
#define STR_IMPL(x) #x
|
||||
#define STR(x) STR_IMPL(x)
|
||||
|
||||
std::vector<tagRecord*> tagDB;
|
||||
std::unordered_map<std::string, varStruct> varDB;
|
||||
std::unordered_map<int, HwType> hwdata = {
|
||||
@@ -118,6 +121,7 @@ void fillNode(JsonObject& tag, const tagRecord* taginfo) {
|
||||
tag["apip"] = taginfo->apIp.toString();
|
||||
tag["rotate"] = taginfo->rotate;
|
||||
tag["lut"] = taginfo->lut;
|
||||
tag["invert"] = taginfo->invert;
|
||||
tag["ch"] = taginfo->currentChannel;
|
||||
tag["ver"] = taginfo->tagSoftwareVersion;
|
||||
}
|
||||
@@ -213,6 +217,7 @@ void loadDB(const String& filename) {
|
||||
taginfo->apIp.fromString(tag["apip"].as<String>());
|
||||
taginfo->rotate = tag["rotate"] | 0;
|
||||
taginfo->lut = tag["lut"] | 0;
|
||||
taginfo->invert = tag["invert"] | 0;
|
||||
taginfo->currentChannel = tag["ch"] | 0;
|
||||
taginfo->tagSoftwareVersion = tag["ver"] | 0;
|
||||
}
|
||||
@@ -259,7 +264,7 @@ uint32_t getTagCount(uint32_t& timeoutcount) {
|
||||
// not initialised, timeout if not seen last 10 minutes
|
||||
if (timeout > 600) timeoutcount++;
|
||||
} else if (now - taginfo->expectedNextCheckin > 600) {
|
||||
//expected checkin is behind, timeout if not seen last 10 minutes
|
||||
// expected checkin is behind, timeout if not seen last 10 minutes
|
||||
if (timeout > 600) timeoutcount++;
|
||||
}
|
||||
}
|
||||
@@ -300,6 +305,7 @@ void initAPconfig() {
|
||||
config.channel = APconfig["channel"] | 0;
|
||||
if (APconfig["alias"]) strlcpy(config.alias, APconfig["alias"], sizeof(config.alias));
|
||||
config.led = APconfig["led"] | 255;
|
||||
config.tft = APconfig["tft"] | 255;
|
||||
config.language = APconfig["language"] | getDefaultLanguage();
|
||||
config.maxsleep = APconfig["maxsleep"] | 10;
|
||||
config.stopsleep = APconfig["stopsleep"] | 1;
|
||||
@@ -309,6 +315,8 @@ void initAPconfig() {
|
||||
// default wifi power 8.5 dbM
|
||||
// see https://github.com/espressif/arduino-esp32/blob/master/libraries/WiFi/src/WiFiGeneric.h#L111
|
||||
config.wifiPower = APconfig["wifipower"] | 34;
|
||||
config.repo = APconfig["repo"] | "jjwbruijn/OpenEPaperLink";
|
||||
config.env = APconfig["env"] | STR(BUILD_ENV_NAME);
|
||||
if (APconfig["timezone"]) {
|
||||
strlcpy(config.timeZone, APconfig["timezone"], sizeof(config.timeZone));
|
||||
} else {
|
||||
@@ -323,6 +331,7 @@ void saveAPconfig() {
|
||||
APconfig["channel"] = config.channel;
|
||||
APconfig["alias"] = config.alias;
|
||||
APconfig["led"] = config.led;
|
||||
APconfig["tft"] = config.tft;
|
||||
APconfig["language"] = config.language;
|
||||
APconfig["maxsleep"] = config.maxsleep;
|
||||
APconfig["stopsleep"] = config.stopsleep;
|
||||
@@ -331,6 +340,8 @@ void saveAPconfig() {
|
||||
APconfig["timezone"] = config.timeZone;
|
||||
APconfig["sleeptime1"] = config.sleepTime1;
|
||||
APconfig["sleeptime2"] = config.sleepTime2;
|
||||
APconfig["repo"] = config.repo;
|
||||
APconfig["env"] = config.env;
|
||||
serializeJsonPretty(APconfig, configFile);
|
||||
configFile.close();
|
||||
xSemaphoreGive(fsMutex);
|
||||
@@ -372,19 +383,19 @@ HwType getHwType(const uint8_t id) {
|
||||
}
|
||||
}
|
||||
|
||||
bool setVarDB(const std::string& key, const String& value) {
|
||||
bool setVarDB(const std::string& key, const String& value, const bool notify) {
|
||||
auto it = varDB.find(key);
|
||||
if (it == varDB.end()) {
|
||||
varStruct newVar;
|
||||
newVar.value = value;
|
||||
newVar.changed = true;
|
||||
newVar.changed = notify;
|
||||
varDB[key] = newVar;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (it->second.value != value) {
|
||||
it->second.value = value;
|
||||
it->second.changed = true;
|
||||
it->second.changed = notify;
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
|
||||
145
ESP32_AP-Flasher/src/tagdata.cpp
Normal file
145
ESP32_AP-Flasher/src/tagdata.cpp
Normal file
@@ -0,0 +1,145 @@
|
||||
#include "tagdata.h"
|
||||
|
||||
#include "tag_db.h"
|
||||
#include "util.h"
|
||||
|
||||
std::unordered_map<size_t, TagData::Parser> TagData::parsers = {};
|
||||
|
||||
void TagData::loadParsers(const String& filename) {
|
||||
const long start = millis();
|
||||
|
||||
Storage.begin();
|
||||
fs::File file = contentFS->open(filename, "r");
|
||||
if (!file) {
|
||||
return;
|
||||
}
|
||||
Serial.println("Reading parsers from file");
|
||||
|
||||
if (file.find("[")) {
|
||||
DynamicJsonDocument doc(1000);
|
||||
bool parsing = true;
|
||||
while (parsing) {
|
||||
DeserializationError err = deserializeJson(doc, file);
|
||||
if (!err) {
|
||||
const JsonObject parserDoc = doc[0];
|
||||
const auto& id = parserDoc["id"];
|
||||
const auto& name = parserDoc["name"];
|
||||
if (!id || !name) {
|
||||
Serial.printf("Error: Parser must have name and id\n");
|
||||
continue;
|
||||
}
|
||||
|
||||
Parser parser;
|
||||
parser.name = name.as<String>();
|
||||
|
||||
for (const auto& parserField : parserDoc["parser"].as<JsonArray>()) {
|
||||
const uint8_t type = parserField["type"].as<uint8_t>();
|
||||
if (type >= (uint8_t)Type::MAX) {
|
||||
Serial.printf("Error: Type %d is not a valid tag data parser data type\n", type);
|
||||
continue;
|
||||
}
|
||||
|
||||
const auto& mult = parserField["mult"];
|
||||
const uint8_t decimals = parserField["decimals"].as<uint8_t>();
|
||||
if (mult) {
|
||||
parser.fields.emplace_back(parserField["name"].as<String>(),
|
||||
static_cast<Type>(type),
|
||||
parserField["length"].as<uint8_t>(),
|
||||
decimals,
|
||||
std::make_optional(mult.as<double>()));
|
||||
} else {
|
||||
parser.fields.emplace_back(parserField["name"].as<String>(),
|
||||
static_cast<Type>(type),
|
||||
parserField["length"].as<uint8_t>(),
|
||||
decimals);
|
||||
}
|
||||
}
|
||||
|
||||
parsers.emplace(id.as<uint8_t>(), parser);
|
||||
} else {
|
||||
Serial.print(F("deserializeJson() failed: "));
|
||||
Serial.println(err.c_str());
|
||||
parsing = false;
|
||||
}
|
||||
parsing = parsing && file.find(",");
|
||||
}
|
||||
}
|
||||
|
||||
file.close();
|
||||
Serial.printf("Loaded %d parsers in %d ms\n", parsers.size(), millis() - start);
|
||||
}
|
||||
|
||||
void TagData::parse(const uint8_t src[8], const size_t id, const uint8_t* data, const uint8_t len) {
|
||||
char buffer[64];
|
||||
|
||||
const auto it = parsers.find(id);
|
||||
if (it == parsers.end()) {
|
||||
const String log = util::formatString<64>(buffer, "Error: No parser with id %d found(%d)", id, parsers.size());
|
||||
wsErr(log);
|
||||
Serial.println(log);
|
||||
return;
|
||||
}
|
||||
|
||||
const String mac = util::formatString<64>(buffer, "%02X%02X%02X%02X%02X%02X%02X%02X.", src[7], src[6], src[5], src[4], src[3], src[2], src[1], src[0]);
|
||||
|
||||
uint16_t offset = 0;
|
||||
for (const Field& field : it->second.fields) {
|
||||
const String& name = field.name;
|
||||
const uint8_t length = field.length;
|
||||
|
||||
if (offset + length > len) {
|
||||
const String log = util::formatString<64>(buffer, "Error: Not enough data for field %s", name.c_str());
|
||||
wsErr(log);
|
||||
Serial.println(log);
|
||||
return;
|
||||
}
|
||||
|
||||
const Type type = field.type;
|
||||
const uint8_t* fieldData = data + offset;
|
||||
offset += length;
|
||||
String value = "";
|
||||
switch (type) {
|
||||
case Type::INT: {
|
||||
const double mult = field.mult.value_or(1.0);
|
||||
value = String(bytesTo<int64_t>(fieldData, length) * mult, (unsigned int)field.decimals);
|
||||
} break;
|
||||
case Type::UINT: {
|
||||
const double mult = field.mult.value_or(1.0f);
|
||||
value = String(bytesTo<uint64_t>(fieldData, length) * mult, (unsigned int)field.decimals);
|
||||
} break;
|
||||
case Type::FLOAT: {
|
||||
const double mult = field.mult.value_or(1.0f);
|
||||
|
||||
if (length == 4) {
|
||||
value = String(bytesTo<float>(fieldData, length) * mult, (unsigned int)field.decimals);
|
||||
} else if (length == 8) {
|
||||
value = String(bytesTo<double>(fieldData, length) * mult, (unsigned int)field.decimals);
|
||||
} else {
|
||||
const String log = "Error: Float can only be 4 or 8 bytes long";
|
||||
wsErr(log);
|
||||
Serial.println(log);
|
||||
}
|
||||
} break;
|
||||
case Type::STRING: {
|
||||
value = bytesTo<String>(fieldData, length);
|
||||
} break;
|
||||
|
||||
default:
|
||||
const String log = util::formatString<64>(buffer, "Error: Type %d not implemented", static_cast<uint8_t>(type));
|
||||
wsErr(log);
|
||||
Serial.println(log);
|
||||
break;
|
||||
}
|
||||
|
||||
if (value.isEmpty()) {
|
||||
const String log = util::formatString<64>(buffer, "Error: Empty value for field %s", name.c_str());
|
||||
wsErr(log);
|
||||
Serial.println(log);
|
||||
continue;
|
||||
}
|
||||
|
||||
const std::string varName = (mac + name).c_str();
|
||||
setVarDB(varName, value);
|
||||
Serial.printf("Set %s to %s\n", varName.c_str(), value.c_str());
|
||||
}
|
||||
}
|
||||
@@ -1,13 +1,14 @@
|
||||
#include "udp.h"
|
||||
|
||||
#include <Arduino.h>
|
||||
#include <WiFi.h>
|
||||
|
||||
#include "AsyncUDP.h"
|
||||
#include "commstructs.h"
|
||||
#include "newproto.h"
|
||||
#include "serialap.h"
|
||||
#include "tag_db.h"
|
||||
#include "web.h"
|
||||
#include "serialap.h"
|
||||
#include "udp.h"
|
||||
|
||||
#define UDPIP IPAddress(239, 10, 0, 1)
|
||||
#define UDPPORT 16033
|
||||
@@ -41,8 +42,9 @@ void UDPcomm::init() {
|
||||
}
|
||||
|
||||
void UDPcomm::processPacket(AsyncUDPPacket packet) {
|
||||
|
||||
if (config.runStatus == RUNSTATUS_STOP) return;
|
||||
if (config.runStatus == RUNSTATUS_STOP) {
|
||||
return;
|
||||
}
|
||||
IPAddress senderIP = packet.remoteIP();
|
||||
|
||||
switch (packet.data()[0]) {
|
||||
@@ -127,7 +129,7 @@ void autoselect(void* pvParameters) {
|
||||
}
|
||||
if (curChannel.channel == 0) {
|
||||
curChannel.channel = 11;
|
||||
}
|
||||
}
|
||||
config.channel = curChannel.channel;
|
||||
do {
|
||||
vTaskDelay(1000 / portTICK_PERIOD_MS);
|
||||
|
||||
@@ -20,14 +20,13 @@
|
||||
#include "serialap.h"
|
||||
#include "settings.h"
|
||||
#include "storage.h"
|
||||
#include "system.h"
|
||||
#include "tag_db.h"
|
||||
#include "udp.h"
|
||||
#include "wifimanager.h"
|
||||
|
||||
extern uint8_t data_to_send[];
|
||||
|
||||
// const char *http_username = "admin";
|
||||
// const char *http_password = "admin";
|
||||
AsyncWebServer server(80);
|
||||
AsyncWebSocket ws("/ws");
|
||||
WifiManager wm;
|
||||
@@ -35,7 +34,7 @@ WifiManager wm;
|
||||
SemaphoreHandle_t wsMutex;
|
||||
uint32_t lastssidscan = 0;
|
||||
|
||||
void wsLog(String text) {
|
||||
void wsLog(const String &text) {
|
||||
StaticJsonDocument<250> doc;
|
||||
doc["logMsg"] = text;
|
||||
if (wsMutex) xSemaphoreTake(wsMutex, portMAX_DELAY);
|
||||
@@ -43,7 +42,7 @@ void wsLog(String text) {
|
||||
if (wsMutex) xSemaphoreGive(wsMutex);
|
||||
}
|
||||
|
||||
void wsErr(String text) {
|
||||
void wsErr(const String &text) {
|
||||
StaticJsonDocument<250> doc;
|
||||
doc["errMsg"] = text;
|
||||
if (wsMutex) xSemaphoreTake(wsMutex, portMAX_DELAY);
|
||||
@@ -69,7 +68,7 @@ void wsSendSysteminfo() {
|
||||
time(&now);
|
||||
static int freeSpaceLastRun = 0;
|
||||
static size_t tagDBsize = 0;
|
||||
static size_t freeSpace = Storage.freeSpace();
|
||||
static uint64_t freeSpace = Storage.freeSpace();
|
||||
sys["currtime"] = now;
|
||||
sys["heap"] = ESP.getFreeHeap();
|
||||
sys["recordcount"] = tagDBsize;
|
||||
@@ -80,6 +79,11 @@ void wsSendSysteminfo() {
|
||||
freeSpaceLastRun = millis();
|
||||
}
|
||||
sys["littlefsfree"] = freeSpace;
|
||||
|
||||
#if BOARD_HAS_PSRAM
|
||||
sys["psfree"] = ESP.getFreePsram();
|
||||
#endif
|
||||
|
||||
sys["apstate"] = apInfo.state;
|
||||
sys["runstate"] = config.runStatus;
|
||||
#if !defined(CONFIG_IDF_TARGET_ESP32)
|
||||
@@ -98,8 +102,14 @@ void wsSendSysteminfo() {
|
||||
uint32_t tagcount = getTagCount(timeoutcount);
|
||||
char result[40];
|
||||
if (timeoutcount > 0) {
|
||||
#ifdef HAS_RGB_LED
|
||||
if (apInfo.state == AP_STATE_ONLINE && apInfo.isOnline == true) rgbIdleColor = CRGB::DarkBlue;
|
||||
#endif
|
||||
snprintf(result, sizeof(result), "%lu / %lu, %lu timed out", tagcount, tagDB.size(), timeoutcount);
|
||||
} else {
|
||||
#ifdef HAS_RGB_LED
|
||||
if (apInfo.state == AP_STATE_ONLINE && apInfo.isOnline == true) rgbIdleColor = CRGB::Green;
|
||||
#endif
|
||||
snprintf(result, sizeof(result), "%lu / %lu", tagcount, tagDB.size());
|
||||
}
|
||||
setVarDB("ap_tagcount", result);
|
||||
@@ -167,7 +177,7 @@ void wsSendAPitem(struct APlist *apitem) {
|
||||
if (wsMutex) xSemaphoreGive(wsMutex);
|
||||
}
|
||||
|
||||
void wsSerial(String text) {
|
||||
void wsSerial(const String &text) {
|
||||
StaticJsonDocument<250> doc;
|
||||
doc["console"] = text;
|
||||
Serial.println(text);
|
||||
@@ -184,12 +194,10 @@ void init_web() {
|
||||
wsMutex = xSemaphoreCreateMutex();
|
||||
Storage.begin();
|
||||
WiFi.mode(WIFI_STA);
|
||||
|
||||
WiFi.setTxPower(static_cast<wifi_power_t>(config.wifiPower));
|
||||
|
||||
wm.connectToWifi();
|
||||
|
||||
// server.addHandler(new SPIFFSEditor(*contentFS, http_username, http_password));
|
||||
server.addHandler(new SPIFFSEditor(*contentFS));
|
||||
|
||||
server.addHandler(&ws);
|
||||
@@ -270,6 +278,9 @@ void init_web() {
|
||||
if (request->hasParam("lut", true)) {
|
||||
taginfo->lut = atoi(request->getParam("lut", true)->value().c_str());
|
||||
}
|
||||
if (request->hasParam("invert", true)) {
|
||||
taginfo->invert = atoi(request->getParam("invert", true)->value().c_str());
|
||||
}
|
||||
// memset(taginfo->md5, 0, 16 * sizeof(uint8_t));
|
||||
// memset(taginfo->md5pending, 0, 16 * sizeof(uint8_t));
|
||||
wsSendTaginfo(mac, SYNC_USERCFG);
|
||||
@@ -424,48 +435,59 @@ void init_web() {
|
||||
});
|
||||
|
||||
server.on("/save_apcfg", HTTP_POST, [](AsyncWebServerRequest *request) {
|
||||
if (request->hasParam("alias", true) && request->hasParam("channel", true)) {
|
||||
if (request->hasParam("alias", true)) {
|
||||
String aliasValue = request->getParam("alias", true)->value();
|
||||
size_t aliasLength = aliasValue.length();
|
||||
if (aliasLength > 31) aliasLength = 31;
|
||||
aliasValue.toCharArray(config.alias, aliasLength + 1);
|
||||
config.alias[aliasLength] = '\0';
|
||||
|
||||
config.channel = static_cast<uint8_t>(request->getParam("channel", true)->value().toInt());
|
||||
if (request->hasParam("led", true)) {
|
||||
config.led = static_cast<int16_t>(request->getParam("led", true)->value().toInt());
|
||||
updateBrightnessFromConfig();
|
||||
}
|
||||
if (request->hasParam("language", true)) {
|
||||
config.language = static_cast<uint8_t>(request->getParam("language", true)->value().toInt());
|
||||
updateLanguageFromConfig();
|
||||
}
|
||||
if (request->hasParam("maxsleep", true)) {
|
||||
config.maxsleep = static_cast<uint8_t>(request->getParam("maxsleep", true)->value().toInt());
|
||||
}
|
||||
if (request->hasParam("stopsleep", true)) {
|
||||
config.stopsleep = static_cast<uint8_t>(request->getParam("stopsleep", true)->value().toInt());
|
||||
}
|
||||
if (request->hasParam("preview", true)) {
|
||||
config.preview = static_cast<uint8_t>(request->getParam("preview", true)->value().toInt());
|
||||
}
|
||||
if (request->hasParam("sleeptime1", true)) {
|
||||
config.sleepTime1 = static_cast<uint8_t>(request->getParam("sleeptime1", true)->value().toInt());
|
||||
config.sleepTime2 = static_cast<uint8_t>(request->getParam("sleeptime2", true)->value().toInt());
|
||||
}
|
||||
if (request->hasParam("wifipower", true)) {
|
||||
config.wifiPower = static_cast<uint8_t>(request->getParam("wifipower", true)->value().toInt());
|
||||
WiFi.setTxPower(static_cast<wifi_power_t>(config.wifiPower));
|
||||
}
|
||||
if (request->hasParam("timezone", true)) {
|
||||
strncpy(config.timeZone, request->getParam("timezone", true)->value().c_str(), sizeof(config.timeZone) - 1);
|
||||
config.timeZone[sizeof(config.timeZone) - 1] = '\0';
|
||||
setenv("TZ", config.timeZone, 1);
|
||||
tzset();
|
||||
}
|
||||
saveAPconfig();
|
||||
setAPchannel();
|
||||
}
|
||||
if (request->hasParam("channel", true)) {
|
||||
config.channel = static_cast<uint8_t>(request->getParam("channel", true)->value().toInt());
|
||||
}
|
||||
if (request->hasParam("led", true)) {
|
||||
config.led = static_cast<int16_t>(request->getParam("led", true)->value().toInt());
|
||||
updateBrightnessFromConfig();
|
||||
}
|
||||
if (request->hasParam("tft", true)) {
|
||||
config.tft = static_cast<int16_t>(request->getParam("tft", true)->value().toInt());
|
||||
updateBrightnessFromConfig();
|
||||
}
|
||||
if (request->hasParam("language", true)) {
|
||||
config.language = static_cast<uint8_t>(request->getParam("language", true)->value().toInt());
|
||||
updateLanguageFromConfig();
|
||||
}
|
||||
if (request->hasParam("maxsleep", true)) {
|
||||
config.maxsleep = static_cast<uint8_t>(request->getParam("maxsleep", true)->value().toInt());
|
||||
}
|
||||
if (request->hasParam("stopsleep", true)) {
|
||||
config.stopsleep = static_cast<uint8_t>(request->getParam("stopsleep", true)->value().toInt());
|
||||
}
|
||||
if (request->hasParam("preview", true)) {
|
||||
config.preview = static_cast<uint8_t>(request->getParam("preview", true)->value().toInt());
|
||||
}
|
||||
if (request->hasParam("sleeptime1", true)) {
|
||||
config.sleepTime1 = static_cast<uint8_t>(request->getParam("sleeptime1", true)->value().toInt());
|
||||
config.sleepTime2 = static_cast<uint8_t>(request->getParam("sleeptime2", true)->value().toInt());
|
||||
}
|
||||
if (request->hasParam("wifipower", true)) {
|
||||
config.wifiPower = static_cast<uint8_t>(request->getParam("wifipower", true)->value().toInt());
|
||||
WiFi.setTxPower(static_cast<wifi_power_t>(config.wifiPower));
|
||||
}
|
||||
if (request->hasParam("timezone", true)) {
|
||||
strncpy(config.timeZone, request->getParam("timezone", true)->value().c_str(), sizeof(config.timeZone) - 1);
|
||||
config.timeZone[sizeof(config.timeZone) - 1] = '\0';
|
||||
setenv("TZ", config.timeZone, 1);
|
||||
tzset();
|
||||
}
|
||||
if (request->hasParam("repo", true)) {
|
||||
config.repo = request->getParam("repo", true)->value();
|
||||
}
|
||||
if (request->hasParam("env", true)) {
|
||||
config.env = request->getParam("env", true)->value();
|
||||
}
|
||||
saveAPconfig();
|
||||
setAPchannel();
|
||||
request->send(200, "text/plain", "Ok, saved");
|
||||
});
|
||||
|
||||
@@ -563,8 +585,26 @@ void init_web() {
|
||||
request->send(200, "text/plain", "Ok, saved");
|
||||
|
||||
ws.enable(false);
|
||||
refreshAllPending();
|
||||
saveDB("/current/tagDB.json");
|
||||
|
||||
if (jsonObj["ssid"].as<String>() == "factory") {
|
||||
preferences.begin("wifi", false);
|
||||
preferences.putString("ssid", "");
|
||||
preferences.putString("pw", "");
|
||||
preferences.end();
|
||||
contentFS->remove("/AP_FW_Pack.bin");
|
||||
contentFS->remove("/OpenEPaperLink_esp32_C6.bin");
|
||||
contentFS->remove("/bootloader.bin");
|
||||
contentFS->remove("/partition-table.bin");
|
||||
contentFS->remove("/update_actions.json");
|
||||
contentFS->remove("/log.txt");
|
||||
contentFS->remove("/current/tagDB.json");
|
||||
delay(100);
|
||||
ESP.restart();
|
||||
} else {
|
||||
refreshAllPending();
|
||||
saveDB("/current/tagDB.json");
|
||||
}
|
||||
|
||||
ws.closeAll();
|
||||
delay(100);
|
||||
ESP.restart();
|
||||
@@ -607,16 +647,19 @@ void init_web() {
|
||||
}
|
||||
|
||||
void doImageUpload(AsyncWebServerRequest *request, String filename, size_t index, uint8_t *data, size_t len, bool final) {
|
||||
if (config.runStatus != RUNSTATUS_RUN) {
|
||||
request->send(409, "text/plain", "come back later");
|
||||
return;
|
||||
}
|
||||
static bool imageUploadBusy = false;
|
||||
if (!index) {
|
||||
if (config.runStatus != RUNSTATUS_RUN || imageUploadBusy) {
|
||||
request->send(409, "text/plain", "Come back later");
|
||||
return;
|
||||
}
|
||||
if (request->hasParam("mac", true)) {
|
||||
filename = request->getParam("mac", true)->value() + ".jpg";
|
||||
} else {
|
||||
filename = "unknown.jpg";
|
||||
}
|
||||
imageUploadBusy = true;
|
||||
logLine("http imageUpload " + filename);
|
||||
xSemaphoreTake(fsMutex, portMAX_DELAY);
|
||||
request->_tempFile = contentFS->open("/" + filename, "w");
|
||||
}
|
||||
@@ -652,6 +695,7 @@ void doImageUpload(AsyncWebServerRequest *request, String filename, size_t index
|
||||
} else {
|
||||
request->send(400, "text/plain", "parameters incomplete");
|
||||
}
|
||||
imageUploadBusy = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
{
|
||||
"id": 0,
|
||||
"name": "Static image",
|
||||
"desc": "Shows a static image, from file system, painter or external source",
|
||||
"desc": "Shows a static image, from file system, painter or external source. Make sure to resize the image to the correct resolution.",
|
||||
"hwtype": [
|
||||
0,
|
||||
1,
|
||||
@@ -17,7 +17,7 @@
|
||||
"key": "filename",
|
||||
"name": "Filename",
|
||||
"desc": "Local filename on the littlefs drive",
|
||||
"type": "text"
|
||||
"type": "jpgfile"
|
||||
},
|
||||
{
|
||||
"key": "timetolive",
|
||||
@@ -34,6 +34,47 @@
|
||||
"0": "off",
|
||||
"1": "on"
|
||||
}
|
||||
},
|
||||
{
|
||||
"key": "preload",
|
||||
"name": "Display or Preload",
|
||||
"desc": "Display now or preload for later use",
|
||||
"type": "select",
|
||||
"options": {
|
||||
"0": "Display",
|
||||
"1": "Preload"
|
||||
}
|
||||
},
|
||||
{
|
||||
"key": "preload_lut",
|
||||
"name": "Preload LUT",
|
||||
"desc": "Triggered preload images will display with this LUT",
|
||||
"type": "select",
|
||||
"options": {
|
||||
"0": "Default",
|
||||
"1": "No Repeats",
|
||||
"2": "Fast No Reds",
|
||||
"3": "Fast"
|
||||
}
|
||||
},
|
||||
{
|
||||
"key": "preload_type",
|
||||
"name": "Preload Image type",
|
||||
"desc": "Preload type to send to tag, for later recall, or special use",
|
||||
"type": "select",
|
||||
"options": {
|
||||
"0": "Normal",
|
||||
"1": "UI: Splash Screen",
|
||||
"2": "UI: Lost connection",
|
||||
"3": "UI: AP Found",
|
||||
"4": "UI: No AP Found",
|
||||
"5": "UI: Long Term Sleep",
|
||||
"15": "Slideshow image",
|
||||
"16": "Wake: Button 1",
|
||||
"17": "Wake: Button 2",
|
||||
"29": "Wake: GPIO",
|
||||
"30": "Wake: NFC"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -332,7 +373,7 @@
|
||||
"key": "filename",
|
||||
"name": "Filename",
|
||||
"desc": "Filename of the json template. See OpenEpaperLink wiki for the right json format. Specify a url OR a filename",
|
||||
"type": "text"
|
||||
"type": "jsonfile"
|
||||
},
|
||||
{
|
||||
"key": "interval",
|
||||
@@ -406,7 +447,7 @@
|
||||
{
|
||||
"id": 5,
|
||||
"name": "Firmware update",
|
||||
"desc": "To update tag firmware",
|
||||
"desc": "To update tag firmware. Make sure you send the right .bin file! You can brick your tag if you send a wrong file.",
|
||||
"hwtype": [
|
||||
0,
|
||||
1,
|
||||
@@ -422,7 +463,7 @@
|
||||
"key": "filename",
|
||||
"name": "Filename",
|
||||
"desc": "Local file on littlefs partition",
|
||||
"type": "text"
|
||||
"type": "binfile"
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -649,6 +690,9 @@
|
||||
"id": 21,
|
||||
"name": "Access point info",
|
||||
"desc": "Displays information about the currently connected access point",
|
||||
"hwtype": [0, 1]
|
||||
"hwtype": [
|
||||
0,
|
||||
1
|
||||
]
|
||||
}
|
||||
]
|
||||
]
|
||||
@@ -39,376 +39,420 @@
|
||||
</nav>
|
||||
</header>
|
||||
|
||||
<form>
|
||||
<div class="container">
|
||||
<div class="container">
|
||||
|
||||
<div class="window">
|
||||
<div class="window">
|
||||
|
||||
<div id="hometab" class="tabcontent">
|
||||
<table>
|
||||
<tr onclick="setFilterAndShow('')">
|
||||
<td class="material-symbols-outlined" style="color:#239f26" id="dashboardStatusIcon">
|
||||
check_circle
|
||||
</td>
|
||||
<td id="dashboardStatus" style="color:#239f26" colspan="2">
|
||||
initialising...
|
||||
</td>
|
||||
</tr>
|
||||
<tr onclick="setFilterAndShow('')">
|
||||
<td class="material-symbols-outlined" style="color:#77239e">
|
||||
<div id="hometab" class="tabcontent">
|
||||
<table>
|
||||
<tr onclick="setFilterAndShow('')">
|
||||
<td class="material-symbols-outlined" style="color:#239f26" id="dashboardStatusIcon">
|
||||
check_circle
|
||||
</td>
|
||||
<td id="dashboardStatus" style="color:#239f26" colspan="2">
|
||||
initialising...
|
||||
</td>
|
||||
</tr>
|
||||
<tr onclick="setFilterAndShow('')">
|
||||
<td class="material-symbols-outlined" style="color:#77239e">
|
||||
sell
|
||||
</td>
|
||||
<td>
|
||||
tags
|
||||
</td>
|
||||
<td id="dashboardTagCount" style="color:#77239e">
|
||||
0
|
||||
</td>
|
||||
</tr>
|
||||
<tr onclick="setFilterAndShow('pending')">
|
||||
<td class="material-symbols-outlined" style="color:#235f9e">
|
||||
hourglass_empty
|
||||
</td>
|
||||
<td>
|
||||
pending data
|
||||
</td>
|
||||
<td id="dashboardPending" style="color:#235f9e">
|
||||
0
|
||||
</td>
|
||||
</tr>
|
||||
<tr onclick="setFilterAndShow('lowbatt')">
|
||||
<td class="material-symbols-outlined" style="color:#9e9223">
|
||||
battery_low
|
||||
</td>
|
||||
<td>
|
||||
low battery
|
||||
</td>
|
||||
<td id="dashboardLowBatt" style="color:#9e9223">
|
||||
0
|
||||
</td>
|
||||
</tr>
|
||||
<tr onclick="setFilterAndShow('inactive')">
|
||||
<td class="material-symbols-outlined" style="color:#9e2323">
|
||||
signal_disconnected
|
||||
</td>
|
||||
<td>
|
||||
timeout
|
||||
</td>
|
||||
<td id="dashboardTimeout" style="color:#9e2323">
|
||||
0
|
||||
</td>
|
||||
</tr>
|
||||
<!--
|
||||
<tr onclick="$(`[data-target='aptab']`).click()">
|
||||
<td class="material-symbols-outlined" style="color:#239f26">
|
||||
cell_tower
|
||||
</td>
|
||||
<td>
|
||||
access points
|
||||
</td>
|
||||
<td id="dashboardApCount" style="color:#239f26">
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
-->
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<div id="tagtab" class="tabcontent">
|
||||
<div class="tagheader">
|
||||
<h3>Currently active tags</h3>
|
||||
<div id="activefilter"></div><button class="material-symbols-outlined"
|
||||
id="toggleFilters">filter_alt</button>
|
||||
</div>
|
||||
<div id="filterOptions">
|
||||
<div>
|
||||
<div>group by</div>
|
||||
<div>
|
||||
<input type="radio" name="group" value="" id="rnone" checked><label
|
||||
for="rnone">None</label>
|
||||
</div>
|
||||
<div>
|
||||
<input type="radio" name="group" value="model" id="rtagtype"><label for="rtagtype">Tag
|
||||
model</label>
|
||||
</div>
|
||||
<div>
|
||||
<input type="radio" name="group" value="contentmode" id="rcontent"><label
|
||||
for="rcontent">Content</label>
|
||||
</div>
|
||||
<div>
|
||||
<input type="radio" name="group" value="data-channel" id="rchannel"><label
|
||||
for="rchannel">Channel</label>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<div>sort by</div>
|
||||
<div>
|
||||
<input type="radio" name="sort" value="alias" id="ralias" checked><label
|
||||
for="ralias">Alias</label>
|
||||
</div>
|
||||
<div>
|
||||
<input type="radio" name="sort" value="mac" id="rmac"><label for="rmac">Mac</label>
|
||||
</div>
|
||||
<div>
|
||||
<input type="radio" name="sort" value="data-lastseen" id="rlastseen"><label
|
||||
for="rlastseen">Last seen</label>
|
||||
</div>
|
||||
<div>
|
||||
<input type="radio" name="sort" value="data-nextupdate" id="rnext"><label
|
||||
for="rnext">Next update</label>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<div>filter</div>
|
||||
<div>
|
||||
<input type="checkbox" name="filter" value="local" id="rlocal"><label
|
||||
for="rlocal">local</label>
|
||||
</div>
|
||||
<div>
|
||||
<input type="checkbox" name="filter" value="remote" id="rremote"><label
|
||||
for="rremote">remote</label>
|
||||
</div>
|
||||
<div>
|
||||
<input type="checkbox" name="filter" value="inactive" id="rinactive"><label
|
||||
for="rinactive">timed out</label>
|
||||
</div>
|
||||
<div>
|
||||
<input type="checkbox" name="filter" value="pending" id="rpending"><label
|
||||
for="rpending">pending</label>
|
||||
</div>
|
||||
<div>
|
||||
<input type="checkbox" name="filter" value="lowbatt" id="rlowbatt"><label
|
||||
for="rlowbatt">low battery</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="taglist" class="taglist">
|
||||
<div class="tagcard" id="tagtemplate">
|
||||
<div class="currimg"><canvas class="tagimg"></div>
|
||||
<div class="mac"></div>
|
||||
<div class="alias"></div>
|
||||
<div class="model"></div>
|
||||
<div class="received"></div>
|
||||
<div class="contentmode"></div>
|
||||
<div class="lastseen"></div>
|
||||
<div class="nextcheckin"></div>
|
||||
<div class="nextupdate"></div>
|
||||
<div class="corner">
|
||||
<div class="pendingicon" title="A new message is waiting for the tag to pick up">
|
||||
↻</div>
|
||||
<div class="warningicon" title="This tag has not been seen for a long time">⚠
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="logtab" class="tabcontent">
|
||||
<div class="tabheader">
|
||||
<div><img id="clearlog" src="data:image/gif;base64,R0lGODlhEAAQAPMAANXV1e3t7d/f39HR0dvb2/Hx8dTU1OLi4urq6mZmZpmZmf///wAAAAAAAAAAAAAAACH5BAEAAAwALAAAAAAQABAAAARBkMlJq71Yrp3ZXkr4WWCYnOZSgQVyEMYwJCq1nHhe20qgCAoA7QLyAYU7njE4JPV+zOSkCEUSFbmTVPPpbjvgTAQAOw==
|
||||
"></div>
|
||||
<div><input type="checkbox" id="showdebug" value="1"><label for="showdebug">Show all websocket
|
||||
traffic</label></div>
|
||||
</div>
|
||||
<ul id="messages" class="messages">
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div id="aptab" class="tabcontent">
|
||||
<h3>Active access points</h3>
|
||||
|
||||
<div id="aplist">
|
||||
<div id="apcard" class="apcard">
|
||||
<p class="apip">194.109.6.66</p>
|
||||
<p class="apalias">AP kitchen</p>
|
||||
<div>
|
||||
<span class="material-symbols-outlined">
|
||||
sell
|
||||
</td>
|
||||
<td>
|
||||
tags
|
||||
</td>
|
||||
<td id="dashboardTagCount" style="color:#77239e">
|
||||
0
|
||||
</td>
|
||||
</tr>
|
||||
<tr onclick="setFilterAndShow('pending')">
|
||||
<td class="material-symbols-outlined" style="color:#235f9e">
|
||||
hourglass_empty
|
||||
</td>
|
||||
<td>
|
||||
pending data
|
||||
</td>
|
||||
<td id="dashboardPending" style="color:#235f9e">
|
||||
0
|
||||
</td>
|
||||
</tr>
|
||||
<tr onclick="setFilterAndShow('lowbatt')">
|
||||
<td class="material-symbols-outlined" style="color:#9e9223">
|
||||
battery_low
|
||||
</td>
|
||||
<td>
|
||||
low battery
|
||||
</td>
|
||||
<td id="dashboardLowBatt" style="color:#9e9223">
|
||||
0
|
||||
</td>
|
||||
</tr>
|
||||
<tr onclick="setFilterAndShow('inactive')">
|
||||
<td class="material-symbols-outlined" style="color:#9e2323">
|
||||
signal_disconnected
|
||||
</td>
|
||||
<td>
|
||||
timeout
|
||||
</td>
|
||||
<td id="dashboardTimeout" style="color:#9e2323">
|
||||
0
|
||||
</td>
|
||||
</tr>
|
||||
<!--
|
||||
<tr onclick="$(`[data-target='aptab']`).click()">
|
||||
<td class="material-symbols-outlined" style="color:#239f26">
|
||||
</span>
|
||||
<span class="aptagcount">13</span>
|
||||
<span class="material-symbols-outlined space">
|
||||
cell_tower
|
||||
</td>
|
||||
<td>
|
||||
access points
|
||||
</td>
|
||||
<td id="dashboardApCount" style="color:#239f26">
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
-->
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<div id="tagtab" class="tabcontent">
|
||||
<div class="tagheader">
|
||||
<h3>Currently active tags</h3>
|
||||
<div id="activefilter"></div><button class="material-symbols-outlined"
|
||||
id="toggleFilters">filter_alt</button>
|
||||
</div>
|
||||
<div id="filterOptions">
|
||||
<div>
|
||||
<div>group by</div>
|
||||
<div>
|
||||
<input type="radio" name="group" value="" id="rnone" checked><label
|
||||
for="rnone">None</label>
|
||||
</div>
|
||||
<div>
|
||||
<input type="radio" name="group" value="model" id="rtagtype"><label for="rtagtype">Tag
|
||||
model</label>
|
||||
</div>
|
||||
<div>
|
||||
<input type="radio" name="group" value="contentmode" id="rcontent"><label
|
||||
for="rcontent">Content</label>
|
||||
</div>
|
||||
<div>
|
||||
<input type="radio" name="group" value="data-channel" id="rchannel"><label
|
||||
for="rchannel">Channel</label>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<div>sort by</div>
|
||||
<div>
|
||||
<input type="radio" name="sort" value="alias" id="ralias" checked><label
|
||||
for="ralias">Alias</label>
|
||||
</div>
|
||||
<div>
|
||||
<input type="radio" name="sort" value="mac" id="rmac"><label for="rmac">Mac</label>
|
||||
</div>
|
||||
<div>
|
||||
<input type="radio" name="sort" value="data-lastseen" id="rlastseen"><label
|
||||
for="rlastseen">Last seen</label>
|
||||
</div>
|
||||
<div>
|
||||
<input type="radio" name="sort" value="data-nextupdate" id="rnext"><label
|
||||
for="rnext">Next update</label>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<div>filter</div>
|
||||
<div>
|
||||
<input type="checkbox" name="filter" value="local" id="rlocal"><label
|
||||
for="rlocal">local</label>
|
||||
</div>
|
||||
<div>
|
||||
<input type="checkbox" name="filter" value="remote" id="rremote"><label
|
||||
for="rremote">remote</label>
|
||||
</div>
|
||||
<div>
|
||||
<input type="checkbox" name="filter" value="inactive" id="rinactive"><label
|
||||
for="rinactive">timed out</label>
|
||||
</div>
|
||||
<div>
|
||||
<input type="checkbox" name="filter" value="pending" id="rpending"><label
|
||||
for="rpending">pending</label>
|
||||
</div>
|
||||
<div>
|
||||
<input type="checkbox" name="filter" value="lowbatt" id="rlowbatt"><label
|
||||
for="rlowbatt">low battery</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="taglist" class="taglist">
|
||||
<div class="tagcard" id="tagtemplate">
|
||||
<div class="currimg"><canvas class="tagimg"></div>
|
||||
<div class="mac"></div>
|
||||
<div class="alias"></div>
|
||||
<div class="model"></div>
|
||||
<div class="received"></div>
|
||||
<div class="contentmode"></div>
|
||||
<div class="lastseen"></div>
|
||||
<div class="nextcheckin"></div>
|
||||
<div class="nextupdate"></div>
|
||||
<div class="corner">
|
||||
<div class="pendingicon" title="A new message is waiting for the tag to pick up">
|
||||
↻</div>
|
||||
<div class="warningicon" title="This tag has not been seen for a long time">⚠
|
||||
</div>
|
||||
</div>
|
||||
</span>
|
||||
<span class="apchannel">25</span>
|
||||
</div>
|
||||
<p class="apswversion">
|
||||
fetching software version...
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="logtab" class="tabcontent">
|
||||
<div class="tabheader">
|
||||
<div><img id="clearlog" src="data:image/gif;base64,R0lGODlhEAAQAPMAANXV1e3t7d/f39HR0dvb2/Hx8dTU1OLi4urq6mZmZpmZmf///wAAAAAAAAAAAAAAACH5BAEAAAwALAAAAAAQABAAAARBkMlJq71Yrp3ZXkr4WWCYnOZSgQVyEMYwJCq1nHhe20qgCAoA7QLyAYU7njE4JPV+zOSkCEUSFbmTVPPpbjvgTAQAOw==
|
||||
"></div>
|
||||
<div><input type="checkbox" id="showdebug" value="1"><label for="showdebug">Show all websocket
|
||||
traffic</label></div>
|
||||
</div>
|
||||
<ul id="messages" class="messages">
|
||||
</ul>
|
||||
</div>
|
||||
<div id="templatetab" class="tabcontent">
|
||||
Work in progress...
|
||||
</div>
|
||||
|
||||
<div id="aptab" class="tabcontent">
|
||||
<h3>Active access points</h3>
|
||||
<div id="configtab" class="tabcontent">
|
||||
<h3>Access Point config</h3>
|
||||
<p>
|
||||
<label for="apcfgalias">Alias</label>
|
||||
<input id="apcfgalias" type="text">
|
||||
</p>
|
||||
<p>
|
||||
<label for="apcfgchid">IEEE 802.15.4 channel</label>
|
||||
<select id="apcfgchid">
|
||||
<option value="0" selected>auto</option>
|
||||
<option value="11">11</option>
|
||||
<option value="15">15</option>
|
||||
<option value="20">20</option>
|
||||
<option value="25">25</option>
|
||||
<option value="26">26</option>
|
||||
<option value="27">27</option>
|
||||
</select>
|
||||
</p>
|
||||
<p>
|
||||
<label for="apcfgledbrightness">RGB LED brightness</label>
|
||||
<select id="apcfgledbrightness">
|
||||
<option value="-1">off</option>
|
||||
<option value="15">10%</option>
|
||||
<option value="31">25%</option>
|
||||
<option value="127" selected>50%</option>
|
||||
<option value="191">75%</option>
|
||||
<option value="255">100%</option>
|
||||
</select>
|
||||
</p>
|
||||
<p>
|
||||
<label for="apcfgtftbrightness">TFT brightness</label>
|
||||
<select id="apcfgtftbrightness">
|
||||
<option value="0">off</option>
|
||||
<option value="20">10%</option>
|
||||
<option value="64">25%</option>
|
||||
<option value="128">50%</option>
|
||||
<option value="192">75%</option>
|
||||
<option value="255" selected>100%</option>
|
||||
</select>
|
||||
</p>
|
||||
<p>
|
||||
<label for="apcfglanguage">Content language</label>
|
||||
<select id="apcfglanguage">
|
||||
<option value="0" selected>EN English</option>
|
||||
<option value="1">NL Nederlands</option>
|
||||
<option value="2">DE Deutsch</option>
|
||||
</select>
|
||||
</p>
|
||||
<p title="Depending on the content, a tag can sleep for
|
||||
longer periods when no updates are expected
|
||||
(like a date display). This setting specifies
|
||||
the maximum sleep time.">
|
||||
<label for="apclatency">Maximum sleep</label>
|
||||
<select id="apclatency">
|
||||
<option value="0" selected>shortest (40 sec)</option>
|
||||
<option value="5">5 minutes</option>
|
||||
<option value="10">10 minute</option>
|
||||
<option value="30">30 minutes</option>
|
||||
<option value="60">1 hour</option>
|
||||
</select>
|
||||
</p>
|
||||
<p title="If connected to the website, don't sleep extra.
|
||||
Latency will be around 40 seconds.">
|
||||
<label for="apcpreventsleep">Shorten latency during config</label>
|
||||
<select id="apcpreventsleep">
|
||||
<option value="0">no</option>
|
||||
<option value="1" selected>yes</option>
|
||||
</select>
|
||||
</p>
|
||||
<p
|
||||
title="Stops updates at night, and put the tags to sleep. During the configured night time, this overrides the maximum sleep time.">
|
||||
<label for="apcnight1">No updates between</label>
|
||||
<select id="apcnight1"></select>
|
||||
<span style="align-self:center;">and</span>
|
||||
<select id="apcnight2"></select>
|
||||
</p>
|
||||
<p title="Turn off preview images on the webpage if you want to manage many tags,
|
||||
to save file system space">
|
||||
<label for="apcpreview">Preview images</label>
|
||||
<select id="apcpreview">
|
||||
<option value="1" selected>yes</option>
|
||||
<option value="0">no</option>
|
||||
</select>
|
||||
</p>
|
||||
<p title="Wifi transmit power">
|
||||
<label for="apcwifipower">Wifi power</label>
|
||||
<select id="apcwifipower">
|
||||
<option value="78">19.5 dBm</option>
|
||||
<option value="76">19.0 dBm</option>
|
||||
<option value="74">18.5 dBm</option>
|
||||
<option value="68">17.0 dBm</option>
|
||||
<option value="60">15.0 dBm</option>
|
||||
<option value="52">13.0 dBm</option>
|
||||
<option value="44">11.0 dBm</option>
|
||||
<option value="34" selected>8.5 dBm</option>
|
||||
<option value="28">7.0 dBm</option>
|
||||
<option value="20">5.0 dBm</option>
|
||||
<option value="8">2.0 dBm</option>
|
||||
</select>
|
||||
</p>
|
||||
<p title="Your local time zone">
|
||||
<label for="apctimezone">Local time zone</label>
|
||||
<select id="apctimezone">
|
||||
<optgroup label="Europe">
|
||||
<option value="CET-1CEST-2,M3.5.0/02:00:00,M10.5.0/03:00:00" selected>Central European
|
||||
Time</option>
|
||||
<option value="EET-2EEST-3,M3.5.0/03:00:00,M10.5.0/04:00:00">Athens, Greece</option>
|
||||
<option value="GMT+0IST-1,M3.5.0/01:00:00,M10.5.0/02:00:00">Dublin, Ireland</option>
|
||||
<option value="EET-2EEST-3,M3.5.0/03:00:00,M10.5.0/04:00:00">Helsinki, Finland</option>
|
||||
<option value="WET-0WEST-1,M3.5.0/01:00:00,M10.5.0/02:00:00">Lisbon, Portugal</option>
|
||||
<option value="GMT+0BST-1,M3.5.0/01:00:00,M10.5.0/02:00:00">London, Great Britain
|
||||
</option>
|
||||
<option value="EET-2EEST,M3.5.0/3,M10.5.0/4">Kyiv, Ukraine</option>
|
||||
</optgroup>
|
||||
<optgroup label="USA / Canada">
|
||||
<option value="HAW10">Hawaii Time</option>
|
||||
<option value="AKST9AKDT">Alaska Time</option>
|
||||
<option value="PST8PDT">Pacific Time</option>
|
||||
<option value="MST7MDT">Mountain Time</option>
|
||||
<option value="MST7">Arizona, no DST</option>
|
||||
<option value="CST6CDT">Central Time</option>
|
||||
<option value="EST5EDT">Eastern Time</option>
|
||||
</optgroup>
|
||||
<optgroup label="Australia / New Zealand">
|
||||
<option value="EST-10EDT-11,M10.5.0/02:00:00,M3.5.0/03:00:00">Melbourne, Sydney</option>
|
||||
<option value="WST-8">Perth</option>
|
||||
<option value="EST-10">Brisbane</option>
|
||||
<option value="CST-9:30CDT-10:30,M10.5.0/02:00:00,M3.5.0/03:00:00">Adelaide</option>
|
||||
<option value="CST-9:30">Darwin</option>
|
||||
<option value="EST-10EDT-11,M10.1.0/02:00:00,M3.5.0/03:00:00">Hobart</option>
|
||||
<option value="NZST-12NZDT-13,M9.4.0/02:00:00,M4.1.0/03:00:00">New Zealand</option>
|
||||
</optgroup>
|
||||
<optgroup label="Asia">
|
||||
<option value="JST-9">Tokyo</option>
|
||||
<option value="WIB-7">Jakarta</option>
|
||||
<option value="GMT+2">Jerusalem</option>
|
||||
<option value="SGT-8">Singapore</option>
|
||||
<option value="ULAT-8ULAST,M3.5.0/2,M9.5.0/2">Ulaanbaatar, Mongolia</option>
|
||||
</optgroup>
|
||||
<optgroup label="Central and South America">
|
||||
<option value="BRST+3BRDT+2,M10.3.0,M2.3.0">Brazil, Sao Paulo</option>
|
||||
<option value="UTC+3">Argentina</option>
|
||||
<option value="CST+6">Central America</option>
|
||||
</optgroup>
|
||||
</select>
|
||||
</p>
|
||||
<p>
|
||||
<input type="button" value="Save" id="apcfgsave"><span id="apcfgmsg"></span>
|
||||
</p>
|
||||
<h3>Manage</h3>
|
||||
<p>
|
||||
<button type="button" id="rebootbutton">Reboot AP</button> Saves the tagDB and instantly reboots the Access
|
||||
Point
|
||||
</p>
|
||||
<p>
|
||||
<a href="/backup_db" id="downloadDBbutton">Download tagDB</a>
|
||||
</p>
|
||||
<p>
|
||||
<button type="button" id="updatebutton" class="tablinks" data-target="updatetab" title="Update">Update</button> Manage firmware of the ESP32
|
||||
</p>
|
||||
<p>
|
||||
<a href="/setup" target="setup" class="wifibutton">WiFi config</a> Opens a new window with WiFi
|
||||
config options
|
||||
</p>
|
||||
<p>
|
||||
<br>
|
||||
<a href="https://github.com/jjwbruijn/OpenEPaperLink" target="_new">Github
|
||||
OpenEPaperLink</a><br>
|
||||
<a href="https://github.com/jjwbruijn/OpenEPaperLink/wiki" target="_new">OpenEPaperLink
|
||||
Wiki</a><br>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div id="aplist">
|
||||
<div id="apcard" class="apcard">
|
||||
<p class="apip">194.109.6.66</p>
|
||||
<p class="apalias">AP kitchen</p>
|
||||
<div>
|
||||
<span class="material-symbols-outlined">
|
||||
sell
|
||||
<div id="updatetab" class="tabcontent">
|
||||
<h3>Firmware Updates</h3>
|
||||
<div>
|
||||
<div class="updateCol1">
|
||||
<div id="easyupdate"></div>
|
||||
<h4>Repository</h4>
|
||||
<div>
|
||||
<label for="repo">Repo</label><input type="text" id="repo" value="">
|
||||
<button id="selectRepo">Change</button><br>
|
||||
<p id="repoWarning" style="display:none" class="warning">
|
||||
To change to this repository, select and confirm the build environment.
|
||||
</p>
|
||||
<label for="environment">Environment</label><input type="text" id="environment" readonly value="">
|
||||
<button id="confirmSelectRepo">Confirm</button><button id="cancelSelectRepo">Cancel</button>
|
||||
</div>
|
||||
<h4>Releases</h4>
|
||||
<div id="releasetable"></div>
|
||||
<h4>Other actions</h4>
|
||||
<div>
|
||||
<p>
|
||||
<div id="rollbackOption" style="display:none"><button type="button" id="rollbackBtn">Rollback to previous
|
||||
firmware</button></div>
|
||||
</p>
|
||||
<p>
|
||||
<span id="c6Option">
|
||||
<div id="updateC6Option"><button type="button" id="updateC6Btn">Update ESP32-C6</button> <input type="checkbox"
|
||||
value="1" checked id="c6download"> download latest version</div>
|
||||
</span>
|
||||
<span class="aptagcount">13</span>
|
||||
<span class="material-symbols-outlined space">
|
||||
cell_tower
|
||||
</span>
|
||||
<span class="apchannel">25</span>
|
||||
</div>
|
||||
<p class="apswversion">
|
||||
fetching software version...
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="console" id="updateconsole"></div>
|
||||
</div>
|
||||
|
||||
<div id="templatetab" class="tabcontent">
|
||||
Work in progress...
|
||||
</div>
|
||||
|
||||
<div id="configtab" class="tabcontent">
|
||||
<h3>Access Point config</h3>
|
||||
<p>
|
||||
<label for="apcfgalias">Alias</label>
|
||||
<input id="apcfgalias" type="text">
|
||||
</p>
|
||||
<p>
|
||||
<label for="apcfgchid">Channel</label>
|
||||
<select id="apcfgchid">
|
||||
<option value="0" selected>auto</option>
|
||||
<option value="11">11</option>
|
||||
<option value="15">15</option>
|
||||
<option value="20">20</option>
|
||||
<option value="25">25</option>
|
||||
<option value="26">26</option>
|
||||
<option value="27">27</option>
|
||||
</select>
|
||||
</p>
|
||||
<p>
|
||||
<label for="apcfgledbrightness">LED brightness</label>
|
||||
<select id="apcfgledbrightness">
|
||||
<option value="-1">off</option>
|
||||
<option value="20">10%</option>
|
||||
<option value="64">25%</option>
|
||||
<option value="128" selected>50%</option>
|
||||
<option value="192">75%</option>
|
||||
<option value="255">100%</option>
|
||||
</select>
|
||||
</p>
|
||||
<p>
|
||||
<label for="apcfglanguage">Content language</label>
|
||||
<select id="apcfglanguage">
|
||||
<option value="0" selected>EN English</option>
|
||||
<option value="1">NL Nederlands</option>
|
||||
<option value="2">DE Deutsch</option>
|
||||
</select>
|
||||
</p>
|
||||
<p title="Depending on the content, a tag can sleep for
|
||||
longer periods when no updates are expected
|
||||
(like a date display). This setting specifies
|
||||
the maximum sleep time.">
|
||||
<label for="apclatency">Maximum sleep</label>
|
||||
<select id="apclatency">
|
||||
<option value="0" selected>shortest (40 sec)</option>
|
||||
<option value="5">5 minutes</option>
|
||||
<option value="10">10 minute</option>
|
||||
<option value="30">30 minutes</option>
|
||||
<option value="60">1 hour</option>
|
||||
</select>
|
||||
</p>
|
||||
<p title="If connected to the website, don't sleep extra.
|
||||
Latency will be around 40 seconds.">
|
||||
<label for="apcpreventsleep">Shorten latency during config</label>
|
||||
<select id="apcpreventsleep">
|
||||
<option value="0">no</option>
|
||||
<option value="1" selected>yes</option>
|
||||
</select>
|
||||
</p>
|
||||
<p
|
||||
title="Stops updates at night, and put the tags to sleep. During the configured night time, this overrides the maximum sleep time.">
|
||||
<label for="apcnight1">No updates between</label>
|
||||
<select id="apcnight1"></select>
|
||||
<span style="align-self:center;">and</span>
|
||||
<select id="apcnight2"></select>
|
||||
</p>
|
||||
<p title="Turn off preview images on the webpage if you want to manage many tags,
|
||||
to save file system space">
|
||||
<label for="apcpreview">Preview images</label>
|
||||
<select id="apcpreview">
|
||||
<option value="1" selected>yes</option>
|
||||
<option value="0">no</option>
|
||||
</select>
|
||||
</p>
|
||||
<p title="Wifi transmit power">
|
||||
<label for="apcwifipower">Wifi power</label>
|
||||
<select id="apcwifipower">
|
||||
<option value="78">19.5 dBm</option>
|
||||
<option value="76">19.0 dBm</option>
|
||||
<option value="74">18.5 dBm</option>
|
||||
<option value="68">17.0 dBm</option>
|
||||
<option value="60">15.0 dBm</option>
|
||||
<option value="52">13.0 dBm</option>
|
||||
<option value="44">11.0 dBm</option>
|
||||
<option value="34" selected>8.5 dBm</option>
|
||||
<option value="28">7.0 dBm</option>
|
||||
<option value="20">5.0 dBm</option>
|
||||
<option value="8">2.0 dBm</option>
|
||||
</select>
|
||||
</p>
|
||||
<p title="Your local time zone">
|
||||
<label for="apctimezone">Local time zone</label>
|
||||
<select id="apctimezone">
|
||||
<optgroup label="Europe">
|
||||
<option value="CET-1CEST-2,M3.5.0/02:00:00,M10.5.0/03:00:00" selected>Central European
|
||||
Time</option>
|
||||
<option value="EET-2EEST-3,M3.5.0/03:00:00,M10.5.0/04:00:00">Athens, Greece</option>
|
||||
<option value="GMT+0IST-1,M3.5.0/01:00:00,M10.5.0/02:00:00">Dublin, Ireland</option>
|
||||
<option value="EET-2EEST-3,M3.5.0/03:00:00,M10.5.0/04:00:00">Helsinki, Finland</option>
|
||||
<option value="WET-0WEST-1,M3.5.0/01:00:00,M10.5.0/02:00:00">Lisbon, Portugal</option>
|
||||
<option value="GMT+0BST-1,M3.5.0/01:00:00,M10.5.0/02:00:00">London, Great Britain
|
||||
</option>
|
||||
<option value="EET-2EEST,M3.5.0/3,M10.5.0/4">Kyiv, Ukraine</option>
|
||||
</optgroup>
|
||||
<optgroup label="USA / Canada">
|
||||
<option value="HAW10">Hawaii Time</option>
|
||||
<option value="AKST9AKDT">Alaska Time</option>
|
||||
<option value="PST8PDT">Pacific Time</option>
|
||||
<option value="MST7MDT">Mountain Time</option>
|
||||
<option value="MST7">Arizona, no DST</option>
|
||||
<option value="CST6CDT">Central Time</option>
|
||||
<option value="EST5EDT">Eastern Time</option>
|
||||
</optgroup>
|
||||
<optgroup label="Australia / New Zealand">
|
||||
<option value="EST-10EDT-11,M10.5.0/02:00:00,M3.5.0/03:00:00">Melbourne, Sydney</option>
|
||||
<option value="WST-8">Perth</option>
|
||||
<option value="EST-10">Brisbane</option>
|
||||
<option value="CST-9:30CDT-10:30,M10.5.0/02:00:00,M3.5.0/03:00:00">Adelaide</option>
|
||||
<option value="CST-9:30">Darwin</option>
|
||||
<option value="EST-10EDT-11,M10.1.0/02:00:00,M3.5.0/03:00:00">Hobart</option>
|
||||
<option value="NZST-12NZDT-13,M9.4.0/02:00:00,M4.1.0/03:00:00">New Zealand</option>
|
||||
</optgroup>
|
||||
<optgroup label="Asia">
|
||||
<option value="JST-9">Tokyo</option>
|
||||
<option value="WIB-7">Jakarta</option>
|
||||
<option value="GMT+2">Jerusalem</option>
|
||||
<option value="SGT-8">Singapore</option>
|
||||
<option value="ULAT-8ULAST,M3.5.0/2,M9.5.0/2">Ulaanbaatar, Mongolia</option>
|
||||
</optgroup>
|
||||
<optgroup label="Central and South America">
|
||||
<option value="BRST+3BRDT+2,M10.3.0,M2.3.0">Brazil, Sao Paulo</option>
|
||||
<option value="UTC+3">Argentina</option>
|
||||
<option value="CST+6">Central America</option>
|
||||
</optgroup>
|
||||
</select>
|
||||
</p>
|
||||
<p>
|
||||
<input type="button" value="Save" id="apcfgsave"><span id="apcfgmsg"></span>
|
||||
</p>
|
||||
<h3>Manage</h3>
|
||||
<p>
|
||||
<button id="rebootbutton">Reboot AP</button> Saves the tagDB and instantly reboots the Access
|
||||
Point
|
||||
</p>
|
||||
<p>
|
||||
<a href="/backup_db" id="downloadDBbutton">Download tagDB</a>
|
||||
</p>
|
||||
<p>
|
||||
<button id="updatebutton">Update</button> Manage firmware of the ESP32
|
||||
</p>
|
||||
<p>
|
||||
<a href="/setup" target="setup" class="wifibutton">WiFi config</a> Opens a new window with WiFi
|
||||
config options
|
||||
</p>
|
||||
<p>
|
||||
<br>
|
||||
<a href="https://github.com/jjwbruijn/OpenEPaperLink" target="_new">Github
|
||||
OpenEPaperLink</a><br>
|
||||
<a href="https://github.com/jjwbruijn/OpenEPaperLink/wiki" target="_new">OpenEPaperLink
|
||||
Wiki</a><br>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
</form>
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
<footer class="logbox">
|
||||
<p>
|
||||
@@ -447,6 +491,13 @@
|
||||
<option value="0">auto</option>
|
||||
</select>
|
||||
</p>
|
||||
<p>
|
||||
<label for="cfginvert">Invert colors</label>
|
||||
<select id="cfginvert">
|
||||
<option value="0">off</option>
|
||||
<option value="1">on</option>
|
||||
</select>
|
||||
</p>
|
||||
<p class="tagbuttons">
|
||||
<button id="cfgrefresh">force refresh</button>
|
||||
<button id="cfgclrpending">clear pending</button>
|
||||
@@ -464,27 +515,6 @@
|
||||
</p>
|
||||
</dialog>
|
||||
|
||||
<div id="apupdatebox">
|
||||
<div class="closebtn">✖</div>
|
||||
<h3>Update dashboard</h3>
|
||||
<div id="easyupdate"></div>
|
||||
<div id="advanceddiv">
|
||||
<!--<div>
|
||||
repo: <input type="text" name="repo"> <button id="switchRepo">Switch</button><br>
|
||||
environment: <span id="environment">environment</span>
|
||||
</div>-->
|
||||
<div id="releasetable"></div>
|
||||
<div>
|
||||
<div id="rollbackOption" style="display:none"><button id="rollbackBtn">Rollback to previous
|
||||
firmware</button></div>
|
||||
<span id="c6Option">
|
||||
<div id="updateC6Option"><button id="updateC6Btn">Update ESP32-C6</button> <input type="checkbox"
|
||||
value="1" checked id="c6download"> download latest version</div>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<ul id="context-menu"
|
||||
style="display: none; position: absolute; background: white; border: 1px solid gray; padding: 0; list-style: none;">
|
||||
</ul>
|
||||
|
||||
@@ -65,7 +65,7 @@ footer {
|
||||
.logo {
|
||||
margin: 0 auto;
|
||||
height: 50px;
|
||||
text-indent: 50px;
|
||||
text-indent: 12px;
|
||||
overflow: hidden;
|
||||
font-size: 2.5em;
|
||||
color: white;
|
||||
@@ -202,7 +202,8 @@ label {
|
||||
}
|
||||
|
||||
#aptab,
|
||||
#configtab {
|
||||
#configtab,
|
||||
#updatetab {
|
||||
padding: 10px;
|
||||
|
||||
& p {
|
||||
@@ -210,6 +211,35 @@ label {
|
||||
}
|
||||
}
|
||||
|
||||
#updatetab {
|
||||
&>div {
|
||||
display: flex;
|
||||
gap: 2em;
|
||||
flex-flow: wrap;
|
||||
}
|
||||
& label {
|
||||
width: 100px;
|
||||
display: inline-block;
|
||||
vertical-align: baseline;
|
||||
padding: 7px 0px;
|
||||
}
|
||||
& input[type="text"] {
|
||||
width: 200px;
|
||||
}
|
||||
& button {
|
||||
margin: 0px 5px;
|
||||
}
|
||||
& input:read-only {
|
||||
background-color: #ccc;
|
||||
}
|
||||
& .warning {
|
||||
padding: 5px;
|
||||
color: #f02000;
|
||||
background-color: #ffffc0;
|
||||
font-weight: bold;
|
||||
}
|
||||
}
|
||||
|
||||
#aplist {
|
||||
display: flex;
|
||||
gap: 1em;
|
||||
@@ -356,6 +386,7 @@ select {
|
||||
display: flex;
|
||||
gap: 5px;
|
||||
align-items: flex-start;
|
||||
max-width: 400px;
|
||||
}
|
||||
|
||||
#configbox h3,
|
||||
@@ -719,7 +750,10 @@ ul.messages li.new {
|
||||
/* updatescreens */
|
||||
|
||||
#easyupdate {
|
||||
margin-top: 10px;
|
||||
padding: 10px;
|
||||
background-color: white;
|
||||
width: 400px;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
#easyupdate button {
|
||||
@@ -733,13 +767,10 @@ ul.messages li.new {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
#advanceddiv {
|
||||
display: none;
|
||||
}
|
||||
|
||||
#advanceddiv div:nth-child(2) {
|
||||
display: flex;
|
||||
gap: 10px;
|
||||
h4 {
|
||||
font-size: 1.25em;
|
||||
margin: 10px 0px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
#releasetable {
|
||||
@@ -764,7 +795,7 @@ ul.messages li.new {
|
||||
}
|
||||
|
||||
#releasetable td:nth-child(2) {
|
||||
word-wrap: nowrap;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
#releasetable button {
|
||||
@@ -780,17 +811,21 @@ ul.messages li.new {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.updateCol1 {
|
||||
flex-grow: 1;
|
||||
}
|
||||
|
||||
.console {
|
||||
width: 100%;
|
||||
width: 450px;
|
||||
background-color: black;
|
||||
font-family: 'lucida console', 'ui-monospace';
|
||||
color: white;
|
||||
padding: 5px 10px;
|
||||
margin: 20px 0px;
|
||||
padding-bottom: 25px;
|
||||
height: 400px;
|
||||
height: calc(100vh - 200px);
|
||||
overflow-y: scroll;
|
||||
white-space: break-spaces;
|
||||
flex-grow: 1;
|
||||
}
|
||||
|
||||
.console div {
|
||||
|
||||
@@ -83,7 +83,8 @@ function initTabs() {
|
||||
const tabContents = document.querySelectorAll(".tabcontent");
|
||||
|
||||
tabLinks.forEach(tabLink => {
|
||||
tabLink.addEventListener("click", function () {
|
||||
tabLink.addEventListener("click", function (event) {
|
||||
event.preventDefault();
|
||||
const targetId = this.getAttribute("data-target");
|
||||
const loadTabEvent = new CustomEvent('loadTab', { detail: targetId });
|
||||
document.dispatchEvent(loadTabEvent);
|
||||
@@ -134,11 +135,24 @@ function connect() {
|
||||
processTags(msg.tags);
|
||||
}
|
||||
if (msg.sys) {
|
||||
let filesystem = 'filesystem free: ' + convertSize(msg.sys.littlefsfree);
|
||||
if (msg.sys.littlefsfree < 31000) {
|
||||
filesystem = 'filesystem <span class="blink-red" title="Generating content is paused">FULL! ' + convertSize(msg.sys.littlefsfree) + '</span>';
|
||||
}
|
||||
$('#sysinfo').innerHTML = 'free heap: ' + convertSize(msg.sys.heap) + ' ┇ db size: ' + convertSize(msg.sys.dbsize) + ' ┇ db record count: ' + msg.sys.recordcount + ' ┇ ' + filesystem;
|
||||
let str = "";
|
||||
str += `free heap: ${convertSize(msg.sys.heap)} ┇ `;
|
||||
if (msg.sys.psfree) {
|
||||
str += `free PSRAM: ${convertSize(msg.sys.psfree)} ┇ `;
|
||||
}
|
||||
str += `db size: ${convertSize(msg.sys.dbsize)} ┇ `;
|
||||
str += `db record count: ${msg.sys.recordcount} ┇ `;
|
||||
|
||||
if (msg.sys.littlefsfree < 31000) {
|
||||
str += `filesystem <span class="blink-red" title="Generating content is paused">FULL! ${convertSize(
|
||||
msg.sys.littlefsfree
|
||||
)} </span>`;
|
||||
} else {
|
||||
str += `filesystem free: ${convertSize(msg.sys.littlefsfree)}`;
|
||||
}
|
||||
|
||||
$("#sysinfo").innerHTML = str;
|
||||
|
||||
if (msg.sys.apstate) {
|
||||
$("#apstatecolor").style.color = apstate[msg.sys.apstate].color;
|
||||
$("#apstate").innerHTML = apstate[msg.sys.apstate].state;
|
||||
@@ -208,7 +222,6 @@ function processTags(tagArray) {
|
||||
if (!alias) alias = tagmac.replace(/^0{1,4}/, '');
|
||||
if ($('#tag' + tagmac + ' .alias').innerHTML != alias) {
|
||||
$('#tag' + tagmac + ' .alias').innerHTML = alias;
|
||||
//GroupSortFilter();
|
||||
}
|
||||
|
||||
let contentDefObj = getContentDefById(element.contentMode);
|
||||
@@ -302,6 +315,7 @@ function processTags(tagArray) {
|
||||
break;
|
||||
case WAKEUP_REASON_NFC:
|
||||
$('#tag' + tagmac + ' .nextcheckin').innerHTML = "NFC wakeup"
|
||||
$('#tag' + tagmac).style.background = "#c8f1bb";
|
||||
break;
|
||||
case WAKEUP_REASON_NETWORK_SCAN:
|
||||
$('#tag' + tagmac + ' .nextcheckin').innerHTML = "<font color=yellow>Network scan</font>"
|
||||
@@ -332,7 +346,6 @@ function updatecards() {
|
||||
$('#taglist').querySelectorAll('[data-mac]').forEach(item => {
|
||||
let tagmac = item.dataset.mac;
|
||||
tagcount++;
|
||||
if (tagDB[tagmac].pending) pendingcount++;
|
||||
if (tagDB[tagmac].batteryMv < 2400 && tagDB[tagmac].batteryMv != 0 && tagDB[tagmac].batteryMv != 1337) lowbattcount++;
|
||||
if (item.dataset.lastseen && item.dataset.lastseen > (Date.now() / 1000) - servertimediff - 30 * 24 * 3600 * 60) {
|
||||
let idletime = (Date.now() / 1000) - servertimediff - item.dataset.lastseen;
|
||||
@@ -342,6 +355,8 @@ function updatecards() {
|
||||
$('#tag' + tagmac).classList.remove("tagpending")
|
||||
$('#tag' + tagmac).style.background = '#e0e0a0';
|
||||
timeoutcount++;
|
||||
} else {
|
||||
if (tagDB[tagmac].pending) pendingcount++;
|
||||
}
|
||||
if (idletime > 24 * 3600) {
|
||||
$('#tag' + tagmac).style.opacity = '.5';
|
||||
@@ -424,6 +439,7 @@ function loadContentCard(mac) {
|
||||
}
|
||||
$('#cfgrotate').value = tagdata.rotate;
|
||||
$('#cfglut').value = tagdata.lut;
|
||||
$('#cfginvert').value = tagdata.invert;
|
||||
$('#cfgmore').innerHTML = '▼';
|
||||
$('#configbox').showModal();
|
||||
})
|
||||
@@ -477,6 +493,7 @@ $('#cfgsave').onclick = function () {
|
||||
|
||||
formData.append("rotate", $('#cfgrotate').value);
|
||||
formData.append("lut", $('#cfglut').value);
|
||||
formData.append("invert", $('#cfginvert').value);
|
||||
|
||||
fetch("/save_cfg", {
|
||||
method: "POST",
|
||||
@@ -539,11 +556,13 @@ $('#cfgreset').onclick = function () {
|
||||
|
||||
$('#rebootbutton').onclick = function (event) {
|
||||
event.preventDefault();
|
||||
showMessage("rebooting AP....", true);
|
||||
if (!confirm('Reboot AP now?')) return;
|
||||
socket.close();
|
||||
fetch("/reboot", {
|
||||
method: "POST"
|
||||
});
|
||||
socket.close();
|
||||
alert('Rebooted. Webpage will reload.');
|
||||
location.reload()
|
||||
}
|
||||
|
||||
$('#configbox').addEventListener('click', (event) => {
|
||||
@@ -564,6 +583,7 @@ document.addEventListener("loadTab", function (event) {
|
||||
$('#apcfgalias').value = data.alias;
|
||||
$('#apcfgchid').value = data.channel;
|
||||
$("#apcfgledbrightness").value = data.led;
|
||||
$("#apcfgtftbrightness").value = data.tft;
|
||||
$("#apcfglanguage").value = data.language;
|
||||
$("#apclatency").value = data.maxsleep;
|
||||
$("#apcpreventsleep").value = data.stopsleep;
|
||||
@@ -575,6 +595,10 @@ document.addEventListener("loadTab", function (event) {
|
||||
})
|
||||
$('#apcfgmsg').innerHTML = '';
|
||||
break;
|
||||
case 'updatetab':
|
||||
$('#updateconsole').innerHTML = '';
|
||||
loadOTA();
|
||||
break;
|
||||
}
|
||||
});
|
||||
|
||||
@@ -583,6 +607,7 @@ $('#apcfgsave').onclick = function () {
|
||||
formData.append("alias", $('#apcfgalias').value);
|
||||
formData.append("channel", $('#apcfgchid').value);
|
||||
formData.append('led', $('#apcfgledbrightness').value);
|
||||
formData.append('tft', $('#apcfgtftbrightness').value);
|
||||
formData.append('language', $('#apcfglanguage').value);
|
||||
formData.append('maxsleep', $('#apclatency').value);
|
||||
formData.append('stopsleep', $('#apcpreventsleep').value);
|
||||
@@ -605,12 +630,6 @@ $('#apcfgsave').onclick = function () {
|
||||
.catch(error => showMessage('Error: ' + error));
|
||||
}
|
||||
|
||||
$('#updatebutton').onclick = function (event) {
|
||||
event.preventDefault();
|
||||
$('#apupdatebox').style.display = 'block';
|
||||
loadOTA();
|
||||
}
|
||||
|
||||
async function loadOTA() {
|
||||
otamodule = await import('./ota.js?v=' + Date.now());
|
||||
otamodule.initUpdate();
|
||||
@@ -684,6 +703,31 @@ function contentselected() {
|
||||
input.type = "text";
|
||||
input.disabled = true;
|
||||
break;
|
||||
case 'jpgfile':
|
||||
case 'binfile':
|
||||
case 'jsonfile':
|
||||
input = document.createElement("select");
|
||||
fetch('/edit?list=%2F&recursive=1')
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
let files = data.filter(item => item.type === "file" && item.name.endsWith(".jpg"));
|
||||
if (element.type == 'binfile') files = data.filter(item => item.type === "file" && item.name.endsWith(".bin"));
|
||||
if (element.type == 'jsonfile') files = data.filter(item => item.type === "file" && item.name.endsWith(".json"));
|
||||
const optionElement = document.createElement("option");
|
||||
optionElement.value = "";
|
||||
optionElement.text = "";
|
||||
input.appendChild(optionElement);
|
||||
files.forEach(item => {
|
||||
const optionElement = document.createElement("option");
|
||||
optionElement.value = item.name;
|
||||
optionElement.text = item.name;
|
||||
input.appendChild(optionElement);
|
||||
})
|
||||
})
|
||||
.catch(error => {
|
||||
console.error("Error fetching JSON data:", error);
|
||||
});
|
||||
break;
|
||||
case 'select':
|
||||
input = document.createElement("select");
|
||||
for (const key in element.options) {
|
||||
@@ -978,10 +1022,18 @@ $('#activefilter').addEventListener('click', (event) => {
|
||||
});
|
||||
|
||||
async function getTagtype(hwtype) {
|
||||
if (tagTypes[hwtype]) {
|
||||
if (tagTypes[hwtype] && tagTypes[hwtype].busy == false) {
|
||||
return tagTypes[hwtype];
|
||||
}
|
||||
|
||||
// nice, but no possibility to invalidate this cache yet.
|
||||
/*
|
||||
const storedData = JSON.parse(localStorage.getItem("tagTypes"));
|
||||
if (storedData && storedData[hwtype]) {
|
||||
return storedData[hwtype];
|
||||
}
|
||||
*/
|
||||
|
||||
if (getTagtypeBusy) {
|
||||
await new Promise(resolve => {
|
||||
const checkBusy = setInterval(() => {
|
||||
@@ -1000,7 +1052,7 @@ async function getTagtype(hwtype) {
|
||||
clearInterval(checkBusy);
|
||||
resolve();
|
||||
}
|
||||
}, 10);
|
||||
}, 50);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1009,8 +1061,8 @@ async function getTagtype(hwtype) {
|
||||
}
|
||||
|
||||
try {
|
||||
tagTypes[hwtype] = { busy: true };
|
||||
getTagtypeBusy = true;
|
||||
tagTypes[hwtype] = { busy: true };
|
||||
const response = await fetch('/tagtypes/' + hwtype.toString(16).padStart(2, '0').toUpperCase() + '.json');
|
||||
if (!response.ok) {
|
||||
let data = { name: 'unknown id ' + hwtype, width: 0, height: 0, bpp: 0, rotatebuffer: 0, colortable: [], busy: false };
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
const repoUrl = 'https://api.github.com/repos/jjwbruijn/OpenEPaperLink/releases';
|
||||
var repo = apConfig.repo || 'jjwbruijn/OpenEPaperLink';
|
||||
var repoUrl = 'https://api.github.com/repos/' + repo + '/releases';
|
||||
|
||||
const $ = document.querySelector.bind(document);
|
||||
|
||||
@@ -8,19 +9,28 @@ let env = '', currentVer = '', currentBuildtime = 0;
|
||||
let buttonState = false;
|
||||
|
||||
export async function initUpdate() {
|
||||
if (!$("#updateconsole")) {
|
||||
const consoleDiv = document.createElement('div');
|
||||
consoleDiv.classList.add('console');
|
||||
consoleDiv.id = "updateconsole";
|
||||
$('#apupdatebox').appendChild(consoleDiv);
|
||||
}
|
||||
$("#updateconsole").innerHTML = "";
|
||||
|
||||
const response = await fetch("/version.txt");
|
||||
let filesystemversion = await response.text();
|
||||
if (!filesystemversion) filesystemversion = "unknown";
|
||||
$('#repo').value = repo;
|
||||
|
||||
fetch("/sysinfo")
|
||||
const envBox = $('#environment');
|
||||
if (envBox?.tagName === 'SELECT') {
|
||||
const inputElement = document.createElement('input');
|
||||
inputElement.type = 'text';
|
||||
inputElement.id = 'environment';
|
||||
envBox.parentNode.replaceChild(inputElement, envBox);
|
||||
}
|
||||
$('#environment').value = '';
|
||||
$('#environment').setAttribute('readonly', true);
|
||||
$('#repo').removeAttribute('readonly');
|
||||
$('#confirmSelectRepo').style.display = 'none';
|
||||
$('#cancelSelectRepo').style.display = 'none';
|
||||
$('#selectRepo').style.display = 'inline-block';
|
||||
$('#repoWarning').style.display = 'none';
|
||||
|
||||
const sysinfoPromise = fetch("/sysinfo")
|
||||
.then(response => {
|
||||
if (response.status != 200) {
|
||||
print("Error fetching sysinfo: " + response.status, "red");
|
||||
@@ -34,33 +44,36 @@ export async function initUpdate() {
|
||||
return response.json();
|
||||
}
|
||||
})
|
||||
.then(data => {
|
||||
if (data.env) {
|
||||
let matchtest = '';
|
||||
if (data.buildversion != filesystemversion && filesystemversion != "custom" && data.buildversion != "custom") matchtest = " <- not matching!"
|
||||
print(`env: ${data.env}`);
|
||||
print(`build date: ${formatEpoch(data.buildtime)}`);
|
||||
print(`esp32 version: ${data.buildversion}`);
|
||||
print(`filesystem version: ${filesystemversion}` + matchtest);
|
||||
print(`sha: ${data.sha}`);
|
||||
print(`psram size: ${data.psramsize}`);
|
||||
print(`flash size: ${data.flashsize}`);
|
||||
print("--------------------------", "gray");
|
||||
env = data.env;
|
||||
currentVer = data.buildversion;
|
||||
currentBuildtime = data.buildtime;
|
||||
if (data.rollback) $("#rollbackOption").style.display = 'block';
|
||||
if (data.env == 'ESP32_S3_16_8_YELLOW_AP') $("#c6Option").style.display = 'block';
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
print('Error fetching sysinfo: ' + error, "red");
|
||||
});
|
||||
|
||||
fetch(repoUrl)
|
||||
const repoPromise = fetch(repoUrl)
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
const releaseDetails = data.map(release => {
|
||||
|
||||
|
||||
Promise.all([sysinfoPromise, repoPromise])
|
||||
.then(([sdata, rdata]) => {
|
||||
|
||||
if (sdata.env) {
|
||||
let matchtest = '';
|
||||
if (sdata.buildversion != filesystemversion && filesystemversion != "custom" && sdata.buildversion != "custom") matchtest = " <- not matching!"
|
||||
print(`env: ${sdata.env}`);
|
||||
print(`build date: ${formatEpoch(sdata.buildtime)}`);
|
||||
print(`esp32 version: ${sdata.buildversion}`);
|
||||
print(`filesystem version: ${filesystemversion}` + matchtest);
|
||||
print(`psram size: ${sdata.psramsize}`);
|
||||
print(`flash size: ${sdata.flashsize}`);
|
||||
print("--------------------------", "gray");
|
||||
env = sdata.env;
|
||||
currentVer = sdata.buildversion;
|
||||
currentBuildtime = sdata.buildtime;
|
||||
if (sdata.rollback) $("#rollbackOption").style.display = 'block';
|
||||
if (sdata.env == 'ESP32_S3_16_8_YELLOW_AP') $("#c6Option").style.display = 'block';
|
||||
$('#environment').value = env;
|
||||
}
|
||||
|
||||
const releaseDetails = rdata.map(release => {
|
||||
const assets = release.assets;
|
||||
const filesJsonAsset = assets.find(asset => asset.name === 'filesystem.json');
|
||||
const binariesJsonAsset = assets.find(asset => asset.name === 'binaries.json');
|
||||
@@ -76,7 +89,7 @@ export async function initUpdate() {
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
|
||||
const easyupdate = $('#easyupdate');
|
||||
if (releaseDetails.length === 0) {
|
||||
easyupdate.innerHTML = ("No releases found.");
|
||||
@@ -92,7 +105,6 @@ export async function initUpdate() {
|
||||
}
|
||||
}
|
||||
}
|
||||
easyupdate.innerHTML += "<br><a onclick=\"$('#advanceddiv').style.display='block'\">advanced options</a>"
|
||||
|
||||
const table = document.createElement('table');
|
||||
const tableHeader = document.createElement('tr');
|
||||
@@ -101,9 +113,9 @@ export async function initUpdate() {
|
||||
|
||||
let rowCounter = 0;
|
||||
releaseDetails.forEach(release => {
|
||||
if (rowCounter < 3 && release?.html_url) {
|
||||
if (rowCounter < 4 && release?.html_url) {
|
||||
const tableRow = document.createElement('tr');
|
||||
let tablerow = `<td><a href="${release.html_url}" target="_new">${release.tag_name}</a></td><td>${release.date}</td><td>${release.name}</td><td><button onclick="otamodule.updateESP('${release.bin_url}', true)">ESP32</button></td><td><button onclick="otamodule.updateWebpage('${release.file_url}','${release.tag_name}', true)">Filesystem</button></td>`;
|
||||
let tablerow = `<td><a href="${release.html_url}" target="_new">${release.tag_name}</a></td><td>${release.date}</td><td>${release.name}</td><td><button type="button" onclick="otamodule.updateWebpage('${release.file_url}','${release.tag_name}', true)">Filesystem</button></td><td><button type="button" onclick="otamodule.updateESP('${release.bin_url}', true)">ESP32</button></td>`;
|
||||
if (release.tag_name == currentVer) {
|
||||
tablerow += "<td>current version</td>";
|
||||
} else if (release.date < formatEpoch(currentBuildtime)) {
|
||||
@@ -362,6 +374,90 @@ $('#updateC6Btn').onclick = function () {
|
||||
disableButtons(false);
|
||||
}
|
||||
|
||||
$('#selectRepo').onclick = function (event) {
|
||||
event.preventDefault();
|
||||
$('#updateconsole').innerHTML = '';
|
||||
|
||||
let repoUrl = 'https://api.github.com/repos/' + $('#repo').value + '/releases';
|
||||
fetch(repoUrl)
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
if (Array.isArray(data) && data.length > 0) {
|
||||
const release = data[0];
|
||||
print("Repo found! Latest release: " + release.name + " created " + release.created_at);
|
||||
const assets = release.assets;
|
||||
const filesJsonAsset = assets.find(asset => asset.name === 'filesystem.json');
|
||||
const binariesJsonAsset = assets.find(asset => asset.name === 'binaries.json');
|
||||
if (filesJsonAsset && binariesJsonAsset) {
|
||||
const updateUrl = "http://openepaperlink.eu/getupdate/?url=" + binariesJsonAsset.browser_download_url + "&env=" + $('#repo').value;
|
||||
return fetch(updateUrl);
|
||||
} else {
|
||||
throw new Error("Json file binaries.json and/or filesystem.json not found in the release assets");
|
||||
}
|
||||
};
|
||||
})
|
||||
.then(updateResponse => {
|
||||
if (!updateResponse.ok) {
|
||||
throw new Error("Network response was not OK");
|
||||
}
|
||||
return updateResponse.text();
|
||||
})
|
||||
.then(responseBody => {
|
||||
if (!responseBody.trim().startsWith("[")) {
|
||||
throw new Error("Failed to fetch the release info file");
|
||||
}
|
||||
const updateData = JSON.parse(responseBody).filter(item => !item.name.endsWith('_full.bin'));
|
||||
|
||||
const inputParent = $('#environment').parentNode;
|
||||
const selectElement = document.createElement('select');
|
||||
selectElement.id = 'environment';
|
||||
updateData.forEach(item => {
|
||||
const option = document.createElement('option');
|
||||
option.value = item.name.replace('.bin', '');
|
||||
option.text = item.name.replace('.bin', '');
|
||||
selectElement.appendChild(option);
|
||||
});
|
||||
inputParent.replaceChild(selectElement, $('#environment'));
|
||||
$('#environment').value = env;
|
||||
$('#confirmSelectRepo').style.display = 'inline-block';
|
||||
$('#cancelSelectRepo').style.display = 'inline-block';
|
||||
$('#selectRepo').style.display = 'none';
|
||||
$('#repo').setAttribute('readonly', true);
|
||||
$('#repoWarning').style.display = 'block';
|
||||
})
|
||||
.catch(error => {
|
||||
print('Error fetching releases:' + error, "red");
|
||||
});
|
||||
}
|
||||
|
||||
$('#cancelSelectRepo').onclick = function (event) {
|
||||
event.preventDefault();
|
||||
$('#updateconsole').innerHTML = '';
|
||||
initUpdate();
|
||||
}
|
||||
|
||||
$('#confirmSelectRepo').onclick = function (event) {
|
||||
event.preventDefault();
|
||||
|
||||
repo = $('#repo').value;
|
||||
let formData = new FormData();
|
||||
formData.append("repo", repo);
|
||||
formData.append("env", $('#environment').value);
|
||||
fetch("/save_apcfg", {
|
||||
method: "POST",
|
||||
body: formData
|
||||
})
|
||||
.then(response => response.text())
|
||||
.then(data => {
|
||||
window.dispatchEvent(loadConfig);
|
||||
print('OK, Saved');
|
||||
})
|
||||
.catch(error => print('Error: ' + error));
|
||||
$('#updateconsole').innerHTML = '';
|
||||
repoUrl = 'https://api.github.com/repos/' + repo + '/releases';
|
||||
initUpdate();
|
||||
}
|
||||
|
||||
export function print(line, color = "white") {
|
||||
const consoleDiv = document.getElementById('updateconsole');
|
||||
if (consoleDiv) {
|
||||
@@ -464,7 +560,7 @@ const writeVersion = async (content, name, path) => {
|
||||
};
|
||||
|
||||
function disableButtons(active) {
|
||||
$("#apupdatebox").querySelectorAll('button').forEach(button => {
|
||||
$("#configtab").querySelectorAll('button').forEach(button => {
|
||||
button.disabled = active;
|
||||
});
|
||||
buttonState = active;
|
||||
|
||||
@@ -104,7 +104,7 @@ function startPainter(mac, width, height) {
|
||||
const xhr = new XMLHttpRequest();
|
||||
xhr.open('POST', '/imgupload');
|
||||
xhr.send(formData);
|
||||
$('#configbox').style.display = 'none';
|
||||
$('#configbox').close();
|
||||
});
|
||||
|
||||
$("#buttonbar").appendChild(blackButton);
|
||||
|
||||
@@ -34,7 +34,7 @@ Not all connections are required by all tags! If you want to solder fewer wires,
|
||||
|
||||
## Flashing the flasher
|
||||
Clone the [Tag_Flasher repo](https://github.com/jjwbruijn/OpenEPaperLink/tree/master/Tag_Flasher/ESP32_Flasher) and open into PlatformIO. Choose the correct COM-port and hit 'Upload'.
|
||||
Also, the precompiled binaries are part of any [release](https://github.com/jjwbruijn/OpenEPaperLink/releases), and to make it even easier, you can use the web flasher on https://install.openepaperlink.nl to even flash it without installing any extra software.
|
||||
Also, the precompiled binaries are part of any [release](https://github.com/jjwbruijn/OpenEPaperLink/releases), and to make it even easier, you can use the web flasher on https://install.openepaperlink.de to even flash it without installing any extra software.
|
||||
|
||||
## OEPL-Flasher.py
|
||||
|
||||
|
||||
Binary file not shown.
Binary file not shown.
BIN
binaries/Tag/SOLUM_154_SSD1619-tag-00-0022.bin
Normal file
BIN
binaries/Tag/SOLUM_154_SSD1619-tag-00-0022.bin
Normal file
Binary file not shown.
BIN
binaries/Tag/SOLUM_29_SSD1619-tag-01-0022.bin
Normal file
BIN
binaries/Tag/SOLUM_29_SSD1619-tag-01-0022.bin
Normal file
Binary file not shown.
BIN
binaries/Tag/SOLUM_29_UC8151-tag-11-0022.bin
Normal file
BIN
binaries/Tag/SOLUM_29_UC8151-tag-11-0022.bin
Normal file
Binary file not shown.
BIN
binaries/Tag/SOLUM_42_SSD1619-tag-02-0022.bin
Normal file
BIN
binaries/Tag/SOLUM_42_SSD1619-tag-02-0022.bin
Normal file
Binary file not shown.
BIN
binaries/Tag/SOLUM_M2_BWR_75-tag-26-0004-full.bin
Normal file
BIN
binaries/Tag/SOLUM_M2_BWR_75-tag-26-0004-full.bin
Normal file
Binary file not shown.
BIN
binaries/Tag/SOLUM_M2_BWR_75-tag-26-0004-ota.bin
Normal file
BIN
binaries/Tag/SOLUM_M2_BWR_75-tag-26-0004-ota.bin
Normal file
Binary file not shown.
BIN
binaries/Tag/SOLUM_M3_22_BWR-tag-31-0016-full.bin
Normal file
BIN
binaries/Tag/SOLUM_M3_22_BWR-tag-31-0016-full.bin
Normal file
Binary file not shown.
BIN
binaries/Tag/SOLUM_M3_22_BWR-tag-31-0016-ota.bin
Normal file
BIN
binaries/Tag/SOLUM_M3_22_BWR-tag-31-0016-ota.bin
Normal file
Binary file not shown.
BIN
binaries/Tag/SOLUM_M3_29_BWR-tag-33-0016-full.bin
Normal file
BIN
binaries/Tag/SOLUM_M3_29_BWR-tag-33-0016-full.bin
Normal file
Binary file not shown.
BIN
binaries/Tag/SOLUM_M3_29_BWR-tag-33-0016-ota.bin
Normal file
BIN
binaries/Tag/SOLUM_M3_29_BWR-tag-33-0016-ota.bin
Normal file
Binary file not shown.
BIN
binaries/Tag/SOLUM_M3_43_BWR-tag-34-0016-full.bin
Normal file
BIN
binaries/Tag/SOLUM_M3_43_BWR-tag-34-0016-full.bin
Normal file
Binary file not shown.
BIN
binaries/Tag/SOLUM_M3_43_BWR-tag-34-0016-ota.bin
Normal file
BIN
binaries/Tag/SOLUM_M3_43_BWR-tag-34-0016-ota.bin
Normal file
Binary file not shown.
BIN
binaries/Tag/SOLUM_M3_60_BWR-tag-35-0016-full.bin
Normal file
BIN
binaries/Tag/SOLUM_M3_60_BWR-tag-35-0016-full.bin
Normal file
Binary file not shown.
BIN
binaries/Tag/SOLUM_M3_60_BWR-tag-35-0016-ota.bin
Normal file
BIN
binaries/Tag/SOLUM_M3_60_BWR-tag-35-0016-ota.bin
Normal file
Binary file not shown.
BIN
binaries/Tag/SOLUM_M3_75_BWR-tag-36-0016-full.bin
Normal file
BIN
binaries/Tag/SOLUM_M3_75_BWR-tag-36-0016-full.bin
Normal file
Binary file not shown.
BIN
binaries/Tag/SOLUM_M3_75_BWR-tag-36-0016-ota.bin
Normal file
BIN
binaries/Tag/SOLUM_M3_75_BWR-tag-36-0016-ota.bin
Normal file
Binary file not shown.
BIN
binaries/Tag/Tag_FW_Pack.bin
Normal file
BIN
binaries/Tag/Tag_FW_Pack.bin
Normal file
Binary file not shown.
Binary file not shown.
@@ -52,7 +52,7 @@ dt_string = now.strftime("%d/%m/%Y %H:%M:%S")
|
||||
tag = sys.argv[1]
|
||||
|
||||
binaries = generate_file_hashes2(rp + "/espbinaries",tag)
|
||||
tagota = generate_file_hashes2(rp + "/binaries",tag)
|
||||
#tagota = generate_file_hashes2(rp + "/binaries",tag)
|
||||
files1 = generate_file_hashes(rp + "/ESP32_AP-Flasher/data/www","/www/",tag)
|
||||
files1.extend(generate_file_hashes(rp + "/ESP32_AP-Flasher/data","/",tag))
|
||||
files1.extend(generate_file_hashes(rp + "/ESP32_AP-Flasher/data/fonts","/fonts/",tag))
|
||||
@@ -65,7 +65,7 @@ jsonarray = {
|
||||
"builddate": dt_string,
|
||||
"binaries": binaries,
|
||||
"files": files1,
|
||||
"tagota": tagota,
|
||||
# "tagota": tagota,
|
||||
}
|
||||
|
||||
with open("jsonfiles/binaries.json", "w") as json_file:
|
||||
@@ -74,8 +74,8 @@ with open("jsonfiles/binaries.json", "w") as json_file:
|
||||
with open("jsonfiles/files.json", "w") as json_file:
|
||||
json.dump(jsonarray, json_file, indent=4)
|
||||
|
||||
with open("jsonfiles/tagota.json", "w") as json_file:
|
||||
json.dump(tagota, json_file, indent=4)
|
||||
#with open("jsonfiles/tagota.json", "w") as json_file:
|
||||
# json.dump(tagota, json_file, indent=4)
|
||||
|
||||
with open("jsonfiles/filesystem.json", "w") as json_file:
|
||||
json.dump(files1, json_file, indent=4)
|
||||
|
||||
@@ -57,18 +57,48 @@
|
||||
#define CMD_DO_RESET_SETTINGS 2
|
||||
#define CMD_DO_DEEPSLEEP 3
|
||||
#define CMD_DO_LEDFLASH 4
|
||||
#define CMD_ERASE_EEPROM_IMAGES 5
|
||||
#define CMD_ENTER_SLIDESHOW_FAST 0x06
|
||||
#define CMD_ENTER_SLIDESHOW_MEDIUM 0x07
|
||||
#define CMD_ENTER_SLIDESHOW_SLOW 0x08
|
||||
#define CMD_ENTER_SLIDESHOW_GLACIAL 0x09
|
||||
#define CMD_ENTER_NORMAL_MODE 0x0F
|
||||
|
||||
#define WAKEUP_REASON_TIMED 0
|
||||
#define WAKEUP_REASON_GPIO 2
|
||||
#define WAKEUP_REASON_NFC 3
|
||||
#define WAKEUP_REASON_BUTTON1 4
|
||||
#define WAKEUP_REASON_BUTTON2 5
|
||||
#define WAKEUP_REASON_RF 0x0F
|
||||
#define WAKEUP_REASON_FIRSTBOOT 0xFC
|
||||
#define WAKEUP_REASON_NETWORK_SCAN 0xFD
|
||||
#define WAKEUP_REASON_WDT_RESET 0xFE
|
||||
|
||||
|
||||
#define EPD_LUT_DEFAULT 0
|
||||
#define EPD_LUT_NO_REPEATS 1
|
||||
#define EPD_LUT_FAST_NO_REDS 2
|
||||
#define EPD_LUT_FAST 3
|
||||
#define EPD_LUT_OTA 0x10
|
||||
|
||||
// these are the 'custom image' arguments that will be sent in addition to their 'type'.
|
||||
#define CUSTOM_IMAGE_NOCUSTOM 0x00 // regular image type
|
||||
#define CUSTOM_IMAGE_SPLASHSCREEN 0x01 // will show at first boot/powerup
|
||||
#define CUSTOM_IMAGE_LOST_CONNECTION 0x02 // this image will be shown (if it exists on the tag) if the tag looses its connection
|
||||
#define CUSTOM_IMAGE_APFOUND 0x03 // this image will be shown during bootup if an AP was found
|
||||
#define CUSTOM_IMAGE_NOAPFOUND 0x04 // shown if during bootup no AP was found
|
||||
#define CUSTOM_IMAGE_LONGTERMSLEEP 0x05 // shown if long term sleep is entered via command
|
||||
// UNUSED: 0x06-0x0F
|
||||
#define CUSTOM_IMAGE_SLIDESHOW 0x0F // image is part of a slideshow
|
||||
#define CUSTOM_IMAGE_BUTTON1 0x10
|
||||
#define CUSTOM_IMAGE_BUTTON2 0x11
|
||||
// UNUSED: 0x12 to 0x1B
|
||||
#define CUSTOM_IMAGE_RF_WAKE 0x1C
|
||||
#define CUSTOM_IMAGE_GPIO 0x1D
|
||||
#define CUSTOM_IMAGE_NFC_WAKE 0x1E
|
||||
|
||||
#define TAG_CUSTOM_MODE_NONE 0x00
|
||||
#define TAG_CUSTOM_SLIDESHOW_FAST 0x06
|
||||
#define TAG_CUSTOM_SLIDESHOW_MEDIUM 0x07
|
||||
#define TAG_CUSTOM_SLIDESHOW_SLOW 0x08
|
||||
#define TAG_CUSTOM_SLIDESHOW_GLACIAL 0x09
|
||||
@@ -187,3 +187,9 @@ struct ledFlash {
|
||||
uint8_t repeats;
|
||||
uint8_t spare;
|
||||
} __packed;
|
||||
|
||||
struct imageDataTypeArgStruct {
|
||||
uint8_t lut : 2;
|
||||
uint8_t preloadImage : 1; // set to 0 will draw image immediately
|
||||
uint8_t specialType : 5;
|
||||
} __packed;
|
||||
@@ -24,15 +24,23 @@
|
||||
#include "../oepl-definitions.h"
|
||||
#include "../oepl-proto.h"
|
||||
|
||||
|
||||
// #define DEBUG_MODE
|
||||
|
||||
static const uint64_t __code __at(0x008b) mVersionRom = 0x1000011300000000ull;
|
||||
|
||||
#define TAG_MODE_CHANSEARCH 0
|
||||
#define TAG_MODE_ASSOCIATED 1
|
||||
|
||||
#define DELAY_SLIDESHOW_FAST 30
|
||||
#define DELAY_SLIDESHOW_MEDIUM 60
|
||||
#define DELAY_SLIDESHOW_SLOW 300
|
||||
#define DELAY_SLIDESHOW_GLACIAL 1800
|
||||
|
||||
uint8_t currentTagMode = TAG_MODE_CHANSEARCH;
|
||||
|
||||
uint8_t __xdata slideShowCurrentImg = 0;
|
||||
uint8_t __xdata slideShowRefreshCount = 1;
|
||||
|
||||
void displayLoop() {
|
||||
powerUp(INIT_BASE | INIT_UART);
|
||||
|
||||
@@ -46,22 +54,6 @@ void displayLoop() {
|
||||
showApplyUpdate();
|
||||
timerDelay(TIMER_TICKS_PER_SECOND * 4);
|
||||
|
||||
wdt60s();
|
||||
|
||||
pr("Scanning screen - ");
|
||||
powerUp(INIT_EPD);
|
||||
showScanningWindow();
|
||||
timerDelay(TIMER_TICKS_PER_SECOND * 8);
|
||||
for (uint8_t i = 0; i < 5; i++) {
|
||||
for (uint8_t c = 0; c < 16; c++) {
|
||||
addScanResult(11 + c, 2 * i + 60 + c);
|
||||
}
|
||||
pr("redraw... ");
|
||||
draw();
|
||||
}
|
||||
pr("\n");
|
||||
timerDelay(TIMER_TICKS_PER_SECOND * 4);
|
||||
|
||||
wdt30s();
|
||||
|
||||
pr("AP Found\n");
|
||||
@@ -99,43 +91,16 @@ void displayLoop() {
|
||||
wdtDeviceReset();
|
||||
}
|
||||
|
||||
uint8_t showChannelSelect() { // returns 0 if no accesspoints were found
|
||||
uint8_t __xdata result[sizeof(channelList)];
|
||||
memset(result, 0, sizeof(result));
|
||||
showScanningWindow();
|
||||
drawNoWait();
|
||||
powerUp(INIT_RADIO);
|
||||
for (uint8_t i = 0; i < 4; i++) {
|
||||
for (uint8_t c = 0; c < sizeof(channelList); c++) {
|
||||
if (detectAP(channelList[c])) {
|
||||
if (mLastLqi > result[c]) result[c] = mLastLqi;
|
||||
pr("Channel: %d - LQI: %d RSSI %d\n", channelList[c], mLastLqi, mLastRSSI);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t __xdata highestLqi = 0;
|
||||
uint8_t __xdata highestSlot = 0;
|
||||
for (uint8_t c = 0; c < sizeof(result); c++) {
|
||||
if (result[c] > highestLqi) {
|
||||
highestSlot = channelList[c];
|
||||
highestLqi = result[c];
|
||||
}
|
||||
}
|
||||
powerDown(INIT_RADIO);
|
||||
epdWaitRdy();
|
||||
mLastLqi = highestLqi;
|
||||
return highestSlot;
|
||||
}
|
||||
uint8_t channelSelect() { // returns 0 if no accesspoints were found
|
||||
uint8_t channelSelect(uint8_t rounds) { // returns 0 if no accesspoints were found
|
||||
powerUp(INIT_RADIO);
|
||||
uint8_t __xdata result[16];
|
||||
memset(result, 0, sizeof(result));
|
||||
|
||||
for (uint8_t i = 0; i < 2; i++) {
|
||||
for (uint8_t i = 0; i < rounds; i++) {
|
||||
for (uint8_t c = 0; c < sizeof(channelList); c++) {
|
||||
if (detectAP(channelList[c])) {
|
||||
if (mLastLqi > result[c]) result[c] = mLastLqi;
|
||||
if (rounds > 2) pr("Channel: %d - LQI: %d RSSI %d\n", channelList[c], mLastLqi, mLastRSSI);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -215,6 +180,7 @@ void detectButtonOrJig() {
|
||||
|
||||
void TagAssociated() {
|
||||
// associated
|
||||
bool fastNextCheckin = false;
|
||||
struct AvailDataInfo *__xdata avail;
|
||||
// Is there any reason why we should do a long (full) get data request (including reason, status)?
|
||||
if ((longDataReqCounter > LONG_DATAREQ_INTERVAL) || wakeUpReason != WAKEUP_REASON_TIMED) {
|
||||
@@ -234,7 +200,8 @@ void TagAssociated() {
|
||||
if (curImgSlot != 0xFF) {
|
||||
powerUp(INIT_EEPROM | INIT_EPD);
|
||||
wdt60s();
|
||||
drawImageFromEeprom(curImgSlot);
|
||||
uint8_t lut = getEepromImageDataArgument(curImgSlot) & 0x03;
|
||||
drawImageFromEeprom(curImgSlot, lut);
|
||||
powerDown(INIT_EEPROM | INIT_EPD);
|
||||
} else {
|
||||
powerUp(INIT_EPD);
|
||||
@@ -247,6 +214,29 @@ void TagAssociated() {
|
||||
avail = getAvailDataInfo();
|
||||
powerDown(INIT_RADIO);
|
||||
|
||||
switch (wakeUpReason) {
|
||||
case WAKEUP_REASON_BUTTON1:
|
||||
externalWakeHandler(CUSTOM_IMAGE_BUTTON1);
|
||||
fastNextCheckin = true;
|
||||
break;
|
||||
case WAKEUP_REASON_BUTTON2:
|
||||
externalWakeHandler(CUSTOM_IMAGE_BUTTON2);
|
||||
fastNextCheckin = true;
|
||||
break;
|
||||
case WAKEUP_REASON_GPIO:
|
||||
externalWakeHandler(CUSTOM_IMAGE_GPIO);
|
||||
fastNextCheckin = true;
|
||||
break;
|
||||
case WAKEUP_REASON_RF:
|
||||
externalWakeHandler(CUSTOM_IMAGE_RF_WAKE);
|
||||
fastNextCheckin = true;
|
||||
break;
|
||||
case WAKEUP_REASON_NFC:
|
||||
externalWakeHandler(CUSTOM_IMAGE_NFC_WAKE);
|
||||
fastNextCheckin = true;
|
||||
break;
|
||||
}
|
||||
|
||||
if (avail != NULL) {
|
||||
// we got some data!
|
||||
longDataReqCounter = 0;
|
||||
@@ -254,14 +244,12 @@ void TagAssociated() {
|
||||
wakeUpReason = WAKEUP_REASON_TIMED;
|
||||
}
|
||||
if (tagSettings.enableTagRoaming) {
|
||||
uint8_t roamChannel = channelSelect();
|
||||
uint8_t roamChannel = channelSelect(1);
|
||||
if (roamChannel) currentChannel = roamChannel;
|
||||
}
|
||||
} else {
|
||||
powerUp(INIT_RADIO);
|
||||
|
||||
|
||||
|
||||
#ifdef ENABLE_RETURN_DATA
|
||||
// example code to send data back to the AP. Up to 90 bytes can be sent in one packet
|
||||
uint8_t __xdata blaat[2] = {0xAB, 0xBA};
|
||||
@@ -304,11 +292,22 @@ void TagAssociated() {
|
||||
}
|
||||
}
|
||||
|
||||
// if the AP told us to sleep for a specific period, do so.
|
||||
if (nextCheckInFromAP) {
|
||||
doSleep(nextCheckInFromAP * 60000UL);
|
||||
if (fastNextCheckin) {
|
||||
// do a fast check-in next
|
||||
fastNextCheckin = false;
|
||||
doSleep(100UL);
|
||||
} else {
|
||||
doSleep(getNextSleep() * 1000UL);
|
||||
if (nextCheckInFromAP) {
|
||||
// if the AP told us to sleep for a specific period, do so.
|
||||
if (nextCheckInFromAP & 0x8000) {
|
||||
doSleep((nextCheckInFromAP & 0x7FFF) * 1000UL);
|
||||
} else {
|
||||
doSleep(nextCheckInFromAP * 60000UL);
|
||||
}
|
||||
} else {
|
||||
// sleep determined by algorithm
|
||||
doSleep(getNextSleep() * 1000UL);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -319,7 +318,7 @@ void TagChanSearch() {
|
||||
}
|
||||
|
||||
// try to find a working channel
|
||||
currentChannel = channelSelect();
|
||||
currentChannel = channelSelect(2);
|
||||
|
||||
// Check if we should redraw the screen with icons, info screen or screensaver
|
||||
if ((!currentChannel && !noAPShown && tagSettings.enableNoRFSymbol) ||
|
||||
@@ -328,9 +327,12 @@ void TagChanSearch() {
|
||||
powerUp(INIT_EPD);
|
||||
wdt60s();
|
||||
if (curImgSlot != 0xFF) {
|
||||
powerUp(INIT_EEPROM);
|
||||
drawImageFromEeprom(curImgSlot);
|
||||
powerDown(INIT_EEPROM);
|
||||
if (!displayCustomImage(CUSTOM_IMAGE_LOST_CONNECTION)) {
|
||||
powerUp(INIT_EEPROM);
|
||||
uint8_t lut = getEepromImageDataArgument(curImgSlot) & 0x03;
|
||||
drawImageFromEeprom(curImgSlot, lut);
|
||||
powerDown(INIT_EEPROM);
|
||||
}
|
||||
} else if ((scanAttempts >= (INTERVAL_1_ATTEMPTS + INTERVAL_2_ATTEMPTS - 1))) {
|
||||
showLongTermSleep();
|
||||
} else {
|
||||
@@ -354,6 +356,72 @@ void TagChanSearch() {
|
||||
}
|
||||
}
|
||||
|
||||
void TagSlideShow() {
|
||||
currentChannel = 11; // suppress the no-rf image thing
|
||||
displayCustomImage(CUSTOM_IMAGE_SPLASHSCREEN);
|
||||
|
||||
// do a short channel search
|
||||
currentChannel = channelSelect(2);
|
||||
|
||||
pr("Slideshow mode ch: %d\n", currentChannel);
|
||||
|
||||
// if we did find an AP, check in once
|
||||
if (currentChannel) {
|
||||
doVoltageReading();
|
||||
struct AvailDataInfo *__xdata avail;
|
||||
powerUp(INIT_RADIO);
|
||||
avail = getAvailDataInfo();
|
||||
|
||||
if (avail != NULL) {
|
||||
processAvailDataInfo(avail);
|
||||
}
|
||||
}
|
||||
powerDown(INIT_RADIO);
|
||||
|
||||
// suppress the no-rf image
|
||||
currentChannel = 11;
|
||||
|
||||
while (1) {
|
||||
powerUp(INIT_UART);
|
||||
wdt60s();
|
||||
powerUp(INIT_EEPROM);
|
||||
uint8_t img = findNextSlideshowImage(slideShowCurrentImg);
|
||||
if (img != slideShowCurrentImg) {
|
||||
slideShowCurrentImg = img;
|
||||
uint8_t lut = getEepromImageDataArgument(img) & 0x03;
|
||||
powerUp(INIT_EPD);
|
||||
if (SLIDESHOW_FORCE_FULL_REFRESH_EVERY) {
|
||||
slideShowRefreshCount++;
|
||||
}
|
||||
if ((slideShowRefreshCount == SLIDESHOW_FORCE_FULL_REFRESH_EVERY) || (lut == 0)) {
|
||||
slideShowRefreshCount = 1;
|
||||
lut = 0;
|
||||
}
|
||||
drawImageFromEeprom(img, lut);
|
||||
powerDown(INIT_EPD | INIT_EEPROM);
|
||||
} else {
|
||||
// same image, so don't update the screen; this only happens when there's exactly one slideshow image
|
||||
powerDown(INIT_EEPROM);
|
||||
}
|
||||
|
||||
switch (tagSettings.customMode) {
|
||||
case TAG_CUSTOM_SLIDESHOW_FAST:
|
||||
doSleep(1000UL * SLIDESHOW_INTERVAL_FAST);
|
||||
break;
|
||||
case TAG_CUSTOM_SLIDESHOW_MEDIUM:
|
||||
doSleep(1000UL * SLIDESHOW_INTERVAL_MEDIUM);
|
||||
break;
|
||||
case TAG_CUSTOM_SLIDESHOW_SLOW:
|
||||
doSleep(1000UL * SLIDESHOW_INTERVAL_SLOW);
|
||||
break;
|
||||
case TAG_CUSTOM_SLIDESHOW_GLACIAL:
|
||||
doSleep(1000UL * SLIDESHOW_INTERVAL_GLACIAL);
|
||||
break;
|
||||
}
|
||||
pr("wake...\n");
|
||||
}
|
||||
}
|
||||
|
||||
void executeCommand(uint8_t cmd) {
|
||||
switch (cmd) {
|
||||
case CMD_DO_REBOOT:
|
||||
@@ -364,7 +432,7 @@ void executeCommand(uint8_t cmd) {
|
||||
writeSettings();
|
||||
break;
|
||||
case CMD_DO_SCAN:
|
||||
currentChannel = channelSelect();
|
||||
currentChannel = channelSelect(4);
|
||||
break;
|
||||
case CMD_DO_DEEPSLEEP:
|
||||
powerUp(INIT_EPD);
|
||||
@@ -374,6 +442,61 @@ void executeCommand(uint8_t cmd) {
|
||||
doSleep(-1);
|
||||
}
|
||||
break;
|
||||
case CMD_ERASE_EEPROM_IMAGES:
|
||||
powerUp(INIT_EEPROM);
|
||||
eraseImageBlocks();
|
||||
powerDown(INIT_EEPROM);
|
||||
break;
|
||||
case CMD_ENTER_SLIDESHOW_FAST:
|
||||
powerUp(INIT_EEPROM);
|
||||
if (findSlotDataTypeArg(CUSTOM_IMAGE_SLIDESHOW << 3) == 0xFF) {
|
||||
powerDown(INIT_EEPROM);
|
||||
return;
|
||||
}
|
||||
powerDown(INIT_EEPROM);
|
||||
tagSettings.customMode = TAG_CUSTOM_SLIDESHOW_FAST;
|
||||
writeSettings();
|
||||
wdtDeviceReset();
|
||||
break;
|
||||
case CMD_ENTER_SLIDESHOW_MEDIUM:
|
||||
powerUp(INIT_EEPROM);
|
||||
if (findSlotDataTypeArg(CUSTOM_IMAGE_SLIDESHOW << 3) == 0xFF) {
|
||||
powerDown(INIT_EEPROM);
|
||||
return;
|
||||
}
|
||||
powerDown(INIT_EEPROM);
|
||||
tagSettings.customMode = TAG_CUSTOM_SLIDESHOW_MEDIUM;
|
||||
writeSettings();
|
||||
wdtDeviceReset();
|
||||
break;
|
||||
case CMD_ENTER_SLIDESHOW_SLOW:
|
||||
powerUp(INIT_EEPROM);
|
||||
if (findSlotDataTypeArg(CUSTOM_IMAGE_SLIDESHOW << 3) == 0xFF) {
|
||||
powerDown(INIT_EEPROM);
|
||||
return;
|
||||
}
|
||||
powerDown(INIT_EEPROM);
|
||||
|
||||
tagSettings.customMode = TAG_CUSTOM_SLIDESHOW_SLOW;
|
||||
writeSettings();
|
||||
wdtDeviceReset();
|
||||
break;
|
||||
case CMD_ENTER_SLIDESHOW_GLACIAL:
|
||||
powerUp(INIT_EEPROM);
|
||||
if (findSlotDataTypeArg(CUSTOM_IMAGE_SLIDESHOW << 3) == 0xFF) {
|
||||
powerDown(INIT_EEPROM);
|
||||
return;
|
||||
}
|
||||
powerDown(INIT_EEPROM);
|
||||
tagSettings.customMode = TAG_CUSTOM_SLIDESHOW_GLACIAL;
|
||||
writeSettings();
|
||||
wdtDeviceReset();
|
||||
break;
|
||||
case CMD_ENTER_NORMAL_MODE:
|
||||
tagSettings.customMode = TAG_CUSTOM_MODE_NONE;
|
||||
writeSettings();
|
||||
wdtDeviceReset();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -399,6 +522,17 @@ void main() {
|
||||
// get the highest slot number, number of slots
|
||||
initializeProto();
|
||||
|
||||
switch (tagSettings.customMode) {
|
||||
case TAG_CUSTOM_SLIDESHOW_FAST:
|
||||
case TAG_CUSTOM_SLIDESHOW_MEDIUM:
|
||||
case TAG_CUSTOM_SLIDESHOW_SLOW:
|
||||
case TAG_CUSTOM_SLIDESHOW_GLACIAL:
|
||||
TagSlideShow();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (tagSettings.enableFastBoot) {
|
||||
// Fastboot
|
||||
pr("Doing fast boot\n");
|
||||
@@ -406,7 +540,7 @@ void main() {
|
||||
if (tagSettings.fixedChannel) {
|
||||
currentChannel = tagSettings.fixedChannel;
|
||||
} else {
|
||||
currentChannel = channelSelect();
|
||||
currentChannel = channelSelect(2);
|
||||
}
|
||||
} else {
|
||||
// Normal boot/startup
|
||||
@@ -426,9 +560,9 @@ void main() {
|
||||
detectButtonOrJig();
|
||||
|
||||
// show the splashscreen
|
||||
pr("EPD: First powerup\n");
|
||||
powerUp(INIT_EPD);
|
||||
currentChannel = 11;
|
||||
showSplashScreen();
|
||||
currentChannel = 0;
|
||||
|
||||
// we've now displayed something on the screen; for the SSD1619, we are now aware of the lut-size
|
||||
#ifdef EPD_SSD1619
|
||||
@@ -443,28 +577,25 @@ void main() {
|
||||
writeSettings();
|
||||
|
||||
// scan for channels
|
||||
powerUp(INIT_EPD);
|
||||
wdt30s();
|
||||
if (tagSettings.fixedChannel) {
|
||||
currentChannel = tagSettings.fixedChannel;
|
||||
} else {
|
||||
currentChannel = showChannelSelect();
|
||||
currentChannel = channelSelect(4);
|
||||
}
|
||||
}
|
||||
|
||||
// end of the fastboot option split
|
||||
|
||||
wdt10s();
|
||||
powerUp(INIT_EPD);
|
||||
if (currentChannel) {
|
||||
showAPFound();
|
||||
initPowerSaving(INTERVAL_BASE);
|
||||
powerDown(INIT_EPD | INIT_UART);
|
||||
currentTagMode = TAG_MODE_ASSOCIATED;
|
||||
doSleep(5000UL);
|
||||
} else {
|
||||
showNoAP();
|
||||
initPowerSaving(INTERVAL_AT_MAX_ATTEMPTS);
|
||||
powerDown(INIT_EPD | INIT_UART);
|
||||
currentTagMode = TAG_MODE_CHANSEARCH;
|
||||
doSleep(120000UL);
|
||||
}
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
<?php
|
||||
|
||||
$types[0x00] = "Tag_FW_1.54.bin";
|
||||
$types[0x01] = "Tag_FW_2.9.bin";
|
||||
$types[0x00] = "SOLUM_154_SSD1619-tag-00-0022.bin";
|
||||
$types[0x01] = "SOLUM_29_SSD1619-tag-01-0022";
|
||||
$types[0xF0] = "Tag_FW_Segmented_UK.bin";
|
||||
$types[0x02] = "Tag_FW_4.2.bin";
|
||||
$types[0x11] = "Tag_FW_2.9-uc8151.bin";
|
||||
$types[0x02] = "SOLUM_42_SSD1619-tag-02-0022.bin";
|
||||
$types[0x11] = "SOLUM_29_UC8151-tag-11-0022.bin";
|
||||
|
||||
$binpath = "../binaries/";
|
||||
$binpath = "../binaries/Tag";
|
||||
$tocmaxsize = 512;
|
||||
|
||||
$toc = array();
|
||||
@@ -21,6 +21,7 @@ $version = hexdec($version);
|
||||
*/
|
||||
$version = 0;
|
||||
|
||||
// *** fixme: this should select only filenames containing the latest version. See python version of this script.
|
||||
exec("ls -1 $binpath | grep 'Tag_FW' | grep -v battery | grep -v Pack | grep -v M3", $binaries);
|
||||
foreach($binaries as $file){
|
||||
$file = trim($file);
|
||||
@@ -30,7 +31,7 @@ foreach($binaries as $file){
|
||||
$type = $typeid;
|
||||
}
|
||||
}
|
||||
if($type==-1)die("We don't recognize filetype <$file>, sorry...\n");
|
||||
if($type!=-1)echo("Adding filetype <$file>\n");
|
||||
$binary = file_get_contents($binpath.$file);
|
||||
$length = strlen($binary);
|
||||
$offset = strlen($output);
|
||||
|
||||
58
zbs243_Tag_FW/packagebinaries.py
Normal file
58
zbs243_Tag_FW/packagebinaries.py
Normal file
@@ -0,0 +1,58 @@
|
||||
import os
|
||||
import json
|
||||
|
||||
version = "0022" # You can set your desired version here.
|
||||
|
||||
types = {
|
||||
0x00: "SOLUM_154_SSD1619-tag-00-" + version + ".bin",
|
||||
0x01: "SOLUM_29_SSD1619-tag-01-" + version + ".bin",
|
||||
0xF0: "Tag_FW_Segmented_UK.bin",
|
||||
0x02: "SOLUM_42_SSD1619-tag-02-" + version + ".bin",
|
||||
0x11: "SOLUM_29_UC8151-tag-11-" + version + ".bin",
|
||||
}
|
||||
|
||||
binpath = "../binaries/Tag"
|
||||
tocmaxsize = 512
|
||||
|
||||
toc = []
|
||||
output = b'\0' * tocmaxsize # Initialize as bytes
|
||||
|
||||
binaries = [file for file in os.listdir(binpath) if 'Pack' not in file and version in file]
|
||||
for file in binaries:
|
||||
file = file.strip()
|
||||
type = -1
|
||||
for typeid, typefile in types.items():
|
||||
if typefile == file:
|
||||
type = typeid
|
||||
if type != -1:
|
||||
print("Adding filetype <{}>".format(file))
|
||||
with open(os.path.join(binpath, file), 'rb') as binary_file:
|
||||
binary = binary_file.read()
|
||||
length = len(binary)
|
||||
offset = len(output)
|
||||
subarr = {
|
||||
'type': type,
|
||||
'version': version,
|
||||
'name': file,
|
||||
'offset': offset,
|
||||
'length': length,
|
||||
}
|
||||
toc.append(subarr)
|
||||
output += binary
|
||||
|
||||
jtoc = json.dumps(toc)
|
||||
jtoc = jtoc.replace("'", '"')
|
||||
tocsize = len(jtoc)
|
||||
if tocsize > tocmaxsize:
|
||||
raise ValueError("TOC is too big! (" + str(tocsize) + "). Adjust size and try again")
|
||||
|
||||
# Encode jtoc as bytes
|
||||
jtoc = jtoc.encode('utf-8')
|
||||
|
||||
# Concatenate bytes and write to the file
|
||||
output = jtoc + output[len(jtoc):]
|
||||
with open(os.path.join(binpath, "Tag_FW_Pack.bin"), 'wb') as output_file:
|
||||
output_file.write(output)
|
||||
|
||||
print(toc)
|
||||
print("All done.")
|
||||
@@ -286,41 +286,83 @@ void doSleep(const uint32_t __xdata t) {
|
||||
uartActive = false;
|
||||
eepromActive = false;
|
||||
|
||||
capabilities |= CAPABILITY_HAS_WAKE_BUTTON;
|
||||
|
||||
if (capabilities & CAPABILITY_HAS_WAKE_BUTTON) {
|
||||
// Button setup on TEST pin 1.0 (input pullup)
|
||||
P1FUNC &= ~(1 << 0);
|
||||
P1DIR |= (1 << 0);
|
||||
P1PULL |= (1 << 0);
|
||||
P1LVLSEL |= (1 << 0);
|
||||
P1INTEN = (1 << 0);
|
||||
P1INTEN |= (1 << 0);
|
||||
P1CHSTA &= ~(1 << 0);
|
||||
|
||||
// Button setup on RXD pin 0.7 (input pullup)
|
||||
P0FUNC &= ~(1 << 7);
|
||||
P0DIR |= (1 << 7);
|
||||
P0PULL |= (1 << 7);
|
||||
P0LVLSEL |= (1 << 7);
|
||||
P0INTEN |= (1 << 7);
|
||||
P0CHSTA &= ~(1 << 7);
|
||||
}
|
||||
|
||||
#ifdef ENABLE_GPIO_WAKE
|
||||
// enable wake on pin 0.2 (MISO)
|
||||
P0FUNC &= ~(1 << 3);
|
||||
P0DIR |= (1 << 3);
|
||||
P0PULL |= (1 << 3);
|
||||
P0LVLSEL |= (1 << 3);
|
||||
P0INTEN |= (1 << 3);
|
||||
P0CHSTA &= ~(1 << 3);
|
||||
#endif
|
||||
|
||||
if (capabilities & CAPABILITY_NFC_WAKE) {
|
||||
P1FUNC &= ~(1 << 3);
|
||||
P1DIR |= (1 << 3);
|
||||
P1PULL |= (1 << 3);
|
||||
P1LVLSEL |= (1 << 3);
|
||||
P1INTEN = (1 << 3);
|
||||
P1INTEN |= (1 << 3);
|
||||
P1CHSTA &= ~(1 << 3);
|
||||
}
|
||||
|
||||
if (tagSettings.enableRFWake) {
|
||||
// enabled RF wake, adds a little extra energy draw!
|
||||
// enabled RF wake, adds a little extra energy draw!
|
||||
RADIO_RadioPowerCtl &= 0xFB;
|
||||
}
|
||||
|
||||
// sleepy time
|
||||
sleepForMsec(t);
|
||||
P1INTEN = 0;
|
||||
if ((P1CHSTA & (1 << 0)) && (capabilities & CAPABILITY_HAS_WAKE_BUTTON)) {
|
||||
wakeUpReason = WAKEUP_REASON_GPIO;
|
||||
P1CHSTA &= ~(1 << 0);
|
||||
}
|
||||
P0INTEN = 0;
|
||||
|
||||
if ((P1CHSTA & (1 << 3)) && (capabilities & CAPABILITY_NFC_WAKE)) {
|
||||
wakeUpReason = WAKEUP_REASON_NFC;
|
||||
P1CHSTA &= ~(1 << 3);
|
||||
switch (RADIO_Wake_Reason) {
|
||||
case RADIO_WAKE_REASON_TIMER:
|
||||
break;
|
||||
case RADIO_WAKE_REASON_EXT:
|
||||
if ((P1CHSTA & (1 << 0)) && (capabilities & CAPABILITY_HAS_WAKE_BUTTON)) {
|
||||
wakeUpReason = WAKEUP_REASON_BUTTON1;
|
||||
P1CHSTA &= ~(1 << 0);
|
||||
}
|
||||
|
||||
if ((P0CHSTA & (1 << 7)) && (capabilities & CAPABILITY_HAS_WAKE_BUTTON)) {
|
||||
wakeUpReason = WAKEUP_REASON_BUTTON2;
|
||||
P0CHSTA &= ~(1 << 7);
|
||||
}
|
||||
|
||||
if ((P1CHSTA & (1 << 3)) && (capabilities & CAPABILITY_NFC_WAKE)) {
|
||||
wakeUpReason = WAKEUP_REASON_NFC;
|
||||
P1CHSTA &= ~(1 << 3);
|
||||
}
|
||||
#ifdef ENABLE_GPIO_WAKE
|
||||
if (P0CHSTA & (1 << 3)) {
|
||||
wakeUpReason = WAKEUP_REASON_GPIO;
|
||||
P0CHSTA &= ~(1 << 3);
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
case RADIO_WAKE_REASON_RF:
|
||||
wakeUpReason = WAKEUP_REASON_RF;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -40,6 +40,13 @@
|
||||
#define INTERVAL_2_ATTEMPTS 12 // for 12 attempts (an additional day)
|
||||
#define INTERVAL_3_TIME 86400UL // Finally, try every day
|
||||
|
||||
// slideshow power settings
|
||||
#define SLIDESHOW_FORCE_FULL_REFRESH_EVERY 16 // force a full refresh every X screen draws
|
||||
#define SLIDESHOW_INTERVAL_FAST 15 // interval for 'fast'
|
||||
#define SLIDESHOW_INTERVAL_MEDIUM 60
|
||||
#define SLIDESHOW_INTERVAL_SLOW 300
|
||||
#define SLIDESHOW_INTERVAL_GLACIAL 1800
|
||||
|
||||
extern uint8_t checkButtonOrJig();
|
||||
|
||||
extern void setupPortsInitial();
|
||||
|
||||
@@ -3,11 +3,11 @@
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#define FW_VERSION 21 // version number (max 2.5.5 :) )
|
||||
#define FW_VERSION_SUFFIX "-RET" // suffix, like -RC1 or whatever.
|
||||
#define FW_VERSION 22 // version number (max 2.5.5 :) )
|
||||
#define FW_VERSION_SUFFIX "-RFW" // suffix, like -RC1 or whatever.
|
||||
// #define DEBUGBLOCKS // uncomment to enable extra debug information on the block transfers
|
||||
// #define PRINT_LUT // uncomment if you want the tag to print the LUT for the current temperature bracket
|
||||
|
||||
#define ENABLE_GPIO_WAKE // uncomment to enable GPIO wake
|
||||
// #define ENABLE_RETURN_DATA // enables the tag to send blocks of data back. Enabling this costs about 4 IRAM bytes
|
||||
|
||||
#define SETTINGS_STRUCT_VERSION 0x01
|
||||
@@ -42,4 +42,4 @@ void loadDefaultSettings();
|
||||
void writeSettings();
|
||||
void loadSettings();
|
||||
void loadSettingsFromBuffer(uint8_t* p);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user