From: Eugene Crosser Date: Tue, 23 Jul 2024 10:24:20 +0000 (+0200) Subject: WIP cleanup cache maintnance X-Git-Url: http://average.org/gitweb/?a=commitdiff_plain;h=09eddae71d781d003499633db893f964e4aae2cf;p=ThermoBeaconDisplay.git WIP cleanup cache maintnance --- diff --git a/ThermoBeaconDisplay.ino b/ThermoBeaconDisplay.ino index bb01988..58dfdb7 100644 --- a/ThermoBeaconDisplay.ino +++ b/ThermoBeaconDisplay.ino @@ -8,181 +8,175 @@ #include #include +TFT_eSPI tft = TFT_eSPI(); + #define SLOTS 2 #define MAXAGE 100 struct entry { - struct entry *next; char addr[12]; int bat; int tmp; int hum; int ticks; int rssi; - int age; }; -struct entry *head; - -String viewports[] = { "00:00:0b:15", "00:00:01:40" }; +struct elem { + struct elem *next; + int age; + struct entry entry; +}; -TFT_eSPI tft = TFT_eSPI(); +struct elem *head = NULL; -void displayT(String addr, int bat, int tmp, int hum, int ticks, int rssi) { +void dbgEntry(struct entry *entry) { + if (entry) { + Serial.print(entry->addr); + Serial.print(" Bat: "); + Serial.print(entry->bat); + Serial.print(" Temp: "); + Serial.print(entry->tmp); + Serial.print(" Hum: "); + Serial.print(entry->hum); + Serial.print(" Tm: "); + Serial.print(entry->ticks); + Serial.print(" Rssi: "); + Serial.print(entry->rssi); + } else { + Serial.print(""); + } +} - for (int i = 0; i <= 1; i++) { - if (viewports[i] == addr) { - tft.setViewport(i * (tft.width() / 2) + 4, 4, tft.width() / 2 - 8, tft.height() - 8); - } +void dbgOp(int pos, String str1, struct entry* entry1, + String str2, struct entry* entry2) { + Serial.print("pos "); + Serial.print(pos); + Serial.print(" "); + Serial.print(str1); + Serial.print(" "); + dbgEntry(entry1); + if (str2) { + Serial.print(" "); + Serial.print(str2); + Serial.print(" "); + dbgEntry(entry2); } + Serial.println(); +} + +void display(int pos, entry *oldval, entry* newval) { + if (!newval) return; + tft.setViewport(pos * (tft.width() / 2) + 4, 4, + tft.width() / 2 - 8, tft.height() - 8); tft.fillScreen(TFT_BLACK); tft.setCursor(0, 0, 4); tft.setTextColor(TFT_WHITE); tft.setTextSize(1); - tft.println(addr.substring(3)); + tft.println(newval->addr + 3); tft.setTextColor(TFT_RED); tft.setTextSize(2); - tft.print(tmp / 10); + tft.print(newval->tmp / 10); tft.print("."); - tft.println(tmp % 10); + tft.println(newval->tmp % 10); tft.setTextColor(TFT_BLUE); - tft.print(hum / 10); + tft.print(newval->hum / 10); tft.print("."); - tft.println(hum % 10); + tft.println(newval->hum % 10); // tft.setTextColor(TFT_GREEN); // tft.setTextSize(1); - // tft.print(bat / 100); + // tft.print(newval->bat / 100); // tft.print("."); - // tft.print(bat % 100); + // tft.print(newval->bat % 100); // tft.print(" "); - // tft.println(rssi); + // tft.println(newval->rssi); tft.resetViewport(); } -void updateCache(String addr, int bat, int tmp, int hum, int ticks, int rssi) { - struct entry *update = NULL; - struct entry **cur_p = &head; - struct entry *cur = *cur_p; - struct entry *slots[SLOTS] = {NULL}; +void updateCache(struct entry *newentry) { + struct elem **cur_p = &head; + struct elem *cur = *cur_p; + struct elem *slots[SLOTS] = {NULL}; + struct elem *target = NULL; int pos = 0; - bool needinsert = true; - bool mayupdate = true; - struct entry nentry; - while (cur) { + while (true) { + bool at_the_end = !cur; if (pos < SLOTS) slots[pos] = cur; - if (strcmp(cur->addr, addr.c_str()) == 0) { - Serial.print("found same address "); - Serial.print(addr); - Serial.print(" at pos "); - Serial.println(pos); - if (mayupdate && ((cur->rssi <= rssi) || !cur->next || (cur->next->rssi <= rssi))) { - Serial.print("at suitable insertion point at pos "); - Serial.print(pos); - Serial.print(" new rssi "); - Serial.print(rssi); - Serial.print(" current rssi "); - Serial.print(cur->rssi); - Serial.print(" next rssi "); - Serial.println(cur->next ? cur->next->rssi : 999999); - needinsert = false; - update = cur; - nentry = (struct entry) { - .bat = bat, - .hum = hum, - .ticks = ticks, - .rssi = rssi - }; - strncpy(nentry.addr, addr.c_str(), sizeof(nentry.addr)); - nentry.addr[sizeof(nentry.addr) - 1] = '\0'; + // First handle insertion because it _can_ happen with cur == NULL + if (at_the_end || cur->entry.rssi < newentry->rssi) { + dbgOp(pos, "potentially insert", newentry, + "before", cur ? &(cur->entry) : NULL); + if (cur && strcmp(cur->entry.addr, newentry->addr) == 0) { + dbgOp(pos, "update instead of insert", newentry, + "replacing", &(cur->entry)); + target = cur; } else { - Serial.print("removing same address at pos "); - Serial.println(pos); - (*cur_p) = cur->next; - free(cur); - cur = *cur_p; - if (pos < SLOTS) slots[pos] = NULL; + if (target) { + dbgOp(pos, "not inserting because update scheduled", newentry, + "before", cur ? &(cur->entry) : NULL); + } else { + dbgOp(pos, "really insert", newentry, + "before", cur ? &(cur->entry) : NULL); + (*cur_p) = (struct elem*)malloc(sizeof(struct elem)); + (*cur_p)->next = cur; + (*cur_p)->age = 0; + (*cur_p)->entry = *newentry; + } } } - if (cur->age > MAXAGE) { - Serial.print("removing old age pos "); - Serial.println(pos); - (*cur_p) = cur->next; - free(cur); - cur = *cur_p; - if (pos < SLOTS) slots[pos] = NULL; - } else { - Serial.print("Increaing age for "); - Serial.println(cur->addr); - cur->age++; - } - if (needinsert && (cur->rssi < rssi)) { - Serial.print("inserting addr "); - Serial.print(addr); - Serial.print(" at pos "); - Serial.println(pos); - (*cur_p) = (struct entry*)malloc(sizeof(struct entry)); - (**cur_p) = (struct entry) { - .next = cur, - .bat = bat, - .hum = hum, - .ticks = ticks, - .rssi = rssi - }; - strncpy((*cur_p)->addr, addr.c_str(), sizeof(nentry.addr)); - (*cur_p)->addr[sizeof(nentry.addr) - 1] = '\0'; - needinsert = false; - mayupdate = false; + if (at_the_end) break; + // The rest of the operations in the loop assume that `cur` exists + (cur->age)++; + if (strcmp(cur->entry.addr, newentry->addr) == 0 || cur->age > MAXAGE) { + dbgOp(pos, "potentially delete", &(cur->entry), "", NULL); + if (target == cur) { + dbgOp(pos, "do not delete", &(cur->entry), + "scheduled for replacement by", newentry); + } else { + if (strcmp(cur->entry.addr, newentry->addr) == 0 && + (!(cur->next) || cur->next->entry.rssi < newentry->rssi)) { + dbgOp(pos, "update instead of delete", &(cur->entry), + "already at the insersion point for", newentry); + target = cur; + } else { + dbgOp(pos, "really delete", &(cur->entry), "", NULL); + (*cur_p) = cur->next; + free(cur); + cur = *cur_p; + if (pos < SLOTS) slots[pos] = NULL; + pos--; // This may make it negative, but it will be bumped up next + } + } } + // Proceed to the next element of the list cur_p = &(cur->next); cur = *cur_p; pos++; } - if (needinsert) { - Serial.print("inserting addr "); - Serial.print(addr); - Serial.println(" at the tail"); - (*cur_p) = (struct entry*)malloc(sizeof(struct entry)); - (**cur_p) = (struct entry) { - .next = cur, - .bat = bat, - .hum = hum, - .ticks = ticks, - .rssi = rssi - }; - strncpy((*cur_p)->addr, addr.c_str(), sizeof(nentry.addr)); - (*cur_p)->addr[sizeof(nentry.addr) - 1] = '\0'; - } + // Finished modifying the list, now display for (cur = head, pos = 0; pos < SLOTS; cur = cur ? cur->next : cur, pos++) { - if (update && (slots[pos] == update)) { + if (target && (slots[pos] == target)) { // old = slots[pos], new = nentry - Serial.print("Display as updated pos "); - Serial.print(pos); - Serial.print(" addr was "); - Serial.print(slots[pos] ? slots[pos]->addr : "NONE"); - Serial.print(" now "); - Serial.println(nentry.addr); + dbgOp(pos, "Display before updating, old", slots[pos] ? &(slots[pos]->entry) : NULL, + "new", newentry); + display(pos, slots[pos] ? &(slots[pos]->entry) : NULL, newentry); } else { //old = slots[pos], new = cur - Serial.print("Display as new pos "); - Serial.print(pos); - Serial.print(" addr was "); - Serial.print(slots[pos] ? slots[pos]->addr : "NONE"); - Serial.print(" now "); - Serial.println(cur ? cur->addr : "NULL"); + dbgOp(pos, "Display as different elems, old", slots[pos] ? &(slots[pos]->entry) : NULL, + "new", cur ? &(cur->entry) : NULL); + display(pos, slots[pos] ? &(slots[pos]->entry) : NULL, cur ? &(cur->entry) : NULL); } } - if (update) { - update->bat = nentry.bat; - update->hum = nentry.hum; - update->ticks = nentry.ticks; - update->rssi = nentry.rssi; - update->age = 0; + // Now we can actually update the entry + if (target) { + target->entry = *newentry; + target->age = 0; } - displayT(addr, bat, tmp, hum, ticks, rssi); } -void dbg(BLEDevice peripheral) { +void dbgDevEv(BLEDevice peripheral) { +#if 0 Serial.print("Address: "); Serial.println(peripheral.address()); Serial.print("RSSI: "); @@ -210,35 +204,28 @@ void dbg(BLEDevice peripheral) { Serial.println(); } Serial.println(); +#endif } void advHandler(BLEDevice dev) { if (dev.address().substring(0,6) == "a3:e4:") { - // dbg(dev); + dbgDevEv(dev); if (dev.hasManufacturerData()) { int len = dev.manufacturerDataLength(); if (len == 20) { uint8_t buf[20]; dev.manufacturerData(buf, len); - int bat = ((buf[11] << 8) + buf[10]) / 10; - int tmp = ((buf[13] << 8) + buf[12]) * 10 / 16; - int hum = ((buf[15] << 8) + buf[14]) * 10 / 16; - uint32_t ticks = (buf[18] << 16) + (buf[17] << 8) + buf[16]; - /* - Serial.print(dev.address()); - Serial.print(" Bat: "); - Serial.print(bat); - Serial.print(" Temp: "); - Serial.print(tmp); - Serial.print(" Hum: "); - Serial.print(hum); - Serial.print(" Tm: "); - Serial.print(ticks); - Serial.print(" Rssi: "); - Serial.print(dev.rssi()); - Serial.println(); - */ - updateCache(dev.address().substring(6), bat, tmp, hum, ticks, dev.rssi()); + struct entry newentry = { + .bat = ((buf[11] << 8) + buf[10]) / 10, + .tmp = ((buf[13] << 8) + buf[12]) * 10 / 16, + .hum = ((buf[15] << 8) + buf[14]) * 10 / 16, + .ticks = (buf[18] << 16) + (buf[17] << 8) + buf[16], + .rssi = dev.rssi() + }; + strncpy(newentry.addr, dev.address().substring(6).c_str(), + sizeof(newentry.addr)); + newentry.addr[sizeof(newentry.addr) - 1] = '\0'; + updateCache(&newentry); } } } @@ -251,8 +238,7 @@ void setup() { Serial.println("starting Bluetooth® Low Energy module failed!"); while (1); } - BLE.setEventHandler(BLEDiscovered, advHandler); - BLE.scan(true); + tft.init(); tft.setRotation(1); tft.fillScreen(TFT_BLACK); @@ -262,6 +248,9 @@ void setup() { tft.setViewport(tft.width() / 2, 0, tft.width() / 2, tft.height()); tft.frameViewport(TFT_NAVY, 1); tft.resetViewport(); + + BLE.setEventHandler(BLEDiscovered, advHandler); + BLE.scan(true); } void loop() {