Merge branch 'jjwbruijn:master' into master

This commit is contained in:
Jonas Niesner
2023-09-01 20:17:06 +02:00
committed by GitHub
31 changed files with 609 additions and 395 deletions

View File

@@ -1,26 +1,48 @@
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <inttypes.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/queue.h"
#include "driver/gpio.h"
#include "led.h"
#include "driver/gpio.h"
#include "freertos/FreeRTOS.h"
#include "freertos/queue.h"
#include "freertos/task.h"
#include "freertos/timers.h"
#include "proto.h"
#include <inttypes.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void init_led()
{
gpio_config_t led1 = {};
led1.intr_type = GPIO_INTR_DISABLE;
led1.mode = GPIO_MODE_OUTPUT;
led1.pin_bit_mask = ((1ULL<<LED1) | (1ULL<<LED2));
led1.pull_down_en = 0;
led1.pull_up_en = 0;
gpio_config(&led1);
#define NUM_LEDS 2
const gpio_num_t led_pins[NUM_LEDS] = {LED1, LED2};
TimerHandle_t led_timers[NUM_LEDS] = {0};
void led_timer_callback(TimerHandle_t xTimer) {
int led_index = (int)pvTimerGetTimerID(xTimer);
if (led_index >= 0 && led_index < NUM_LEDS) {
gpio_set_level(led_pins[led_index], 0);
}
}
void led_set(int nr, bool state)
{
gpio_set_level(nr, state);
void init_led() {
gpio_config_t led1 = {};
led1.intr_type = GPIO_INTR_DISABLE;
led1.mode = GPIO_MODE_OUTPUT;
led1.pin_bit_mask = ((1ULL << LED1) | (1ULL << LED2));
led1.pull_down_en = 0;
led1.pull_up_en = 0;
gpio_config(&led1);
for (int i = 0; i < NUM_LEDS; i++) {
led_timers[i] = xTimerCreate("led_timer", pdMS_TO_TICKS(50), pdFALSE, (void *)i, led_timer_callback);
}
}
void led_flash(int nr) {
gpio_set_level(led_pins[nr], 1);
if (nr >= 0 && nr < NUM_LEDS) {
xTimerStart(led_timers[nr], 0);
}
}
void led_set(int nr, bool state) {
gpio_set_level(nr, state);
}

View File

@@ -1,4 +1,6 @@
#pragma once
#include <stdbool.h>
void init_led();
void led_set(int nr, bool state);
void led_set(int nr, bool state);
void led_flash(int nr);

View File

@@ -1,10 +1,6 @@
// Ported to ESP32-C6 By ATC1441(ATCnetz.de) for OpenEPaperLink at ~08.2023
#include "main.h"
#include <esp_mac.h>
#include <math.h>
#include <stdarg.h>
#include <string.h>
#include "driver/gpio.h"
#include "driver/uart.h"
#include "esp_err.h"
@@ -16,21 +12,27 @@
#include "freertos/FreeRTOS.h"
#include "freertos/queue.h"
#include "freertos/task.h"
#include "led.h"
#include "proto.h"
#include "radio.h"
#include "sdkconfig.h"
#include "second_uart.h"
#include "soc/uart_struct.h"
#include "soc/lp_uart_reg.h"
#include "soc/uart_struct.h"
#include "utils.h"
#include "led.h"
#include <esp_mac.h>
#include <math.h>
#include <stdarg.h>
#include <stdbool.h>
#include <stdint.h>
#include <string.h>
static const char *TAG = "MAIN";
const uint8_t channelList[6] = {11, 15, 20, 25, 26, 27};
#define DATATYPE_NOUPDATE 0
#define HW_TYPE 0xFF
#define HW_TYPE 0xC6
#define MAX_PENDING_MACS 250
#define HOUSEKEEPING_INTERVAL 60UL
@@ -38,7 +40,7 @@ const uint8_t channelList[6] = {11, 15, 20, 25, 26, 27};
struct pendingData pendingDataArr[MAX_PENDING_MACS];
// VERSION GOES HERE!
uint16_t version = 0x0017;
uint16_t version = 0x0018;
#define RAW_PKT_PADDING 2
@@ -69,6 +71,8 @@ uint8_t curPower = 10;
uint8_t curPendingData = 0;
uint8_t curNoUpdate = 0;
bool highspeedSerial = false;
void sendXferCompleteAck(uint8_t *dst);
void sendCancelXfer(uint8_t *dst);
void espNotifyAPInfo();
@@ -191,7 +195,7 @@ void processSerial(uint8_t lastchar) {
static uint8_t *serialbufferp;
static uint8_t bytesRemain = 0;
static uint32_t lastSerial = 0;
static uint32_t blockStartTime = 0;
static uint32_t blockStartTime = 0;
if ((RXState != ZBS_RX_WAIT_HEADER) && ((getMillis() - lastSerial) > 1000)) {
RXState = ZBS_RX_WAIT_HEADER;
ESP_LOGI(TAG, "UART Timeout");
@@ -206,9 +210,9 @@ void processSerial(uint8_t lastchar) {
cmdbuffer[3] = lastchar;
if (isSame(cmdbuffer + 1, ">D>", 3)) {
pr("ACK>\n");
pr("ACK>");
blockStartTime = getMillis();
ESP_LOGI(TAG, "Starting BlkData");
ESP_LOGI(TAG, "Starting BlkData, %lu ms after request", blockStartTime - nextBlockAttempt );
blockPosition = 0;
RXState = ZBS_RX_WAIT_BLOCKDATA;
}
@@ -252,11 +256,21 @@ void processSerial(uint8_t lastchar) {
// TODO RESET US HERE
RXState = ZBS_RX_WAIT_HEADER;
}
if (isSame(cmdbuffer, "HSPD", 4)) {
pr("ACK>");
ESP_LOGI(TAG, "HSPD In, switching to 2000000");
delay(100);
uart_switch_speed(2000000);
delay(100);
highspeedSerial = true;
pr("ACK>");
RXState = ZBS_RX_WAIT_HEADER;
}
break;
case ZBS_RX_WAIT_BLOCKDATA:
blockbuffer[blockPosition++] = 0xAA ^ lastchar;
if (blockPosition >= 4100) {
ESP_LOGI(TAG, "Blockdata fully received %lu", getMillis() - blockStartTime);
ESP_LOGI(TAG, "Blockdata fully received in %lu ms, %lu ms after the request", getMillis() - blockStartTime, getMillis() - nextBlockAttempt);
RXState = ZBS_RX_WAIT_HEADER;
}
break;
@@ -272,12 +286,12 @@ void processSerial(uint8_t lastchar) {
if (slot == -1) slot = findFreeSlot();
if (slot != -1) {
memcpy(&(pendingDataArr[slot]), serialbuffer, sizeof(struct pendingData));
pr("ACK>\n");
pr("ACK>");
} else {
pr("NOQ>\n");
pr("NOQ>");
}
} else {
pr("NOK>\n");
pr("NOK>");
}
RXState = ZBS_RX_WAIT_HEADER;
@@ -290,11 +304,10 @@ void processSerial(uint8_t lastchar) {
if (bytesRemain == 0) {
if (checkCRC(serialbuffer, sizeof(struct pendingData))) {
struct pendingData *pd = (struct pendingData *) serialbuffer;
// deleteAllPendingDataForVer((uint8_t *)&pd->availdatainfo.dataVer);
deleteAllPendingDataForMac((uint8_t *) &pd->targetMac);
pr("ACK>\n");
pr("ACK>");
} else {
pr("NOK>\n");
pr("NOK>");
}
RXState = ZBS_RX_WAIT_HEADER;
@@ -316,10 +329,11 @@ void processSerial(uint8_t lastchar) {
curPower = scp->power;
radioSetChannel(scp->channel);
radioSetTxPower(scp->power);
pr("ACK>\n");
ESP_LOGI(TAG, "Set channel: %d power: %d", curChannel, curPower);
pr("ACK>");
} else {
SCPfailed:
pr("NOK>\n");
pr("NOK>");
}
RXState = ZBS_RX_WAIT_HEADER;
}
@@ -381,17 +395,17 @@ void espNotifyTimeOut(const uint8_t *src) {
}
}
void espNotifyAPInfo() {
pr("TYP>%02X\n", HW_TYPE);
pr("VER>%04X\n", version);
pr("TYP>%02X", HW_TYPE);
pr("VER>%04X", version);
pr("MAC>%02X%02X", mSelfMac[0], mSelfMac[1]);
pr("%02X%02X", mSelfMac[2], mSelfMac[3]);
pr("%02X%02X", mSelfMac[4], mSelfMac[5]);
pr("%02X%02X\n", mSelfMac[6], mSelfMac[7]);
pr("ZCH>%02X\n", curChannel);
pr("ZPW>%02X\n", curPower);
pr("%02X%02X", mSelfMac[6], mSelfMac[7]);
pr("ZCH>%02X", curChannel);
pr("ZPW>%02X", curPower);
countSlots();
pr("PEN>%02X\n", curPendingData);
pr("NOP>%02X\n", curNoUpdate);
pr("PEN>%02X", curPendingData);
pr("NOP>%02X", curNoUpdate);
}
// process data from tag
@@ -450,18 +464,17 @@ void processBlockRequest(const uint8_t *buffer, uint8_t forceBlockDownload) {
if (blockStartTimer == 0) {
if (requestDataDownload) {
// check if we need to download the first block; we need to give the ESP32 some additional time to cache the file
if (blockReq->blockId == 0) {
blockRequestAck->pleaseWaitMs = 450;
if (highspeedSerial == true) {
blockRequestAck->pleaseWaitMs = 220;
} else {
blockRequestAck->pleaseWaitMs = 450;
blockRequestAck->pleaseWaitMs = 550;
}
} else {
// block is already in buffer
blockRequestAck->pleaseWaitMs = 50;
blockRequestAck->pleaseWaitMs = 30;
}
} else {
blockRequestAck->pleaseWaitMs = 50;
blockRequestAck->pleaseWaitMs = 30;
}
blockStartTimer = getMillis() + blockRequestAck->pleaseWaitMs;
@@ -624,8 +637,8 @@ void sendPong(void *buf) {
}
void app_main(void) {
init_nvs();
init_led();
init_nvs();
init_led();
init_second_uart();
esp_event_loop_create_default();
@@ -639,23 +652,23 @@ void app_main(void) {
radioSetChannel(curChannel);
radioSetTxPower(10);
pr("RES>\n");
pr("RDY>\n");
pr("RES>");
pr("RDY>");
housekeepingTimer = getMillis();
while (1) {
while ((getMillis() - housekeepingTimer) < ((1000 * HOUSEKEEPING_INTERVAL) - 100)) {
int8_t ret = commsRxUnencrypted(radiorxbuffer);
if (ret > 1) {
led_set(LED1, 1);
led_flash(0);
// received a packet, lets see what it is
switch (getPacketType(radiorxbuffer)) {
case PKT_AVAIL_DATA_REQ:
if (ret == 28) {
// old version of the AvailDataReq struct, set all the new fields to zero, so it will pass the CRC
processAvailDataReq(radiorxbuffer);
memset(radiorxbuffer + 1 + sizeof(struct MacFrameBcast) + sizeof(struct oldAvailDataReq), 0,
sizeof(struct AvailDataReq) - sizeof(struct oldAvailDataReq) + 2);
processAvailDataReq(radiorxbuffer);
} else if (ret == 40) {
// new version of the AvailDataReq struct
processAvailDataReq(radiorxbuffer);
@@ -683,22 +696,24 @@ void app_main(void) {
}
break;
default:
pr("t=%02X\n", getPacketType(radiorxbuffer));
ESP_LOGI(TAG, "t=%02X" , getPacketType(radiorxbuffer));
break;
}
led_set(LED1, 0);
} else if (blockStartTimer == 0) {
vTaskDelay(10 / portTICK_PERIOD_MS);
}
uint8_t curr_char;
while (getRxCharSecond(&curr_char)) processSerial(curr_char);
if (blockStartTimer) {
// BUG: uint32 overflowing; this will break every once in a while. Don't know how to fix this other than ugly global variables
if (getMillis() > blockStartTimer) {
sendBlockData();
blockStartTimer = 0;
}
}
}
for (uint8_t cCount = 0; cCount < MAX_PENDING_MACS; cCount++) {
if (pendingDataArr[cCount].attemptsLeft == 1) {
if (pendingDataArr[cCount].availdatainfo.dataType != DATATYPE_NOUPDATE) {

View File

@@ -1,7 +1,4 @@
#include <esp_mac.h>
#include <math.h>
#include <stdarg.h>
#include <string.h>
#include "radio.h"
#include "driver/gpio.h"
#include "driver/uart.h"
#include "esp_err.h"
@@ -13,28 +10,31 @@
#include "freertos/FreeRTOS.h"
#include "freertos/queue.h"
#include "freertos/task.h"
#include "led.h"
#include "main.h"
#include "proto.h"
#include "sdkconfig.h"
#include "soc/uart_struct.h"
#include "soc/lp_uart_reg.h"
#include "radio.h"
#include "soc/uart_struct.h"
#include "utils.h"
#include "led.h"
#include <esp_mac.h>
#include <math.h>
#include <stdarg.h>
#include <string.h>
static const char *TAG = "RADIO";
uint8_t mSelfMac[8];
volatile uint8_t isInTransmit = 0;
QueueHandle_t packet_bufer = NULL;
QueueHandle_t packet_buffer = NULL;
void esp_ieee802154_receive_done(uint8_t *frame, esp_ieee802154_frame_info_t *frame_info) {
ESP_EARLY_LOGI(TAG, "RX <- : %d", frame[0]);
BaseType_t xHigherPriorityTaskWoken ;
static uint8_t inner_rxPKT[130];
ESP_EARLY_LOGI(TAG, "RX %d", frame[0]);
BaseType_t xHigherPriorityTaskWoken;
static uint8_t inner_rxPKT[130];
memcpy(inner_rxPKT, &frame[0], frame[0] + 1);
xQueueSendFromISR(packet_bufer, (void *) &inner_rxPKT, &xHigherPriorityTaskWoken );
portYIELD_FROM_ISR_ARG(xHigherPriorityTaskWoken );
xQueueSendFromISR(packet_buffer, (void *)&inner_rxPKT, &xHigherPriorityTaskWoken);
portYIELD_FROM_ISR_ARG(xHigherPriorityTaskWoken);
}
void esp_ieee802154_transmit_failed(const uint8_t *frame, esp_ieee802154_tx_error_t error) {
@@ -43,13 +43,12 @@ void esp_ieee802154_transmit_failed(const uint8_t *frame, esp_ieee802154_tx_erro
}
void esp_ieee802154_transmit_done(const uint8_t *frame, const uint8_t *ack, esp_ieee802154_frame_info_t *ack_frame_info) {
isInTransmit = 0;
ESP_EARLY_LOGI(TAG, "TX -> : %d", frame[0]);
isInTransmit = 0;
ESP_EARLY_LOGI(TAG, "TX %d", frame[0]);
}
void radio_init()
{
packet_bufer = xQueueCreate(32, 130);
void radio_init() {
packet_buffer = xQueueCreate(32, 130);
esp_ieee802154_enable();
radioSetChannel(11);
esp_ieee802154_set_panid(PROTO_PAN_ID);
@@ -64,19 +63,17 @@ void radio_init()
}
uint32_t lastZbTx = 0;
bool radioTx(uint8_t *packet)
{
static uint8_t txPKT[130];
led_set(LED2, 1);
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();
lastZbTx = getMillis();
esp_ieee802154_transmit(txPKT, false);
led_set(LED2, 0);
return true;
}
@@ -85,11 +82,10 @@ void radioSetChannel(uint8_t ch) { esp_ieee802154_set_channel(ch); }
void radioSetTxPower(uint8_t power) {}
int8_t commsRxUnencrypted(uint8_t *data) {
static uint8_t inner_rxPKT_out[130];
if (xQueueReceive(packet_bufer, (void *) &inner_rxPKT_out, pdMS_TO_TICKS(100)) == pdTRUE) {
memcpy(data, &inner_rxPKT_out[1], inner_rxPKT_out[0] + 1);
static uint8_t inner_rxPKT_out[130];
if (xQueueReceive(packet_buffer, (void *)&inner_rxPKT_out, pdMS_TO_TICKS(100)) == pdTRUE) {
memcpy(data, &inner_rxPKT_out[1], inner_rxPKT_out[0] + 1);
return inner_rxPKT_out[0] - 2;
}
return 0;
}

View File

@@ -1,9 +1,11 @@
#pragma once
#include <stdbool.h>
#include <stdint.h>
extern uint8_t mSelfMac[8];
void radio_init();
bool radioTx(uint8_t *packet);
bool radioTx(uint8_t *packet);
void radioSetChannel(uint8_t ch);
void radioSetTxPower(uint8_t power);
int8_t commsRxUnencrypted(uint8_t *data);

View File

@@ -51,6 +51,18 @@ void init_second_uart() {
xTaskCreate(uart_event_task, "uart_event_task", 16384, NULL, 12, NULL);
}
void uart_switch_speed(int baudrate) {
uart_config_t uart_config = {
.baud_rate = baudrate,
.data_bits = UART_DATA_8_BITS,
.parity = UART_PARITY_DISABLE,
.stop_bits = UART_STOP_BITS_1,
.flow_ctrl = UART_HW_FLOWCTRL_DISABLE,
.source_clk = UART_SCLK_DEFAULT,
};
ESP_ERROR_CHECK(uart_param_config(1, &uart_config));
}
void uartTx(uint8_t data) { uart_write_bytes(1, (const char *) &data, 1); }
@@ -90,171 +102,16 @@ static void uart_event_task(void *pvParameters) {
vTaskDelete(NULL);
}
static void printchar(char **str, int c) {
if (str) {
**str = c;
++(*str);
} else {
uart_write_bytes(1, (const char *) &c, 1);
}
}
void uart_printf(const char *format, ...) {
va_list args;
va_start(args, format);
#define PAD_RIGHT 1
#define PAD_ZERO 2
char buffer[128];
int len = vsnprintf(buffer, sizeof(buffer), format, args);
static int prints(char **out, const char *string, int width, int pad) {
register int pc = 0, padchar = ' ';
va_end(args);
if (width > 0) {
register int len = 0;
register const char *ptr;
for (ptr = string; *ptr; ++ptr) ++len;
if (len >= width)
width = 0;
else
width -= len;
if (pad & PAD_ZERO) padchar = '0';
}
if (!(pad & PAD_RIGHT)) {
for (; width > 0; --width) {
printchar(out, padchar);
++pc;
}
}
for (; *string; ++string) {
printchar(out, *string);
++pc;
}
for (; width > 0; --width) {
printchar(out, padchar);
++pc;
}
return pc;
}
/* the following should be enough for 32 bit int */
#define PRINT_BUF_LEN 12
static int printi(char **out, int i, int b, int sg, int width, int pad, int letbase) {
char print_buf[PRINT_BUF_LEN];
register char *s;
register int t, neg = 0, pc = 0;
register unsigned int u = i;
if (i == 0) {
print_buf[0] = '0';
print_buf[1] = '\0';
return prints(out, print_buf, width, pad);
}
if (sg && b == 10 && i < 0) {
neg = 1;
u = -i;
}
s = print_buf + PRINT_BUF_LEN - 1;
*s = '\0';
while (u) {
t = u % b;
if (t >= 10) t += letbase - '0' - 10;
*--s = t + '0';
u /= b;
}
if (neg) {
if (width && (pad & PAD_ZERO)) {
printchar(out, '-');
++pc;
--width;
} else {
*--s = '-';
}
}
return pc + prints(out, s, width, pad);
}
static int print(char **out, const char *format, va_list args) {
register int width, pad;
register int pc = 0;
char scr[2];
for (; *format != 0; ++format) {
if (*format == '%') {
++format;
width = pad = 0;
if (*format == '\0') break;
if (*format == '%') goto out;
if (*format == '-') {
++format;
pad = PAD_RIGHT;
}
while (*format == '0') {
++format;
pad |= PAD_ZERO;
}
for (; *format >= '0' && *format <= '9'; ++format) {
width *= 10;
width += *format - '0';
}
if (*format == 's') {
register char *s = (char *) va_arg(args, int);
pc += prints(out, s ? s : "(null)", width, pad);
continue;
}
if (*format == 'd') {
pc += printi(out, va_arg(args, int), 10, 1, width, pad, 'a');
continue;
}
if (*format == 'x') {
pc += printi(out, va_arg(args, int), 16, 0, width, pad, 'a');
continue;
}
if (*format == 'X') {
pc += printi(out, va_arg(args, int), 16, 0, width, pad, 'A');
continue;
}
if (*format == 'u') {
pc += printi(out, va_arg(args, int), 10, 0, width, pad, 'a');
continue;
}
if (*format == 'c') {
/* char are converted to int then pushed on the stack */
scr[0] = (char) va_arg(args, int);
scr[1] = '\0';
pc += prints(out, scr, width, pad);
continue;
}
} else {
out:
printchar(out, *format);
++pc;
}
}
if (out) **out = '\0';
va_end(args);
return pc;
}
int u_printf(const char *format, ...) {
va_list args;
va_start(args, format);
print(0, format, args);
return 0;
}
int u_sprintf(char *out, const char *format, ...) {
va_list args;
va_start(args, format);
return print(&out, format, args);
}
void u_array_printf(unsigned char *data, unsigned int len) {
u_printf("{");
for (int i = 0; i < len; ++i) {
u_printf("%X%s", data[i], i < (len) -1 ? ":" : " ");
}
u_printf("}\n");
if (len > 0) {
uart_write_bytes(1, buffer, len);
}
}

View File

@@ -1,14 +1,11 @@
#pragma once
void init_second_uart();
void uart_switch_speed(int baudrate);
void uartTx(uint8_t data);
bool getRxCharSecond(uint8_t *newChar);
int u_printf(const char *fmt, ...);
int u_sprintf(char *s, const char *fmt, ...);
void u_array_printf(unsigned char *data, unsigned int len);
void uart_printf(const char *format, ...);
#define pr u_printf
#define sprf u_sprintf
#define array_prf u_array_printf
#define pr uart_printf

View File

@@ -1,7 +1,7 @@
{
"name": "TFT 320x170",
"name": "TFT 320x172",
"width": 320,
"height": 170,
"height": 172,
"rotatebuffer": 0,
"bpp": 16,
"colors": 4,
@@ -16,14 +16,14 @@
"usetemplate": 1,
"template": {
"21": [
{ "box": [ 0, 0, 320, 170, 1 ] },
{ "text": [ 5, 5, "OpenEpaperLink AP", "calibrib30", 2, 0, 0, 1 ] },
{ "text": [ 5, 60, "IP address:", "bahnschrift20", "#888888", 0, 0, 1 ] },
{ "text": [ 120, 60, "{ap_ip}", "bahnschrift20", 0, 0, 0, 1 ] },
{ "text": [ 5, 85, "Channel:", "bahnschrift20", "#888888", 0, 0, 1 ] },
{ "text": [ 120, 85, "{ap_ch}", "bahnschrift20", 0, 0, 0, "1" ] },
{ "text": [ 5, 110, "Tag count:", "bahnschrift20", "#888888", 0, 0, 1 ] },
{ "text": [ 120, 110, "{ap_tagcount}", "bahnschrift20", 0, 0, 0, "1" ] }
{ "box": [ 0, 0, 320, 172, 1 ] },
{ "text": [ 10, 15, "OpenEpaperLink AP", "calibrib30", 2, 0, 0, 1 ] },
{ "text": [ 10, 70, "IP address:", "bahnschrift20", "#888888", 0, 0, 1 ] },
{ "text": [ 120, 70, "{ap_ip}", "bahnschrift20", 0, 0, 0, 1 ] },
{ "text": [ 10, 95, "Channel:", "bahnschrift20", "#888888", 0, 0, 1 ] },
{ "text": [ 120, 95, "{ap_ch}", "bahnschrift20", 0, 0, 0, "1" ] },
{ "text": [ 10, 120, "Tag count:", "bahnschrift20", "#888888", 0, 0, 1 ] },
{ "text": [ 120, 120, "{ap_tagcount}", "bahnschrift20", 0, 0, 0, "1" ] }
]
}
}

Binary file not shown.

View File

@@ -126,4 +126,20 @@ struct tagsettings {
uint8_t fixedChannel; // default 0; if set to a valid channel number, the tag will stick to that channel
} __packed;
struct ledFlash {
uint8_t mode : 4;
uint8_t flashDuration : 4;
uint8_t color1;
uint8_t flashCount1 : 4;
uint8_t delay1 : 4;
uint8_t color2;
uint8_t flashCount2 : 4;
uint8_t delay2 : 4;
uint8_t color3;
uint8_t flashCount3 : 4;
uint8_t delay3 : 4;
uint8_t repeats;
uint8_t spare;
} __packed;
#pragma pack(pop)

View File

@@ -0,0 +1,12 @@
#include <Arduino.h>
#include <TFT_eSPI.h>
#ifdef YELLOW_IPS_AP
extern TFT_eSPI tft2;
extern int32_t tftid;
extern uint8_t YellowSense;
void TFTLog(String text);
#endif

View File

@@ -13,7 +13,7 @@ extern void processXferComplete(struct espXferComplete* xfc, bool local);
extern void processXferTimeout(struct espXferComplete* xfc, bool local);
extern void processDataReq(struct espAvailDataReq* adr, bool local);
extern bool sendTagCommand(const uint8_t* dst, uint8_t cmd, bool local);
extern bool sendTagCommand(const uint8_t* dst, uint8_t cmd, bool local, const uint8_t* payload = nullptr);
extern bool sendAPSegmentedData(const uint8_t* dst, String data, uint16_t icons, bool inverted, bool local);
extern bool showAPSegmentedInfo(const uint8_t* dst, bool local);
extern void updateTaginfoitem(struct TagInfo* taginfoitem, IPAddress remoteIP);

View File

@@ -4,6 +4,8 @@
#define WAKEUP_REASON_BOOT 1
#define WAKEUP_REASON_GPIO 2
#define WAKEUP_REASON_NFC 3
#define WAKEUP_REASON_BUTTON1 4
#define WAKEUP_REASON_BUTTON2 5
#define WAKEUP_REASON_FIRSTBOOT 0xFC
#define WAKEUP_REASON_NETWORK_SCAN 0xFD
#define WAKEUP_REASON_WDT_RESET 0xFE

View File

@@ -11,6 +11,8 @@
#define WAKEUP_REASON_BOOTUP 1
#define WAKEUP_REASON_GPIO 2
#define WAKEUP_REASON_NFC 3
#define WAKEUP_REASON_BUTTON1 4
#define WAKEUP_REASON_BUTTON2 5
#define RUNSTATUS_STOP 0
#define RUNSTATUS_PAUSE 1

View File

@@ -40,6 +40,7 @@ class WifiManager {
bool waitForConnection();
void pollSerial();
static void terminalLog(String text);
public:
WifiManager();

View File

@@ -280,9 +280,13 @@ build_flags =
-D FLASHER_AP_TEST=-1
-D FLASHER_AP_TXD=17
-D FLASHER_AP_RXD=18
-D FLASHER_LED=14
-D FLASHER_DEBUG_TXD=19
-D FLASHER_DEBUG_RXD=20
-D FLASHER_LED=16
-D HAS_RGB_LED
-D FLASHER_RGB_LED=48
-D ST7789_DRIVER
-D TFT_WIDTH=170
-D TFT_WIDTH=172
-D TFT_HEIGHT=320
-D TFT_MISO=-1
-D TFT_MOSI=13

View File

@@ -1,7 +1,5 @@
#ifdef YELLOW_IPS_AP
#include <Arduino.h>
#include <FS.h>
#include <TFT_eSPI.h>
#include <WiFi.h>
#include "commstructs.h"
@@ -9,11 +7,45 @@
#include "storage.h"
#include "tag_db.h"
#ifdef YELLOW_IPS_AP
#include "ips_display.h"
#define YELLOW_SENSE 8 // sense AP hardware
#define TFT_BACKLIGHT 14
TFT_eSPI tft2 = TFT_eSPI();
bool first_run = 0;
time_t last_update = 0;
time_t last_checkin = 0;
int32_t tftid = -1;
uint8_t YellowSense = 0;
bool tftLogscreen = true;
void TFTLog(String text) {
if (tftLogscreen == false) {
tft2.fillScreen(TFT_BLACK);
tft2.setCursor(0, 5, 2);
tftLogscreen = true;
}
if (text.isEmpty()) return;
tft2.setTextColor(TFT_SILVER);
if (text.startsWith("!")) {
tft2.setTextColor(TFT_RED);
text = text.substring(1);
} else if (text.indexOf("http") != -1) {
int httpIndex = text.indexOf("http");
tft2.print(text.substring(0, httpIndex));
tft2.setTextColor(TFT_YELLOW);
text = text.substring(httpIndex);
} else if (text.indexOf(":") != -1) {
int colonIndex = text.indexOf(":");
tft2.setTextColor(TFT_SILVER);
tft2.print(text.substring(0, colonIndex + 1));
tft2.setTextColor(TFT_WHITE);
text = text.substring(colonIndex + 1);
} else if (text.endsWith("!")) {
tft2.setTextColor(TFT_GREEN);
}
tft2.println(text);
}
int32_t findId(uint8_t mac[8]) {
for (uint32_t c = 0; c < tagDB.size(); c++) {
@@ -42,28 +74,43 @@ void sendAvail(uint8_t wakeupReason) {
}
void yellow_ap_display_init(void) {
pinMode(YELLOW_SENSE, INPUT_PULLDOWN);
vTaskDelay(100 / portTICK_PERIOD_MS);
if (digitalRead(YELLOW_SENSE) == HIGH) YellowSense = 1;
pinMode(TFT_BACKLIGHT, OUTPUT);
digitalWrite(TFT_BACKLIGHT, HIGH);
ledcSetup(6, 5000, 8);
ledcAttachPin(TFT_BACKLIGHT, 6);
ledcWrite(6, 255); // config.led
tft2.init();
tft2.setRotation(3);
tft2.setRotation(YellowSense == 1 ? 1 : 3);
tft2.fillScreen(TFT_BLACK);
tft2.setCursor(0, 0, 2);
tft2.setCursor(10, 5, 2);
tft2.setTextColor(TFT_WHITE);
tft2.println(" Init\n");
tft2.println("*** Initialising... ***");
tftLogscreen = true;
}
void yellow_ap_display_loop(void) {
static bool first_run = 0;
static time_t last_checkin = 0;
static time_t last_update = 0;
if (millis() - last_checkin >= 60000) {
sendAvail(0);
last_checkin = millis();
tftLogscreen = false;
}
if (first_run == 0) {
sendAvail(0xFC);
first_run = 1;
}
if (millis() - last_update >= 1000) {
if (first_run == 0) {
sendAvail(0xFC);
first_run = 1;
}
// if ((uint32_t)WiFi.localIP() == (uint32_t)0) {}
tagRecord* tag = tagDB.at(tftid);
if (tag->pending) {
String filename = tag->filename;
@@ -82,6 +129,7 @@ void yellow_ap_display_loop(void) {
size_t bytesRead = file.readBytes((char*)spriteData, spr.width() * spr.height() * 2);
file.close();
spr.pushSprite(0, 0);
tftLogscreen = false;
struct espXferComplete xfc = {0};
memcpy(xfc.src, tag->mac, 8);

View File

@@ -149,6 +149,9 @@ void rgbIdleStep() {
void setBrightness(int brightness) {
maxledbrightness = brightness;
#ifdef YELLOW_IPS_AP
// ledcWrite(6, config.led);
#endif
#ifdef HAS_RGB_LED
FastLED.setBrightness(maxledbrightness);
#endif
@@ -180,10 +183,10 @@ void addFadeMono(uint8_t value) {
}
void showMono(uint8_t brightness) {
#ifdef CONFIG_IDF_TARGET_ESP32S2
ledcWrite(7, gamma8[brightness]);
#else
#ifdef CONFIG_IDF_TARGET_ESP32
ledcWrite(7, 255 - gamma8[brightness]);
#else
ledcWrite(7, gamma8[brightness]);
#endif
}

View File

@@ -209,8 +209,9 @@ void spr2buffer(TFT_eSprite &spr, String &fileout, imgParam &imageParams) {
Storage.begin();
#ifdef YELLOW_IPS_AP
extern uint8_t YellowSense;
if (fileout == "direct") {
tft.setRotation(3);
tft.setRotation(YellowSense == 1 ? 1 : 3);
spr.pushSprite(0, 0);
return;
}

View File

@@ -600,12 +600,16 @@ bool showAPSegmentedInfo(const uint8_t* dst, bool local) {
}
}
bool sendTagCommand(const uint8_t* dst, uint8_t cmd, bool local) {
bool sendTagCommand(const uint8_t* dst, uint8_t cmd, bool local, const uint8_t* payload) {
struct pendingData pending = {0};
memcpy(pending.targetMac, dst, 8);
pending.availdatainfo.dataType = DATATYPE_COMMAND_DATA;
pending.availdatainfo.dataTypeArgument = cmd;
pending.availdatainfo.nextCheckIn = 0;
if (payload != nullptr) {
memcpy(&pending.availdatainfo.dataVer, payload, sizeof(uint64_t));
memcpy(&pending.availdatainfo.dataSize, payload + sizeof(uint64_t), sizeof(uint32_t));
}
pending.attemptsLeft = 120;
Serial.printf(">Tag CMD %02X%02X%02X%02X%02X%02X%02X%02X\n\0", dst[7], dst[6], dst[5], dst[4], dst[3], dst[2], dst[1], dst[0]);
if (local) {

View File

@@ -88,7 +88,7 @@ void txEnd() {
}
bool waitCmdReply() {
uint32_t val = millis();
while (millis() < val + 100) {
while (millis() < val + 200) {
switch (cmdReplyValue) {
case CMD_REPLY_WAIT:
break;
@@ -135,6 +135,7 @@ void APEnterEarlyReset() {
// Reset the tag
void APTagReset() {
Serial.println("Resetting tag");
uint8_t powerPins = sizeof(APpowerPins);
if (powerPins > 0 && APpowerPins[0] == -1)
powerPins = 0;
@@ -193,7 +194,7 @@ blksend:
for (c = 0; c < 32; c++) {
AP_SERIAL_PORT.write(0xF5);
}
delay(10);
if (apInfo.type != ESP32_C6) delay(10);
txEnd();
return bd->checksum;
}
@@ -250,6 +251,8 @@ bool sendChannelPower(struct espSetChannelPower* scp) {
}
if (waitCmdReply()) {
txEnd();
apInfo.channel = scp->channel;
apInfo.power = scp->power;
return true;
}
Serial.printf("SCP send failed in try %d\n", attempt);
@@ -259,10 +262,27 @@ bool sendChannelPower(struct espSetChannelPower* scp) {
return false;
}
bool sendPing() {
Serial.print("ping");
int t = millis();
if (!txStart()) return false;
for (uint8_t attempt = 0; attempt < 5; attempt++) {
cmdReplyValue = CMD_REPLY_WAIT;
AP_SERIAL_PORT.print("RDY?");
if (waitCmdReply()) {
txEnd();
Serial.printf(" ok, %dms\n", millis() - t);
return true;
}
}
txEnd();
Serial.println(" failed");
return false;
}
bool sendGetInfo() {
if (!txStart()) return false;
for (uint8_t attempt = 0; attempt < 5; attempt++) {
cmdReplyValue = CMD_REPLY_WAIT;
AP_SERIAL_PORT.print("NFO?");
if (waitCmdReply()) {
txEnd();
return true;
@@ -271,11 +291,11 @@ bool sendPing() {
txEnd();
return false;
}
bool sendGetInfo() {
bool sendHighspeed() {
if (!txStart()) return false;
for (uint8_t attempt = 0; attempt < 5; attempt++) {
cmdReplyValue = CMD_REPLY_WAIT;
AP_SERIAL_PORT.print("NFO?");
AP_SERIAL_PORT.print("HSPD");
if (waitCmdReply()) {
txEnd();
return true;
@@ -312,17 +332,15 @@ void rxCmdProcessor(void* parameter) {
processBlockRequest((struct espBlockRequest*)rxcmd->data);
#ifdef HAS_RGB_LED
shortBlink(CRGB::Blue);
#else
quickBlink(3);
#endif
quickBlink(3);
break;
case RX_CMD_ADR:
processDataReq((struct espAvailDataReq*)rxcmd->data, true);
#ifdef HAS_RGB_LED
shortBlink(CRGB::Aqua);
#else
quickBlink(1);
#endif
quickBlink(1);
break;
case RX_CMD_XFC:
processXferComplete((struct espXferComplete*)rxcmd->data, true);
@@ -336,6 +354,7 @@ void rxCmdProcessor(void* parameter) {
case RX_CMD_RSET:
Serial.println("AP did reset, resending pending\n");
refreshAllPending();
sendChannelPower(&curChannel);
break;
}
if (rxcmd->data) free(rxcmd->data);
@@ -357,7 +376,7 @@ void rxSerialTask(void* parameter) {
lastchar = AP_SERIAL_PORT.read();
switch (RXState) {
case ZBS_RX_WAIT_HEADER:
// Serial.write(lastchar);
Serial.write(lastchar);
// shift characters in
for (uint8_t c = 0; c < 3; c++) {
cmdbuffer[c] = cmdbuffer[c + 1];
@@ -413,6 +432,7 @@ void rxSerialTask(void* parameter) {
pktindex = 0;
packetp = (uint8_t*)calloc(sizeof(struct espBlockRequest) + 8, 1);
memset(cmdbuffer, 0x00, 4);
lastAPActivity = millis();
}
if (strncmp(cmdbuffer, "ADR>", 4) == 0) {
RXState = ZBS_RX_WAIT_DATA_REQ;
@@ -420,6 +440,7 @@ void rxSerialTask(void* parameter) {
pktindex = 0;
packetp = (uint8_t*)calloc(sizeof(struct espAvailDataReq) + 8, 1);
memset(cmdbuffer, 0x00, 4);
lastAPActivity = millis();
}
if (strncmp(cmdbuffer, "XFC>", 4) == 0) {
RXState = ZBS_RX_WAIT_XFERCOMPLETE;
@@ -536,21 +557,26 @@ void rxSerialTask(void* parameter) {
} // end of while(1)
}
#ifdef FLASHER_DEBUG_RXD
void rxSerialTask2(void* parameter) {
char lastchar = 0;
Serial2.begin(115200, SERIAL_8N1, FLASHER_DEBUG_TXD, FLASHER_DEBUG_RXD);
while (1) {
while (Serial2.available()) {
lastchar = Serial2.read();
Serial.write(lastchar);
}
vTaskDelay(1 / portTICK_PERIOD_MS);
}
}
#endif
void ShowAPInfo() {
Serial.printf("| AP Info - type %02X |\n", apInfo.type);
Serial.printf("\n| AP Info - type %02X |\n", apInfo.type);
Serial.printf("| Ch | 0x%02X |\n", apInfo.channel);
Serial.printf("| Power| %02X |\n", apInfo.power);
Serial.printf("| MAC | %02X%02X%02X%02X%02X%02X%02X%02X |\n", apInfo.mac[7], apInfo.mac[6], apInfo.mac[5], apInfo.mac[4], apInfo.mac[3], apInfo.mac[2], apInfo.mac[1], apInfo.mac[0]);
Serial.printf("| Ver | 0x%04X |\n", apInfo.version);
/*if (apInfo.type == SOLUM_154_SSD1619 || apInfo.type == SOLUM_29_SSD1619 || apInfo.type == SOLUM_29_UC8151 || apInfo.type == 0xE0) {
tagRecord* taginfo = nullptr;
taginfo = tagRecord::findByMAC(apInfo.mac);
if (taginfo != nullptr) {
taginfo->contentMode = 21;
taginfo->nextupdate = 0;
}
}*/
}
void notifySegmentedFlash() {
@@ -595,14 +621,24 @@ void segmentedShowIp() {
bool bringAPOnline() {
apInfo.isOnline = false;
apInfo.state = AP_STATE_OFFLINE;
APTagReset();
vTaskDelay(500 / portTICK_PERIOD_MS);
// try without rebooting
AP_SERIAL_PORT.updateBaudRate(115200);
uint32_t bootTimeout = millis();
bool APrdy = false;
while ((!APrdy) && (millis() - bootTimeout < 10 * 1000)) {
while ((!APrdy) && (millis() - bootTimeout < 3 * 1000)) {
APrdy = sendPing();
vTaskDelay(300 / portTICK_PERIOD_MS);
}
if (!APrdy) {
APTagReset();
vTaskDelay(500 / portTICK_PERIOD_MS);
bootTimeout = millis();
APrdy = false;
while ((!APrdy) && (millis() - bootTimeout < 10 * 1000)) {
APrdy = sendPing();
vTaskDelay(300 / portTICK_PERIOD_MS);
}
}
if (!APrdy) {
return false;
} else {
@@ -613,6 +649,15 @@ bool bringAPOnline() {
apInfo.state = AP_STATE_OFFLINE;
return false;
}
if (apInfo.type == ESP32_C6) {
if (sendHighspeed()) {
AP_SERIAL_PORT.flush();
vTaskDelay(10 / portTICK_PERIOD_MS);
AP_SERIAL_PORT.updateBaudRate(2000000);
Serial.println("switched to 2000000 baud");
}
}
vTaskDelay(200 / portTICK_PERIOD_MS);
apInfo.isOnline = true;
apInfo.state = AP_STATE_ONLINE;
@@ -623,6 +668,9 @@ bool bringAPOnline() {
void APTask(void* parameter) {
xTaskCreate(rxCmdProcessor, "rxCmdProcessor", 4000, NULL, configMAX_PRIORITIES - 10, NULL);
xTaskCreate(rxSerialTask, "rxSerialTask", 1750, NULL, configMAX_PRIORITIES - 4, NULL);
#ifdef FLASHER_DEBUG_RXD
xTaskCreate(rxSerialTask2, "rxSerialTask2", 1750, NULL, configMAX_PRIORITIES - 4, NULL);
#endif
#if (AP_PROCESS_PORT == FLASHER_AP_PORT)
AP_SERIAL_PORT.begin(115200, SERIAL_8N1, FLASHER_AP_RXD, FLASHER_AP_TXD);
@@ -638,7 +686,7 @@ void APTask(void* parameter) {
bringAPOnline();
if (checkForcedAPFlash()) {
if (checkForcedAPFlash() && FLASHER_AP_MOSI != -1) {
if (apInfo.type == SOLUM_SEG_UK && apInfo.isOnline) {
notifySegmentedFlash();
}
@@ -666,7 +714,7 @@ void APTask(void* parameter) {
uint16_t fsversion;
fsversion = getAPUpdateVersion(apInfo.type);
if ((fsversion) && (apInfo.version != fsversion)) {
if ((fsversion) && (apInfo.version != fsversion) && (FLASHER_AP_MOSI != -1)) {
Serial.printf("Firmware version on LittleFS: %04X\n", fsversion);
Serial.printf("We're going to try to update the AP's FW in\n");
@@ -708,72 +756,74 @@ void APTask(void* parameter) {
// AP unavailable, maybe time to flash?
apInfo.isOnline = false;
apInfo.state = AP_STATE_OFFLINE;
Serial.println("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. We'll try to flash it!\n");
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");
Serial.printf("If this tag was previously flashed succesfully but this message still shows up, there's probably something wrong with the serial connections.\n");
Serial.printf("The build of this firmware expects an AP tag with TXD/RXD on ESP32 pins %d and %d, does this match with your wiring?\n", FLASHER_AP_RXD, FLASHER_AP_TXD);
Serial.printf("Performing firmware flash in about %d seconds!\n", FLASH_TIMEOUT);
flashCountDown(FLASH_TIMEOUT);
if (doAPFlash()) {
checkWaitPowerCycle();
if (bringAPOnline()) {
// AP works
ShowAPInfo();
if (apInfo.type == SOLUM_SEG_UK) {
segmentedShowIp();
showAPSegmentedInfo(apInfo.mac, true);
}
refreshAllPending();
} else {
Serial.printf("Failed to bring up the AP after successful flashing... That's not supposed to happen!\n");
Serial.printf("This generally means that the flasher connections (MISO/MOSI/CLK/RESET/CS) are okay,\n");
Serial.printf("but we can't (yet) talk to the AP over serial lines. Verify the pins mentioned above.\n\n");
if (FLASHER_AP_MOSI != -1) {
Serial.printf("Performing firmware flash in about %d seconds!\n", FLASH_TIMEOUT);
flashCountDown(FLASH_TIMEOUT);
if (doAPFlash()) {
checkWaitPowerCycle();
if (bringAPOnline()) {
// AP works
ShowAPInfo();
if (apInfo.type == SOLUM_SEG_UK) {
segmentedShowIp();
showAPSegmentedInfo(apInfo.mac, true);
}
refreshAllPending();
} else {
Serial.printf("Failed to bring up the AP after successful flashing... That's not supposed to happen!\n");
Serial.printf("This generally means that the flasher connections (MISO/MOSI/CLK/RESET/CS) are okay,\n");
Serial.printf("but we can't (yet) talk to the AP over serial lines. Verify the pins mentioned above.\n\n");
#ifndef POWER_NO_SOFT_POWER
Serial.printf("The firmware you're using expects soft power control over the AP tag; if it can't\n");
Serial.printf("power-cycle the AP-tag using GPIO pin %d, this can cause this very same issue.\n", APpowerPins[0]);
Serial.printf("The firmware you're using expects soft power control over the AP tag; if it can't\n");
Serial.printf("power-cycle the AP-tag using GPIO pin %d, this can cause this very same issue.\n", APpowerPins[0]);
#endif
#ifdef HAS_RGB_LED
showColorPattern(CRGB::Red, CRGB::Yellow, CRGB::Red);
showColorPattern(CRGB::Red, CRGB::Yellow, CRGB::Red);
#endif
apInfo.isOnline = false;
apInfo.state = 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;
}
} else {
// failed to flash
#ifdef HAS_RGB_LED
showColorPattern(CRGB::Red, CRGB::Red, CRGB::Red);
#endif
apInfo.isOnline = false;
apInfo.state = 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:");
Serial.println("--- ZBS243 based tag ESP32 ---");
Serial.printf(" TXD ---------------- %02d\n", FLASHER_AP_RXD);
Serial.printf(" RXD ---------------- %02d\n", FLASHER_AP_TXD);
Serial.printf(" CS/SS ---------------- %02d\n", FLASHER_AP_SS);
Serial.printf(" MOSI ---------------- %02d\n", FLASHER_AP_MOSI);
Serial.printf(" MISO ---------------- %02d\n", FLASHER_AP_MISO);
Serial.printf(" CLK ---------------- %02d\n", FLASHER_AP_CLK);
Serial.printf(" RSET ---------------- %02d\n", FLASHER_AP_RESET);
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:");
Serial.println("--- ZBS243 based tag ESP32 ---");
Serial.printf(" TXD ---------------- %02d\n", FLASHER_AP_RXD);
Serial.printf(" RXD ---------------- %02d\n", FLASHER_AP_TXD);
Serial.printf(" CS/SS ---------------- %02d\n", FLASHER_AP_SS);
Serial.printf(" MOSI ---------------- %02d\n", FLASHER_AP_MOSI);
Serial.printf(" MISO ---------------- %02d\n", FLASHER_AP_MISO);
Serial.printf(" CLK ---------------- %02d\n", FLASHER_AP_CLK);
Serial.printf(" RSET ---------------- %02d\n", FLASHER_AP_RESET);
#ifdef POWER_NO_SOFT_POWER
Serial.printf("Your firmware is configured without soft power control. This means you'll have to manually power-cycle the tag after flashing.\n");
Serial.printf("Your firmware is configured without soft power control. This means you'll have to manually power-cycle the tag after flashing.\n");
#else
Serial.printf(" POWER ---------------- %02d\n", APpowerPins[0]);
Serial.printf(" POWER ---------------- %02d\n", APpowerPins[0]);
#endif
Serial.println("Please verify your wiring and try again!");
}
Serial.println("Please verify your wiring and try again!");
}
#ifdef HAS_SDCARD
if (SD_CARD_CLK == FLASHER_AP_CLK ||
SD_CARD_MISO == FLASHER_AP_MISO ||
SD_CARD_MOSI == FLASHER_AP_MOSI) {
Serial.println("Reseting in 30 seconds to restore SPI state!\n");
flashCountDown(30);
ESP.restart();
}
if (SD_CARD_CLK == FLASHER_AP_CLK ||
SD_CARD_MISO == FLASHER_AP_MISO ||
SD_CARD_MOSI == FLASHER_AP_MOSI) {
Serial.println("Reseting in 30 seconds to restore SPI state!\n");
flashCountDown(30);
ESP.restart();
}
#endif
}
}
uint8_t attempts = 0;

View File

@@ -77,14 +77,16 @@ void wsSendSysteminfo() {
time_t now;
time(&now);
static int freeSpaceLastRun = 0;
static size_t freeSpace = Storage.freeSpace();
sys["currtime"] = now;
sys["heap"] = ESP.getFreeHeap();
sys["recordcount"] = tagDB.size();
sys["dbsize"] = dbSize();
if (millis() - freeSpaceLastRun > 30000) {
sys["littlefsfree"] = Storage.freeSpace();
freeSpace = Storage.freeSpace();
freeSpaceLastRun = millis();
}
sys["littlefsfree"] = freeSpace;
sys["apstate"] = apInfo.state;
sys["runstate"] = config.runStatus;
#if !defined(CONFIG_IDF_TARGET_ESP32)
@@ -98,7 +100,7 @@ void wsSendSysteminfo() {
setVarDB("ap_ch", String(apInfo.channel));
static uint32_t tagcounttimer = 0;
if (millis() - tagcounttimer > 60000) {
if (millis() - tagcounttimer > 60000 || tagcounttimer == 0) {
uint32_t timeoutcount = 0;
uint32_t tagcount = getTagCount(timeoutcount);
char result[40];
@@ -318,9 +320,11 @@ void init_web() {
if (strcmp(cmdValue, "deepsleep") == 0) {
sendTagCommand(mac, CMD_DO_DEEPSLEEP, !taginfo->isExternal);
}
if (strcmp(cmdValue, "ledflash") == 0) {
}
request->send(200, "text/plain", "Ok, done");
} else {
request->send(200, "text/plain", "Error: mac not found");
request->send(400, "text/plain", "Error: mac not found");
}
}
} else {
@@ -328,6 +332,55 @@ void init_web() {
}
});
server.on("/led_flash", HTTP_GET, [](AsyncWebServerRequest *request) {
// color picker: https://roger-random.github.io/RGB332_color_wheel_three.js/
// http GET to /led_flash?mac=000000000000&pattern=3/0x1C,4,5/0xE0,3,1/0x4F,5,10/5
// (flashDuration/color1,flashCount1,delay1/color2,flashCount2,delay2/color3,flashCount3,delay3/repeats)
if (request->hasParam("mac")) {
String dst = request->getParam("mac")->value();
uint8_t mac[8];
if (hex2mac(dst, mac)) {
tagRecord *taginfo = tagRecord::findByMAC(mac);
if (taginfo != nullptr) {
if (request->hasParam("pattern")) {
String pattern = request->getParam("pattern")->value();
struct ledFlash flashData;
int values[13];
int numValues = sscanf(
pattern.c_str(),
"%i/%i,%i,%i/%i,%i,%i/%i,%i,%i/%i",
&values[1], &values[2], &values[3], &values[4], &values[5],
&values[6], &values[7], &values[8], &values[9], &values[10], &values[11]);
if (numValues != 11) {
request->send(400, "text/plain", "Error: wrong number of inputs in pattern");
return;
} else {
flashData.mode = 0;
flashData.flashDuration = values[1] & 0x0F;
flashData.color1 = values[2];
flashData.flashCount1 = values[3] & 0x0F;
flashData.delay1 = values[4] & 0x0F;
flashData.color2 = values[5];
flashData.flashCount2 = values[6] & 0x0F;
flashData.delay2 = values[7] & 0x0F;
flashData.color3 = values[8];
flashData.flashCount3 = values[9] & 0x0F;
flashData.delay3 = values[10] & 0x0F;
flashData.repeats = values[11];
flashData.spare = 0;
const uint8_t *payload = reinterpret_cast<const uint8_t *>(&flashData);
sendTagCommand(mac, CMD_DO_LEDFLASH, !taginfo->isExternal, payload);
}
}
}
}
}
request->send(400, "text/plain", "parameters are missing");
});
server.on("/get_ap_config", HTTP_GET, [](AsyncWebServerRequest *request) {
UDPcomm udpsync;
udpsync.getAPList();

View File

@@ -9,6 +9,7 @@
#include "tag_db.h"
#include "udp.h"
#include "web.h"
#include "ips_display.h"
uint8_t WifiManager::apClients = 0;
uint8_t x_buffer[100];
@@ -29,10 +30,17 @@ WifiManager::WifiManager() {
WiFi.onEvent(WiFiEvent);
}
void WifiManager::terminalLog(String text) {
Serial.println(text);
#ifdef YELLOW_IPS_AP
TFTLog(text);
#endif
}
void WifiManager::poll() {
if (wifiStatus == AP && millis() > _nextReconnectCheck && _ssid != "") {
if (apClients == 0) {
Serial.println("Attempting to reconnect to WiFi.");
terminalLog("Attempting to reconnect to WiFi.");
logLine("Attempting to reconnect to WiFi.");
_APstarted = false;
wifiStatus = NOINIT;
@@ -45,7 +53,7 @@ void WifiManager::poll() {
if (wifiStatus == CONNECTED && millis() > _nextReconnectCheck) {
if (WiFi.status() != WL_CONNECTED) {
_connected = false;
Serial.println("WiFi connection lost. Attempting to reconnect.");
terminalLog("WiFi connection lost. Attempting to reconnect.");
logLine("WiFi connection lost. Attempting to reconnect.");
WiFi.reconnect();
waitForConnection();
@@ -63,12 +71,12 @@ bool WifiManager::connectToWifi() {
_ssid = preferences.getString("ssid", WiFi_SSID());
_pass = preferences.getString("pw", WiFi_psk());
if (_ssid == "") {
Serial.println("No connection information specified");
logLine("No connection information specified");
terminalLog("No connection information saved");
logLine("No connection information saved");
startManagementServer();
return false;
}
Serial.println("Stored ssid: " + String(_ssid));
terminalLog("Stored ssid: " + String(_ssid));
String ip = preferences.getString("ip", "");
String mask = preferences.getString("mask", "");
@@ -80,7 +88,7 @@ bool WifiManager::connectToWifi() {
if (staticIP.fromString(ip) && subnetMask.fromString(mask) && gatewayIP.fromString(gw)) {
if (dns.length() > 0) dnsIP.fromString(dns);
WiFi.config(staticIP, gatewayIP, subnetMask, dnsIP);
Serial.println("Setting static IP");
terminalLog("Setting static IP: " + ip);
}
}
@@ -98,7 +106,7 @@ bool WifiManager::connectToWifi(String ssid, String pass, bool savewhensuccessfu
WiFi.mode(WIFI_STA);
WiFi.setSleep(WIFI_PS_NONE);
Serial.println("Connecting to WiFi...");
terminalLog("Connecting to WiFi...");
logLine("Connecting to WiFi...");
WiFi.persistent(savewhensuccessfull);
WiFi.begin(_ssid.c_str(), _pass.c_str());
@@ -112,7 +120,7 @@ bool WifiManager::waitForConnection() {
while (WiFi.status() != WL_CONNECTED) {
if (millis() > timeout) {
Serial.println("Unable to connect to WiFi");
terminalLog("!Unable to connect to WiFi");
logLine("Unable to connect to WiFi");
startManagementServer();
return false;
@@ -131,8 +139,8 @@ bool WifiManager::waitForConnection() {
WiFi.setAutoReconnect(true);
WiFi.persistent(true);
IPAddress IP = WiFi.localIP();
Serial.printf("Connected! IP Address: %s\n", IP.toString().c_str());
logLine("Connected! IP Address: " + String(IP.toString().c_str()));
terminalLog("Connected!");
logLine("Connected!");
_nextReconnectCheck = millis() + _reconnectIntervalCheck;
wifiStatus = CONNECTED;
return true;
@@ -140,13 +148,13 @@ bool WifiManager::waitForConnection() {
void WifiManager::startManagementServer() {
if (!_APstarted) {
Serial.println("Starting configuration AP, ssid OpenEPaperLink");
terminalLog("Starting configuration AP, ssid: OpenEPaperLink");
logLine("Starting configuration AP, ssid OpenEPaperLink");
WiFi.mode(WIFI_AP);
WiFi.softAP("OpenEPaperLink", "", 1, false);
WiFi.softAPsetHostname("OpenEPaperLink");
IPAddress IP = WiFi.softAPIP();
Serial.printf("IP Address: %s\n", IP.toString().c_str());
terminalLog("Connect to it, visit http://" + String(IP.toString().c_str()) + "/setup");
_APstarted = true;
_nextReconnectCheck = millis() + _retryIntervalCheck;
wifiStatus = AP;
@@ -194,7 +202,7 @@ void WifiManager::WiFiEvent(WiFiEvent_t event) {
eventname = "Connected to access point";
break;
case ARDUINO_EVENT_WIFI_STA_DISCONNECTED:
eventname = "Disconnected from WiFi access point";
// eventname = "Disconnected from WiFi access point";
break;
case ARDUINO_EVENT_WIFI_STA_AUTHMODE_CHANGE:
eventname = "Authentication mode of access point has changed";
@@ -208,27 +216,27 @@ void WifiManager::WiFiEvent(WiFiEvent_t event) {
break;
case ARDUINO_EVENT_WIFI_AP_START:
eventname = "WiFi access point started";
// eventname = "WiFi access point started";
break;
case ARDUINO_EVENT_WIFI_AP_STOP:
eventname = "WiFi access point stopped";
// eventname = "WiFi access point stopped";
break;
case ARDUINO_EVENT_WIFI_AP_STACONNECTED:
apClients++;
eventname = "Client connected";
// eventname = "Client connected";
break;
case ARDUINO_EVENT_WIFI_AP_STADISCONNECTED:
apClients--;
eventname = "Client disconnected";
// eventname = "Client disconnected";
break;
case ARDUINO_EVENT_WIFI_AP_STAIPASSIGNED:
eventname = "Assigned IP address to client";
// eventname = "Assigned IP address to client";
break;
default:
break;
}
Serial.println(eventname);
terminalLog(eventname);
logLine("WiFi event [" + String(event) + "]: " + eventname);
}

View File

@@ -195,6 +195,8 @@
}
</style>
<script>
const $ = document.querySelector.bind(document);
if (typeof XMLHttpRequest === "undefined") {
XMLHttpRequest = function () {
try { return new ActiveXObject("Msxml2.XMLHTTP.6.0"); } catch (e) { }
@@ -403,8 +405,81 @@
edfname.value = filename + "." + ext;
ge("editor").style.display = "none";
preview.style.display = "block";
preview.innerHTML = '<img src="/edit?edit=' + path + '&_cb=' + Date.now() + '" style="max-width:100%; max-height:100%; margin:auto; display:block;" />';
if (ext == "raw" || ext == "pending") {
let storedTagTypes = localStorage.getItem("tagTypes");
let tagTypes = JSON.parse(storedTagTypes);
let mac = name.substring(name.lastIndexOf('/') + 1);
let targetDiv = null;
if (window.opener && !window.opener.closed) {
targetDiv = window.opener.document.querySelector(`div[data-mac="${mac}"]`);
} else {
preview.innerHTML = `<p class=\"tvu\">I cannot reach the window with the tag overview. Close this window, and open it again from the tag overview.</p>`;
return;
}
if (targetDiv) {
preview.innerHTML = `<p class=\"tvu\">Preview image for tag ${mac}<p><p><canvas id=\"previewimg\"></p>`;
var hwtype = targetDiv.getAttribute("data-hwtype");
console.log("data-hwtype:", hwtype);
const canvas = $('#previewimg');
canvas.style.display = 'block';
fetch(path)
.then(response => response.arrayBuffer())
.then(buffer => {
[canvas.width, canvas.height] = [tagTypes[hwtype].width, tagTypes[hwtype].height] || [0, 0];
if (tagTypes[hwtype].rotatebuffer) [canvas.width, canvas.height] = [canvas.height, canvas.width];
const ctx = canvas.getContext('2d');
const imageData = ctx.createImageData(canvas.width, canvas.height);
const data = new Uint8ClampedArray(buffer);
if (data.length == 0) canvas.style.display = 'none';
if (tagTypes[hwtype].bpp == 16) {
const is16Bit = data.length == tagTypes[hwtype].width * tagTypes[hwtype].height * 2;
for (let i = 0; i < min(tagTypes[hwtype].width * tagTypes[hwtype].height, data.length); i++) {
const dataIndex = is16Bit ? i * 2 : i;
const rgb = is16Bit ? (data[dataIndex] << 8) | data[dataIndex + 1] : data[dataIndex];
imageData.data[i * 4] = is16Bit ? ((rgb >> 11) & 0x1F) << 3 : (((rgb >> 5) & 0x07) << 5) * 1.13;
imageData.data[i * 4 + 1] = is16Bit ? ((rgb >> 5) & 0x3F) << 2 : (((rgb >> 2) & 0x07) << 5) * 1.13;
imageData.data[i * 4 + 2] = is16Bit ? (rgb & 0x1F) << 3 : ((rgb & 0x03) << 6) * 1.3;
imageData.data[i * 4 + 3] = 255;
}
} else {
const offsetRed = (data.length >= (canvas.width * canvas.height / 8) * 2) ? canvas.width * canvas.height / 8 : 0;
let pixelValue = 0;
const colorTable = tagTypes[hwtype].colortable;
for (let i = 0; i < data.length; i++) {
for (let j = 0; j < 8; j++) {
const pixelIndex = i * 8 + j;
if (offsetRed) {
pixelValue = ((data[i] & (1 << (7 - j))) ? 1 : 0) | (((data[i + offsetRed] & (1 << (7 - j))) ? 1 : 0) << 1);
} else {
pixelValue = ((data[i] & (1 << (7 - j))) ? 1 : 0);
}
imageData.data[pixelIndex * 4] = colorTable[pixelValue][0];
imageData.data[pixelIndex * 4 + 1] = colorTable[pixelValue][1];
imageData.data[pixelIndex * 4 + 2] = colorTable[pixelValue][2];
imageData.data[pixelIndex * 4 + 3] = 255;
}
}
}
ctx.putImageData(imageData, 0, 0);
})
.catch(error => {
console.log(error);
});
} else {
preview.innerHTML = `<p class=\"tvu\">No current tag found with this mac. You can safely delete this file.</p>`;
}
} else {
preview.innerHTML = '<img src="/edit?edit=' + path + '&_cb=' + Date.now() + '" style="max-width:100%; max-height:100%; margin:auto; display:block;" />';
}
}
function fillFileMenu(el, path) {
@@ -596,6 +671,7 @@
case "gif":
case "bmp":
case "pending":
case "raw":
return true;
}
}

View File

@@ -82,6 +82,7 @@
<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>

View File

@@ -4,6 +4,8 @@ const WAKEUP_REASON_TIMED = 0;
const WAKEUP_REASON_BOOT = 1;
const WAKEUP_REASON_GPIO = 2;
const WAKEUP_REASON_NFC = 3;
const WAKEUP_REASON_BUTTON1 = 4;
const WAKEUP_REASON_BUTTON2 = 5;
const WAKEUP_REASON_FIRSTBOOT = 0xFC;
const WAKEUP_REASON_NETWORK_SCAN = 0xFD;
const WAKEUP_REASON_WDT_RESET = 0xFE;
@@ -250,6 +252,14 @@ function processTags(tagArray) {
$('#tag' + tagmac + ' .nextcheckin').innerHTML = "GPIO wakeup"
$('#tag' + tagmac).style.background = "#c8f1bb";
break;
case WAKEUP_REASON_BUTTON1:
$('#tag' + tagmac + ' .nextcheckin').innerHTML = "Button 1 pressed"
$('#tag' + tagmac).style.background = "#c8f1bb";
break;
case WAKEUP_REASON_BUTTON2:
$('#tag' + tagmac + ' .nextcheckin').innerHTML = "Button 2 pressed"
$('#tag' + tagmac).style.background = "#c8f1bb";
break;
case WAKEUP_REASON_NFC:
$('#tag' + tagmac + ' .nextcheckin').innerHTML = "NFC wakeup"
break;
@@ -933,6 +943,7 @@ async function getTagtype(hwtype) {
busy: false
};
tagTypes[hwtype] = data;
localStorage.setItem("tagTypes", JSON.stringify(tagTypes));
getTagtypeBusy = false;
return data;
@@ -1063,7 +1074,6 @@ function dropUpload() {
const contextMenu = $('#context-menu');
$('#taglist').addEventListener('contextmenu', (e) => {
console.log("contextmenu");
e.preventDefault();
const clickedGridItem = e.target.closest('.tagcard');
@@ -1095,7 +1105,10 @@ $('#taglist').addEventListener('contextmenu', (e) => {
});
contextMenu.appendChild(li);
});
const contextMenuPosition = { left: e.clientX, top: e.clientY };
const contextMenuPosition = {
left: e.clientX + window.scrollX,
top: e.clientY + window.scrollY
};
contextMenu.style.left = `${contextMenuPosition.left}px`;
contextMenu.style.top = `${contextMenuPosition.top}px`;
contextMenu.style.display = 'block';

25
Tag_Flasher/patch_mac.py Normal file
View File

@@ -0,0 +1,25 @@
import argparse
def patch_mac(file_path, mac):
try:
with open(file_path, "r+b") as file:
offset = 0x0148
mac_bytes = bytearray.fromhex(mac)
mac_bytes.reverse() # Reverse the byte order
file.seek(offset)
file.write(mac_bytes)
print(f"MAC address patched successfully.")
except FileNotFoundError:
print("Error: File not found.")
except Exception as e:
print(f"An error occurred: {e}")
if __name__ == "__main__":
parser = argparse.ArgumentParser(description="Patch MAC address in a binary firmware file for the 88MZ100 7.4 inch esl")
parser.add_argument("-mac", required=True, help="MAC address (without colons)")
parser.add_argument("filename", help="Binary file to patch")
args = parser.parse_args()
patch_mac(args.filename, args.mac)

View File

@@ -5,6 +5,7 @@
#define SOLUM_SEG_UK 0xF0
#define SOLUM_SEG_EU 0xF1
#define SOLUM_NODISPLAY 0xFF
#define ESP32_C6 0xC6
#define SOLUM_M2_BWR_16 0x20
#define SOLUM_M2_BWR_29 0x23
@@ -55,10 +56,13 @@
#define CMD_DO_SCAN 1
#define CMD_DO_RESET_SETTINGS 2
#define CMD_DO_DEEPSLEEP 3
#define CMD_DO_LEDFLASH 4
#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_FIRSTBOOT 0xFC
#define WAKEUP_REASON_NETWORK_SCAN 0xFD
#define WAKEUP_REASON_WDT_RESET 0xFE