#include <SPI.h>
#include <TFT_eSPI.h>
+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("<NULL ENTRY>");
+ }
+}
- 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: ");
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);
}
}
}
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);
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() {