Version 1 færdig
Læser og kalder API som det skal. OTA virker Opsætning af wifi via ESP32's eget hotspot virker Mangler at få lavet skrivning, men det bliver v2.
This commit is contained in:
32
README.md
32
README.md
@@ -1,2 +1,34 @@
|
||||
# filamentguard_esp32
|
||||
|
||||
## Build-miljoeer
|
||||
|
||||
`dev` er standard og bruger:
|
||||
|
||||
```text
|
||||
http://192.168.1.6:5011
|
||||
```
|
||||
|
||||
Byg og upload dev-firmware:
|
||||
|
||||
```powershell
|
||||
pio run -e dev -t upload
|
||||
```
|
||||
|
||||
`prod` bruges til OTA-firmware og bruger:
|
||||
|
||||
```text
|
||||
http://192.168.3.2:9090
|
||||
```
|
||||
|
||||
Byg prod-firmware til OTA:
|
||||
|
||||
```powershell
|
||||
pio run -e prod
|
||||
```
|
||||
|
||||
OTA-binaren ligger derefter i:
|
||||
|
||||
```text
|
||||
.pio/build/prod/firmware.bin
|
||||
```
|
||||
|
||||
|
||||
@@ -2,6 +2,18 @@
|
||||
|
||||
#include <Arduino.h>
|
||||
|
||||
#ifndef FILAMENT_GUARD_API_ENV
|
||||
#define FILAMENT_GUARD_API_ENV 0
|
||||
#endif
|
||||
|
||||
#if FILAMENT_GUARD_API_ENV == 0
|
||||
#define FILAMENT_GUARD_API_BASE_URL "http://192.168.1.6:5011"
|
||||
#elif FILAMENT_GUARD_API_ENV == 1
|
||||
#define FILAMENT_GUARD_API_BASE_URL "http://192.168.3.2:9090"
|
||||
#else
|
||||
#error "FILAMENT_GUARD_API_ENV skal vaere 0 (dev) eller 1 (prod)."
|
||||
#endif
|
||||
|
||||
class FilamentGuardApiClient
|
||||
{
|
||||
public:
|
||||
@@ -20,11 +32,16 @@ public:
|
||||
|
||||
private:
|
||||
static constexpr const char* TagReadEndpointUrl =
|
||||
"http://192.168.1.6:5011/api/Tag/detected";
|
||||
FILAMENT_GUARD_API_BASE_URL
|
||||
"/api/Tag/detected";
|
||||
|
||||
static constexpr const char* TagEventEndpointUrl =
|
||||
"http://192.168.1.6:5011/api/Tag/removed";
|
||||
FILAMENT_GUARD_API_BASE_URL
|
||||
"/api/Tag/removed";
|
||||
|
||||
static constexpr const char* LogEndpointUrl =
|
||||
"http://192.168.1.6:5011/api/Log/create";
|
||||
FILAMENT_GUARD_API_BASE_URL
|
||||
"/api/Log/create";
|
||||
};
|
||||
|
||||
#undef FILAMENT_GUARD_API_BASE_URL
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
|
||||
struct FilamentGuardTagRead
|
||||
{
|
||||
String readerId;
|
||||
FilamentGuardDeviceInfo device;
|
||||
OpenPrintTagData tag;
|
||||
};
|
||||
};
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include <Arduino.h>
|
||||
#include <PN5180ISO14443.h>
|
||||
#include <PN5180ISO15693.h>
|
||||
|
||||
#include "FilamentGuardApiClient.h"
|
||||
@@ -12,11 +11,18 @@
|
||||
#include "OpenPrintTagData.h"
|
||||
#include "OpenPrintTagParser.h"
|
||||
|
||||
#ifndef FILAMENT_GUARD_NFC_DIAGNOSTICS
|
||||
#define FILAMENT_GUARD_NFC_DIAGNOSTICS 0
|
||||
#endif
|
||||
|
||||
class Pn5180Reader
|
||||
{
|
||||
public:
|
||||
explicit Pn5180Reader(
|
||||
FilamentGuardLogger& logger);
|
||||
Pn5180Reader(
|
||||
FilamentGuardLogger& logger,
|
||||
uint8_t nssPin,
|
||||
uint8_t busyPin,
|
||||
uint8_t resetPin);
|
||||
|
||||
void begin();
|
||||
|
||||
@@ -24,24 +30,37 @@ public:
|
||||
const FilamentGuardDeviceInfo& deviceInfo);
|
||||
|
||||
void printVersionInformation();
|
||||
void checkForTag();
|
||||
|
||||
const String& getReaderId() const;
|
||||
|
||||
bool scanForTag(
|
||||
uint8_t* uid,
|
||||
uint16_t& signalStrength);
|
||||
|
||||
bool registerTag(
|
||||
const uint8_t* uid,
|
||||
uint8_t uidLength);
|
||||
|
||||
bool isActiveTag(
|
||||
const uint8_t* uid,
|
||||
uint8_t uidLength) const;
|
||||
|
||||
bool hasActiveTag() const;
|
||||
|
||||
void markTagPresent();
|
||||
|
||||
bool markTagMissing();
|
||||
|
||||
private:
|
||||
enum class TagProtocol : uint8_t
|
||||
{
|
||||
None,
|
||||
Iso14443A,
|
||||
Iso15693
|
||||
};
|
||||
|
||||
static constexpr uint8_t NssPin = 5;
|
||||
static constexpr uint8_t BusyPin = 16;
|
||||
static constexpr uint8_t ResetPin = 17;
|
||||
|
||||
static constexpr uint8_t RequiredMissingScans = 3;
|
||||
|
||||
PN5180ISO15693 iso15693Reader;
|
||||
PN5180ISO14443 iso14443Reader;
|
||||
|
||||
OpenPrintTagParser openPrintTagParser;
|
||||
FilamentGuardTagReadSerializer tagReadSerializer;
|
||||
@@ -49,6 +68,7 @@ private:
|
||||
FilamentGuardLogger& logger;
|
||||
|
||||
FilamentGuardDeviceInfo deviceInfo;
|
||||
String readerId;
|
||||
|
||||
uint8_t lastUid[10] = {};
|
||||
uint8_t lastUidLength = 0;
|
||||
@@ -56,11 +76,22 @@ private:
|
||||
TagProtocol activeProtocol = TagProtocol::None;
|
||||
uint8_t missingScanCount = 0;
|
||||
|
||||
bool checkIso14443Tag();
|
||||
bool checkIso15693Tag();
|
||||
#if FILAMENT_GUARD_NFC_DIAGNOSTICS
|
||||
unsigned long nextDiagnosticAt = 0;
|
||||
#endif
|
||||
|
||||
void handleTagMissing();
|
||||
|
||||
bool performInventory(
|
||||
uint8_t* uid);
|
||||
|
||||
bool readIso15693BlockRange(
|
||||
const uint8_t* uid,
|
||||
uint8_t firstBlock,
|
||||
uint8_t blockCount,
|
||||
uint8_t* blockData,
|
||||
uint8_t blockSize);
|
||||
|
||||
bool isSameUid(
|
||||
const uint8_t* uid,
|
||||
uint8_t uidLength) const;
|
||||
@@ -77,8 +108,8 @@ private:
|
||||
uint8_t uidLength,
|
||||
bool reverseOrder) const;
|
||||
|
||||
void dumpIso15693Tag(
|
||||
uint8_t* uid,
|
||||
bool dumpIso15693Tag(
|
||||
const uint8_t* uid,
|
||||
uint8_t uidLength);
|
||||
|
||||
void logTagRead(
|
||||
|
||||
BIN
ota/bridge/filamentguard-1.0.3.bin
Normal file
BIN
ota/bridge/filamentguard-1.0.3.bin
Normal file
Binary file not shown.
BIN
ota/downgrade/filamentguard-0.5.0.bin
Normal file
BIN
ota/downgrade/filamentguard-0.5.0.bin
Normal file
Binary file not shown.
@@ -8,7 +8,10 @@
|
||||
; Please visit documentation for the other options and examples
|
||||
; https://docs.platformio.org/page/projectconf.html
|
||||
|
||||
[env:esp32dev]
|
||||
[platformio]
|
||||
default_envs = dev
|
||||
|
||||
[env]
|
||||
platform = espressif32
|
||||
board = esp32dev
|
||||
framework = arduino
|
||||
@@ -19,5 +22,20 @@ board_build.filesystem = spiffs
|
||||
lib_deps =
|
||||
tzapu/WiFiManager
|
||||
chrisjoyce911/esp32FOTA
|
||||
https://github.com/ATrappmann/PN5180-Library.git
|
||||
https://github.com/wilson-elechouse/PN5180_ELECHOUSE.git#c413f0a91e8efa317256afb1e3bba074d3f122dc
|
||||
soburi/TinyCBOR@^0.5.3-arduino2
|
||||
|
||||
[env:dev]
|
||||
build_src_filter =
|
||||
+<*>
|
||||
-<pn5180_probe.cpp>
|
||||
build_flags =
|
||||
-D FILAMENT_GUARD_API_ENV=0
|
||||
|
||||
[env:prod]
|
||||
build_src_filter =
|
||||
+<*>
|
||||
-<pn5180_probe.cpp>
|
||||
build_flags =
|
||||
-D FILAMENT_GUARD_API_ENV=1
|
||||
|
||||
|
||||
@@ -2,52 +2,55 @@
|
||||
|
||||
#include <HTTPClient.h>
|
||||
#include <WiFi.h>
|
||||
#include <freertos/FreeRTOS.h>
|
||||
#include <freertos/queue.h>
|
||||
#include <freertos/task.h>
|
||||
#include <new>
|
||||
|
||||
namespace
|
||||
{
|
||||
constexpr uint16_t HttpTimeoutMilliseconds =
|
||||
15000;
|
||||
5000;
|
||||
|
||||
constexpr UBaseType_t ApiQueueLength =
|
||||
24;
|
||||
|
||||
constexpr uint32_t ApiWorkerStackSize =
|
||||
4096;
|
||||
|
||||
struct ApiRequest
|
||||
{
|
||||
String endpointUrl;
|
||||
String json;
|
||||
String description;
|
||||
bool reportSuccess = true;
|
||||
};
|
||||
|
||||
QueueHandle_t apiQueue = nullptr;
|
||||
TaskHandle_t apiWorkerHandle = nullptr;
|
||||
|
||||
bool postJson(
|
||||
const char* endpointUrl,
|
||||
const String& json,
|
||||
const char* description,
|
||||
int* returnedResponseCode = nullptr,
|
||||
String* returnedResponseBody = nullptr)
|
||||
const ApiRequest& request)
|
||||
{
|
||||
if (returnedResponseCode != nullptr)
|
||||
{
|
||||
*returnedResponseCode = 0;
|
||||
}
|
||||
|
||||
if (returnedResponseBody != nullptr)
|
||||
{
|
||||
returnedResponseBody->clear();
|
||||
}
|
||||
|
||||
if (WiFi.status() != WL_CONNECTED)
|
||||
{
|
||||
Serial.print(description);
|
||||
Serial.print(
|
||||
request.description);
|
||||
|
||||
Serial.println(
|
||||
" blev ikke sendt: Wi-Fi er ikke forbundet.");
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if (json.isEmpty())
|
||||
{
|
||||
Serial.print(description);
|
||||
Serial.println(
|
||||
" blev ikke sendt: JSON-data er tomme.");
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
HTTPClient httpClient;
|
||||
|
||||
if (!httpClient.begin(endpointUrl))
|
||||
if (!httpClient.begin(
|
||||
request.endpointUrl))
|
||||
{
|
||||
Serial.print(description);
|
||||
Serial.print(
|
||||
request.description);
|
||||
|
||||
Serial.println(
|
||||
" kunne ikke initialiseres.");
|
||||
|
||||
@@ -62,12 +65,8 @@ namespace
|
||||
HttpTimeoutMilliseconds);
|
||||
|
||||
const int responseCode =
|
||||
httpClient.POST(json);
|
||||
|
||||
if (returnedResponseCode != nullptr)
|
||||
{
|
||||
*returnedResponseCode = responseCode;
|
||||
}
|
||||
httpClient.POST(
|
||||
request.json);
|
||||
|
||||
if (responseCode <= 0)
|
||||
{
|
||||
@@ -75,16 +74,14 @@ namespace
|
||||
httpClient.errorToString(
|
||||
responseCode);
|
||||
|
||||
if (returnedResponseBody != nullptr)
|
||||
{
|
||||
*returnedResponseBody = errorMessage;
|
||||
}
|
||||
Serial.print(
|
||||
request.description);
|
||||
|
||||
Serial.print(description);
|
||||
Serial.print(
|
||||
" fejlede. HTTPClient-fejl: ");
|
||||
|
||||
Serial.println(errorMessage);
|
||||
Serial.println(
|
||||
errorMessage);
|
||||
|
||||
httpClient.end();
|
||||
|
||||
@@ -94,37 +91,172 @@ namespace
|
||||
const String responseBody =
|
||||
httpClient.getString();
|
||||
|
||||
if (returnedResponseBody != nullptr)
|
||||
{
|
||||
*returnedResponseBody = responseBody;
|
||||
}
|
||||
|
||||
const bool successful =
|
||||
responseCode >= 200 &&
|
||||
responseCode < 300;
|
||||
|
||||
if (!successful)
|
||||
if (!successful ||
|
||||
request.reportSuccess)
|
||||
{
|
||||
Serial.print(description);
|
||||
Serial.print(
|
||||
" blev afvist. HTTP-status: ");
|
||||
request.description);
|
||||
|
||||
Serial.println(responseCode);
|
||||
Serial.print(
|
||||
successful
|
||||
? " sendt. HTTP-status: "
|
||||
: " blev afvist. HTTP-status: ");
|
||||
|
||||
if (!responseBody.isEmpty())
|
||||
{
|
||||
Serial.println(
|
||||
"Svar fra API:");
|
||||
Serial.println(
|
||||
responseCode);
|
||||
}
|
||||
|
||||
Serial.println(
|
||||
responseBody);
|
||||
}
|
||||
if (!successful &&
|
||||
!responseBody.isEmpty())
|
||||
{
|
||||
Serial.println(
|
||||
"Svar fra API:");
|
||||
|
||||
Serial.println(
|
||||
responseBody);
|
||||
}
|
||||
|
||||
httpClient.end();
|
||||
|
||||
return successful;
|
||||
}
|
||||
|
||||
void apiWorkerTask(
|
||||
void*)
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
ApiRequest* request = nullptr;
|
||||
|
||||
if (xQueueReceive(
|
||||
apiQueue,
|
||||
&request,
|
||||
portMAX_DELAY) != pdTRUE)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (request == nullptr)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
postJson(
|
||||
*request);
|
||||
|
||||
delete request;
|
||||
}
|
||||
}
|
||||
|
||||
bool ensureApiWorkerStarted()
|
||||
{
|
||||
if (apiQueue != nullptr)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
apiQueue =
|
||||
xQueueCreate(
|
||||
ApiQueueLength,
|
||||
sizeof(ApiRequest*));
|
||||
|
||||
if (apiQueue == nullptr)
|
||||
{
|
||||
Serial.println(
|
||||
"API-koen kunne ikke oprettes.");
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
const BaseType_t taskCreated =
|
||||
xTaskCreate(
|
||||
apiWorkerTask,
|
||||
"filamentguard-api",
|
||||
ApiWorkerStackSize,
|
||||
nullptr,
|
||||
1,
|
||||
&apiWorkerHandle);
|
||||
|
||||
if (taskCreated != pdPASS)
|
||||
{
|
||||
Serial.println(
|
||||
"API-worker kunne ikke startes.");
|
||||
|
||||
vQueueDelete(
|
||||
apiQueue);
|
||||
|
||||
apiQueue = nullptr;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool enqueueJson(
|
||||
const char* endpointUrl,
|
||||
const String& json,
|
||||
const char* description,
|
||||
const bool reportSuccess = true)
|
||||
{
|
||||
if (json.isEmpty())
|
||||
{
|
||||
Serial.print(
|
||||
description);
|
||||
|
||||
Serial.println(
|
||||
" blev ikke lagt i ko: JSON-data er tomme.");
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!ensureApiWorkerStarted())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
ApiRequest* request =
|
||||
new (std::nothrow) ApiRequest;
|
||||
|
||||
if (request == nullptr)
|
||||
{
|
||||
Serial.println(
|
||||
"Der er ikke hukommelse til en API-anmodning.");
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
request->endpointUrl =
|
||||
endpointUrl;
|
||||
|
||||
request->json =
|
||||
json;
|
||||
|
||||
request->description =
|
||||
description;
|
||||
|
||||
request->reportSuccess =
|
||||
reportSuccess;
|
||||
|
||||
if (xQueueSend(
|
||||
apiQueue,
|
||||
&request,
|
||||
0) != pdTRUE)
|
||||
{
|
||||
Serial.println(
|
||||
"API-koen er fuld.");
|
||||
|
||||
delete request;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
bool FilamentGuardApiClient::sendTagRead(
|
||||
@@ -132,12 +264,23 @@ bool FilamentGuardApiClient::sendTagRead(
|
||||
int& responseCode,
|
||||
String& responseBody) const
|
||||
{
|
||||
return postJson(
|
||||
TagReadEndpointUrl,
|
||||
json,
|
||||
"tagregistrering",
|
||||
&responseCode,
|
||||
&responseBody);
|
||||
const bool queued =
|
||||
enqueueJson(
|
||||
TagReadEndpointUrl,
|
||||
json,
|
||||
"tagregistrering");
|
||||
|
||||
responseCode =
|
||||
queued
|
||||
? 202
|
||||
: 0;
|
||||
|
||||
responseBody =
|
||||
queued
|
||||
? "{\"queued\":true}"
|
||||
: "{\"queued\":false}";
|
||||
|
||||
return queued;
|
||||
}
|
||||
|
||||
bool FilamentGuardApiClient::sendTagEvent(
|
||||
@@ -145,19 +288,31 @@ bool FilamentGuardApiClient::sendTagEvent(
|
||||
int& responseCode,
|
||||
String& responseBody) const
|
||||
{
|
||||
return postJson(
|
||||
TagEventEndpointUrl,
|
||||
json,
|
||||
"tagfjernelse",
|
||||
&responseCode,
|
||||
&responseBody);
|
||||
const bool queued =
|
||||
enqueueJson(
|
||||
TagEventEndpointUrl,
|
||||
json,
|
||||
"tagfjernelse");
|
||||
|
||||
responseCode =
|
||||
queued
|
||||
? 202
|
||||
: 0;
|
||||
|
||||
responseBody =
|
||||
queued
|
||||
? "{\"queued\":true}"
|
||||
: "{\"queued\":false}";
|
||||
|
||||
return queued;
|
||||
}
|
||||
|
||||
bool FilamentGuardApiClient::sendLogEntry(
|
||||
const String& json) const
|
||||
{
|
||||
return postJson(
|
||||
return enqueueJson(
|
||||
LogEndpointUrl,
|
||||
json,
|
||||
"log");
|
||||
"log",
|
||||
false);
|
||||
}
|
||||
|
||||
@@ -9,6 +9,16 @@ String FilamentGuardTagReadSerializer::serialize(
|
||||
|
||||
json += '{';
|
||||
|
||||
json += "\"reader\":{";
|
||||
|
||||
appendStringProperty(
|
||||
json,
|
||||
"id",
|
||||
tagRead.readerId,
|
||||
false);
|
||||
|
||||
json += "},";
|
||||
|
||||
json += "\"device\":{";
|
||||
|
||||
appendStringProperty(
|
||||
@@ -232,4 +242,4 @@ void FilamentGuardTagReadSerializer::appendBooleanProperty(
|
||||
{
|
||||
json += ',';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@ namespace
|
||||
"filamentguard";
|
||||
|
||||
constexpr const char* FirmwareVersion =
|
||||
"1.0.1";
|
||||
"1.0.2";
|
||||
|
||||
constexpr const char* ManifestUrl =
|
||||
"https://ota-filamentguard.maximuss.dk/firmware/manifest.json";
|
||||
@@ -160,4 +160,4 @@ void FirmwareUpdater::checkForUpdate()
|
||||
"Downloader og installerer firmware.");
|
||||
|
||||
firmwareUpdate.execOTA();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,16 +2,42 @@
|
||||
|
||||
#include <cstring>
|
||||
|
||||
namespace
|
||||
{
|
||||
// Antal gange getInventory forsoeges pr. scan, foer vi giver op.
|
||||
// ISO15693 er slot-baseret og et enkelt scan kan sagtens misse
|
||||
// et svag-koblet tag i sit slot. Retries er standardpraksis.
|
||||
constexpr uint8_t MaxInventoryAttempts = 3;
|
||||
constexpr uint16_t InventoryRetryDelayMilliseconds = 10;
|
||||
|
||||
// Tid RF-feltet skal vaere aktivt foer inventory sendes, saa
|
||||
// passive tags naar at faa opladet deres kondensator.
|
||||
constexpr uint16_t RfSettleDelayMilliseconds = 20;
|
||||
|
||||
bool isValidIso15693Uid(
|
||||
const uint8_t* uid)
|
||||
{
|
||||
if (uid == nullptr)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// ISO15693-UID'er leveres LSB foerst af PN5180. Den sidste byte
|
||||
// skal derfor vaere ISO/IEC 15963-markoeren 0xE0. Kontrollen
|
||||
// afviser blandt andet bibliotekets falske nul-UID.
|
||||
return uid[7] == 0xE0;
|
||||
}
|
||||
}
|
||||
|
||||
Pn5180Reader::Pn5180Reader(
|
||||
FilamentGuardLogger& newLogger)
|
||||
FilamentGuardLogger& newLogger,
|
||||
const uint8_t nssPin,
|
||||
const uint8_t busyPin,
|
||||
const uint8_t resetPin)
|
||||
: iso15693Reader(
|
||||
NssPin,
|
||||
BusyPin,
|
||||
ResetPin),
|
||||
iso14443Reader(
|
||||
NssPin,
|
||||
BusyPin,
|
||||
ResetPin),
|
||||
nssPin,
|
||||
busyPin,
|
||||
resetPin),
|
||||
logger(newLogger)
|
||||
{
|
||||
}
|
||||
@@ -19,10 +45,66 @@ Pn5180Reader::Pn5180Reader(
|
||||
void Pn5180Reader::begin()
|
||||
{
|
||||
iso15693Reader.begin();
|
||||
iso14443Reader.begin();
|
||||
|
||||
iso15693Reader.reset();
|
||||
iso15693Reader.setupRF();
|
||||
|
||||
uint8_t dieIdentifier[16] = {};
|
||||
|
||||
if (!iso15693Reader.readEEprom(
|
||||
DIE_IDENTIFIER,
|
||||
dieIdentifier,
|
||||
sizeof(dieIdentifier)))
|
||||
{
|
||||
logger.error(
|
||||
"NfcReader",
|
||||
"PN5180 reader-ID kunne ikke laeses.");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
bool allZero = true;
|
||||
bool allOnes = true;
|
||||
|
||||
for (const uint8_t value :
|
||||
dieIdentifier)
|
||||
{
|
||||
allZero =
|
||||
allZero &&
|
||||
value == 0x00;
|
||||
|
||||
allOnes =
|
||||
allOnes &&
|
||||
value == 0xFF;
|
||||
}
|
||||
|
||||
if (allZero ||
|
||||
allOnes)
|
||||
{
|
||||
logger.error(
|
||||
"NfcReader",
|
||||
"PN5180 returnerede et ugyldigt reader-ID.");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
readerId.reserve(
|
||||
sizeof(dieIdentifier) *
|
||||
2);
|
||||
|
||||
for (const uint8_t value :
|
||||
dieIdentifier)
|
||||
{
|
||||
if (value < 0x10)
|
||||
{
|
||||
readerId += '0';
|
||||
}
|
||||
|
||||
readerId += String(
|
||||
value,
|
||||
HEX);
|
||||
}
|
||||
|
||||
readerId.toUpperCase();
|
||||
}
|
||||
|
||||
void Pn5180Reader::setDeviceInfo(
|
||||
@@ -68,7 +150,9 @@ void Pn5180Reader::printVersionInformation()
|
||||
}
|
||||
|
||||
const String versionData =
|
||||
String("{\"productVersion\":\"") +
|
||||
String("{\"readerId\":\"") +
|
||||
readerId +
|
||||
"\",\"productVersion\":\"" +
|
||||
productVersion[1] +
|
||||
"." +
|
||||
productVersion[0] +
|
||||
@@ -88,164 +172,149 @@ void Pn5180Reader::printVersionInformation()
|
||||
versionData);
|
||||
}
|
||||
|
||||
void Pn5180Reader::checkForTag()
|
||||
const String& Pn5180Reader::getReaderId() const
|
||||
{
|
||||
bool tagFound = false;
|
||||
|
||||
if (activeProtocol ==
|
||||
TagProtocol::Iso14443A)
|
||||
{
|
||||
tagFound =
|
||||
checkIso14443Tag();
|
||||
}
|
||||
else if (activeProtocol ==
|
||||
TagProtocol::Iso15693)
|
||||
{
|
||||
tagFound =
|
||||
checkIso15693Tag();
|
||||
}
|
||||
else
|
||||
{
|
||||
tagFound =
|
||||
checkIso14443Tag();
|
||||
|
||||
if (!tagFound)
|
||||
{
|
||||
tagFound =
|
||||
checkIso15693Tag();
|
||||
}
|
||||
}
|
||||
|
||||
if (tagFound)
|
||||
{
|
||||
missingScanCount = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
handleTagMissing();
|
||||
return readerId;
|
||||
}
|
||||
|
||||
bool Pn5180Reader::checkIso14443Tag()
|
||||
bool Pn5180Reader::scanForTag(
|
||||
uint8_t* uid,
|
||||
uint16_t& signalStrength)
|
||||
{
|
||||
uint8_t uid[10] = {};
|
||||
signalStrength = 0;
|
||||
|
||||
iso14443Reader.reset();
|
||||
iso14443Reader.setupRF();
|
||||
|
||||
if (!iso14443Reader.isCardPresent())
|
||||
if (uid == nullptr)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
const uint8_t uidLength =
|
||||
iso14443Reader.readCardSerial(
|
||||
uid);
|
||||
|
||||
if (uidLength == 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (activeProtocol ==
|
||||
TagProtocol::Iso14443A)
|
||||
{
|
||||
return isSameUid(
|
||||
uid,
|
||||
uidLength);
|
||||
}
|
||||
|
||||
if (activeProtocol !=
|
||||
TagProtocol::None)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
rememberUid(
|
||||
std::memset(
|
||||
uid,
|
||||
uidLength,
|
||||
TagProtocol::Iso14443A);
|
||||
0,
|
||||
8);
|
||||
|
||||
const String tagData =
|
||||
String("{\"protocol\":\"ISO14443A\",") +
|
||||
"\"tagUid\":\"" +
|
||||
formatUid(
|
||||
uid,
|
||||
uidLength,
|
||||
false) +
|
||||
"\"}";
|
||||
iso15693Reader.reset();
|
||||
|
||||
logger.info(
|
||||
"NfcReader",
|
||||
"ISO14443A-tag fundet.",
|
||||
tagData);
|
||||
const bool rfReady =
|
||||
iso15693Reader.setupRF();
|
||||
|
||||
if (rfReady)
|
||||
{
|
||||
// Giv det passive tag tid til at blive forsynet efter skiftet
|
||||
// mellem de to antenners RF-felter.
|
||||
delay(RfSettleDelayMilliseconds);
|
||||
}
|
||||
|
||||
const ISO15693ErrorCode result =
|
||||
rfReady
|
||||
? (performInventory(uid)
|
||||
? ISO15693_EC_OK
|
||||
: EC_NO_CARD)
|
||||
: ISO15693_EC_UNKNOWN_ERROR;
|
||||
|
||||
#if FILAMENT_GUARD_NFC_DIAGNOSTICS
|
||||
if (static_cast<long>(
|
||||
millis() -
|
||||
nextDiagnosticAt) >= 0)
|
||||
{
|
||||
nextDiagnosticAt =
|
||||
millis() +
|
||||
2000;
|
||||
|
||||
Serial.print(
|
||||
"[Debug] [NfcReader] readerId=");
|
||||
Serial.print(
|
||||
readerId);
|
||||
Serial.print(
|
||||
", rfReady=");
|
||||
Serial.print(
|
||||
rfReady
|
||||
? "true"
|
||||
: "false");
|
||||
Serial.print(
|
||||
", inventoryResult=");
|
||||
Serial.print(
|
||||
static_cast<int>(
|
||||
result));
|
||||
Serial.print(
|
||||
", rawUid=");
|
||||
|
||||
for (uint8_t index = 0;
|
||||
index < 8;
|
||||
++index)
|
||||
{
|
||||
if (uid[7 - index] < 0x10)
|
||||
{
|
||||
Serial.print('0');
|
||||
}
|
||||
|
||||
Serial.print(
|
||||
uid[7 - index],
|
||||
HEX);
|
||||
|
||||
if (index < 7)
|
||||
{
|
||||
Serial.print(':');
|
||||
}
|
||||
}
|
||||
|
||||
Serial.println();
|
||||
}
|
||||
#endif
|
||||
|
||||
if (result != ISO15693_EC_OK ||
|
||||
!isValidIso15693Uid(uid))
|
||||
{
|
||||
iso15693Reader.setRF_off();
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
uint32_t rfStatus = 0;
|
||||
|
||||
if (iso15693Reader.readRegister(
|
||||
RF_STATUS,
|
||||
&rfStatus))
|
||||
{
|
||||
signalStrength =
|
||||
static_cast<uint16_t>(
|
||||
rfStatus &
|
||||
0x03FF);
|
||||
}
|
||||
|
||||
iso15693Reader.setRF_off();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Pn5180Reader::checkIso15693Tag()
|
||||
bool Pn5180Reader::registerTag(
|
||||
const uint8_t* uid,
|
||||
const uint8_t uidLength)
|
||||
{
|
||||
uint8_t uid[8] = {};
|
||||
if (uid == nullptr ||
|
||||
uidLength != 8 ||
|
||||
!isValidIso15693Uid(uid) ||
|
||||
activeProtocol !=
|
||||
TagProtocol::None)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
iso15693Reader.reset();
|
||||
iso15693Reader.setupRF();
|
||||
|
||||
const ISO15693ErrorCode result =
|
||||
iso15693Reader.getInventory(
|
||||
uid);
|
||||
|
||||
if (result != ISO15693_EC_OK)
|
||||
if (!iso15693Reader.setupRF())
|
||||
{
|
||||
iso15693Reader.setRF_off();
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
constexpr uint8_t uidLength = 8;
|
||||
|
||||
if (activeProtocol ==
|
||||
TagProtocol::Iso15693)
|
||||
{
|
||||
return isSameUid(
|
||||
uid,
|
||||
uidLength);
|
||||
}
|
||||
|
||||
if (activeProtocol !=
|
||||
TagProtocol::None)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
uint8_t confirmedUid[uidLength] = {};
|
||||
|
||||
delay(20);
|
||||
|
||||
iso15693Reader.reset();
|
||||
iso15693Reader.setupRF();
|
||||
|
||||
const ISO15693ErrorCode confirmationResult =
|
||||
iso15693Reader.getInventory(
|
||||
confirmedUid);
|
||||
|
||||
if (confirmationResult !=
|
||||
ISO15693_EC_OK)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (std::memcmp(
|
||||
uid,
|
||||
confirmedUid,
|
||||
uidLength) != 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
rememberUid(
|
||||
uid,
|
||||
uidLength,
|
||||
TagProtocol::Iso15693);
|
||||
delay(RfSettleDelayMilliseconds);
|
||||
|
||||
const String tagData =
|
||||
String("{\"protocol\":\"ISO15693\",") +
|
||||
String("{\"readerId\":\"") +
|
||||
readerId +
|
||||
"\",\"protocol\":\"ISO15693\"," +
|
||||
"\"tagUid\":\"" +
|
||||
formatUid(
|
||||
uid,
|
||||
@@ -258,18 +327,60 @@ bool Pn5180Reader::checkIso15693Tag()
|
||||
"ISO15693-tag fundet.",
|
||||
tagData);
|
||||
|
||||
dumpIso15693Tag(
|
||||
if (!dumpIso15693Tag(
|
||||
uid,
|
||||
uidLength))
|
||||
{
|
||||
iso15693Reader.setRF_off();
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
rememberUid(
|
||||
uid,
|
||||
uidLength);
|
||||
uidLength,
|
||||
TagProtocol::Iso15693);
|
||||
|
||||
delay(50);
|
||||
|
||||
iso15693Reader.reset();
|
||||
iso15693Reader.setupRF();
|
||||
iso15693Reader.setRF_off();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Pn5180Reader::isActiveTag(
|
||||
const uint8_t* uid,
|
||||
const uint8_t uidLength) const
|
||||
{
|
||||
return activeProtocol ==
|
||||
TagProtocol::Iso15693 &&
|
||||
isSameUid(
|
||||
uid,
|
||||
uidLength);
|
||||
}
|
||||
|
||||
bool Pn5180Reader::hasActiveTag() const
|
||||
{
|
||||
return activeProtocol !=
|
||||
TagProtocol::None;
|
||||
}
|
||||
|
||||
void Pn5180Reader::markTagPresent()
|
||||
{
|
||||
missingScanCount = 0;
|
||||
}
|
||||
|
||||
bool Pn5180Reader::markTagMissing()
|
||||
{
|
||||
const bool wasActive =
|
||||
activeProtocol !=
|
||||
TagProtocol::None;
|
||||
|
||||
handleTagMissing();
|
||||
|
||||
return wasActive &&
|
||||
activeProtocol ==
|
||||
TagProtocol::None;
|
||||
}
|
||||
|
||||
void Pn5180Reader::handleTagMissing()
|
||||
{
|
||||
if (activeProtocol ==
|
||||
@@ -286,18 +397,16 @@ void Pn5180Reader::handleTagMissing()
|
||||
return;
|
||||
}
|
||||
|
||||
const bool reverseOrder =
|
||||
activeProtocol ==
|
||||
TagProtocol::Iso15693;
|
||||
|
||||
const String tagUid =
|
||||
formatUid(
|
||||
lastUid,
|
||||
lastUidLength,
|
||||
reverseOrder);
|
||||
true);
|
||||
|
||||
const String tagData =
|
||||
String("{\"tagUid\":\"") +
|
||||
String("{\"readerId\":\"") +
|
||||
readerId +
|
||||
"\",\"tagUid\":\"" +
|
||||
tagUid +
|
||||
"\"}";
|
||||
|
||||
@@ -307,7 +416,9 @@ void Pn5180Reader::handleTagMissing()
|
||||
tagData);
|
||||
|
||||
const String eventJson =
|
||||
String("{\"device\":{") +
|
||||
String("{\"reader\":{\"id\":\"") +
|
||||
readerId +
|
||||
"\"},\"device\":{" +
|
||||
"\"deviceId\":\"" +
|
||||
deviceInfo.deviceId +
|
||||
"\",\"hostname\":\"" +
|
||||
@@ -326,28 +437,274 @@ void Pn5180Reader::handleTagMissing()
|
||||
responseCode,
|
||||
responseBody);
|
||||
|
||||
const String responseMessage =
|
||||
String("Tag removed API-svar. HTTP-status: ") +
|
||||
responseCode;
|
||||
|
||||
if (successful)
|
||||
{
|
||||
logger.info(
|
||||
"Api",
|
||||
responseMessage,
|
||||
"Tagfjernelse lagt i API-ko.",
|
||||
responseBody);
|
||||
}
|
||||
else
|
||||
{
|
||||
logger.error(
|
||||
"Api",
|
||||
responseMessage,
|
||||
"Tagfjernelse kunne ikke laegges i API-ko.",
|
||||
responseBody);
|
||||
}
|
||||
|
||||
clearLastUid();
|
||||
}
|
||||
|
||||
bool Pn5180Reader::performInventory(
|
||||
uint8_t* uid)
|
||||
{
|
||||
if (uid == nullptr)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
ISO15693ErrorCode lastResult =
|
||||
ISO15693_EC_UNKNOWN_ERROR;
|
||||
|
||||
for (uint8_t attempt = 0;
|
||||
attempt < MaxInventoryAttempts;
|
||||
++attempt)
|
||||
{
|
||||
std::memset(
|
||||
uid,
|
||||
0,
|
||||
8);
|
||||
|
||||
lastResult =
|
||||
iso15693Reader.getInventory(
|
||||
uid);
|
||||
|
||||
if (lastResult == ISO15693_EC_OK &&
|
||||
isValidIso15693Uid(uid))
|
||||
{
|
||||
#if FILAMENT_GUARD_NFC_DIAGNOSTICS
|
||||
if (attempt > 0)
|
||||
{
|
||||
Serial.print(
|
||||
"[Debug] [NfcReader] readerId=");
|
||||
Serial.print(
|
||||
readerId);
|
||||
Serial.print(
|
||||
", inventory succeeded on attempt ");
|
||||
Serial.println(
|
||||
attempt + 1);
|
||||
}
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
if (attempt + 1 < MaxInventoryAttempts)
|
||||
{
|
||||
delay(InventoryRetryDelayMilliseconds);
|
||||
}
|
||||
}
|
||||
|
||||
#if FILAMENT_GUARD_NFC_DIAGNOSTICS
|
||||
if (lastResult != EC_NO_CARD)
|
||||
{
|
||||
Serial.print(
|
||||
"[Debug] [NfcReader] readerId=");
|
||||
Serial.print(
|
||||
readerId);
|
||||
Serial.print(
|
||||
", inventory failed after ");
|
||||
Serial.print(
|
||||
MaxInventoryAttempts);
|
||||
Serial.print(
|
||||
" attempts, lastResult=");
|
||||
Serial.println(
|
||||
static_cast<int>(lastResult));
|
||||
}
|
||||
#endif
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Pn5180Reader::readIso15693BlockRange(
|
||||
const uint8_t* uid,
|
||||
const uint8_t firstBlock,
|
||||
const uint8_t blockCount,
|
||||
uint8_t* blockData,
|
||||
const uint8_t blockSize)
|
||||
{
|
||||
constexpr uint8_t maximumBlocksPerRequest = 8;
|
||||
constexpr uint16_t maximumResponseLength =
|
||||
1 +
|
||||
maximumBlocksPerRequest *
|
||||
4 +
|
||||
2;
|
||||
constexpr uint32_t receiveErrorMask =
|
||||
(1UL << 16) |
|
||||
(1UL << 17) |
|
||||
(1UL << 18);
|
||||
|
||||
if (uid == nullptr ||
|
||||
blockData == nullptr ||
|
||||
blockCount == 0 ||
|
||||
blockCount >
|
||||
maximumBlocksPerRequest ||
|
||||
blockSize != 4)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
uint8_t command[12] =
|
||||
{
|
||||
0x22,
|
||||
static_cast<uint8_t>(
|
||||
blockCount == 1
|
||||
? 0x20
|
||||
: 0x23),
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
firstBlock,
|
||||
static_cast<uint8_t>(
|
||||
blockCount - 1)
|
||||
};
|
||||
|
||||
std::memcpy(
|
||||
command + 2,
|
||||
uid,
|
||||
8);
|
||||
|
||||
const uint8_t commandLength =
|
||||
blockCount == 1
|
||||
? 11
|
||||
: 12;
|
||||
|
||||
if (!iso15693Reader.clearIRQStatus(
|
||||
0xFFFFFFFF) ||
|
||||
!iso15693Reader.sendData(
|
||||
command,
|
||||
commandLength))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
const unsigned long startedWaiting =
|
||||
millis();
|
||||
uint32_t irqStatus = 0;
|
||||
|
||||
do
|
||||
{
|
||||
irqStatus = 0;
|
||||
|
||||
if (!iso15693Reader.readRegister(
|
||||
IRQ_STATUS,
|
||||
&irqStatus))
|
||||
{
|
||||
iso15693Reader.clearIRQStatus(
|
||||
0xFFFFFFFF);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if ((irqStatus &
|
||||
GENERAL_ERROR_IRQ_STAT) != 0)
|
||||
{
|
||||
iso15693Reader.clearIRQStatus(
|
||||
0xFFFFFFFF);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if ((irqStatus &
|
||||
RX_IRQ_STAT) != 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
delay(1);
|
||||
}
|
||||
while (millis() -
|
||||
startedWaiting <
|
||||
150);
|
||||
|
||||
if ((irqStatus &
|
||||
RX_IRQ_STAT) == 0 ||
|
||||
(irqStatus &
|
||||
RX_SOF_DET_IRQ_STAT) == 0)
|
||||
{
|
||||
iso15693Reader.clearIRQStatus(
|
||||
0xFFFFFFFF);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
uint32_t rxStatus = 0;
|
||||
|
||||
if (!iso15693Reader.readRegister(
|
||||
RX_STATUS,
|
||||
&rxStatus) ||
|
||||
(rxStatus &
|
||||
receiveErrorMask) != 0)
|
||||
{
|
||||
iso15693Reader.clearIRQStatus(
|
||||
0xFFFFFFFF);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
const uint16_t responseLength =
|
||||
static_cast<uint16_t>(
|
||||
rxStatus &
|
||||
0x01FF);
|
||||
const uint16_t dataLength =
|
||||
static_cast<uint16_t>(
|
||||
blockCount) *
|
||||
blockSize;
|
||||
const uint16_t minimumResponseLength =
|
||||
1 +
|
||||
dataLength;
|
||||
|
||||
if (responseLength <
|
||||
minimumResponseLength ||
|
||||
responseLength >
|
||||
minimumResponseLength +
|
||||
2 ||
|
||||
responseLength >
|
||||
maximumResponseLength)
|
||||
{
|
||||
iso15693Reader.clearIRQStatus(
|
||||
0xFFFFFFFF);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
uint8_t response[
|
||||
maximumResponseLength] = {};
|
||||
|
||||
if (!iso15693Reader.readData(
|
||||
responseLength,
|
||||
response))
|
||||
{
|
||||
iso15693Reader.clearIRQStatus(
|
||||
0xFFFFFFFF);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
iso15693Reader.clearIRQStatus(
|
||||
0xFFFFFFFF);
|
||||
|
||||
if ((response[0] &
|
||||
0x01) != 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
std::memcpy(
|
||||
blockData,
|
||||
response + 1,
|
||||
dataLength);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Pn5180Reader::isSameUid(
|
||||
const uint8_t* uid,
|
||||
const uint8_t uidLength) const
|
||||
@@ -461,8 +818,8 @@ String Pn5180Reader::formatUid(
|
||||
return result;
|
||||
}
|
||||
|
||||
void Pn5180Reader::dumpIso15693Tag(
|
||||
uint8_t* uid,
|
||||
bool Pn5180Reader::dumpIso15693Tag(
|
||||
const uint8_t* uid,
|
||||
const uint8_t uidLength)
|
||||
{
|
||||
constexpr uint8_t blockSize = 4;
|
||||
@@ -474,8 +831,6 @@ void Pn5180Reader::dumpIso15693Tag(
|
||||
numberOfBlocks;
|
||||
|
||||
uint8_t memory[memorySize] = {};
|
||||
bool allBlocksRead = true;
|
||||
|
||||
const String memoryData =
|
||||
String("{\"blockSizeBytes\":") +
|
||||
blockSize +
|
||||
@@ -490,50 +845,63 @@ void Pn5180Reader::dumpIso15693Tag(
|
||||
"Laeser ISO15693-hukommelse.",
|
||||
memoryData);
|
||||
|
||||
for (uint8_t blockNumber = 0;
|
||||
blockNumber < numberOfBlocks;
|
||||
++blockNumber)
|
||||
constexpr uint8_t blocksPerRequest = 8;
|
||||
|
||||
for (uint8_t firstBlock = 0;
|
||||
firstBlock < numberOfBlocks;
|
||||
firstBlock += blocksPerRequest)
|
||||
{
|
||||
uint8_t* blockData =
|
||||
uint8_t* destination =
|
||||
memory +
|
||||
static_cast<size_t>(
|
||||
blockNumber) *
|
||||
firstBlock) *
|
||||
blockSize;
|
||||
|
||||
const ISO15693ErrorCode readResult =
|
||||
iso15693Reader.readSingleBlock(
|
||||
if (readIso15693BlockRange(
|
||||
uid,
|
||||
blockNumber,
|
||||
blockData,
|
||||
blockSize);
|
||||
|
||||
if (readResult !=
|
||||
ISO15693_EC_OK)
|
||||
firstBlock,
|
||||
blocksPerRequest,
|
||||
destination,
|
||||
blockSize))
|
||||
{
|
||||
allBlocksRead = false;
|
||||
|
||||
const String errorData =
|
||||
String("{\"blockNumber\":") +
|
||||
blockNumber +
|
||||
",\"errorCode\":" +
|
||||
static_cast<int>(
|
||||
readResult) +
|
||||
"}";
|
||||
|
||||
logger.error(
|
||||
"NfcReader",
|
||||
"ISO15693-blok kunne ikke laeses.",
|
||||
errorData);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (!allBlocksRead)
|
||||
{
|
||||
logger.error(
|
||||
"NfcReader",
|
||||
"OpenPrintTag-parseren blev ikke startet, fordi en eller flere blokke ikke kunne laeses.");
|
||||
for (uint8_t offset = 0;
|
||||
offset < blocksPerRequest;
|
||||
++offset)
|
||||
{
|
||||
const uint8_t blockNumber =
|
||||
firstBlock +
|
||||
offset;
|
||||
|
||||
return;
|
||||
if (!readIso15693BlockRange(
|
||||
uid,
|
||||
blockNumber,
|
||||
1,
|
||||
memory +
|
||||
static_cast<size_t>(
|
||||
blockNumber) *
|
||||
blockSize,
|
||||
blockSize))
|
||||
{
|
||||
const String errorData =
|
||||
String("{\"blockNumber\":") +
|
||||
blockNumber +
|
||||
"}";
|
||||
|
||||
logger.error(
|
||||
"NfcReader",
|
||||
"ISO15693-blok kunne ikke laeses.",
|
||||
errorData);
|
||||
|
||||
logger.error(
|
||||
"NfcReader",
|
||||
"OpenPrintTag-parseren blev ikke startet, fordi hukommelsen ikke kunne laeses komplet.");
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
logger.info(
|
||||
@@ -551,7 +919,7 @@ void Pn5180Reader::dumpIso15693Tag(
|
||||
"NfcReader",
|
||||
"OpenPrintTag-data kunne ikke fortolkes.");
|
||||
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
openPrintTagData.tagUid =
|
||||
@@ -562,6 +930,9 @@ void Pn5180Reader::dumpIso15693Tag(
|
||||
|
||||
FilamentGuardTagRead tagRead;
|
||||
|
||||
tagRead.readerId =
|
||||
readerId;
|
||||
|
||||
tagRead.device =
|
||||
deviceInfo;
|
||||
|
||||
@@ -573,6 +944,8 @@ void Pn5180Reader::dumpIso15693Tag(
|
||||
|
||||
sendTagRead(
|
||||
tagRead);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void Pn5180Reader::logTagRead(
|
||||
@@ -604,22 +977,18 @@ void Pn5180Reader::sendTagRead(
|
||||
responseCode,
|
||||
responseBody);
|
||||
|
||||
const String message =
|
||||
String("Tag detected API-svar. HTTP-status: ") +
|
||||
responseCode;
|
||||
|
||||
if (successful)
|
||||
{
|
||||
logger.info(
|
||||
"Api",
|
||||
message,
|
||||
"Tagregistrering lagt i API-ko.",
|
||||
responseBody);
|
||||
}
|
||||
else
|
||||
{
|
||||
logger.error(
|
||||
"Api",
|
||||
message,
|
||||
"Tagregistrering kunne ikke laegges i API-ko.",
|
||||
responseBody);
|
||||
}
|
||||
}
|
||||
|
||||
252
src/main.cpp
252
src/main.cpp
@@ -11,7 +11,57 @@
|
||||
namespace
|
||||
{
|
||||
constexpr const char* FirmwareVersion =
|
||||
"1.0.1";
|
||||
"1.0.2";
|
||||
|
||||
constexpr uint8_t UidLength = 8;
|
||||
|
||||
struct ReaderPins
|
||||
{
|
||||
uint8_t nssPin;
|
||||
uint8_t busyPin;
|
||||
uint8_t resetPin;
|
||||
};
|
||||
|
||||
// Pin-tabel for alle PN5180-laesere. Hver raekke er \u00e9n laeser
|
||||
// (NSS, BUSY, RESET). For at tilfoeje/fjerne en laeser: aendr denne
|
||||
// liste OG readers[]-instansen nedenfor tilsvarende.
|
||||
// Faelles SPI-bus: SCK=18, MISO=19, MOSI=23.
|
||||
constexpr ReaderPins readerPins[] =
|
||||
{
|
||||
{ 5, 16, 17 }, // Reader 1
|
||||
{ 27, 26, 25 }, // Reader 2
|
||||
// Forbered til indx-8 (4 laesere) - aktiver n\u00e5r hardwaren er klar:
|
||||
// { 32, 33, 4 }, // Reader 3
|
||||
// { 14, 13, 21 }, // Reader 4
|
||||
};
|
||||
|
||||
constexpr size_t ReaderCount =
|
||||
sizeof(readerPins) /
|
||||
sizeof(readerPins[0]);
|
||||
|
||||
void prepareReaderPins(
|
||||
const ReaderPins& pins)
|
||||
{
|
||||
pinMode(
|
||||
pins.nssPin,
|
||||
OUTPUT);
|
||||
|
||||
digitalWrite(
|
||||
pins.nssPin,
|
||||
HIGH);
|
||||
|
||||
pinMode(
|
||||
pins.busyPin,
|
||||
INPUT);
|
||||
|
||||
pinMode(
|
||||
pins.resetPin,
|
||||
OUTPUT);
|
||||
|
||||
digitalWrite(
|
||||
pins.resetPin,
|
||||
HIGH);
|
||||
}
|
||||
}
|
||||
|
||||
FilamentGuardLogger logger;
|
||||
@@ -22,7 +72,15 @@ DeviceIdentity deviceIdentity;
|
||||
WifiSetup wifiSetup(logger);
|
||||
FirmwareUpdater firmwareUpdater(logger);
|
||||
|
||||
Pn5180Reader pn5180Reader(logger);
|
||||
// PN5180-instanser. Antal og indeks skal matche readerPins[] ovenfor.
|
||||
// Tilfoej/fjern raekker parallelt med readerPins for at aendre antal laesere.
|
||||
Pn5180Reader readers[ReaderCount] =
|
||||
{
|
||||
{ logger, readerPins[0].nssPin, readerPins[0].busyPin, readerPins[0].resetPin },
|
||||
{ logger, readerPins[1].nssPin, readerPins[1].busyPin, readerPins[1].resetPin },
|
||||
// { logger, readerPins[2].nssPin, readerPins[2].busyPin, readerPins[2].resetPin },
|
||||
// { logger, readerPins[3].nssPin, readerPins[3].busyPin, readerPins[3].resetPin },
|
||||
};
|
||||
|
||||
FilamentGuardDeviceInfo deviceInfo;
|
||||
|
||||
@@ -43,10 +101,44 @@ void setup()
|
||||
|
||||
logger.info(
|
||||
"NfcReader",
|
||||
"Initialiserer PN5180.");
|
||||
String("Initialiserer ") +
|
||||
ReaderCount +
|
||||
" PN5180-laesere.");
|
||||
|
||||
pn5180Reader.begin();
|
||||
pn5180Reader.printVersionInformation();
|
||||
// Deaktiver alle moduler, foer den faelles SPI-bus startes. Ellers kan
|
||||
// et endnu ikke initialiseret modul svare samtidig med det aktive modul.
|
||||
for (size_t index = 0;
|
||||
index < ReaderCount;
|
||||
++index)
|
||||
{
|
||||
prepareReaderPins(
|
||||
readerPins[index]);
|
||||
}
|
||||
|
||||
for (size_t index = 0;
|
||||
index < ReaderCount;
|
||||
++index)
|
||||
{
|
||||
const String readerLabel =
|
||||
String("PN5180 nr. ") +
|
||||
(index + 1);
|
||||
|
||||
logger.info(
|
||||
"NfcReader",
|
||||
String("Initialiserer ") +
|
||||
readerLabel +
|
||||
".");
|
||||
|
||||
readers[index].begin();
|
||||
|
||||
logger.info(
|
||||
"NfcReader",
|
||||
String("Laeser versionsoplysninger fra ") +
|
||||
readerLabel +
|
||||
".");
|
||||
|
||||
readers[index].printVersionInformation();
|
||||
}
|
||||
|
||||
const String hostname =
|
||||
deviceSettings.getOrCreateHostname();
|
||||
@@ -58,8 +150,13 @@ void setup()
|
||||
logger.setDeviceInfo(
|
||||
deviceInfo);
|
||||
|
||||
pn5180Reader.setDeviceInfo(
|
||||
deviceInfo);
|
||||
for (size_t index = 0;
|
||||
index < ReaderCount;
|
||||
++index)
|
||||
{
|
||||
readers[index].setDeviceInfo(
|
||||
deviceInfo);
|
||||
}
|
||||
|
||||
const String deviceData =
|
||||
String("{\"deviceId\":\"") +
|
||||
@@ -91,13 +188,148 @@ void setup()
|
||||
|
||||
logger.info(
|
||||
"NfcReader",
|
||||
"Klar til at laese ISO15693-tags.");
|
||||
String("Alle ") +
|
||||
ReaderCount +
|
||||
" PN5180-laesere er klar.");
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
pn5180Reader.checkForTag();
|
||||
// Scan alle readers hver cyklus \u2014 hver reader arbejder uafhaengigt.
|
||||
// Multi-reader use case (fx indx-8): hver spole-position skal kunne
|
||||
// have sit eget tag samtidig.
|
||||
uint8_t uids[ReaderCount][UidLength] = {};
|
||||
uint16_t signalStrengths[ReaderCount] = {};
|
||||
bool tagFound[ReaderCount] = {};
|
||||
|
||||
for (size_t index = 0;
|
||||
index < ReaderCount;
|
||||
++index)
|
||||
{
|
||||
tagFound[index] =
|
||||
readers[index].scanForTag(
|
||||
uids[index],
|
||||
signalStrengths[index]);
|
||||
}
|
||||
|
||||
// Fase 1: For hver reader med en aktiv tag, opdater tilstedevaerelsen.
|
||||
for (size_t index = 0;
|
||||
index < ReaderCount;
|
||||
++index)
|
||||
{
|
||||
if (!readers[index].hasActiveTag())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (tagFound[index] &&
|
||||
readers[index].isActiveTag(
|
||||
uids[index],
|
||||
UidLength))
|
||||
{
|
||||
readers[index].markTagPresent();
|
||||
}
|
||||
else
|
||||
{
|
||||
readers[index].markTagMissing();
|
||||
}
|
||||
}
|
||||
|
||||
// Fase 2: For readers UDEN aktiv tag der fandt en tag, vaelg den
|
||||
// med hoejest signalstyrke og registrer der. Undg\u00e5 UIDs der allerede
|
||||
// er aktive p\u00e5 en anden reader (samme tag i overlappende felter).
|
||||
int selectedIndex = -1;
|
||||
uint16_t bestSignal = 0;
|
||||
|
||||
for (size_t index = 0;
|
||||
index < ReaderCount;
|
||||
++index)
|
||||
{
|
||||
if (readers[index].hasActiveTag())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!tagFound[index])
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
bool alreadyActiveElsewhere = false;
|
||||
|
||||
for (size_t other = 0;
|
||||
other < ReaderCount;
|
||||
++other)
|
||||
{
|
||||
if (other == index)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (readers[other].isActiveTag(
|
||||
uids[index],
|
||||
UidLength))
|
||||
{
|
||||
alreadyActiveElsewhere = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (alreadyActiveElsewhere)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (signalStrengths[index] >= bestSignal)
|
||||
{
|
||||
bestSignal =
|
||||
signalStrengths[index];
|
||||
|
||||
selectedIndex =
|
||||
static_cast<int>(index);
|
||||
}
|
||||
}
|
||||
|
||||
if (selectedIndex >= 0)
|
||||
{
|
||||
String selectionData =
|
||||
String("{\"selectedReaderId\":\"") +
|
||||
readers[selectedIndex].getReaderId() +
|
||||
"\",\"readers\":[";
|
||||
|
||||
for (size_t index = 0;
|
||||
index < ReaderCount;
|
||||
++index)
|
||||
{
|
||||
if (index > 0)
|
||||
{
|
||||
selectionData += ",";
|
||||
}
|
||||
|
||||
selectionData += "{\"index\":";
|
||||
selectionData += index + 1;
|
||||
selectionData += ",\"found\":";
|
||||
selectionData += tagFound[index]
|
||||
? "true"
|
||||
: "false";
|
||||
selectionData += ",\"agc\":";
|
||||
selectionData += signalStrengths[index];
|
||||
selectionData += "}";
|
||||
}
|
||||
|
||||
selectionData += "]}";
|
||||
|
||||
logger.info(
|
||||
"NfcReader",
|
||||
"Naermeste PN5180-laeser valgt.",
|
||||
selectionData);
|
||||
|
||||
readers[selectedIndex].registerTag(
|
||||
uids[selectedIndex],
|
||||
UidLength);
|
||||
}
|
||||
|
||||
logger.process();
|
||||
|
||||
delay(200);
|
||||
}
|
||||
}
|
||||
|
||||
130
src/pn5180_probe.cpp
Normal file
130
src/pn5180_probe.cpp
Normal file
@@ -0,0 +1,130 @@
|
||||
#include <Arduino.h>
|
||||
#include <PN5180ISO15693.h>
|
||||
|
||||
#ifndef PN5180_PROBE_READER
|
||||
#define PN5180_PROBE_READER 1
|
||||
#endif
|
||||
|
||||
namespace
|
||||
{
|
||||
constexpr uint8_t Reader1NssPin = 5;
|
||||
constexpr uint8_t Reader1BusyPin = 16;
|
||||
constexpr uint8_t Reader1ResetPin = 17;
|
||||
|
||||
constexpr uint8_t Reader2NssPin = 27;
|
||||
constexpr uint8_t Reader2BusyPin = 26;
|
||||
constexpr uint8_t Reader2ResetPin = 25;
|
||||
|
||||
#if PN5180_PROBE_READER == 1
|
||||
PN5180ISO15693 reader(
|
||||
Reader1NssPin,
|
||||
Reader1BusyPin,
|
||||
Reader1ResetPin);
|
||||
#else
|
||||
PN5180ISO15693 reader(
|
||||
Reader2NssPin,
|
||||
Reader2BusyPin,
|
||||
Reader2ResetPin);
|
||||
#endif
|
||||
|
||||
void printUid(
|
||||
const uint8_t* uid)
|
||||
{
|
||||
for (int8_t index = 7;
|
||||
index >= 0;
|
||||
--index)
|
||||
{
|
||||
if (uid[index] < 0x10)
|
||||
{
|
||||
Serial.print('0');
|
||||
}
|
||||
|
||||
Serial.print(
|
||||
uid[index],
|
||||
HEX);
|
||||
|
||||
if (index > 0)
|
||||
{
|
||||
Serial.print(':');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void setup()
|
||||
{
|
||||
Serial.begin(115200);
|
||||
delay(1000);
|
||||
|
||||
Serial.println();
|
||||
Serial.print(
|
||||
"[Probe] Starter isoleret PN5180 reader ");
|
||||
Serial.println(
|
||||
PN5180_PROBE_READER);
|
||||
|
||||
reader.begin();
|
||||
reader.reset();
|
||||
|
||||
uint8_t productVersion[2] = {};
|
||||
|
||||
if (reader.readEEprom(
|
||||
PRODUCT_VERSION,
|
||||
productVersion,
|
||||
sizeof(productVersion)))
|
||||
{
|
||||
Serial.print(
|
||||
"[Probe] PN5180 svarer. Produktversion: ");
|
||||
Serial.print(
|
||||
productVersion[1]);
|
||||
Serial.print('.');
|
||||
Serial.println(
|
||||
productVersion[0]);
|
||||
}
|
||||
else
|
||||
{
|
||||
Serial.println(
|
||||
"[Probe] FEJL: PN5180 svarer ikke paa SPI.");
|
||||
}
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
uint8_t uid[8] = {};
|
||||
|
||||
reader.reset();
|
||||
|
||||
if (!reader.setupRF())
|
||||
{
|
||||
Serial.println(
|
||||
"[Probe] FEJL: RF kunne ikke startes.");
|
||||
delay(1000);
|
||||
return;
|
||||
}
|
||||
|
||||
delay(20);
|
||||
|
||||
const ISO15693ErrorCode result =
|
||||
reader.getInventory(
|
||||
uid);
|
||||
|
||||
reader.setRF_off();
|
||||
|
||||
if (result == ISO15693_EC_OK)
|
||||
{
|
||||
Serial.print(
|
||||
"[Probe] TAG FUNDET: ");
|
||||
printUid(
|
||||
uid);
|
||||
Serial.println();
|
||||
}
|
||||
else
|
||||
{
|
||||
Serial.print(
|
||||
"[Probe] Intet tag. Fejlkode: ");
|
||||
Serial.println(
|
||||
static_cast<int>(
|
||||
result));
|
||||
}
|
||||
|
||||
delay(500);
|
||||
}
|
||||
121
tools/test-api.ps1
Normal file
121
tools/test-api.ps1
Normal file
@@ -0,0 +1,121 @@
|
||||
param(
|
||||
[string]$BaseUrl = "http://192.168.3.2:9090"
|
||||
)
|
||||
|
||||
$ErrorActionPreference = "Stop"
|
||||
|
||||
function Invoke-FilamentGuardPost {
|
||||
param(
|
||||
[Parameter(Mandatory)]
|
||||
[string]$Name,
|
||||
|
||||
[Parameter(Mandatory)]
|
||||
[string]$Path,
|
||||
|
||||
[Parameter(Mandatory)]
|
||||
[object]$Payload
|
||||
)
|
||||
|
||||
$url = $BaseUrl.TrimEnd("/") + $Path
|
||||
$json = $Payload | ConvertTo-Json -Depth 10 -Compress
|
||||
|
||||
Write-Host ""
|
||||
Write-Host "=== $Name ===" -ForegroundColor Cyan
|
||||
Write-Host "POST $url"
|
||||
Write-Host $json
|
||||
|
||||
try {
|
||||
$response = Invoke-WebRequest `
|
||||
-Uri $url `
|
||||
-Method Post `
|
||||
-ContentType "application/json; charset=utf-8" `
|
||||
-Body $json `
|
||||
-UseBasicParsing
|
||||
|
||||
Write-Host "HTTP $([int]$response.StatusCode)" -ForegroundColor Green
|
||||
|
||||
if ($response.Content) {
|
||||
Write-Host $response.Content
|
||||
}
|
||||
}
|
||||
catch {
|
||||
$statusCode = 0
|
||||
$responseBody = ""
|
||||
|
||||
if ($_.Exception.Response) {
|
||||
$statusCode = [int]$_.Exception.Response.StatusCode
|
||||
|
||||
try {
|
||||
$stream = $_.Exception.Response.GetResponseStream()
|
||||
$reader = [System.IO.StreamReader]::new($stream)
|
||||
$responseBody = $reader.ReadToEnd()
|
||||
$reader.Dispose()
|
||||
}
|
||||
catch {
|
||||
$responseBody = ""
|
||||
}
|
||||
}
|
||||
|
||||
Write-Host "HTTP $statusCode" -ForegroundColor Red
|
||||
|
||||
if ($responseBody) {
|
||||
Write-Host $responseBody
|
||||
}
|
||||
else {
|
||||
Write-Host $_.Exception.Message
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$deviceId = "ESP32-API-TEST"
|
||||
$hostname = "filamentguard-api-test"
|
||||
$tagUid = "E0:04:01:23:45:67:89:AB"
|
||||
|
||||
$tagRead = @{
|
||||
reader = @{
|
||||
id = "00112233445566778899AABBCCDDEEFF"
|
||||
}
|
||||
device = @{
|
||||
deviceId = $deviceId
|
||||
hostname = $hostname
|
||||
}
|
||||
tag = @{
|
||||
tagUid = $tagUid
|
||||
instanceUuid = "00000000-0000-0000-0000-000000000001"
|
||||
materialName = "API test PLA"
|
||||
materialType = "PLA"
|
||||
brand = "Test"
|
||||
colorHex = "#FF0000"
|
||||
actualWeightGrams = 1000
|
||||
nominalWeightGrams = 1000
|
||||
spoolWeightGrams = 200
|
||||
consumedWeightGrams = 0
|
||||
remainingWeightGrams = 1000
|
||||
hasActualWeight = $true
|
||||
hasNominalWeight = $true
|
||||
hasSpoolWeight = $true
|
||||
hasConsumedWeight = $true
|
||||
}
|
||||
}
|
||||
|
||||
$logEntry = @{
|
||||
deviceId = $deviceId
|
||||
hostname = $hostname
|
||||
firmwareVersion = "1.0.2"
|
||||
level = "Info"
|
||||
category = "ApiTest"
|
||||
message = "Ekstern API-test"
|
||||
data = '{"source":"test-api.ps1"}'
|
||||
tagUid = $tagUid
|
||||
uptimeMilliseconds = 12345
|
||||
}
|
||||
|
||||
Invoke-FilamentGuardPost `
|
||||
-Name "Tagregistrering" `
|
||||
-Path "/api/Tag/detected" `
|
||||
-Payload $tagRead
|
||||
|
||||
Invoke-FilamentGuardPost `
|
||||
-Name "Logoprettelse" `
|
||||
-Path "/api/Log/create" `
|
||||
-Payload $logEntry
|
||||
Reference in New Issue
Block a user