1#include <freertos/queue.h>
5#include "HardwareSerial.h"
7#include <ArduinoJson.h>
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
57
58
65U8X8_SSD1315_128X64_NONAME_SW_I2C
u8x8(
130 Serial.begin(115200);
131 vTaskDelay(500 / portTICK_PERIOD_MS);
132 Serial.println(
" hello world!");
140 u8x8.setFont(u8x8_font_chroma48medium8_r);
142 u8x8.drawString(0, 2,
"FS Init...");
148 if (LittleFS.begin()) {
150 Serial.println(
"Config loaded from LittleFS");
151 Serial.println(
"SSID: " +
SSID);
152 Serial.println(
"PASS: " +
PASS);
154 u8x8.drawString(0, 2,
"FS OK ");
161 Serial.println(
"SERVER_BASE empty; offline authorization disabled "
165
166
167
168
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
206 WiFi.begin(
SSID.c_str(),
PASS.c_str());
213 Serial.println(
"[AuthSync] Offline cache preloaded (after WiFi init)");
216 while (WiFiClass::status() != WL_CONNECTED && tries < 80) {
217 vTaskDelay(500 / portTICK_PERIOD_MS);
222 if (WiFiClass::status() == WL_CONNECTED) {
224 Serial.println(
"WiFi connected");
225 Serial.print(
"IP address: ");
226 Serial.println(WiFi.localIP());
227 u8x8.drawString(0, 2,
"WiFi OK ");
230 vTaskDelay(100 / portTICK_PERIOD_MS);
241 u8x8.drawString(0, 3,
"DB OK");
245 u8x8.drawString(0, 3,
"DB OFFLINE ");
249 "[AuthSync] Using offline cache (sync failed or server unreachable)");
252 u8x8.drawString(0, 2,
"WiFi FAIL");
256 vTaskDelay(100 / portTICK_PERIOD_MS);
267#if defined(CONFIG_FREERTOS_UNICORE)
277 Serial.println(
"[Tasks] NetworkTask started on IdleTask priority");
279 xTaskCreatePinnedToCore(
287 Serial.println(
"[Tasks] NetworkTask started on IdleTask priority");
291 Serial.println(
"[Tasks] scanQueue created");
293 Serial.println(
"[Tasks] Failed to create scanQueue");
298 Serial.println(
"[Tasks] Failed to create/start display timer");
300 Serial.println(
"[Tasks] Display timer started");
308 if (
rfid.PICC_IsNewCardPresent() &&
rfid.PICC_ReadCardSerial()) {
310 Serial.println(
"Scanned: " + uid);
316
317
318
319
320
321
322
323
330 rfid.PCD_StopCrypto1();
331 vTaskDelay(100 / portTICK_PERIOD_MS);
335 uid.toCharArray(item
.uid,
sizeof(item
.uid));
336 if (xQueueSend(
scanQueue, &item, 0) != pdPASS) {
337 Serial.println(
"[Queue] scanQueue full; dropping UID post");
339 Serial.printf(
"[Queue] Enqueued UID=%s\n", item
.uid);
370 if (Serial.available()) {
371 int c = Serial.read();
372 if (c ==
'm' || c ==
'M') {
373 if (authSync) authSync->TEST_dumpMemoryStats();
383 for (byte i = 0; i <
rfid.uid.size; i++) {
384 if (
rfid.uid.uidByte[i] < 0x10)
386 uid += String(
rfid.uid.uidByte[i], HEX);
394 static bool headerDrawn =
false;
397 u8x8.drawString(0, 0,
"RFID Access");
409 u8x8.drawString(0, 3,
"DB OK ");
411 u8x8.drawString(0, 3,
"DB LOST ");
418 String line =
"UID:" +
lastUID;
419 if (line.length() > 16)
420 line = line.substring(0, 16);
422 while (line.length() < 16)
424 u8x8.drawString(0, 1, line.c_str());
431 0, 4, (String(
"Auth:") + (
lastAuthorized ?
"YES" :
"NO ")).c_str());
438 snprintf(hashStr,
sizeof(hashStr),
"H:%08X",
439 static_cast<uint32_t>(
lastHash & 0xFFFFFFFF));
440 u8x8.drawString(0, 7, hashStr);
453 bool currentBlink = on;
459 u8x8.drawString(14, 0,
" ");
463 u8x8.drawString(14, 0,
" ");
476 if (WiFi.status() != WL_CONNECTED)
487 http.setTimeout(1500);
488 http.begin(String(
SERVER_BASE) +
"/api/last_scan");
489 http.addHeader(
"Content-Type",
"application/json");
490 String body = R"({"uid":")" + uid +
"\"}";
491 int code = http.POST(body);
492 Serial.printf(
"[HTTP] POST /api/last_scan -> code=%d, body=%s\n", code, body.c_str());
493 if (code < 200 || code >= 300) {
494 Serial.printf(
"postLastScan failed: %d\n", code);
498 String payload = http.getString();
499 Serial.printf(
"[HTTP] /api/last_scan payload: %s\n", payload.c_str());
502 DeserializationError err = deserializeJson(out, payload);
504 Serial.printf(
"postLastScan: JSON parse error: %s\n", err.c_str());
516 if (WiFi.status() != WL_CONNECTED ||
SERVER_BASE.length() == 0) {
523 http.setTimeout(1500);
526 int code = http.GET();
527 if (code > 0 && code < 400)
529 String payload = http.getString();
531 DeserializationError err = deserializeJson(doc, payload);
533 const char *m = doc[
"enroll_mode"] |
nullptr;
535 if (m && strlen(m) > 0) {
550 bool nowReachable =
false;
551 if (WiFiClass::status() == WL_CONNECTED && SERVER_BASE.length() > 0) {
553 http.setTimeout(1500);
555 int code = http.GET();
557 nowReachable = (code == 200);
580 Serial.printf(
"[Tasks] NetworkTask running on core %d\n", xPortGetCoreID());
585 Serial.println(
"[Tasks] Failed to create/start server check timer");
587 Serial.println(
"[Tasks] Server check timer started");
592 Serial.println(
"[Tasks] Failed to create/start auth sync timer");
594 Serial.println(
"[Tasks] AuthSync timer started");
603 Serial.println(
"[Tasks] Auth sync requested");
608 for (
int i = 0; i < 3;
612 if (xQueueReceive(
scanQueue, &item, 0) == pdPASS) {
615 Serial.printf(
"[Queue] Posting UID=%s\n", item
.uid);
619 Serial.printf(
"[Queue] postLastScan returned size=%u\n",
static_cast<
unsigned>(resp.size()));
622 if (resp.size() > 0) {
623 bool enrolled =
false;
624 if (resp[
"enrolled"].is<
bool>()) {
625 enrolled = resp[
"enrolled"].as<
bool>();
632 Serial.println(
"[Queue] Enrollment cleared (requested display update)");
636 Serial.println(
"[Queue] postLastScan: no valid response");
647 vTaskDelay(pdMS_TO_TICKS(50));
bool createServerCheckTimer(TimerCallbackFunction_t callback, TickType_t periodTicks)
bool createDisplayTimer(TimerCallbackFunction_t callback, TickType_t periodTicks)
bool createAuthSyncTimer(TimerCallbackFunction_t callback, TickType_t periodTicks)
void setServerProbeResult(bool ok, unsigned long probeMillis)
void dumpMemoryStats() const
bool isAuthorized(const String &uid)
AuthSync(const String &serverBase)
static bool loadConfig(String &ssid, String &pass, String &serverBase)
void NetworkTask(void *pv)
static volatile bool authSyncRequested
bool displayedEnrollBlink
bool postLastScan(const String &uid, JsonDocument &out)
String displayedEnrollMode
unsigned long lastDisplayUpdate
U8X8_SSD1315_128X64_NONAME_SW_I2C u8x8(22, 21, U8X8_PIN_NONE)
constexpr uint8_t RST_PIN
MFRC522 rfid(SS_PIN, RST_PIN)
static volatile bool displayUpdateRequested
void drawEnrollIndicator(bool on)
bool displayedServerReachable
static constexpr unsigned long ENROLL_POLL_INTERVAL_MS
void updateEnrollStatus()
void authSyncTimerCallback(TimerHandle_t xTimer)
static void displayTimerCallback(TimerHandle_t xTimer)
void serverCheckTimerCallback(TimerHandle_t xTimer)
static unsigned long lastEnrollPoll
unsigned long enrollBlinkMillis
static QueueHandle_t scanQueue
uint64_t hashUid(const String &s)