diff --git a/ap_fw/apfw.bin b/ap_fw/apfw.bin
index 8c6b0502..59e55a7a 100644
Binary files a/ap_fw/apfw.bin and b/ap_fw/apfw.bin differ
diff --git a/ap_fw/main.c b/ap_fw/main.c
index a4c7ed4a..242e8d6d 100644
--- a/ap_fw/main.c
+++ b/ap_fw/main.c
@@ -138,7 +138,7 @@ struct espAvailDataReq {
} __packed;
#define TIMER_TICKS_PER_MS 1333UL
-uint16_t __xdata version = 0x0006;
+uint16_t __xdata version = 0x0007;
#define RAW_PKT_PADDING 2
static uint8_t __xdata mRxBuf[COMMS_MAX_PACKET_SZ];
@@ -245,7 +245,8 @@ uint8_t getBlockDataLength() {
// pendingdata slot stuff
int8_t findSlotForMac(const uint8_t *mac) {
for (uint8_t __xdata c = 0; c < MAX_PENDING_MACS; c++) {
- if (u64_isEq((uint64_t __xdata *)mac, (uint64_t __xdata *)&(pendingDataArr[c].targetMac))) { // this costs 1 sloc :(
+ //if (u64_isEq((uint64_t __xdata *)mac, (uint64_t __xdata *)&(pendingDataArr[c].targetMac))) { // this costs 1 sloc :(
+ if (memcmp(mac, ((uint8_t __xdata *)&(pendingDataArr[c].targetMac)), 8) == 0) {
if (pendingDataArr[c].attemptsLeft != 0) {
return c;
}
@@ -320,7 +321,9 @@ void processSerial(uint8_t lastchar) {
bytesRemain--;
if (bytesRemain == 0) {
if (checkCRC(serialbuffer, sizeof(struct pendingData))) {
- int8_t slot = findFreeSlot();
+ struct pendingData *pd = (struct pendingData *)serialbuffer;
+ int8_t slot = findSlotForMac(pd->targetMac);
+ if (slot == -1) slot = findFreeSlot();
if (slot != -1) {
xMemCopyShort(&(pendingDataArr[slot]), serialbuffer, sizeof(struct pendingData));
pr("ACK>\n");
@@ -396,7 +399,17 @@ void espNotifyXferComplete(const uint8_t *src) {
uartTx(((uint8_t *)exfc)[c]);
}
}
-void espNotifyTimeOut() {
+void espNotifyTimeOut(const uint8_t *src) {
+ struct espXferComplete exfc;
+ xMemCopy8(&exfc.src, src);
+ uartTx('X');
+ uartTx('T');
+ uartTx('O');
+ uartTx('>');
+ addCRC(&exfc, sizeof(exfc));
+ for (uint8_t c = 0; c < sizeof(exfc); c++) {
+ uartTx(((uint8_t *)exfc)[c]);
+ }
}
// process data from tag
@@ -738,7 +751,7 @@ void main(void) {
for (uint8_t __xdata c = 0; c < MAX_PENDING_MACS; c++) {
if (pendingDataArr[c].attemptsLeft == 1) {
- espNotifyTimeOut();
+ espNotifyTimeOut(pendingDataArr[c].targetMac);
pendingDataArr[c].attemptsLeft = 0;
} else if (pendingDataArr[c].attemptsLeft > 1) {
pendingDataArr[c].attemptsLeft--;
diff --git a/esp32_fw/data/www/main.js b/esp32_fw/data/www/main.js
index 27d3529f..504bd8cf 100644
--- a/esp32_fw/data/www/main.js
+++ b/esp32_fw/data/www/main.js
@@ -139,7 +139,7 @@ function updatecards() {
if (item.dataset.lastseen && item.dataset.lastseen > 1672531200) {
let idletime = (Date.now() / 1000) + servertimediff - item.dataset.lastseen;
$('#tag' + tagmac + ' .lastseen').innerHTML = "last seen"+displayTime(Math.floor(idletime))+" ago";
- if ((Date.now() / 1000) + servertimediff - 60 > item.dataset.nextcheckin) {
+ if ((Date.now() / 1000) + servertimediff - 300 > item.dataset.nextcheckin) {
$('#tag' + tagmac + ' .warningicon').style.display='inline-block';
$('#tag' + tagmac).classList.remove("tagpending")
$('#tag' + tagmac).style.background = '#ffffcc';
diff --git a/esp32_fw/include/newproto.h b/esp32_fw/include/newproto.h
index c41b3972..5d98df56 100644
--- a/esp32_fw/include/newproto.h
+++ b/esp32_fw/include/newproto.h
@@ -8,4 +8,5 @@ extern void prepareIdleReq(uint8_t* dst, uint16_t nextCheckin);
extern bool prepareDataAvail(String* filename, uint8_t dataType, uint8_t* dst, uint16_t nextCheckin);
extern void processJoinNetwork(struct espJoinNetwork* xjn);
extern void processXferComplete(struct espXferComplete* xfc);
+extern void processXferTimeout(struct espXferComplete* xfc);
extern void processDataReq(struct espAvailDataReq* adr);
\ No newline at end of file
diff --git a/esp32_fw/src/contentmanager.cpp b/esp32_fw/src/contentmanager.cpp
index 2d0b1d30..fb5e96df 100644
--- a/esp32_fw/src/contentmanager.cpp
+++ b/esp32_fw/src/contentmanager.cpp
@@ -88,26 +88,26 @@ void drawNew(uint8_t mac[8], bool buttonPressed, tagRecord *&taginfo) {
case Today:
drawDate(filename, taginfo);
- updateTagImage(filename, mac, (midnight - now) / 60 - 10);
taginfo->nextupdate = midnight;
+ updateTagImage(filename, mac, (midnight - now) / 60 - 10);
break;
case CountDays:
if (buttonPressed) cfgobj["counter"] = 0;
drawNumber(filename, (int32_t)cfgobj["counter"], (int32_t)cfgobj["thresholdred"], taginfo);
- updateTagImage(filename, mac, (buttonPressed?0:15));
- cfgobj["counter"] = (int32_t)cfgobj["counter"] + 1;
taginfo->nextupdate = midnight;
+ updateTagImage(filename, mac, (buttonPressed ? 0 : 15));
+ cfgobj["counter"] = (int32_t)cfgobj["counter"] + 1;
break;
case CountHours:
if (buttonPressed) cfgobj["counter"] = 0;
drawNumber(filename, (int32_t)cfgobj["counter"], (int32_t)cfgobj["thresholdred"], taginfo);
- updateTagImage(filename, mac, (buttonPressed?0:5));
- cfgobj["counter"] = (int32_t)cfgobj["counter"] + 1;
taginfo->nextupdate = now + 3600;
+ updateTagImage(filename, mac, (buttonPressed ? 0 : 5));
+ cfgobj["counter"] = (int32_t)cfgobj["counter"] + 1;
break;
case Weather:
@@ -118,8 +118,8 @@ void drawNew(uint8_t mac[8], bool buttonPressed, tagRecord *&taginfo) {
// https://github.com/erikflowers/weather-icons
drawWeather(filename, cfgobj["location"], taginfo);
- updateTagImage(filename, mac, 15);
taginfo->nextupdate = now + 3600;
+ updateTagImage(filename, mac, 15);
break;
case Firmware:
@@ -142,16 +142,16 @@ void drawNew(uint8_t mac[8], bool buttonPressed, tagRecord *&taginfo) {
case Memo:
drawIdentify(filename, taginfo);
+ taginfo->nextupdate = now + 12 * 3600;
updateTagImage(filename, mac, 0);
- taginfo->nextupdate = now + 12*3600;
break;
case ImageUrl:
if (getImgURL(filename, cfgobj["url"], (time_t)cfgobj["#fetched"])) {
+ taginfo->nextupdate = now + 60 * (cfgobj["interval"].as() < 5 ? 5 : cfgobj["interval"].as());
updateTagImage(filename, mac, cfgobj["interval"].as());
cfgobj["#fetched"] = now;
- taginfo->nextupdate = now + 60 * (cfgobj["interval"].as() < 5 ? 5 : cfgobj["interval"].as());
} else {
taginfo->nextupdate = now + 300;
}
diff --git a/esp32_fw/src/newproto.cpp b/esp32_fw/src/newproto.cpp
index bbd2f148..efad9f80 100644
--- a/esp32_fw/src/newproto.cpp
+++ b/esp32_fw/src/newproto.cpp
@@ -58,7 +58,7 @@ void prepareIdleReq(uint8_t* dst, uint16_t nextCheckin) {
memcpy(pending.targetMac, dst, 8);
pending.availdatainfo.dataType = DATATYPE_NOUPDATE;
pending.availdatainfo.nextCheckIn = nextCheckin;
- pending.attemptsLeft = 10;
+ pending.attemptsLeft = 10 + MIN_RESPONSE_TIME;
char buffer[64];
uint8_t src[8];
@@ -124,6 +124,7 @@ bool prepareDataAvail(String* filename, uint8_t dataType, uint8_t* dst, uint16_t
md5.getBytes(md5bytes);
}
+ uint16_t attempts = 60;
uint8_t src[8];
*((uint64_t*)src) = swap64(*((uint64_t*)dst));
uint8_t mac[6];
@@ -131,11 +132,20 @@ bool prepareDataAvail(String* filename, uint8_t dataType, uint8_t* dst, uint16_t
tagRecord* taginfo = nullptr;
taginfo = tagRecord::findByMAC(mac);
if (taginfo != nullptr) {
+
if (memcmp(md5bytes, taginfo->md5pending, 16) == 0) {
wsLog("new image is the same as current image. not updating tag.");
wsSendTaginfo(mac);
return true;
}
+
+ time_t now;
+ time(&now);
+ uint16_t minutesUntilNextCheckin = 0;
+ if (taginfo->expectedNextCheckin > now) minutesUntilNextCheckin = (taginfo->expectedNextCheckin - now) / 60;
+ attempts += minutesUntilNextCheckin;
+ } else {
+ wsErr("Tag not found, this shouldn't happen.");
}
// the message that will be sent to the AP to tell the tag there is data pending
@@ -145,7 +155,7 @@ bool prepareDataAvail(String* filename, uint8_t dataType, uint8_t* dst, uint16_t
pending.availdatainfo.dataVer = *((uint64_t*)md5bytes);
pending.availdatainfo.dataSize = file.size();
pending.availdatainfo.nextCheckIn = nextCheckin;
- pending.attemptsLeft = 10;
+ pending.attemptsLeft = attempts;
sendDataAvail(&pending);
// data for the cache on the esp32; needs to hold the data longer than the maximum timeout on the AP
@@ -284,6 +294,29 @@ void processXferComplete(struct espXferComplete* xfc) {
wsSendTaginfo(mac);
}
+void processXferTimeout(struct espXferComplete* xfc) {
+ char buffer[64];
+ uint8_t src[8];
+ *((uint64_t*)src) = swap64(*((uint64_t*)xfc->src));
+ sprintf(buffer, "< %02X%02X%02X%02X%02X%02X xfer timeout\n\0", src[2], src[3], src[4], src[5], src[6], src[7]);
+ wsErr((String)buffer);
+ Serial.print(buffer);
+ uint8_t mac[6];
+ memcpy(mac, src + 2, sizeof(mac));
+
+ time_t now;
+ time(&now);
+ tagRecord* taginfo = nullptr;
+ taginfo = tagRecord::findByMAC(mac);
+ if (taginfo != nullptr) {
+ taginfo->expectedNextCheckin = now + 60;
+ taginfo->CheckinInMinPending = 0;
+ taginfo->pending = false;
+ memset(taginfo->md5pending, 0, 16 * sizeof(uint8_t));
+ }
+ wsSendTaginfo(mac);
+}
+
void processDataReq(struct espAvailDataReq* eadr) {
digitalWrite(ONBOARD_LED, LOW);
diff --git a/esp32_fw/src/serial.cpp b/esp32_fw/src/serial.cpp
index 6b2c1379..2331151a 100644
--- a/esp32_fw/src/serial.cpp
+++ b/esp32_fw/src/serial.cpp
@@ -19,6 +19,7 @@
#define ZBS_RX_WAIT_XFERCOMPLETE 8
#define ZBS_RX_WAIT_DATA_REQ 9
#define ZBS_RX_WAIT_JOINNETWORK 10
+#define ZBS_RX_WAIT_XFERTIMEOUT 11
uint8_t restartBlockRequest = 0;
@@ -111,6 +112,7 @@ void Ping() {
void SerialRXLoop() {
if (Serial1.available()) {
lastchar = Serial1.read();
+ //Serial.write(lastchar);
switch (RXState) {
case ZBS_RX_WAIT_HEADER:
Serial.write(lastchar);
@@ -119,8 +121,7 @@ void SerialRXLoop() {
cmdbuffer[c] = cmdbuffer[c + 1];
}
cmdbuffer[3] = lastchar;
- if ((strncmp(cmdbuffer, "VER>", 4) == 0) && waitingForVersion) {
- waitingForVersion = 0;
+ if ((strncmp(cmdbuffer, "VER>", 4) == 0)) {
pktindex = 0;
RXState = ZBS_RX_WAIT_VER;
charindex = 0;
@@ -151,6 +152,12 @@ void SerialRXLoop() {
packetp = (uint8_t*)calloc(sizeof(struct espXferComplete) + 8, 1);
memset(cmdbuffer, 0x00, 4);
}
+ if (strncmp(cmdbuffer, "XTO>", 4) == 0) {
+ RXState = ZBS_RX_WAIT_XFERTIMEOUT;
+ pktindex = 0;
+ packetp = (uint8_t*)calloc(sizeof(struct espXferComplete) + 8, 1);
+ memset(cmdbuffer, 0x00, 4);
+ }
break;
case ZBS_RX_BLOCK_REQUEST:
packetp[pktindex] = lastchar;
@@ -171,6 +178,16 @@ void SerialRXLoop() {
RXState = ZBS_RX_WAIT_HEADER;
}
break;
+ case ZBS_RX_WAIT_XFERTIMEOUT:
+ packetp[pktindex] = lastchar;
+ pktindex++;
+ if (pktindex == sizeof(struct espXferComplete)) {
+ struct espXferComplete* xfc = (struct espXferComplete*)packetp;
+ processXferTimeout(xfc);
+ free(packetp);
+ RXState = ZBS_RX_WAIT_HEADER;
+ }
+ break;
case ZBS_RX_WAIT_DATA_REQ:
packetp[pktindex] = lastchar;
pktindex++;
@@ -182,6 +199,7 @@ void SerialRXLoop() {
}
break;
case ZBS_RX_WAIT_VER:
+ waitingForVersion = 0;
cmdbuffer[charindex] = lastchar;
charindex++;
if (charindex == 4) {
@@ -214,6 +232,8 @@ void zbsRxTask(void* parameter) {
Serial1.begin(230400, SERIAL_8N1, RXD1, TXD1);
simplePowerOn();
+ bool firstrun = true;
+
Serial1.print("VER?");
waitingForVersion = esp_timer_get_time();
while (1) {
@@ -223,14 +243,30 @@ void zbsRxTask(void* parameter) {
Serial1.write(Serial.read());
}
vTaskDelay(1 / portTICK_PERIOD_MS);
+
if (waitingForVersion) {
if (esp_timer_get_time() - waitingForVersion > 10000*1000ULL) {
- waitingForVersion = esp_timer_get_time();
+ waitingForVersion = 0;
//performDeviceFlash();
Serial.println("I wasn't able to connect to a ZBS tag, trying to reboot the tag.");
Serial.println("If this problem persists, please check wiring and definitions in the settings.h file, and presence of the right firmware");
simplePowerOn();
}
}
+
+ if (version && firstrun) {
+ Serial.printf("ZBS/Zigbee FW version: %04X\n", version);
+ uint16_t fsversion;
+ lookupFirmwareFile(fsversion);
+ if ((fsversion) && (version != fsversion)) {
+ Serial.printf("Firmware version on LittleFS: %04X\n", fsversion);
+ Serial.printf("Performing flash update in about 30 seconds");
+ vTaskDelay(30000 / portTICK_PERIOD_MS);
+ performDeviceFlash();
+ } else if (!fsversion) {
+ Serial.println("No ZBS/Zigbee FW binary found on SPIFFS, please upload a zigbeebase000X.bin - format binary to enable flashing");
+ }
+ firstrun = false;
+ }
}
}