Add extracted tools: CitrineOS, OpenOCPP, ShapeShifter

- CitrineOS core extracted (CSMS OCPP 2.0.1)
- OpenOCPP extracted (firmware OCPP 1.6J/2.0.1)
- ShapeShifter library installed (pip install -e)
- ShapeShifter specification extracted
- EVerest extracted

TODO updated with progress
This commit is contained in:
Eric F
2026-06-08 00:38:27 -04:00
parent 468cfeaa50
commit d398a6ced2
7326 changed files with 1177561 additions and 7 deletions

View File

@@ -0,0 +1,6 @@
ev_add_module(NxpNfcFrontendTokenProvider)
ev_add_module(PN532TokenProvider)
if(EVEREST_DEPENDENCY_ENABLED_LIBNFC_NCI)
ev_add_module(PN7160TokenProvider)
endif()

View File

@@ -0,0 +1,47 @@
#
# AUTO GENERATED - MARKED REGIONS WILL BE KEPT
# template version 3
#
# module setup:
# - ${MODULE_NAME}: module name
ev_setup_cpp_module()
# ev@bcc62523-e22b-41d7-ba2f-825b493a3c97:v1
set(EXTERNAL_NXPNFCRDLIB_ZIP_PATH_${MODULE_NAME} "" CACHE PATH "Set the path to NxpNfcRdLib_Linux_v07.10.00_PUB.zip to enable building the wrapper.")
target_include_directories(${MODULE_NAME}
PRIVATE
include/
)
target_link_libraries(${MODULE_NAME}
PRIVATE
everest::helpers)
# Use either the named pipe implementation as source, or the real-hardware-interfacing NxpNfcFrontend class
if(EXTERNAL_NXPNFCRDLIB_ZIP_PATH_${MODULE_NAME} AND EXISTS "${EXTERNAL_NXPNFCRDLIB_ZIP_PATH_${MODULE_NAME}}")
set(EXTERNAL_NXPNFCRDLIB_ZIP_PATH "${EXTERNAL_NXPNFCRDLIB_ZIP_PATH_${MODULE_NAME}}")
add_subdirectory(nxpnfcrdlib_wrapper)
target_link_libraries(${MODULE_NAME} PRIVATE NxpNfcFrontend)
else()
add_library(namedPipeDataSource)
target_sources(namedPipeDataSource PRIVATE namedPipeDataSource/namedPipeDataSource.cpp)
target_link_libraries(${MODULE_NAME} PRIVATE namedPipeDataSource)
target_include_directories(namedPipeDataSource PUBLIC ${CMAKE_CURRENT_LIST_DIR}/namedPipeDataSource/)
target_compile_definitions(${MODULE_NAME} PRIVATE BUILD_WITH_NAMED_PIPE_DATASOURCE)
endif()
# ev@bcc62523-e22b-41d7-ba2f-825b493a3c97:v1
target_sources(${MODULE_NAME}
PRIVATE
"main/auth_token_providerImpl.cpp"
)
# ev@c55432ab-152c-45a9-9d2e-7281d50c69c3:v1
# insert other things like install cmds etc here
# ev@c55432ab-152c-45a9-9d2e-7281d50c69c3:v1

View File

@@ -0,0 +1,16 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright 2020 - 2025 Pionix GmbH and Contributors to EVerest
#include "NxpNfcFrontendTokenProvider.hpp"
namespace module {
void NxpNfcFrontendTokenProvider::init() {
invoke_init(*p_main);
}
void NxpNfcFrontendTokenProvider::ready() {
invoke_ready(*p_main);
}
} // namespace module

View File

@@ -0,0 +1,59 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright 2020 - 2025 Pionix GmbH and Contributors to EVerest
#ifndef NXP_NFC_FRONTEND_TOKEN_PROVIDER_HPP
#define NXP_NFC_FRONTEND_TOKEN_PROVIDER_HPP
//
// AUTO GENERATED - MARKED REGIONS WILL BE KEPT
// template version 2
//
#include "ld-ev.hpp"
// headers for provided interface implementations
#include <generated/interfaces/auth_token_provider/Implementation.hpp>
// ev@4bf81b14-a215-475c-a1d3-0a484ae48918:v1
// insert your custom include headers here
// ev@4bf81b14-a215-475c-a1d3-0a484ae48918:v1
namespace module {
struct Conf {};
class NxpNfcFrontendTokenProvider : public Everest::ModuleBase {
public:
NxpNfcFrontendTokenProvider() = delete;
NxpNfcFrontendTokenProvider(const ModuleInfo& info, std::unique_ptr<auth_token_providerImplBase> p_main,
Conf& config) :
ModuleBase(info), p_main(std::move(p_main)), config(config){};
const std::unique_ptr<auth_token_providerImplBase> p_main;
const Conf& config;
// ev@1fce4c5e-0ab8-41bb-90f7-14277703d2ac:v1
// insert your public definitions here
// ev@1fce4c5e-0ab8-41bb-90f7-14277703d2ac:v1
protected:
// ev@4714b2ab-a24f-4b95-ab81-36439e1478de:v1
// insert your protected definitions here
// ev@4714b2ab-a24f-4b95-ab81-36439e1478de:v1
private:
friend class LdEverest;
void init();
void ready();
// ev@211cfdbe-f69a-4cd6-a4ec-f8aaa3d1b6c8:v1
// insert your private definitions here
// ev@211cfdbe-f69a-4cd6-a4ec-f8aaa3d1b6c8:v1
};
// ev@087e516b-124c-48df-94fb-109508c7cda9:v1
// insert other definitions here
// ev@087e516b-124c-48df-94fb-109508c7cda9:v1
} // namespace module
#endif // NXP_NFC_FRONTEND_TOKEN_PROVIDER_HPP

View File

@@ -0,0 +1,82 @@
.. _everest_modules_handwritten_NxpNfcFrontendTokenProvider:
.. ***************************
.. NxpNfcFrontendTokenProvider
.. ***************************
The module ``NxpNfcFrontendTokenProvider`` implements the ``auth_token_provider`` interface.
It reads data from NXP NFC frontend chips like CLRC663.
It relies on **NxpNfcRdLib_Linux_v07.10.00_PUB.zip** which users need to obtain from NXP: `nxp.com <https://www.nxp.com/design/design-center/development-boards-and-designs/nfc-reader-library-software-support-for-nfc-frontend-solutions:NFC-READER-LIBRARY>`_.
The variety of hardware supported by ``NxpNfcFrontendTokenProvider`` is limited at the time of writing but could be extended by modification of the ``nxpnfcrdlib_wrapper``.
Building the module
===================
The module can be built in two ways:
* Setting *CMake* variable ``EXTERNAL_NXPNFCRDLIB_ZIP_PATH_NxpNfcFrontendTokenProvider`` to the path to ``NxpNfcRdLib_Linux_v07.10.00_PUB.zip``.
* Leaving this option undefined uses the included ``NamedPipeDataSource`` which acts as a drop-in replacement without any external build dependencies but does not support real NFC hardware.
To enable users who do not use NxpNfcFrontend to build EVerest without having to explicitly set variables or options, the variable is undefined by default.
NamedPipeDataSource
-------------------
Cannot interface real NFC hardware.
During runtime it creates a named pipe (FIFO) at ``/tmp/EV_NXP_NFC_FRONTEND_TOKEN_PROVIDER_FIFO_SUBSTITUTE`` and tries to read from it.
As soon, as it can read a ``\n``-terminated line, it tries to parse it as ``<protocol>:<uid>`` (see examples below).
Configuring the module
======================
Runtime configuration allows to
* *token_debounce_interval_ms*: select a minimum intervall between publishes
See ``manifest.yaml`` for details.
Testing the module
==================
The module does not implement any commands.
Using NamedPipeDataSource
-------------------------
Possible input for ISO14443 (MIFARE card) emulation:
.. code-block:: bash
echo "ISO14443:44332211" > /tmp/EV_NXP_NFC_FRONTEND_TOKEN_PROVIDER_FIFO_SUBSTITUTE
Possible input for ISO15693 (Vicinity card) emulation:
.. code-block:: bash
echo "ISO15693:8877665544332211" > /tmp/EV_NXP_NFC_FRONTEND_TOKEN_PROVIDER_FIFO_SUBSTITUTE
It publishes an ``types::authorization::ProvidedIdToken`` to the topic ``everest/tokenprovider/main/var``.
It publishes whenever the NFC chip is able to detect a RFID card of the supported types.
``Published JSON:``
.. code-block:: JSON
{
"data": {
"authorization_type" : "RFID",
"id_token" : {
"type" : "ISO14443",
"value" : "74F2EF5B"
}
},
"name" : "provided_token"
}
Using NxpNfcFrontendWrapper
---------------------------
Requires NFC hardware from NXP.
A hardware setup similar to the one shown in the ``nxpnfcrdlib_wrapper`` documentation can be used.
Detection of an RFID card of the supported type will trigger publishing of a ``types::authorization::ProvidedIdToken``.

View File

@@ -0,0 +1,76 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright 2020 - 2025 Pionix GmbH and Contributors to EVerest
#include "auth_token_providerImpl.hpp"
#include <everest/helpers/helpers.hpp>
#include <iomanip>
#include <sstream>
namespace module {
namespace main {
static std::string nfcidToString(const std::vector<std::uint8_t>& nfcid) {
std::ostringstream oss;
for (std::uint16_t byte : nfcid) {
oss << std::setfill('0') << std::setw(2) << std::uppercase << std::hex << byte;
}
return oss.str();
}
void auth_token_providerImpl::detected_rfid_token_callback(
const std::pair<std::string, std::vector<std::uint8_t>>& reply) {
auto& [protocol, nfcid] = reply;
const auto now = std::chrono::steady_clock::now();
const auto debounce_interval = std::chrono::milliseconds(config.token_debounce_interval_ms);
types::authorization::ProvidedIdToken provided_token;
try {
provided_token.id_token = {nfcidToString(nfcid), types::authorization::string_to_id_token_type(protocol)};
} catch (const std::out_of_range& e) {
return;
}
provided_token.authorization_type = types::authorization::AuthorizationType::RFID;
if (now < last_rfid_submit + debounce_interval) {
EVLOG_debug << "Ignoring rfid/nfc token (debouncing): " << protocol << ": "
<< everest::helpers::redact(provided_token);
return;
}
EVLOG_debug << "Publishing new rfid/nfc token: " << protocol << ": " << everest::helpers::redact(provided_token);
publish_provided_token(provided_token);
last_rfid_submit = now;
}
void auth_token_providerImpl::error_log_callback(const std::string& message) {
EVLOG_warning << "NxpNfcFrontend: " << message;
}
void auth_token_providerImpl::init() {
try {
nxpNfcFrontend = std::make_unique<NxpNfcFrontendDataSource>();
} catch (const std::exception& e) {
EVLOG_error << "Failed to initialize NxpNfcFrontend: " << e.what();
}
nxpNfcFrontend->setDetectionCallback(
[this](auto&&... args) { this->detected_rfid_token_callback(std::forward<decltype(args)>(args)...); });
nxpNfcFrontend->setErrorLogCallback(
[this](auto&&... args) { this->error_log_callback(std::forward<decltype(args)>(args)...); });
}
void auth_token_providerImpl::ready() {
if (nxpNfcFrontend) {
nxpNfcFrontend->run();
}
}
} // namespace main
} // namespace module

View File

@@ -0,0 +1,81 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright 2020 - 2025 Pionix GmbH and Contributors to EVerest
#ifndef MAIN_AUTH_TOKEN_PROVIDER_IMPL_HPP
#define MAIN_AUTH_TOKEN_PROVIDER_IMPL_HPP
//
// AUTO GENERATED - MARKED REGIONS WILL BE KEPT
// template version 3
//
#include <generated/interfaces/auth_token_provider/Implementation.hpp>
#include "../NxpNfcFrontendTokenProvider.hpp"
// ev@75ac1216-19eb-4182-a85c-820f1fc2c091:v1
// insert your custom include headers here
#include <atomic>
#include <chrono>
#include <memory>
#ifndef BUILD_WITH_NAMED_PIPE_DATASOURCE
#include <nxpnfcfrontend.hpp>
using NxpNfcFrontendDataSource = NxpNfcFrontendWrapper::NxpNfcFrontend;
#endif // BUILD_WITH_NAMED_PIPE_DATASOURCE
#ifdef BUILD_WITH_NAMED_PIPE_DATASOURCE
#include <namedPipeDataSource.hpp>
using NxpNfcFrontendDataSource = NamedPipeDataSource;
#endif // BUILD_WITH_NAMED_PIPE_DATASOURCE
// ev@75ac1216-19eb-4182-a85c-820f1fc2c091:v1
namespace module {
namespace main {
struct Conf {
int token_debounce_interval_ms;
};
class auth_token_providerImpl : public auth_token_providerImplBase {
public:
auth_token_providerImpl() = delete;
auth_token_providerImpl(Everest::ModuleAdapter* ev, const Everest::PtrContainer<NxpNfcFrontendTokenProvider>& mod,
Conf& config) :
auth_token_providerImplBase(ev, "main"), mod(mod), config(config){};
// ev@8ea32d28-373f-4c90-ae5e-b4fcc74e2a61:v1
// insert your public definitions here
// ev@8ea32d28-373f-4c90-ae5e-b4fcc74e2a61:v1
protected:
// no commands defined for this interface
// ev@d2d1847a-7b88-41dd-ad07-92785f06f5c4:v1
// insert your protected definitions here
// ev@d2d1847a-7b88-41dd-ad07-92785f06f5c4:v1
private:
const Everest::PtrContainer<NxpNfcFrontendTokenProvider>& mod;
const Conf& config;
virtual void init() override;
virtual void ready() override;
// ev@3370e4dd-95f4-47a9-aaec-ea76f34a66c9:v1
// insert your private definitions here
void detected_rfid_token_callback(const std::pair<std::string, std::vector<std::uint8_t>>&);
void error_log_callback(const std::string&);
std::unique_ptr<NxpNfcFrontendDataSource> nxpNfcFrontend;
std::chrono::steady_clock::time_point last_rfid_submit{};
// ev@3370e4dd-95f4-47a9-aaec-ea76f34a66c9:v1
};
// ev@3d7da0ad-02c2-493d-9920-0bbbd56b9876:v1
// insert other definitions here
// ev@3d7da0ad-02c2-493d-9920-0bbbd56b9876:v1
} // namespace main
} // namespace module
#endif // MAIN_AUTH_TOKEN_PROVIDER_IMPL_HPP

View File

@@ -0,0 +1,18 @@
description: NXP NFC Reader Library token provider returning the token as soon as the tag can be read by the reader
provides:
main:
description: Implementation of NXP NFC Reader Library based token provider
interface: auth_token_provider
config:
token_debounce_interval_ms:
description: Minimal wait time in ms until next token will be published (debounce interval).
type: integer
default: 2000
minimum: 500
maximum: 10000
metadata:
license: https://opensource.org/licenses/Apache-2.0
authors:
- Christoph Burandt
- Cornelius Claussen

View File

@@ -0,0 +1,12 @@
# This is a standalone file, to compile the namedPipeTokenProvider as standalone executable
cmake_minimum_required(VERSION 3.15)
project(testNamedPipeDataSource)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED True)
add_library(namedPipeDataSource)
target_sources(namedPipeDataSource PRIVATE namedPipeDataSource.cpp)
target_include_directories(namedPipeDataSource PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})

View File

@@ -0,0 +1,216 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright 2020 - 2025 Pionix GmbH and Contributors to EVerest
#include "namedPipeDataSource.hpp"
#include <algorithm>
#include <cmath>
#include <fcntl.h>
#include <filesystem>
#include <stdexcept>
#include <string_view>
#include <sys/epoll.h>
#include <sys/stat.h>
#include <unistd.h>
namespace {
static bool createdFifo = false;
constexpr mode_t fifo_permissions = 0666;
bool isHexCoded(const std::string& input) {
return std::all_of(input.begin(), input.end(), [](unsigned char byte) { return std::isxdigit(byte); });
}
void createFifoFile(const std::string& pathToNamedPipe) {
const std::filesystem::path path = {pathToNamedPipe};
if (not std::filesystem::is_fifo(path)) {
if (std::filesystem::exists(path)) {
throw std::runtime_error("Could not create FIFO at '" + path.string() + "': file exists as non-FIFO");
}
// Create FIFO:
const int ret = mkfifo(pathToNamedPipe.c_str(), fifo_permissions);
if (ret == -1) {
throw std::runtime_error("Could not create FIFO at '" + path.string() + "': mkfifo returned '-1'");
}
createdFifo = true;
}
}
class FilePoller {
public:
explicit FilePoller(const std::string_view& filename) : m_filename(filename) {
openFileAndConfigureEpoll();
}
FilePoller(const FilePoller&) = delete;
FilePoller(const FilePoller&&) = delete;
FilePoller operator=(const FilePoller&) = delete;
FilePoller operator=(const FilePoller&&) = delete;
~FilePoller() {
closeFileAndEpoll();
}
std::string wait(int timeout_ms) {
std::array<struct epoll_event, EVENT_BUFFER_SIZE> m_epoll_event_buffer{};
const int eventCount = epoll_wait(m_epoll_list_fd, m_epoll_event_buffer.data(), EVENT_BUFFER_SIZE, timeout_ms);
std::string partialLine;
if (eventCount > 0) {
std::array<char, READ_BUFFER_SIZE> buffer{};
for (int i = 0; i < eventCount; i++) {
if ((m_epoll_event_buffer.at(i).events & EPOLLIN) != 0) {
const struct epoll_event& event = m_epoll_event_buffer.at(i);
const std::size_t readCount = read(event.data.fd, buffer.data(), READ_BUFFER_SIZE - 1);
buffer.at(readCount) = '\0';
partialLine.append(buffer.data());
}
}
// After treating EPOLLIN (input) events, look for EPOLLHUP (Hang-up) events
// If the exist, reopen file and reconfigure EPoll,
// otherwise, HUP will happen forever and use the full CPU
for (int i = 0; i < eventCount; i++) {
if ((m_epoll_event_buffer.at(i).events & EPOLLHUP) != 0) {
reOpenFileAndConfigureEpoll();
break;
}
}
}
return partialLine;
}
private:
void openFileAndConfigureEpoll() {
m_fifo_fd = open(m_filename.c_str(), O_RDONLY | O_NONBLOCK);
m_epoll_list_fd = epoll_create1(EPOLL_CLOEXEC);
struct epoll_event m_epoll_event = {};
m_epoll_event.events = EPOLLIN;
m_epoll_event.data.fd = m_fifo_fd;
epoll_ctl(m_epoll_list_fd, EPOLL_CTL_ADD, m_fifo_fd, &m_epoll_event);
}
void reOpenFileAndConfigureEpoll() {
closeFileAndEpoll();
openFileAndConfigureEpoll();
}
void closeFileAndEpoll() const {
close(m_epoll_list_fd);
close(m_fifo_fd);
}
std::string m_filename;
int m_fifo_fd{0};
int m_epoll_list_fd{0};
static const std::size_t READ_BUFFER_SIZE = 64;
static const std::size_t EVENT_BUFFER_SIZE = 16;
};
} // namespace
NamedPipeDataSource::NamedPipeDataSource(const std::string& filename) : m_filename(filename) {
createFifoFile(filename);
}
NamedPipeDataSource::NamedPipeDataSource() :
NamedPipeDataSource("/tmp/EV_NXP_NFC_FRONTEND_TOKEN_PROVIDER_FIFO_SUBSTITUTE") {
}
NamedPipeDataSource::~NamedPipeDataSource() {
stopped = true;
m_line_reader->join();
if (createdFifo) {
std::remove(m_filename.c_str());
}
}
void NamedPipeDataSource::setDetectionCallback(
const std::function<void(const std::pair<std::string, std::vector<std::uint8_t>>&)>& callback) {
m_callback = callback;
}
void NamedPipeDataSource::setErrorLogCallback(const std::function<void(const std::string&)>& callback) {
m_err_callback = callback;
}
void NamedPipeDataSource::run() {
m_line_reader = std::make_unique<std::thread>(&NamedPipeDataSource::getLinesForever, this);
}
void NamedPipeDataSource::getLinesForever() {
constexpr int wait_timeout_ms = 1000;
constexpr std::size_t max_line_length = 128;
std::string line{};
FilePoller poller(m_filename);
while (not stopped) {
const std::string partialLine = poller.wait(wait_timeout_ms);
if (not partialLine.empty()) {
line.append(partialLine);
const std::size_t cr_pos = line.find('\n');
if (cr_pos != std::string::npos) {
if (auto result = parseInput(line)) {
m_callback(*result);
} else {
m_err_callback("Could not parse '" + line + "'");
}
line.clear();
} else {
if (line.size() > max_line_length) {
line.clear();
}
}
}
}
}
std::optional<std::pair<std::string, std::vector<std::uint8_t>>>
NamedPipeDataSource::parseInput(const std::string& input) {
constexpr std::size_t protocol_designator_len = 8;
constexpr std::size_t iso14443_uid_len = 8;
constexpr std::size_t iso15693_uid_len = 16;
if (input.size() < protocol_designator_len + 1) {
return std::nullopt;
}
const std::string protocol = input.substr(0, protocol_designator_len);
std::size_t expectedUidSize{0};
if (protocol == "ISO14443") {
expectedUidSize = iso14443_uid_len;
} else if (protocol == "ISO15693") {
expectedUidSize = iso15693_uid_len;
} else {
return std::nullopt;
}
// "+2" accounts for the ':' and '\n'
const std::size_t expectedStringSize = protocol_designator_len + expectedUidSize + 2;
if (input.size() != expectedStringSize) {
return std::nullopt;
}
const std::string uid_str = input.substr(9, expectedUidSize);
if (not isHexCoded(uid_str)) {
return std::nullopt;
}
std::vector<std::uint8_t> nfcid;
for (std::size_t i = 0; i < uid_str.length(); i += 2) {
const std::string single_byte_str = uid_str.substr(i, 2);
const std::uint8_t byte = static_cast<std::uint8_t>(std::stoi(single_byte_str, nullptr, 16));
nfcid.push_back(byte);
}
return std::make_pair(protocol, nfcid);
}

View File

@@ -0,0 +1,43 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright 2020 - 2025 Pionix GmbH and Contributors to EVerest
#ifndef NAMED_PIPE_TOKEN_PROVIDER_IMPL_HPP
#define NAMED_PIPE_TOKEN_PROVIDER_IMPL_HPP
#include <atomic>
#include <functional>
#include <memory>
#include <optional>
#include <string>
#include <thread>
#include <utility>
#include <vector>
class NamedPipeDataSource {
public:
NamedPipeDataSource();
explicit NamedPipeDataSource(const std::string& filename);
NamedPipeDataSource(const NamedPipeDataSource&) = delete;
NamedPipeDataSource(const NamedPipeDataSource&&) = delete;
NamedPipeDataSource operator=(const NamedPipeDataSource&) = delete;
NamedPipeDataSource operator=(const NamedPipeDataSource&&) = delete;
~NamedPipeDataSource();
void setDetectionCallback(const std::function<void(const std::pair<std::string, std::vector<std::uint8_t>>&)>&);
void setErrorLogCallback(const std::function<void(const std::string&)>&);
void run();
private:
void getLinesForever();
std::optional<std::pair<std::string, std::vector<std::uint8_t>>> parseInput(const std::string& input);
std::string m_filename;
std::function<void(const std::pair<std::string, std::vector<std::uint8_t>>&)> m_callback;
std::function<void(const std::string&)> m_err_callback;
std::unique_ptr<std::thread> m_line_reader;
std::atomic<bool> stopped{false};
};
#endif // NAMED_PIPE_TOKEN_PROVIDER_IMPL_HPP

View File

@@ -0,0 +1,55 @@
cmake_minimum_required(VERSION 3.15)
project(
NxpNfcFrontendLib
VERSION 07.10.00
DESCRIPTION "NXP NFC Frontend Lib"
LANGUAGES CXX C
)
find_package(Threads REQUIRED)
set(EXTRACTION_PATH ${CMAKE_CURRENT_BINARY_DIR}/_deps)
set(PATH_NXPNFCRDLIB "${EXTRACTION_PATH}/NxpNfcRdLib_Linux_v07.10.00_PUB/")
if(EXTERNAL_NXPNFCRDLIB_ZIP_PATH AND EXISTS "${EXTERNAL_NXPNFCRDLIB_ZIP_PATH}")
file(ARCHIVE_EXTRACT
INPUT
"${EXTERNAL_NXPNFCRDLIB_ZIP_PATH}"
DESTINATION
"${EXTRACTION_PATH}")
else()
message(FATAL_ERROR "EXTERNAL_NXPNFCRDLIB_ZIP_PATH not set or invalid. Cannot build the NxpNfcFrontendLib wrapper library.")
endif()
if (NOT EXISTS "${PATH_NXPNFCRDLIB}/CMakeLists.txt")
message(FATAL_ERROR "Path to NxpNfcRdLib looks empty: Did not find ${PATH_NXPNFCRDLIB}/CMakeLists.txt")
endif()
add_subdirectory(lib)
add_library(NxpNfcFrontend)
target_sources(NxpNfcFrontend
PRIVATE
src/errorDecoding.cpp
src/nxpnfcfrontend.cpp
src/NxpNfcRdLibIncludes.hpp
src/NxpNfcRdLibIfc.hpp
src/NxpNfcRdLibIfc.cpp
)
target_compile_features(NxpNfcFrontend
INTERFACE
cxx_std_17
)
target_include_directories(NxpNfcFrontend
PRIVATE
src
PUBLIC
inc
)
target_link_libraries(NxpNfcFrontend
PRIVATE
NxpRdLib
Threads::Threads
)
add_subdirectory(testApplication)

View File

@@ -0,0 +1,118 @@
# nxpnfcrdlib_wrapper
This library provides elementary RFID functionality using NXP's Nfc Reader Library for Nfc frontend chips.
These so called frontend chips require tight control from the host controller in order to execute standard conforming NFC communication.
The proprietary `NXP Nfc Reader Library` is therefore used.
It underlies an EULA and therefore not be shipped with `EVerest`.
It needs to be configured at compile-time to match the target device (both Linux host and interfaced NFC chip).
## Folder Structure
```
nxpnfcrdlib_wrapper
├── doc
├── inc
├── lib/customization
├── src
├── testApplication
├── CMakeLists.txt
└── README.md
```
- `doc`: Documentation (graphics)
- `inc`: Public include file required be users of ``nxpnfcrdlib_wrapper``
- `lib/customization`: Build scripts and suplemental C code for a customized build of the `NXP Nfc Reader Library` within `EVerest`
- `src`: C++ code of this module
- `testApplication`: Minimal application which shows how to use ``nxpnfcrdlib_wrapper``
- `CMakeLists.txt`: Build file
- `README.MD`: This file
## Use
At this time this code only works for **RC663** NFC Frontend Chips.
It could be extended to support different chips (**PN51[8,9]0**).
### Building
1. Setup environment for EVerest as usual
2. Get **NxpNfcRdLib_Linux_v07.10.00_PUB.zip** from [nxp.com](https://www.nxp.com/design/design-center/development-boards-and-designs/nfc-reader-library-software-support-for-nfc-frontend-solutions:NFC-READER-LIBRARY)
3. Store zip file at arbitrary location
4. Provide this location to your EVerest build at configuration time: ``-DEXTERNAL_NXPNFCRDLIB_ZIP_PATH_NxpNfcFrontendTokenProvider=/<path>/<to>/<your>/NxpNfcRdLib_Linux_v07.10.00_PUB.zip``
5. EVerest will automatically choose to include these sources into the build of the ``NxpNfcFrontendTokenProvider``
### Example
```
git clone git@github.com:EVerest/EVerest.git
# download NxpNfcRdLib_Linux_v07.10.00_PUB.zip
mkdir build
cmake -S EVerest -B build -DEXTERNAL_NXPNFCRDLIB_ZIP_PATH_NxpNfcFrontendTokenProvider=/<path>/<to>/<your>/NxpNfcRdLib_Linux_v07.10.00_PUB.zip
cmake --build build --parallel -j
cmake --install build/
```
The use with different boards/chips requires customization **before** compilation (see below)!
## Customization
The code delivered by NXP implements SPI interfaced chips only.
As an example GPIO access has been implemented by NXP with userspace code for the Raspberry Pi 3.
Adaptions to different Linux boards can be done by adding files to ```lib/customization/```.
While ```RTOS/phOsal``` (OS abstraction layer) can usually be left as is, ```Platform/DAL``` (Device abstraction layer) will most likely need additional code.
### Example Raspberry Pi 4
As a minmal adaption example, this repository contains a customization for Raspberry Pi 4.
A new ```Platform/DAL/cfg/BoardSelection.h``` has been provided, in order to choose a different board specific header file (```Platform/DAL/boards/Board_Pi4Rc663.h```).
The latter contains a changed GPIO pinount (compared to the Raspberry Pi 3).
Function wrappers (to provide neutral naming) and convenience functions are provided in ```Platform/DAL/src/rpi4_gpio.c```.
They call functions from the original ```external/Platform/DAL/src/Linux/phDriver_Linux_Int.c```.
### General
* Provide new device-specific (=fitting the individual board/chip combination) ```Platform/DAL/boards/Board_xyz.h```.
* Allow it to be chosen in ```Platform/DAL/cfg/BoardSelection.h```
* Change compile definition in ```Platform/DAL/CMakeLists.txt``` from the given ```PHDRIVER_PI4RC663_BOARD``` to the one required by the modified ```BoardSelection.h```
* If required, add c-files in ```Platform/DAL/src``` which implement hardware access differently, i.e. access to GPIOs, SPI/I²C. Use ```lib/external/Platform/DAL/src/Linux/*.c``` as templates.
* Register access (via I²C or SPI) requires implementation of (cmp. ```external/Platform/DAL/inc/phbalReg.h```):
* ```phStatus_t phbalReg_Init(...)```
* ```phStatus_t phbalReg_Exchange(...)```
* ```phStatus_t phbalReg_SetConfig(...)```
* ```phStatus_t phbalReg_GetConfig(...)```
* GPIO access requires implementation of (cmp. ```external/Platform/DAL/inc/phDriver_Gpio.h```):
* ```phStatus_t phDriver_PinConfig(...)```
* ```uint8_t phDriver_PinRead(...)```
* ```phStatus_t phDriver_IRQPinRead(...)```
* ```phStatus_t phDriver_IRQPinPoll(...)```
* ```void phDriver_PinWrite(...)```
* ```void phDriver_PinClearIntStatus(...)```
* GPIO access also requires implementation of (cmp. ```Platform/DAL/boards/Board_Pi4Rc663.h```) - these can be implemented based on existing functions like in ```external/Platform/DAL/src/Linux/phDriver_Linux_Int.c``` or from scratch:
* ```void GPIO_reconfigure_pin(size_t gpio, int output_int)```
* ```phStatus_t GPIO_read_pin(size_t gpio, uint8_t *pGpioVal)```
* ```phStatus_t GPIO_poll_pin(size_t gpio, int timeOutms)```
* Change ```Platform/DAL/CMakeLists.txt``` in order to include the customized files in the build, in addition and/or instead of the ones provided by NXP
## Example Hardware Setup
The NxpNfcFrontendLib has been tested with a *Raspberry Pi 4* (SPI needs to be activated) and the [CLEV6630B](https://www.nxp.com/part/CLEV6630B) development board.
The *CLEV6630B* was powered from the Raspberry Pi via USB (jumpers need to be set accordingly: "USB", "VDD: +3.3V", "TVDD: +5V"); the onboard LPC microcontroller has beed detached from the NFC chip (solder bridges removed).
There are 9 electrical connections to the Raspberry Pi required:
| CLEV6630B Pin | Raspberry Pi Pin |
|:--------------|:------------------|
| MOSI | SPI-MOSI (GPIO 10)|
| MISO | SPI-MISO (GPIO 9) |
| SCK | SPI-CLK (GPIO 11) |
| SSEL | SPI-CE0 (GPIO 8) |
| CLRC_NRST | GPIO 24 |
| IRQ | GPIO 23 |
| IFSEL0 (F0) | GPIO 27 |
| IFSEL1 (F1) | GPIO 22 |
| GND | GND |
![Wiring Schema](./doc/NxpNfc_CLEV6630B.svg)

View File

@@ -0,0 +1,801 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
width="195.28593mm"
height="103.53428mm"
viewBox="0 0 195.28593 103.53428"
version="1.1"
id="svg5"
xml:space="preserve"
inkscape:version="1.2.2 (b0a8486541, 2022-12-01)"
sodipodi:docname="NxpNfc_CLEV6630B.svg"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg"><sodipodi:namedview
id="namedview7"
pagecolor="#ffffff"
bordercolor="#000000"
borderopacity="0.25"
inkscape:showpageshadow="2"
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="0"
inkscape:deskcolor="#d1d1d1"
inkscape:document-units="mm"
showgrid="false"
inkscape:zoom="2.0384476"
inkscape:cx="378.71957"
inkscape:cy="209.47313"
inkscape:window-width="2560"
inkscape:window-height="1371"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="1"
inkscape:current-layer="layer1" /><defs
id="defs2"><marker
style="overflow:visible"
id="TriangleStart"
refX="0"
refY="0"
orient="auto-start-reverse"
inkscape:stockid="TriangleStart"
markerWidth="2"
markerHeight="2"
viewBox="0 0 5.3244081 6.1553851"
inkscape:isstock="true"
inkscape:collect="always"
preserveAspectRatio="xMidYMid"><path
transform="scale(0.5)"
style="fill:context-stroke;fill-rule:evenodd;stroke:context-stroke;stroke-width:1pt"
d="M 5.77,0 -2.88,5 V -5 Z"
id="path135" /></marker><rect
x="35.53083"
y="171.24704"
width="285.69534"
height="112.51573"
id="rect9461" /><rect
x="35.53083"
y="171.24704"
width="285.69534"
height="112.51573"
id="rect9571" /><rect
x="35.53083"
y="171.24704"
width="285.69534"
height="112.51573"
id="rect10353" /><rect
x="35.53083"
y="171.24704"
width="285.69534"
height="112.51573"
id="rect10365" /><rect
x="35.53083"
y="171.24704"
width="285.69534"
height="112.51573"
id="rect10371" /><rect
x="35.53083"
y="171.24704"
width="285.69534"
height="112.51573"
id="rect10377" /><rect
x="35.53083"
y="171.24704"
width="285.69534"
height="112.51573"
id="rect10383" /><rect
x="35.53083"
y="171.24704"
width="285.69534"
height="112.51573"
id="rect10389" /><rect
x="35.53083"
y="171.24704"
width="285.69534"
height="112.51573"
id="rect10395" /><rect
x="35.53083"
y="171.24704"
width="285.69534"
height="112.51573"
id="rect10389-2" /><rect
x="35.53083"
y="171.24704"
width="285.69534"
height="112.51573"
id="rect11910" /><rect
x="35.53083"
y="171.24704"
width="285.69534"
height="112.51573"
id="rect11918" /><rect
x="35.53083"
y="171.24704"
width="285.69534"
height="112.51573"
id="rect10389-2-1" /><rect
x="35.53083"
y="171.24704"
width="285.69534"
height="112.51573"
id="rect14078" /><rect
x="35.53083"
y="171.24704"
width="285.69534"
height="112.51573"
id="rect14259" /><rect
x="35.53083"
y="171.24704"
width="285.69534"
height="112.51573"
id="rect14269" /><rect
x="35.53083"
y="171.24704"
width="285.69534"
height="112.51573"
id="rect15395" /><rect
x="35.53083"
y="171.24704"
width="285.69534"
height="112.51573"
id="rect15692" /><rect
x="35.53083"
y="171.24704"
width="285.69534"
height="112.51573"
id="rect15818" /><rect
x="35.53083"
y="171.24704"
width="285.69534"
height="112.51573"
id="rect15820" /><rect
x="35.53083"
y="171.24704"
width="285.69534"
height="112.51573"
id="rect15840" /><rect
x="35.53083"
y="171.24704"
width="285.69534"
height="112.51573"
id="rect15842" /><rect
x="35.53083"
y="171.24704"
width="285.69534"
height="112.51573"
id="rect15862" /><rect
x="35.53083"
y="171.24704"
width="285.69534"
height="112.51573"
id="rect15892" /><rect
x="35.53083"
y="171.24704"
width="285.69534"
height="112.51573"
id="rect15894" /><rect
x="35.53083"
y="171.24704"
width="285.69534"
height="112.51573"
id="rect17088" /></defs><g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(-34.225212,14.492536)"><rect
style="fill:#71d281;fill-opacity:1;stroke:none;stroke-width:1.05202;stroke-dasharray:none;stroke-opacity:1"
id="rect15680"
width="95.316772"
height="16.347263"
x="34.225212"
y="72.694481" /><g
id="g7345"
transform="translate(-0.52916667,-25.400001)"><path
style="fill:#004794;fill-opacity:1;stroke-width:0.264583"
d="m 34.969861,16.060045 v 74.26147 h 87.165169 v -11.47322 h 22.27385 v 16.11313 h 85.63143 v -84.05396 h -85.63143 v 14.94651 h -22.27385 v -9.79393 z"
id="path242"
sodipodi:nodetypes="ccccccccccccc" /><path
style="fill:#ffffff;fill-opacity:1;stroke:#b2c1d7;stroke-width:0.5;stroke-dasharray:none;stroke-opacity:1"
d="m 188.35712,21.178215 v 63.51245"
id="path3377" /><path
style="fill:#ffffff;fill-opacity:1;stroke:#b2c1d7;stroke-width:0.5;stroke-dasharray:none;stroke-opacity:1"
d="m 156.60089,52.934445 h 63.51245"
id="path6193" /><rect
style="fill:#303030;fill-opacity:1;stroke:#000000;stroke-width:0.499999;stroke-dasharray:none;stroke-opacity:1"
id="rect6247"
width="17.534277"
height="17.534277"
x="59.52792"
y="52.54977" /></g><text
xml:space="preserve"
transform="matrix(0,-0.26458333,0.26458333,0,36.528052,47.73313)"
id="text10387-5-9"
style="font-size:8px;letter-spacing:0px;word-spacing:0px;white-space:pre;shape-inside:url(#rect10389-2-1);display:inline;fill:#ff0000;fill-opacity:1;stroke:#000000;stroke-width:1.88976;stroke-dasharray:none;stroke-opacity:1"><tspan
x="35.53125"
y="178.5251"
id="tspan17661"><tspan
style="font-weight:bold;-inkscape-font-specification:'sans-serif Bold';stroke:none"
id="tspan17659">Removed</tspan></tspan></text><text
xml:space="preserve"
transform="matrix(0.26458333,0,0,0.26458333,59.817081,-40.970561)"
id="text10387-5"
style="font-size:8px;letter-spacing:0px;word-spacing:0px;white-space:pre;shape-inside:url(#rect10389-2);display:inline;fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:1.88976;stroke-dasharray:none;stroke-opacity:1"><tspan
x="35.53125"
y="178.5251"
id="tspan17665"><tspan
style="font-weight:bold;-inkscape-font-specification:'sans-serif Bold';fill:#e0e0e0;stroke:none"
id="tspan17663">USB</tspan></tspan></text><circle
style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:0.499999;stroke-dasharray:none;stroke-opacity:1"
id="path8125"
cx="48.940239"
cy="62.953655"
r="1.4523464" /><circle
style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:0.499999;stroke-dasharray:none;stroke-opacity:1"
id="circle8647"
cx="52.115238"
cy="62.953655"
r="1.4523464" /><circle
style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:0.499999;stroke-dasharray:none;stroke-opacity:1"
id="circle8649"
cx="55.290237"
cy="62.953655"
r="1.4523464" /><circle
style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:0.499999;stroke-dasharray:none;stroke-opacity:1"
id="circle8651"
cx="58.465237"
cy="62.953655"
r="1.4523464" /><circle
style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:0.499999;stroke-dasharray:none;stroke-opacity:1"
id="circle8653"
cx="73.281898"
cy="62.953655"
r="1.4523464" /><circle
style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:0.499999;stroke-dasharray:none;stroke-opacity:1"
id="circle8655"
cx="76.456902"
cy="62.953655"
r="1.4523464" /><circle
style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:0.499999;stroke-dasharray:none;stroke-opacity:1"
id="circle8657"
cx="79.631897"
cy="62.953655"
r="1.4523464" /><circle
style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:0.499999;stroke-dasharray:none;stroke-opacity:1"
id="circle8659"
cx="82.806892"
cy="62.953655"
r="1.4523464" /><circle
style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:0.499999;stroke-dasharray:none;stroke-opacity:1"
id="circle8661"
cx="85.981888"
cy="62.953655"
r="1.4523464" /><circle
style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:0.499999;stroke-dasharray:none;stroke-opacity:1"
id="circle8663"
cx="89.156891"
cy="62.953655"
r="1.4523464" /><circle
style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:0.499999;stroke-dasharray:none;stroke-opacity:1"
id="circle8665"
cx="92.331886"
cy="62.953655"
r="1.4523464" /><circle
style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:0.499999;stroke-dasharray:none;stroke-opacity:1"
id="circle8667"
cx="95.506882"
cy="62.953655"
r="1.4523464" /><circle
style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:0.499999;stroke-dasharray:none;stroke-opacity:1"
id="circle8669"
cx="102.38605"
cy="52.899487"
r="1.4523464" /><circle
style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:0.499999;stroke-dasharray:none;stroke-opacity:1"
id="circle8671"
cx="105.56105"
cy="52.899487"
r="1.4523464" /><circle
style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:0.499999;stroke-dasharray:none;stroke-opacity:1"
id="circle8673"
cx="108.73605"
cy="52.899487"
r="1.4523464" /><circle
style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:0.499999;stroke-dasharray:none;stroke-opacity:1"
id="circle8675"
cx="111.91106"
cy="52.899487"
r="1.4523464" /><circle
style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:0.499999;stroke-dasharray:none;stroke-opacity:1"
id="circle8677"
cx="115.08603"
cy="52.899487"
r="1.4523464" /><circle
style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:0.499999;stroke-dasharray:none;stroke-opacity:1"
id="circle8679"
cx="118.26105"
cy="52.899487"
r="1.4523464" /><text
xml:space="preserve"
transform="matrix(0,-0.26458333,0.26458333,0,2.0710406,70.384326)"
id="text9459"
style="font-size:10.6667px;white-space:pre;shape-inside:url(#rect9461);display:inline;fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:1.88976;stroke-dasharray:none;stroke-opacity:1"><tspan
x="35.53125"
y="180.95146"
id="tspan17669"><tspan
style="font-weight:bold;-inkscape-font-specification:'sans-serif Bold';fill:#e0e0e0;stroke:none"
id="tspan17667">GND</tspan></tspan></text><text
xml:space="preserve"
transform="matrix(0,-0.26458333,0.26458333,0,5.0216731,70.384326)"
id="text9569"
style="font-size:10.6667px;white-space:pre;shape-inside:url(#rect9571);display:inline;fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:1.88976;stroke-dasharray:none;stroke-opacity:1"><tspan
x="35.53125"
y="180.95146"
id="tspan17673"><tspan
style="font-weight:bold;-inkscape-font-specification:'sans-serif Bold';fill:#e0e0e0;stroke:none"
id="tspan17671">IRQ</tspan></tspan></text><text
xml:space="preserve"
transform="matrix(0,-0.26458333,0.26458333,0,29.378859,70.384326)"
id="text10351"
style="font-size:10.6667px;letter-spacing:0px;word-spacing:0px;white-space:pre;shape-inside:url(#rect10353);display:inline;fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:1.88976;stroke-dasharray:none;stroke-opacity:1"><tspan
x="35.53125"
y="180.95146"
id="tspan17677"><tspan
style="font-weight:bold;-inkscape-font-specification:'sans-serif Bold';fill:#e0e0e0;stroke:none"
id="tspan17675">CLRC_NRST</tspan></tspan></text><text
xml:space="preserve"
transform="matrix(0,-0.26458333,0.26458333,0,32.553858,70.384326)"
id="text10363"
style="font-size:10.6667px;letter-spacing:0px;word-spacing:0px;white-space:pre;shape-inside:url(#rect10365);display:inline;fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:1.88976;stroke-dasharray:none;stroke-opacity:1"><tspan
x="35.53125"
y="180.95146"
id="tspan17681"><tspan
style="font-weight:bold;-inkscape-font-specification:'sans-serif Bold';fill:#e0e0e0;stroke:none"
id="tspan17679">SSEL</tspan></tspan></text><text
xml:space="preserve"
transform="matrix(0,-0.26458333,0.26458333,0,35.728857,70.384326)"
id="text10369"
style="font-size:10.6667px;letter-spacing:0px;word-spacing:0px;white-space:pre;shape-inside:url(#rect10371);display:inline;fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:1.88976;stroke-dasharray:none;stroke-opacity:1"><tspan
x="35.53125"
y="180.95146"
id="tspan17685"><tspan
style="font-weight:bold;-inkscape-font-specification:'sans-serif Bold';fill:#e0e0e0;stroke:none"
id="tspan17683">MOSI</tspan></tspan></text><text
xml:space="preserve"
transform="matrix(0,-0.26458333,0.26458333,0,38.903856,70.384326)"
id="text10375"
style="font-size:10.6667px;letter-spacing:0px;word-spacing:0px;white-space:pre;shape-inside:url(#rect10377);display:inline;fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:1.88976;stroke-dasharray:none;stroke-opacity:1"><tspan
x="35.53125"
y="180.95146"
id="tspan17689"><tspan
style="font-weight:bold;-inkscape-font-specification:'sans-serif Bold';fill:#e0e0e0;stroke:none"
id="tspan17687">MISO</tspan></tspan></text><text
xml:space="preserve"
transform="matrix(0,-0.26458333,0.26458333,0,42.078855,70.384326)"
id="text10381"
style="font-size:10.6667px;letter-spacing:0px;word-spacing:0px;white-space:pre;shape-inside:url(#rect10383);display:inline;fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:1.88976;stroke-dasharray:none;stroke-opacity:1"><tspan
x="35.53125"
y="180.95146"
id="tspan17693"><tspan
style="font-weight:bold;-inkscape-font-specification:'sans-serif Bold';fill:#e0e0e0;stroke:none"
id="tspan17691">SCK</tspan></tspan></text><text
xml:space="preserve"
transform="matrix(0,-0.26458333,0.26458333,0,71.391844,59.800992)"
id="text10387"
style="font-size:10.6667px;letter-spacing:0px;word-spacing:0px;white-space:pre;shape-inside:url(#rect10389);display:inline;fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:1.88976;stroke-dasharray:none;stroke-opacity:1"><tspan
x="35.53125"
y="180.95146"
id="tspan17697"><tspan
style="font-weight:bold;-inkscape-font-specification:'sans-serif Bold';fill:#e0e0e0;stroke:none"
id="tspan17695">F1</tspan></tspan></text><text
xml:space="preserve"
transform="matrix(0,-0.26458333,0.26458333,0,68.216845,59.800992)"
id="text10393"
style="font-size:10.6667px;letter-spacing:0px;word-spacing:0px;white-space:pre;shape-inside:url(#rect10395);display:inline;fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:1.88976;stroke-dasharray:none;stroke-opacity:1"><tspan
x="35.53125"
y="180.95146"
id="tspan17701"><tspan
style="font-weight:bold;-inkscape-font-specification:'sans-serif Bold';fill:#e0e0e0;stroke:none"
id="tspan17699">F0</tspan></tspan></text><g
id="g10455"
transform="matrix(0.89267452,0,0,0.89267452,9.2600959,3.1549247)"><rect
style="fill:#ffa0a0;fill-opacity:1;stroke:none;stroke-width:0.499999;stroke-dasharray:none;stroke-opacity:1"
id="rect10449"
width="4.6956158"
height="2.1317554"
x="83.932693"
y="29.395861" /><rect
style="fill:#802020;fill-opacity:1;stroke:none;stroke-width:0.335498;stroke-dasharray:none;stroke-opacity:1"
id="rect10451"
width="2.114136"
height="2.1317554"
x="85.223434"
y="29.395861" /></g><g
id="g10479"
transform="matrix(0.89267452,0,0,0.89267452,9.2600959,5.2715915)"><rect
style="fill:#ffa0a0;fill-opacity:1;stroke:none;stroke-width:0.499999;stroke-dasharray:none;stroke-opacity:1"
id="rect10475"
width="4.6956158"
height="2.1317554"
x="83.932693"
y="29.395861" /><rect
style="fill:#802020;fill-opacity:1;stroke:none;stroke-width:0.335498;stroke-dasharray:none;stroke-opacity:1"
id="rect10477"
width="2.114136"
height="2.1317554"
x="85.223434"
y="29.395861" /></g><g
id="g10485"
transform="matrix(0.89267452,0,0,0.89267452,9.2600959,7.3882583)"><rect
style="fill:#ffa0a0;fill-opacity:1;stroke:none;stroke-width:0.499999;stroke-dasharray:none;stroke-opacity:1"
id="rect10481"
width="4.6956158"
height="2.1317554"
x="83.932693"
y="29.395861" /><rect
style="fill:#802020;fill-opacity:1;stroke:none;stroke-width:0.335498;stroke-dasharray:none;stroke-opacity:1"
id="rect10483"
width="2.114136"
height="2.1317554"
x="85.223434"
y="29.395861" /></g><g
id="g10491"
transform="matrix(0.89267452,0,0,0.89267452,9.2600959,9.5049251)"><rect
style="fill:#ffa0a0;fill-opacity:1;stroke:none;stroke-width:0.499999;stroke-dasharray:none;stroke-opacity:1"
id="rect10487"
width="4.6956158"
height="2.1317554"
x="83.932693"
y="29.395861" /><rect
style="fill:#802020;fill-opacity:1;stroke:none;stroke-width:0.335498;stroke-dasharray:none;stroke-opacity:1"
id="rect10489"
width="2.114136"
height="2.1317554"
x="85.223434"
y="29.395861" /></g><g
id="g10497"
transform="matrix(0.89267452,0,0,0.89267452,14.022596,3.1549247)"><rect
style="fill:#e0e0e0;fill-opacity:1;stroke:none;stroke-width:0.499999;stroke-dasharray:none;stroke-opacity:1"
id="rect10493"
width="4.6956158"
height="2.1317554"
x="83.932693"
y="29.395861" /><rect
style="fill:#202020;fill-opacity:1;stroke:none;stroke-width:0.335498;stroke-dasharray:none;stroke-opacity:1"
id="rect10495"
width="2.114136"
height="2.1317554"
x="85.223434"
y="29.395861" /></g><g
id="g10503"
transform="matrix(0.89267452,0,0,0.89267452,14.022596,5.2715915)"><rect
style="fill:#e0e0e0;fill-opacity:1;stroke:none;stroke-width:0.499999;stroke-dasharray:none;stroke-opacity:1"
id="rect10499"
width="4.6956158"
height="2.1317554"
x="83.932693"
y="29.395861" /><rect
style="fill:#202020;fill-opacity:1;stroke:none;stroke-width:0.335498;stroke-dasharray:none;stroke-opacity:1"
id="rect10501"
width="2.114136"
height="2.1317554"
x="85.223434"
y="29.395861" /></g><g
id="g10509"
transform="matrix(0.89267452,0,0,0.89267452,14.022596,7.3882583)"><rect
style="fill:#e0e0e0;fill-opacity:1;stroke:none;stroke-width:0.499999;stroke-dasharray:none;stroke-opacity:1"
id="rect10505"
width="4.6956158"
height="2.1317554"
x="83.932693"
y="29.395861" /><rect
style="fill:#202020;fill-opacity:1;stroke:none;stroke-width:0.335498;stroke-dasharray:none;stroke-opacity:1"
id="rect10507"
width="2.114136"
height="2.1317554"
x="85.223434"
y="29.395861" /></g><g
id="g10515"
transform="matrix(0.89267452,0,0,0.89267452,14.022596,9.5049251)"><rect
style="fill:#e0e0e0;fill-opacity:1;stroke:none;stroke-width:0.499999;stroke-dasharray:none;stroke-opacity:1"
id="rect10511"
width="4.6956158"
height="2.1317554"
x="83.932693"
y="29.395861" /><rect
style="fill:#202020;fill-opacity:1;stroke:none;stroke-width:0.335498;stroke-dasharray:none;stroke-opacity:1"
id="rect10513"
width="2.114136"
height="2.1317554"
x="85.223434"
y="29.395861" /></g><g
id="g10581"><rect
style="fill:#202020;fill-opacity:1;stroke:none;stroke-width:0.499999;stroke-dasharray:none;stroke-opacity:1"
id="rect10569"
width="9.4519472"
height="2.9962199"
x="71.574905"
y="7.2480688" /><rect
style="fill:#e0e0e0;fill-opacity:1;stroke:none;stroke-width:0.123038;stroke-dasharray:none;stroke-opacity:1"
id="rect10571"
width="1.3334424"
height="1.2860498"
x="75.634155"
y="8.1031542" /><rect
style="fill:#e0e0e0;fill-opacity:1;stroke:none;stroke-width:0.123038;stroke-dasharray:none;stroke-opacity:1"
id="rect10573"
width="1.3334424"
height="1.2860498"
x="78.809151"
y="8.1031542" /><rect
style="fill:#e0e0e0;fill-opacity:1;stroke:none;stroke-width:0.123038;stroke-dasharray:none;stroke-opacity:1"
id="rect10575"
width="1.3334424"
height="1.2860498"
x="72.459152"
y="8.1031542" /></g><g
id="g10591"
transform="translate(15.875)"><rect
style="fill:#202020;fill-opacity:1;stroke:none;stroke-width:0.499999;stroke-dasharray:none;stroke-opacity:1"
id="rect10583"
width="9.4519472"
height="2.9962199"
x="71.574905"
y="7.2480688" /><rect
style="fill:#e0e0e0;fill-opacity:1;stroke:none;stroke-width:0.123038;stroke-dasharray:none;stroke-opacity:1"
id="rect10585"
width="1.3334424"
height="1.2860498"
x="75.634155"
y="8.1031542" /><rect
style="fill:#e0e0e0;fill-opacity:1;stroke:none;stroke-width:0.123038;stroke-dasharray:none;stroke-opacity:1"
id="rect10587"
width="1.3334424"
height="1.2860498"
x="78.809151"
y="8.1031542" /><rect
style="fill:#e0e0e0;fill-opacity:1;stroke:none;stroke-width:0.123038;stroke-dasharray:none;stroke-opacity:1"
id="rect10589"
width="1.3334424"
height="1.2860498"
x="72.459152"
y="8.1031542" /></g><g
id="g10601"
transform="translate(26.458334)"><rect
style="fill:#202020;fill-opacity:1;stroke:none;stroke-width:0.499999;stroke-dasharray:none;stroke-opacity:1"
id="rect10593"
width="9.4519472"
height="2.9962199"
x="71.574905"
y="7.2480688" /><rect
style="fill:#e0e0e0;fill-opacity:1;stroke:none;stroke-width:0.123038;stroke-dasharray:none;stroke-opacity:1"
id="rect10595"
width="1.3334424"
height="1.2860498"
x="75.634155"
y="8.1031542" /><rect
style="fill:#e0e0e0;fill-opacity:1;stroke:none;stroke-width:0.123038;stroke-dasharray:none;stroke-opacity:1"
id="rect10597"
width="1.3334424"
height="1.2860498"
x="78.809151"
y="8.1031542" /><rect
style="fill:#e0e0e0;fill-opacity:1;stroke:none;stroke-width:0.123038;stroke-dasharray:none;stroke-opacity:1"
id="rect10599"
width="1.3334424"
height="1.2860498"
x="72.459152"
y="8.1031542" /></g><rect
style="fill:none;fill-opacity:1;stroke:#0080ff;stroke-width:0.974908;stroke-dasharray:none;stroke-opacity:1"
id="rect10603"
width="6.0848989"
height="2.8062096"
x="71.658791"
y="7.3430738" /><rect
style="fill:none;fill-opacity:1;stroke:#0080ff;stroke-width:0.974908;stroke-dasharray:none;stroke-opacity:1"
id="rect11749"
width="6.0848989"
height="2.8062096"
x="87.533783"
y="7.3430738" /><rect
style="fill:none;fill-opacity:1;stroke:#0080ff;stroke-width:0.974908;stroke-dasharray:none;stroke-opacity:1"
id="rect11751"
width="6.0848989"
height="2.8062096"
x="101.29211"
y="7.3430738" /><text
xml:space="preserve"
transform="matrix(0,-0.26458333,0.26458333,0,41.339154,16.299122)"
id="text11908"
style="font-size:8px;letter-spacing:0px;word-spacing:0px;white-space:pre;shape-inside:url(#rect11910);display:inline;fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:1.88976;stroke-dasharray:none;stroke-opacity:1"><tspan
x="35.53125"
y="178.5251"
id="tspan17705"><tspan
style="font-weight:bold;-inkscape-font-specification:'sans-serif Bold';fill:#e0e0e0;stroke:none"
id="tspan17703">+3,3V</tspan></tspan></text><text
xml:space="preserve"
transform="matrix(0,-0.26458333,0.26458333,0,61.185024,15.805938)"
id="text11916"
style="font-size:8px;letter-spacing:0px;word-spacing:0px;white-space:pre;shape-inside:url(#rect11918);display:inline;fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:1.88976;stroke-dasharray:none;stroke-opacity:1"><tspan
x="35.53125"
y="178.5251"
id="tspan17709"><tspan
style="font-weight:bold;-inkscape-font-specification:'sans-serif Bold';fill:#e0e0e0;stroke:none"
id="tspan17707">+5V</tspan></tspan></text><g
id="g14282"
transform="translate(-0.83994341,1.7318017)"><rect
style="fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:0.688959;stroke-dasharray:none;stroke-opacity:1"
id="rect13758"
width="4.9264355"
height="2.0696454"
x="74.677605"
y="1.7462211" /><text
xml:space="preserve"
transform="matrix(0.26458333,0,0,0.26458333,65.795687,-43.708654)"
id="text14076"
style="font-size:8px;letter-spacing:0px;word-spacing:0px;white-space:pre;shape-inside:url(#rect14078);display:inline;fill:#004794;fill-opacity:1;stroke:#000000;stroke-width:1.88976;stroke-dasharray:none;stroke-opacity:1"><tspan
x="35.53125"
y="178.5251"
id="tspan17713"><tspan
style="font-weight:bold;-inkscape-font-specification:'sans-serif Bold';stroke:none"
id="tspan17711">+5V</tspan></tspan></text></g><g
id="g14288"
transform="translate(-0.83993578,1.7318017)"><rect
style="fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:0.688959;stroke-dasharray:none;stroke-opacity:1"
id="rect14251"
width="4.9264355"
height="2.0696454"
x="90.552597"
y="1.7462211" /><text
xml:space="preserve"
transform="matrix(0.26458333,0,0,0.26458333,81.421972,-43.69807)"
id="text14257"
style="font-size:8px;letter-spacing:0px;word-spacing:0px;white-space:pre;shape-inside:url(#rect14259);display:inline;fill:#004794;fill-opacity:1;stroke:#000000;stroke-width:1.88976;stroke-dasharray:none;stroke-opacity:1"><tspan
x="35.53125"
y="178.5251"
id="tspan17717"><tspan
style="font-weight:bold;-inkscape-font-specification:'sans-serif Bold';stroke:none"
id="tspan17715">VDD</tspan></tspan></text></g><g
id="g14294"
transform="translate(-1.608386,1.7318017)"><rect
style="fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:0.789142;stroke-dasharray:none;stroke-opacity:1"
id="rect14261"
width="6.4633322"
height="2.0696454"
x="101.13593"
y="1.7462211" /><text
xml:space="preserve"
transform="matrix(0.26458333,0,0,0.26458333,92.139814,-43.69807)"
id="text14267"
style="font-size:8px;letter-spacing:0px;word-spacing:0px;white-space:pre;shape-inside:url(#rect14269);display:inline;fill:#004794;fill-opacity:1;stroke:#000000;stroke-width:1.88976;stroke-dasharray:none;stroke-opacity:1"><tspan
x="35.53125"
y="178.5251"
id="tspan17721"><tspan
style="font-weight:bold;-inkscape-font-specification:'sans-serif Bold';stroke:none"
id="tspan17719">TVDD</tspan></tspan></text></g><path
style="fill:#004794;fill-opacity:1;stroke:#ff0080;stroke-width:1;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#TriangleStart)"
d="m 48.940239,63.213981 v 8.087728"
id="path14490"
sodipodi:nodetypes="cc" /><text
xml:space="preserve"
transform="matrix(0,-0.26458333,0.26458333,0,2.0710406,88.905159)"
id="text15393"
style="font-size:10.6667px;white-space:pre;shape-inside:url(#rect15395);display:inline;fill:#ff0080;fill-opacity:1;stroke:#000000;stroke-width:1.88976;stroke-dasharray:none;stroke-opacity:1"><tspan
x="35.53125"
y="180.95146"
id="tspan17725"><tspan
style="font-weight:bold;-inkscape-font-specification:'sans-serif Bold';stroke:none"
id="tspan17723">GND</tspan></tspan></text><path
style="fill:#004794;fill-opacity:1;stroke:#ff0080;stroke-width:1;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#TriangleStart)"
d="m 52.115238,63.213981 v 8.087728"
id="path15686"
sodipodi:nodetypes="cc" /><text
xml:space="preserve"
transform="matrix(0,-0.26458333,0.26458333,0,5.2460405,93.652153)"
id="text15690"
style="font-size:10.6667px;white-space:pre;shape-inside:url(#rect15692);display:inline;fill:#ff0080;fill-opacity:1;stroke:#000000;stroke-width:1.88976;stroke-dasharray:none;stroke-opacity:1"><tspan
x="35.53125"
y="180.95146"
id="tspan17729"><tspan
style="font-weight:bold;-inkscape-font-specification:'sans-serif Bold';stroke:none"
id="tspan17727">GPIO 23</tspan></tspan></text><path
style="fill:#004794;fill-opacity:1;stroke:#ff0080;stroke-width:1;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#TriangleStart)"
d="m 76.456908,63.213981 v 8.087728"
id="path15806"
sodipodi:nodetypes="cc" /><text
xml:space="preserve"
transform="matrix(0,-0.26458333,0.26458333,0,29.587709,93.652153)"
id="text15810"
style="font-size:10.6667px;white-space:pre;shape-inside:url(#rect15818);display:inline;fill:#ff0080;fill-opacity:1;stroke:#000000;stroke-width:1.88976;stroke-dasharray:none;stroke-opacity:1"><tspan
x="35.53125"
y="180.95146"
id="tspan17733"><tspan
style="font-weight:bold;-inkscape-font-specification:'sans-serif Bold';stroke:none"
id="tspan17731">GPIO 24</tspan></tspan></text><path
style="fill:#004794;fill-opacity:1;stroke:#ff0080;stroke-width:1;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#TriangleStart)"
d="m 79.631907,63.213981 v 8.087728"
id="path15812"
sodipodi:nodetypes="cc" /><text
xml:space="preserve"
transform="matrix(0,-0.26458333,0.26458333,0,32.762709,93.652153)"
id="text15816"
style="font-size:10.6667px;white-space:pre;shape-inside:url(#rect15820);display:inline;fill:#ff0080;fill-opacity:1;stroke:#000000;stroke-width:1.88976;stroke-dasharray:none;stroke-opacity:1"><tspan
x="35.53125"
y="180.95146"
id="tspan17737"><tspan
style="font-weight:bold;-inkscape-font-specification:'sans-serif Bold';stroke:none"
id="tspan17735">GPIO 8</tspan></tspan></text><path
style="fill:#004794;fill-opacity:1;stroke:#ff0080;stroke-width:1;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#TriangleStart)"
d="m 82.806909,63.213981 v 8.087728"
id="path15828"
sodipodi:nodetypes="cc" /><text
xml:space="preserve"
transform="matrix(0,-0.26458333,0.26458333,0,35.93771,93.652153)"
id="text15832"
style="font-size:10.6667px;white-space:pre;shape-inside:url(#rect15840);display:inline;fill:#ff0080;fill-opacity:1;stroke:#000000;stroke-width:1.88976;stroke-dasharray:none;stroke-opacity:1"><tspan
x="35.53125"
y="180.95146"
id="tspan17741"><tspan
style="font-weight:bold;-inkscape-font-specification:'sans-serif Bold';stroke:none"
id="tspan17739">GPIO 10</tspan></tspan></text><path
style="fill:#004794;fill-opacity:1;stroke:#ff0080;stroke-width:1;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#TriangleStart)"
d="m 85.981908,63.213981 v 8.087728"
id="path15834"
sodipodi:nodetypes="cc" /><text
xml:space="preserve"
transform="matrix(0,-0.26458333,0.26458333,0,39.11271,93.652153)"
id="text15838"
style="font-size:10.6667px;white-space:pre;shape-inside:url(#rect15842);display:inline;fill:#ff0080;fill-opacity:1;stroke:#000000;stroke-width:1.88976;stroke-dasharray:none;stroke-opacity:1"><tspan
x="35.53125"
y="180.95146"
id="tspan17745"><tspan
style="font-weight:bold;-inkscape-font-specification:'sans-serif Bold';stroke:none"
id="tspan17743">GPIO 9</tspan></tspan></text><path
style="fill:#004794;fill-opacity:1;stroke:#ff0080;stroke-width:1;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#TriangleStart)"
d="m 89.15691,63.213981 v 8.087728"
id="path15850"
sodipodi:nodetypes="cc" /><text
xml:space="preserve"
transform="matrix(0,-0.26458333,0.26458333,0,42.287711,93.652153)"
id="text15854"
style="font-size:10.6667px;white-space:pre;shape-inside:url(#rect15862);display:inline;fill:#ff0080;fill-opacity:1;stroke:#000000;stroke-width:1.88976;stroke-dasharray:none;stroke-opacity:1"><tspan
x="35.53125"
y="180.95146"
id="tspan17749"><tspan
style="font-weight:bold;-inkscape-font-specification:'sans-serif Bold';stroke:none"
id="tspan17747">GPIO 11</tspan></tspan></text><path
style="fill:#004794;fill-opacity:1;stroke:#ff0080;stroke-width:1;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#TriangleStart)"
d="M 115.08607,53.159814 V 71.301709"
id="path15880"
sodipodi:nodetypes="cc" /><text
xml:space="preserve"
transform="matrix(0,-0.26458333,0.26458333,0,68.216877,93.652153)"
id="text15884"
style="font-size:10.6667px;white-space:pre;shape-inside:url(#rect15892);display:inline;fill:#ff0080;fill-opacity:1;stroke:#000000;stroke-width:1.88976;stroke-dasharray:none;stroke-opacity:1"><tspan
x="35.53125"
y="180.95146"
id="tspan17753"><tspan
style="font-weight:bold;-inkscape-font-specification:'sans-serif Bold';stroke:none"
id="tspan17751">GPIO 27</tspan></tspan></text><path
style="fill:#004794;fill-opacity:1;stroke:#ff0080;stroke-width:1;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#TriangleStart)"
d="M 118.26107,53.159814 V 71.301709"
id="path15886"
sodipodi:nodetypes="cc" /><text
xml:space="preserve"
transform="matrix(0,-0.26458333,0.26458333,0,71.391878,93.652153)"
id="text15890"
style="font-size:10.6667px;white-space:pre;shape-inside:url(#rect15894);display:inline;fill:#ff0080;fill-opacity:1;stroke:#000000;stroke-width:1.88976;stroke-dasharray:none;stroke-opacity:1"><tspan
x="35.53125"
y="180.95146"
id="tspan17757"><tspan
style="font-weight:bold;-inkscape-font-specification:'sans-serif Bold';stroke:none"
id="tspan17755">GPIO 22</tspan></tspan></text><text
xml:space="preserve"
transform="matrix(0.26458333,0,0,0.26458333,60.612676,39.760335)"
id="text17086"
style="font-size:10.6667px;letter-spacing:1px;white-space:pre;shape-inside:url(#rect17088);display:inline;fill:#006000;fill-opacity:1;stroke:#000000;stroke-width:1.88976;stroke-dasharray:none;stroke-opacity:1"><tspan
x="35.53125"
y="180.95146"
id="tspan17761"><tspan
style="font-weight:bold;-inkscape-font-specification:'sans-serif Bold';stroke:none"
id="tspan17759">Raspberry Pi 4</tspan></tspan></text></g></svg>

After

Width:  |  Height:  |  Size: 37 KiB

View File

@@ -0,0 +1,36 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright 2020 - 2025 Pionix GmbH and Contributors to EVerest
#pragma once
#include <atomic>
#include <cstdint>
#include <functional>
#include <memory>
#include <string>
#include <utility>
#include <vector>
namespace NxpNfcFrontendWrapper {
// Forward declarations, to keep headers private
class NxpNfcRdLibIfc;
class NxpNfcFrontend {
public:
NxpNfcFrontend();
~NxpNfcFrontend();
NxpNfcFrontend(const NxpNfcFrontend&) = delete;
NxpNfcFrontend& operator=(const NxpNfcFrontend&) = delete;
void setDetectionCallback(const std::function<void(const std::pair<std::string, std::vector<std::uint8_t>>&)>&);
void setErrorLogCallback(const std::function<void(const std::string&)>&);
void run();
private:
std::unique_ptr<NxpNfcRdLibIfc> m_nfclib_ifc;
static inline std::atomic<bool> s_someInstanceExists{false};
};
} // namespace NxpNfcFrontendWrapper

View File

@@ -0,0 +1,12 @@
cmake_minimum_required(VERSION 3.15)
set(DAL_PATH ${PATH_NXPNFCRDLIB}/Platform/DAL)
set(PHOSAL_PATH ${PATH_NXPNFCRDLIB}/RTOS/phOsal)
set(NXPLIB_PATH ${PATH_NXPNFCRDLIB}/NxpNfcRdLib)
# NOTE: The original CMake build files from NXP's NFC READER LIB are ignored.
# The build is defined completely in the 'customization' folder:
add_subdirectory(customization)

View File

@@ -0,0 +1,17 @@
cmake_minimum_required(VERSION 3.15)
set(CUSTOM_DAL_PATH ${CMAKE_CURRENT_SOURCE_DIR}/Platform/DAL)
set(CUSTOM_NXPLIB_PATH ${CMAKE_CURRENT_SOURCE_DIR}/NxpNfcRdLib)
add_subdirectory(Platform/DAL)
add_subdirectory(RTOS/phOsal)
add_subdirectory(NxpNfcRdLib)
add_library(NxpRdLib INTERFACE)
target_link_libraries(NxpRdLib
INTERFACE
phOsal
DAL
NxpRdLib_phNfcLib
NxpRdLib_acDiscLoop
)

View File

@@ -0,0 +1,264 @@
cmake_minimum_required(VERSION 3.15)
# Interface library to hold common includes and compile definitions
add_library(NxpNfcRdLibCommon INTERFACE)
target_include_directories(NxpNfcRdLibCommon
# INTERFACE
# $<BUILD_INTERFACE:${NXPLIB_PATH}/intfs>
# $<BUILD_INTERFACE:${NXPLIB_PATH}/types>
# $<BUILD_INTERFACE:${PHOSAL_PATH}/inc>
# $<BUILD_INTERFACE:${CUSTOM_NXPLIB_PATH}/types>
# $<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}/intfs>
# $<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}/types>
# $<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}/inc>
INTERFACE
$<BUILD_INTERFACE:${NXPLIB_PATH}/intfs>
$<BUILD_INTERFACE:${NXPLIB_PATH}/types>
$<BUILD_INTERFACE:${PHOSAL_PATH}/inc>
$<BUILD_INTERFACE:${CUSTOM_NXPLIB_PATH}/types>
)
target_compile_definitions(NxpNfcRdLibCommon
INTERFACE
PH_OSAL_LINUX
NXPBUILD_CUSTOMER_HEADER_INCLUDED
)
add_library(NxpRdLib_phTools)
target_sources(NxpRdLib_phTools
PRIVATE
${NXPLIB_PATH}/comps/phTools/src/phTools.c
${NXPLIB_PATH}/comps/phTools/src/phTools_Q.c
)
target_link_libraries(NxpRdLib_phTools
PUBLIC
NxpNfcRdLibCommon
)
add_library(NxpRdLib_phhalHw)
target_sources(NxpRdLib_phhalHw
PRIVATE
${NXPLIB_PATH}/comps/phhalHw/src/phhalHw.c
${NXPLIB_PATH}/comps/phhalHw/src/Rc663/phhalHw_Rc663.c
${NXPLIB_PATH}/comps/phhalHw/src/Rc663/phhalHw_Rc663_Cmd.c
${NXPLIB_PATH}/comps/phhalHw/src/Rc663/phhalHw_Rc663_Int.c
${NXPLIB_PATH}/comps/phhalHw/src/Rc663/phhalHw_Rc663_Wait.c
)
target_include_directories(NxpRdLib_phhalHw
PRIVATE
${NXPLIB_PATH}/comps/phhalHw/src/Rc663
${DAL_PATH}/inc
${CUSTOM_DAL_PATH}/cfg
PUBLIC
$<BUILD_INTERFACE:${DAL_PATH}/boards>
$<BUILD_INTERFACE:${CUSTOM_DAL_PATH}/boards>
$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}/boards>
)
target_compile_definitions(NxpRdLib_phhalHw
PUBLIC
NXPBUILD__PHHAL_HW_RC663
PHDRIVER_PI4RC663_BOARD
)
target_link_libraries(NxpRdLib_phhalHw
PRIVATE
NxpRdLib_phTools
PUBLIC
NxpNfcRdLibCommon
)
add_library(NxpRdLib_palI14443p3a)
target_sources(NxpRdLib_palI14443p3a
PRIVATE
${NXPLIB_PATH}/comps/phpalI14443p3a/src/phpalI14443p3a.c
${NXPLIB_PATH}/comps/phpalI14443p3a/src/Sw/phpalI14443p3a_Sw.c
)
target_include_directories(NxpRdLib_palI14443p3a
PRIVATE
${NXPLIB_PATH}/comps/phpalI14443p3a/src/Sw
)
target_link_libraries(NxpRdLib_palI14443p3a
PRIVATE
NxpRdLib_phhalHw
PUBLIC
NxpNfcRdLibCommon
)
add_library(NxpRdLib_palMifare)
target_sources(NxpRdLib_palMifare
PRIVATE
${NXPLIB_PATH}/comps/phpalMifare/src/phpalMifare.c
${NXPLIB_PATH}/comps/phpalMifare/src/Sw/phpalMifare_Sw.c
)
target_include_directories(NxpRdLib_palMifare
PRIVATE
${NXPLIB_PATH}/comps/NxpRdLib_palMifare/src/Sw
)
target_link_libraries(NxpRdLib_palMifare
PRIVATE
NxpRdLib_phhalHw
PUBLIC
NxpNfcRdLibCommon
)
add_library(NxpRdLib_palSli15693)
target_sources(NxpRdLib_palSli15693
PRIVATE
${NXPLIB_PATH}/comps/phpalSli15693/src/phpalSli15693.c
${NXPLIB_PATH}/comps/phpalSli15693/src/Sw/phpalSli15693_Sw.c
)
target_include_directories(NxpRdLib_palSli15693
PRIVATE
${NXPLIB_PATH}/comps/phpalSli15693/src/Sw
)
target_link_libraries(NxpRdLib_palSli15693
PRIVATE
NxpRdLib_phhalHw
PUBLIC
NxpNfcRdLibCommon
)
add_library(NxpRdLib_alMfc)
target_sources(NxpRdLib_alMfc
PRIVATE
${NXPLIB_PATH}/comps/phalMfc/src/phalMfc.c
${NXPLIB_PATH}/comps/phalMfc/src/phalMfc_Int.c
${NXPLIB_PATH}/comps/phalMfc/src/Sw/phalMfc_Sw.c
)
target_include_directories(NxpRdLib_alMfc
PRIVATE
${NXPLIB_PATH}/comps/phalMfc/src
${NXPLIB_PATH}/comps/phalMfc/src/Sw
)
target_compile_definitions(NxpRdLib_alMfc
PUBLIC
NXPBUILD__PHHAL_HW_RC663
)
target_link_libraries(NxpRdLib_alMfc
PRIVATE
NxpRdLib_palMifare
PUBLIC
NxpNfcRdLibCommon
)
add_library(NxpRdLib_KeyStore)
target_sources(NxpRdLib_KeyStore
PRIVATE
${NXPLIB_PATH}/comps/phKeyStore/src/phKeyStore.c
${NXPLIB_PATH}/comps/phKeyStore/src/Rc663/phKeyStore_Rc663.c
${NXPLIB_PATH}/comps/phKeyStore/src/Sw/phKeyStore_Sw.c
)
target_include_directories(NxpRdLib_KeyStore
PRIVATE
${NXPLIB_PATH}/comps/phKeyStore/src
${NXPLIB_PATH}/comps/phKeyStore/src/Rc663
${NXPLIB_PATH}/comps/phKeyStore/src/Sw
)
target_link_libraries(NxpRdLib_KeyStore
PUBLIC
NxpNfcRdLibCommon
)
add_library(NxpRdLib_phNfcLib)
target_sources(NxpRdLib_phNfcLib
PRIVATE
${NXPLIB_PATH}/comps/phNfcLib/src/phNfcLib.c
${NXPLIB_PATH}/comps/phNfcLib/src/phNfcLib_15693.c
${NXPLIB_PATH}/comps/phNfcLib/src/phNfcLib_Initialization.c
)
target_include_directories(NxpRdLib_phNfcLib
PRIVATE
${NXPLIB_PATH}/comps/phNfcLib/src
)
target_link_libraries(NxpRdLib_phNfcLib
PUBLIC
NxpRdLib_phhalHw
NxpRdLib_palI14443p3a
NxpRdLib_palMifare
NxpRdLib_palSli15693
NxpRdLib_alMfc
NxpRdLib_KeyStore
NxpNfcRdLibCommon
)
add_library(NxpRdLib_alT1T)
target_sources(NxpRdLib_alT1T
PRIVATE
${NXPLIB_PATH}/comps/phalT1T/src/phalT1T.c
${NXPLIB_PATH}/comps/phalT1T/src/Sw/phalT1T_Sw.c
)
target_include_directories(NxpRdLib_alT1T
PRIVATE
${NXPLIB_PATH}/comps/phalT1T/src/Sw
)
target_link_libraries(NxpRdLib_alT1T
PUBLIC
NxpNfcRdLibCommon
)
add_library(NxpRdLib_acDiscLoop)
target_sources(NxpRdLib_acDiscLoop
PRIVATE
${NXPLIB_PATH}/comps/phacDiscLoop/src/phacDiscLoop.c
${NXPLIB_PATH}/comps/phacDiscLoop/src/Sw/phacDiscLoop_Sw.c
${NXPLIB_PATH}/comps/phacDiscLoop/src/Sw/phacDiscLoop_Sw_Int.c
${NXPLIB_PATH}/comps/phacDiscLoop/src/Sw/phacDiscLoop_Sw_Int_A.c
${NXPLIB_PATH}/comps/phacDiscLoop/src/Sw/phacDiscLoop_Sw_Int_B.c
${NXPLIB_PATH}/comps/phacDiscLoop/src/Sw/phacDiscLoop_Sw_Int_F.c
${NXPLIB_PATH}/comps/phacDiscLoop/src/Sw/phacDiscLoop_Sw_Int_I18000p3m3.c
${NXPLIB_PATH}/comps/phacDiscLoop/src/Sw/phacDiscLoop_Sw_Int_ECP.c
${NXPLIB_PATH}/comps/phacDiscLoop/src/Sw/phacDiscLoop_Sw_Int_V.c
)
target_include_directories(NxpRdLib_acDiscLoop
PRIVATE
${NXPLIB_PATH}/comps/phacDiscLoop/src
)
target_link_libraries(NxpRdLib_acDiscLoop
PRIVATE
NxpRdLib_phhalHw
NxpRdLib_palI14443p3a
PUBLIC
NxpNfcRdLibCommon
)
# Theses components have been left out for now.
# phalFelica
# phalI18000p3m3
# phalICode
# phalMfdf
# phalMfdfEVx
# phalMfdfLight
# phalMfNtag42XDna
# phalMfp
# phalMfpEVx
# phalMful
# phalTop
# phalVca
# phceT4T
# phCidManager
# phCryptoRng
# phCryptoSym
# phlnLlcp
# phLog
# phnpSnep
# phpalEpcUid
# phpalFelica
# phpalI14443p3b
# phpalI14443p4
# phpalI14443p4a
# phpalI14443p4mC
# phpalI18000p3m3
# phpalI18092mPI
# phpalI18092mT
# phTMIUtils

View File

@@ -0,0 +1,35 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright 2020 - 2025 Pionix GmbH and Contributors to EVerest
/* Definitions for the build of the NXP NFC Reader Library */
/* Additional protocols, etc, need to be added here, if required*/
#ifndef PH_NXPBUILD_APP_H_INC
#define PH_NXPBUILD_APP_H_INC
/** Protocol Abstraction Layer Components */
#define NXPBUILD__PHPAL_I14443P3A_SW /** ISO 14443-3A SW Component */
//#define NXPBUILD__PHPAL_MIFARE_SW /**< MIFARE SW Component */
#define NXPBUILD__PHPAL_SLI15693_SW /**< SLI 15693 Component */
/** Discovery Loop Properties */
#define NXPBUILD__PHAC_DISCLOOP_SW /**< Discovery Loop Activity */
#define NXPBUILD__PHAC_DISCLOOP_LPCD /**< Low Power Card Detection */
#ifdef NXPBUILD__PHPAL_I14443P3A_SW
#define NXPBUILD__PHAC_DISCLOOP_TYPEA_I3P3_TAGS /**< SRC/DATA to Detect/Collision Resolute/Activate cards such as MFC, MFUL, MFP SL1 */
#endif /* NXPBUILD__PHPAL_I14443P3A_SW */
#ifdef NXPBUILD__PHPAL_SLI15693_SW
#define NXPBUILD__PHAC_DISCLOOP_TYPEV_TAGS /**< SRC/DATA to Detect Type V Cards */
#endif /* NXPBUILD__PHPAL_SLI15693_SW */
/** Simplified API */
#define NXPBUILD__PHNFCLIB /**< Simplified API Interface */
#define NXPBUILD__PH_KEYSTORE_SW /**< SW KeyStore Component */
#endif /* PH_NXPBUILD_APP_H_INC */

View File

@@ -0,0 +1,28 @@
cmake_minimum_required(VERSION 3.15)
project(DAL)
add_library(DAL)
target_sources(DAL
PRIVATE
${DAL_PATH}/src/Linux/phDriver_Linux_Int.c
${DAL_PATH}/src/Linux/phbalReg_Linux_UserSpi.c
${DAL_PATH}/src/Linux/phDriver_Linux.c
# Add c files in src to provide custom implementation of the GPIO and register access (SPI/I²C) interface
# Remove the files given above individually, if a replacement is added below.
# Individual replacements:
src/rpi4_gpio.c
)
target_include_directories(DAL
PUBLIC
$<BUILD_INTERFACE:${DAL_PATH}/src/Linux>
$<BUILD_INTERFACE:${DAL_PATH}/inc>
$<BUILD_INTERFACE:${DAL_PATH}/boards>
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/boards>
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/cfg>
$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}/inc>
)
target_compile_definitions(DAL
PUBLIC
PHDRIVER_PI4RC663_BOARD
)

View File

@@ -0,0 +1,44 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright 2020 - 2025 Pionix GmbH and Contributors to EVerest
#ifndef CUSTOMIZATION_BOARD_PI4RC663_H
#define CUSTOMIZATION_BOARD_PI4RC663_H
/** Provide RPi4 specific functions (implemented by c-file in src and using existing functions from the NXP DAL)*/
void GPIO_reconfigure_pin(size_t gpio, int output_int);
phStatus_t GPIO_read_pin(size_t gpio, uint8_t *pGpioVal);
phStatus_t GPIO_poll_pin(size_t gpio, int timeOutms);
/** Enable User space SPI. (Required for RC663 frontend chip) */
#define PHDRIVER_LINUX_USER_SPI
/** Choose GPIOs */
#define PHDRIVER_PIN_RESET 536 /** GPIO24 **/
#define PHDRIVER_PIN_IRQ 535 /** GPIO23 */
/** Configure RESET and IRQ pins to pull up/down */
#define PHDRIVER_PIN_RESET_PULL_CFG PH_DRIVER_PULL_DOWN
#define PHDRIVER_PIN_IRQ_PULL_CFG PH_DRIVER_PULL_UP
/** Choose trigger type */
#define PIN_IRQ_TRIGGER_TYPE PH_DRIVER_INTERRUPT_RISINGEDGE
/** Front End Reset logic level settings */
#define PH_DRIVER_SET_HIGH 1
#define PH_DRIVER_SET_LOW 0
#define RESET_POWERDOWN_LEVEL PH_DRIVER_SET_HIGH
#define RESET_POWERUP_LEVEL PH_DRIVER_SET_LOW
/** SPI Configuration: "/dev/spidev0.0" @ 5MHz */
#define PHDRIVER_USER_SPI_BUS 0
#define PHDRIVER_USER_SPI_CS 0
#define PHDRIVER_USER_SPI_FREQ 5000000
#define PHDRIVER_USER_SPI_CFG_DIR "/dev/spidev"
#define PHDRIVER_USER_SPI_CFG_MODE SPI_MODE_0
#define PHDRIVER_USER_SPI_CFG_BITS_PER_WORD 8
/** No functionality in this setup (Linux, SPI); just to suppress build errors */
#define PHDRIVER_PIN_SSEL 0xFFFF
#define PHDRIVER_PIN_NSS_PULL_CFG PH_DRIVER_PULL_UP
#endif /* CUSTOMIZATION_BOARD_PI4RC663_H */

View File

@@ -0,0 +1,11 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright 2020 - 2025 Pionix GmbH and Contributors to EVerest
#ifndef CUSTOMIZATION_BOARDSELECTION_H
#define CUSTOMIZATION_BOARDSELECTION_H
#ifdef PHDRIVER_PI4RC663_BOARD
# include <Board_Pi4Rc663.h>
#endif
#endif /* CUSTOMIZATION_BOARDSELECTION_H */

View File

@@ -0,0 +1,26 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright 2020 - 2025 Pionix GmbH and Contributors to EVerest
#include <phDriver_Linux_Int.h>
#include <Board_Pi4Rc663.h>
// argument output as char, in order to avoid the bool from <stdbool.h> to be carried into the c++ user code
void GPIO_reconfigure_pin(size_t gpio, int output_int) {
PiGpio_unexport(gpio);
PiGpio_export(gpio);
bool output = (output_int == 0 ? false : true);
PiGpio_set_direction(gpio, output);
if (PIN_IRQ_TRIGGER_TYPE == PH_DRIVER_INTERRUPT_RISINGEDGE) {
PiGpio_set_edge(gpio, true, false);
} else {
PiGpio_set_edge(gpio, false, true);
}
}
phStatus_t GPIO_read_pin(size_t gpio, uint8_t *pGpioVal) {
return PiGpio_read(gpio, pGpioVal);
}
phStatus_t GPIO_poll_pin(size_t gpio, int timeOutms) {
return PiGpio_poll(PHDRIVER_PIN_IRQ, 1, timeOutms);
}

View File

@@ -0,0 +1,25 @@
cmake_minimum_required(VERSION 3.15)
project(phOsal)
find_package(Threads REQUIRED)
add_library(phOsal)
target_sources(phOsal
PRIVATE
${PHOSAL_PATH}/src/Linux/phOsal_Linux.c
)
target_include_directories(phOsal
PUBLIC
$<BUILD_INTERFACE:${PHOSAL_PATH}/inc>
$<BUILD_INTERFACE:${PHOSAL_PATH}/src/Linux>
$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>
)
target_link_libraries(phOsal
PRIVATE
Threads::Threads -lrt
)
target_compile_definitions(phOsal
PUBLIC
PH_OSAL_LINUX
)

View File

@@ -0,0 +1,297 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright 2020 - 2025 Pionix GmbH and Contributors to EVerest
#include <sstream>
#include <stdexcept>
#include <NxpNfcRdLibIfc.hpp>
using NxpNfcRdLibIfc = NxpNfcFrontendWrapper::NxpNfcRdLibIfc;
NxpNfcRdLibIfc::NxpNfcRdLibIfc() {
phStatus_t status = PH_ERR_INTERNAL_ERROR;
/* Pre-library initialization phase */
/* 1. Prepare OS abstraction layer */
status = phOsal_Init();
if (status != PH_OSAL_SUCCESS) {
std::string error_message = formatErrorInfo("phOsal_Init() failed! (Initialization of "
"Operating System Abstraction Layer)",
decodeErrorCode(status));
throw std::runtime_error(error_message);
}
/* 2. Prepare Bus abstraction layer */
status = phbalReg_Init(&m_sBalParams, sizeof(phbalReg_Type_t));
if (status != PH_DRIVER_SUCCESS) {
std::string error_message = formatErrorInfo("phbalReg_Init() failed! (Initialization of Bus Abstraction Layer)",
decodeErrorCode(status));
throw std::runtime_error(error_message);
}
/* 3. Tell phNfcLib about Bus abstraction layer */
phNfcLib_AppContext_t appContext = {0};
appContext.pBalDataparams = &m_sBalParams;
status = phNfcLib_SetContext(&appContext);
if (status != PH_NFCLIB_STATUS_SUCCESS) {
std::string error_message = formatErrorInfo("phNfcLib_SetContext() failed!", decodeErrorCode(status));
throw std::runtime_error(error_message);
}
/* Initialize library */
status = phNfcLib_Init();
if (status != PH_NFCLIB_STATUS_SUCCESS) {
std::string error_message = formatErrorInfo("phNfcLib_Init() failed!", decodeErrorCode(status));
throw std::runtime_error(error_message);
}
/* Store ptrs to library's internal components' dataparams structs for HAL and DISCLOOP */
m_pHal = static_cast<phhalHw_Rc663_DataParams_t*>(phNfcLib_GetDataParams(PH_COMP_HAL));
m_pDiscLoop = static_cast<phacDiscLoop_Sw_DataParams_t*>(phNfcLib_GetDataParams(PH_COMP_AC_DISCLOOP));
}
void NxpNfcRdLibIfc::setCallback(const callback_func_t& callback) {
m_callback = callback;
}
void NxpNfcRdLibIfc::setErrorCallback(const error_callback_func_t& callback) {
m_err_callback = callback;
}
void NxpNfcRdLibIfc::startThreads() {
m_irq_poll_thread = std::make_unique<std::thread>(&NxpNfcRdLibIfc::runIrqPollThread, this);
m_discloop_thread = std::make_unique<std::thread>(&NxpNfcRdLibIfc::runDiscoveryLoopThread, this);
}
void NxpNfcRdLibIfc::stopThreads() {
m_stopFlag = true;
m_irq_poll_thread->join();
m_discloop_thread->join();
}
void NxpNfcRdLibIfc::runDiscoveryLoopThread() {
phStatus_t status;
/* Get RFID Poll Configuration */
status = phacDiscLoop_GetConfig(m_pDiscLoop, PHAC_DISCLOOP_CONFIG_PAS_POLL_TECH_CFG, &m_bSavePollTechCfg);
if (status != PH_ERR_SUCCESS) {
std::string error_message = formatErrorInfo("phacDiscLoop_GetConfig() failed!", decodeErrorCode(status));
throw std::runtime_error(error_message);
}
/* Switch off RF field */
status = phhalHw_FieldOff(m_pHal);
if (status != PH_ERR_SUCCESS) {
std::string error_message = formatErrorInfo("Initial phhalHw_FieldOff() failed!", decodeErrorCode(status));
throw std::runtime_error(error_message);
}
// From now on, no more exception throwing, because the loop should keep running
uint16_t wEntryPoint = PHAC_DISCLOOP_ENTRY_POINT_POLL;
while (!m_stopFlag) {
status = phacDiscLoop_SetConfig(m_pDiscLoop, PHAC_DISCLOOP_CONFIG_NEXT_POLL_STATE,
PHAC_DISCLOOP_POLL_STATE_DETECTION);
if (status != PH_ERR_SUCCESS) {
doErrorCallback("Discovery Loop: phacDiscLoop_SetConfig: ", decodeErrorCode(status));
}
/* Start discovery loop */
status = phacDiscLoop_Run(m_pDiscLoop, wEntryPoint);
decodeDiscLoopStatusAndCallback(status);
/* Set Poll Configuration */
status = phacDiscLoop_SetConfig(m_pDiscLoop, PHAC_DISCLOOP_CONFIG_PAS_POLL_TECH_CFG, m_bSavePollTechCfg);
if (status != PH_ERR_SUCCESS) {
doErrorCallback("Discovery Loop: phacDiscLoop_SetConfig: ", decodeErrorCode(status));
}
/* Switch off RF field */
status = phhalHw_FieldOff(m_pHal);
if (status != PH_ERR_SUCCESS) {
doErrorCallback("Discovery Loop: phhalHw_FieldOff: ", decodeErrorCode(status));
}
/* Wait for field-off time-out */
status = phhalHw_Wait(m_pHal, PHHAL_HW_TIME_MICROSECONDS, 5100);
if (status != PH_ERR_SUCCESS) {
doErrorCallback("Discovery Loop: phhalHw_Wait: ", decodeErrorCode(status));
}
phOsal_ThreadDelay(HI_LEVEL_LOOP_DELAY_MS);
}
/* Switch off RF field */
phhalHw_FieldOff(m_pHal);
}
void NxpNfcRdLibIfc::runIrqPollThread() {
uint8_t gpioValue = 0;
while (GPIO_read_pin(PHDRIVER_PIN_IRQ, &gpioValue) != PH_ERR_SUCCESS) {
GPIO_reconfigure_pin(PHDRIVER_PIN_IRQ, false);
}
// If it happens to be necessary call the IRQ handler now
if (gpioValue == 1) {
IrqHandler();
}
while (!m_stopFlag) {
// Wait for the IRQ PIN to change, but wait until the timeout only
if (GPIO_poll_pin(PHDRIVER_PIN_IRQ, 1000) == PH_ERR_SUCCESS) {
IrqHandler();
} else {
GPIO_reconfigure_pin(PHDRIVER_PIN_IRQ, false);
}
}
}
void GPIO_reconfigure_pin(size_t gpio) {
PiGpio_unexport(PHDRIVER_PIN_IRQ);
PiGpio_export(PHDRIVER_PIN_IRQ);
PiGpio_set_direction(PHDRIVER_PIN_IRQ, false);
if (PIN_IRQ_TRIGGER_TYPE == PH_DRIVER_INTERRUPT_RISINGEDGE) {
PiGpio_set_edge(PHDRIVER_PIN_IRQ, true, false);
} else {
PiGpio_set_edge(PHDRIVER_PIN_IRQ, false, true);
}
}
void NxpNfcRdLibIfc::IrqHandler() {
if (phDriver_PinRead(PHDRIVER_PIN_IRQ, PH_DRIVER_PINFUNC_INTERRUPT)) {
phDriver_PinClearIntStatus(PHDRIVER_PIN_IRQ);
if (m_pHal->pRFISRCallback != NULL) {
m_pHal->pRFISRCallback(m_pHal);
}
}
}
void NxpNfcRdLibIfc::decodeDiscLoopStatusAndCallback(phStatus_t discLoopStatus) {
switch (discLoopStatus & PH_ERR_MASK) {
case PHAC_DISCLOOP_MULTI_TECH_DETECTED: // Do not try to resolve multi-tech collision
case PHAC_DISCLOOP_MULTI_DEVICES_RESOLVED: // Do not try to resolve multi-device collision
case PHAC_DISCLOOP_NO_TECH_DETECTED: // Nothing to be done here
case PHAC_DISCLOOP_NO_DEVICE_RESOLVED: // Nothing to be done here
case PHAC_DISCLOOP_EXTERNAL_RFON: // External RF is ignored
case PHAC_DISCLOOP_MERGED_SEL_RES_FOUND: // T4T or NFC-DEP devices are ignored
break;
case PHAC_DISCLOOP_DEVICE_ACTIVATED:
handleActivatedDevice();
break;
case PHAC_DISCLOOP_ACTIVE_TARGET_ACTIVATED: // Do not try to connect to active targets
case PHAC_DISCLOOP_PASSIVE_TARGET_ACTIVATED: // Do not try to connect to passive targets
case PHAC_DISCLOOP_LPCD_NO_TECH_DETECTED: // Nothing to be done here
break;
case PHAC_DISCLOOP_FAILURE: {
handleDiscoveryLoopFailure();
break;
}
default:
doErrorCallback("Decoding discovery loop status failed", decodeErrorCode(0x00));
}
}
void NxpNfcRdLibIfc::handleActivatedDevice() {
uint16_t noOfTagsDetected = 0;
phStatus_t status = phacDiscLoop_GetConfig(m_pDiscLoop, PHAC_DISCLOOP_CONFIG_NR_TAGS_FOUND, &noOfTagsDetected);
if (status != PH_ERR_SUCCESS or noOfTagsDetected > 1) {
return;
}
/* Get Detected Technology Type */
uint16_t technologyCodeDetected = 0;
status = phacDiscLoop_GetConfig(m_pDiscLoop, PHAC_DISCLOOP_CONFIG_TECH_DETECTED, &technologyCodeDetected);
if (status != PH_ERR_SUCCESS) {
return;
}
NxpNfcRdLibIfc::Technology technology = NxpNfcRdLibIfc::decodeTechnology(m_pDiscLoop, technologyCodeDetected);
if (technology == NxpNfcRdLibIfc::Technology::UNKNOWN) {
return;
}
std::vector<std::uint8_t> uid = NxpNfcRdLibIfc::getUID(m_pDiscLoop, technology);
if (m_callback) {
m_callback(technology, uid);
}
}
void NxpNfcRdLibIfc::handleDiscoveryLoopFailure() {
uint16_t additionalInfo;
phStatus_t status = phacDiscLoop_GetConfig(m_pDiscLoop, PHAC_DISCLOOP_CONFIG_ADDITIONAL_INFO, &additionalInfo);
if (status != PH_ERR_SUCCESS) {
doErrorCallback("PHAC_DISCLOOP_FAILURE: Trying to get additional Information failed: ",
decodeErrorCode(status));
return;
}
doErrorCallback("Decoding discovery loop status failed (PHAC_DISCLOOP_FAILURE)", decodeErrorCode(additionalInfo));
}
void NxpNfcRdLibIfc::doErrorCallback(std::string customText, ErrorInfo errorInfo) {
std::string formattedMessage = formatErrorInfo(customText, errorInfo);
if (m_err_callback) {
m_err_callback(formattedMessage);
}
}
// static helpers
std::string NxpNfcRdLibIfc::formatErrorInfo(const std::string& customText, const ErrorInfo& errorInfo) {
return customText + ": Error in component '" + errorInfo.component + "': " + errorInfo.type;
}
NxpNfcRdLibIfc::Technology NxpNfcRdLibIfc::decodeTechnology(phacDiscLoop_Sw_DataParams_t* pDataParams,
uint16_t techCode) {
if (PHAC_DISCLOOP_CHECK_ANDMASK(techCode, PHAC_DISCLOOP_POS_BIT_MASK_A)) {
if (pDataParams->sTypeATargetInfo.bT1TFlag) {
return NxpNfcRdLibIfc::Technology::ISO14443A_T1;
} else {
if ((pDataParams->sTypeATargetInfo.aTypeA_I3P3[0].aSak & (uint8_t)0x04) == 0) {
uint8_t tagType = (pDataParams->sTypeATargetInfo.aTypeA_I3P3[0].aSak & 0x60) >> 5;
switch (tagType) {
case PHAC_DISCLOOP_TYPEA_TYPE2_TAG_CONFIG_MASK:
return NxpNfcRdLibIfc::Technology::ISO14443A_T2;
case PHAC_DISCLOOP_TYPEA_TYPE4A_TAG_CONFIG_MASK:
return NxpNfcRdLibIfc::Technology::ISO14443A_T4A;
}
}
}
} else if (PHAC_DISCLOOP_CHECK_ANDMASK(techCode, PHAC_DISCLOOP_POS_BIT_MASK_V)) {
return NxpNfcRdLibIfc::Technology::ISO15693;
}
return NxpNfcRdLibIfc::Technology::UNKNOWN;
}
std::vector<std::uint8_t> NxpNfcRdLibIfc::getUID(phacDiscLoop_Sw_DataParams_t* pDataParams,
NxpNfcRdLibIfc::Technology technology) {
int length = 0;
uint8_t* uidArray = nullptr;
switch (technology) {
case NxpNfcRdLibIfc::Technology::ISO14443A_T1:
case NxpNfcRdLibIfc::Technology::ISO14443A_T2:
case NxpNfcRdLibIfc::Technology::ISO14443A_T4A:
length = pDataParams->sTypeATargetInfo.aTypeA_I3P3[0].bUidSize;
uidArray = pDataParams->sTypeATargetInfo.aTypeA_I3P3[0].aUid;
break;
case NxpNfcRdLibIfc::Technology::ISO15693:
length = 8;
uidArray = pDataParams->sTypeVTargetInfo.aTypeV[0].aUid;
break;
case NxpNfcRdLibIfc::Technology::UNKNOWN: {
}
}
if (uidArray) {
return std::vector<uint8_t>(uidArray, uidArray + length);
} else {
return {};
}
}

View File

@@ -0,0 +1,67 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright 2020 - 2025 Pionix GmbH and Contributors to EVerest
#pragma once
#include <atomic>
#include <cstdint>
#include <functional>
#include <memory>
#include <string>
#include <thread>
#include <vector>
#include "NxpNfcRdLibIncludes.hpp"
namespace NxpNfcFrontendWrapper {
class NxpNfcRdLibIfc {
public:
enum class Technology {
UNKNOWN,
ISO14443A_T1,
ISO14443A_T2,
ISO14443A_T4A,
ISO15693,
};
NxpNfcRdLibIfc();
using callback_func_t = std::function<void(const NxpNfcRdLibIfc::Technology&, const std::vector<std::uint8_t>&)>;
using error_callback_func_t = std::function<void(const std::string&)>;
void setCallback(const callback_func_t& callback);
void setErrorCallback(const error_callback_func_t& callback);
void startThreads();
void stopThreads();
private:
void decodeDiscLoopStatusAndCallback(phStatus_t);
void handleActivatedDevice();
void handleDiscoveryLoopFailure();
void IrqHandler();
void runIrqPollThread();
void runDiscoveryLoopThread();
void doErrorCallback(std::string, ErrorInfo);
static std::string formatErrorInfo(const std::string&, const ErrorInfo&);
static NxpNfcRdLibIfc::Technology decodeTechnology(phacDiscLoop_Sw_DataParams_t*, uint16_t);
static std::vector<std::uint8_t> getUID(phacDiscLoop_Sw_DataParams_t*, NxpNfcRdLibIfc::Technology);
callback_func_t m_callback;
error_callback_func_t m_err_callback;
std::atomic<bool> m_stopFlag{false};
// Nxp Nfc Rd Lib Context
uint16_t m_bSavePollTechCfg =
PHAC_DISCLOOP_POS_BIT_MASK_A | PHAC_DISCLOOP_POS_BIT_MASK_V; // Configure to detect ISO14443A and 15693 cards
phbalReg_Type_t m_sBalParams;
phhalHw_Rc663_DataParams_t* m_pHal;
phacDiscLoop_Profile_t m_bProfile = PHAC_DISCLOOP_PROFILE_UNKNOWN;
phacDiscLoop_Sw_DataParams_t* m_pDiscLoop;
std::unique_ptr<std::thread> m_irq_poll_thread;
std::unique_ptr<std::thread> m_discloop_thread;
};
} // namespace NxpNfcFrontendWrapper

View File

@@ -0,0 +1,32 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright 2020 - 2025 Pionix GmbH and Contributors to EVerest
#ifndef SRC_NXPNFCRDLIBINCLUDES_HPP_
#define SRC_NXPNFCRDLIBINCLUDES_HPP_
#include <string>
extern "C" {
#include <phDriver.h>
#include <phDriver_Linux_Int.h>
#include <phNfcLib.h>
#include <ph_Status.h>
#include <BoardSelection.h>
}
// undo definition from NxpNfcRdLib which defines bool as unsigned char
#ifdef bool
#undef bool
#endif
#define HI_LEVEL_LOOP_DELAY_MS 200
struct ErrorInfo {
std::string component;
std::string type;
};
ErrorInfo decodeErrorCode(phStatus_t);
#endif // SRC_NXPNFCRDLIBINCLUDES_HPP_

View File

@@ -0,0 +1,106 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright 2020 - 2025 Pionix GmbH and Contributors to EVerest
#include <iomanip>
#include <sstream>
#include <string>
#include <unordered_map>
#include "NxpNfcRdLibIncludes.hpp"
namespace {
const std::unordered_map<phStatus_t, std::string> componentMapping = {{PH_COMP_BAL, "BAL"},
{PH_COMP_HAL, "HAL"},
{PH_COMP_PAL_ISO14443P3A, "PAL_ISO14443P3A"},
{PH_COMP_PAL_ISO14443P3B, "PAL_ISO14443P3B"},
{PH_COMP_PAL_ISO14443P4A, "PAL_ISO14443P4A"},
{PH_COMP_PAL_ISO14443P4, "PAL_ISO14443P4"},
{PH_COMP_PAL_FELICA, "PAL_FELICA"},
{PH_COMP_PAL_EPCUID, "PAL_EPCUID"},
{PH_COMP_PAL_SLI15693, "PAL_SLI15693"},
{PH_COMP_PAL_I18000P3M3, "PAL_I18000P3M3"},
{PH_COMP_PAL_I18092MPI, "PAL_I18092MPI"},
{PH_COMP_PAL_I18092MT, "PAL_I18092MT"},
{PH_COMP_PAL_I14443P4MC, "PAL_I14443P4MC"},
{PH_COMP_AC_DISCLOOP, "AC_DISCLOOP"},
{PH_COMP_OSAL, "OSAL"},
{PH_COMP_DRIVER, "DRIVER"}};
static const std::unordered_map<phStatus_t, std::string> phOsalErrorTypeMapping = {
{PH_OSAL_IO_TIMEOUT, "IO_TIMEOUT"},
{PH_OSAL_ERROR, "ERROR"},
{PH_OSAL_FAILURE, "FAILURE"},
{PH_OSAL_UNSUPPORTED_COMMAND, "UNSUPPORTED_COMMAND"}};
static const std::unordered_map<phStatus_t, std::string> balErrorTypeMapping = {{PH_DRIVER_TIMEOUT, "TIMEOUT"},
{PH_DRIVER_ABORTED, "ABORTED"},
{PH_DRIVER_ERROR, "ERROR"},
{PH_DRIVER_FAILURE, "FAILURE"}};
static const std::unordered_map<phStatus_t, std::string> errorTypeMapping = {
{PH_ERR_IO_TIMEOUT, "IO_TIMEOUT"},
{PH_ERR_INTEGRITY_ERROR, "INTEGRITY_ERROR"},
{PH_ERR_COLLISION_ERROR, "COLLISION_ERROR"},
{PH_ERR_BUFFER_OVERFLOW, "BUFFER_OVERFLOW"},
{PH_ERR_FRAMING_ERROR, "FRAMING_ERROR"},
{PH_ERR_PROTOCOL_ERROR, "PROTOCOL_ERROR"},
{PH_ERR_AUTH_ERROR, "AUTH_ERROR"},
{PH_ERR_READ_WRITE_ERROR, "READ_WRITE_ERROR"},
{PH_ERR_TEMPERATURE_ERROR, "TEMPERATURE_ERROR"},
{PH_ERR_RF_ERROR, "RF_ERROR"},
{PH_ERR_INTERFACE_ERROR, "INTERFACE_ERROR"},
{PH_ERR_LENGTH_ERROR, "LENGTH_ERROR"},
{PH_ERR_RESOURCE_ERROR, "RESOURCE_ERROR"},
{PH_ERR_TX_NAK_ERROR, "TX_NAK_ERROR"},
{PH_ERR_RX_NAK_ERROR, "RX_NAK_ERROR"},
{PH_ERR_EXT_RF_ERROR, "EXT_RF_ERROR"},
{PH_ERR_NOISE_ERROR, "NOISE_ERROR"},
{PH_ERR_ABORTED, "ABORTED"},
{PH_ERR_LPCD_ABORTED, "LPCD_ABORTED"},
{PH_ERR_INTERNAL_ERROR, "INTERNAL_ERROR"},
{PH_ERR_INVALID_DATA_PARAMS, "INVALID_DATA_PARAMS"},
{PH_ERR_INVALID_PARAMETER, "INVALID_PARAMETER"},
{PH_ERR_PARAMETER_OVERFLOW, "PARAMETER_OVERFLOW"},
{PH_ERR_UNSUPPORTED_PARAMETER, "UNSUPPORTED_PARAMETER"},
{PH_ERR_UNSUPPORTED_COMMAND, "UNSUPPORTED_COMMAND"},
{PH_ERR_USE_CONDITION, "USE_CONDITION"},
{PH_ERR_KEY, "KEY"},
{PH_ERR_PARAMETER_SIZE, "PARAMETER_SIZE"},
{PH_ERR_UNKNOWN, "UNKNOWN"},
{PH_ERR_INTERNAL_ERROR, "INTERNAL_ERROR"},
{PH_ERR_AUTH_DELAY, "AUTH_DELAY"}};
} // namespace
ErrorInfo decodeErrorCode(phStatus_t wStatus) {
phStatus_t componentCode = wStatus & PH_COMP_MASK;
phStatus_t errorTypeCode = wStatus & PH_ERR_MASK;
std::string component;
std::string type;
try {
component = componentMapping.at(componentCode);
} catch (const std::out_of_range& e) {
std::ostringstream oss;
oss << std::setfill('0') << std::setw(2) << "0x" << std::uppercase << std::hex << componentCode;
component = oss.str();
}
try {
if (componentCode == PH_COMP_OSAL) {
type = phOsalErrorTypeMapping.at(errorTypeCode);
} else if (componentCode == PH_COMP_DRIVER) {
type = balErrorTypeMapping.at(errorTypeCode);
} else {
type = errorTypeMapping.at(errorTypeCode);
}
} catch (const std::out_of_range& e) {
std::ostringstream oss;
oss << std::setfill('0') << std::setw(2) << "0x" << std::uppercase << std::hex << errorTypeCode;
type = oss.str();
}
return {component, type};
}

View File

@@ -0,0 +1,54 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright 2020 - 2025 Pionix GmbH and Contributors to EVerest
#include <string>
#include <NxpNfcRdLibIfc.hpp>
#include <nxpnfcfrontend.hpp>
#include <stdexcept>
using NxpNfcFrontend = NxpNfcFrontendWrapper::NxpNfcFrontend;
NxpNfcFrontend::NxpNfcFrontend() {
if (s_someInstanceExists) {
throw std::runtime_error("Only one NxpNfcFrontend Instance allowed!");
}
s_someInstanceExists = true;
m_nfclib_ifc = std::make_unique<NxpNfcRdLibIfc>();
}
NxpNfcFrontend::~NxpNfcFrontend() {
m_nfclib_ifc->stopThreads();
s_someInstanceExists = false;
}
void NxpNfcFrontend::setDetectionCallback(
const std::function<void(const std::pair<std::string, std::vector<std::uint8_t>>&)>& callback) {
m_nfclib_ifc->setCallback([callback](NxpNfcRdLibIfc::Technology technology, std::vector<std::uint8_t> uid_vec) {
std::string protocol;
switch (technology) {
case NxpNfcRdLibIfc::Technology::ISO14443A_T1:
case NxpNfcRdLibIfc::Technology::ISO14443A_T2:
case NxpNfcRdLibIfc::Technology::ISO14443A_T4A:
protocol = "ISO14443";
break;
case NxpNfcRdLibIfc::Technology::ISO15693:
protocol = "ISO15693";
break;
default:
protocol = "UNKNOWN";
}
callback({protocol, uid_vec});
});
}
void NxpNfcFrontend::setErrorLogCallback(const std::function<void(const std::string&)>& callback) {
m_nfclib_ifc->setErrorCallback(callback);
}
void NxpNfcFrontend::run() {
m_nfclib_ifc->startThreads();
}

View File

@@ -0,0 +1,14 @@
cmake_minimum_required(VERSION 3.15)
project(nxpnfcfrontendDemo
LANGUAGES CXX)
add_executable(nfc_test_application)
target_sources(nfc_test_application PRIVATE src/nfc_test_application.cpp)
target_compile_definitions(nfc_test_application PRIVATE DEBUG)
target_include_directories(nfc_test_application
PRIVATE
include
)
target_link_libraries(nfc_test_application PRIVATE NxpNfcFrontend)

View File

@@ -0,0 +1,50 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright 2020 - 2025 Pionix GmbH and Contributors to EVerest
#include <chrono>
#include <csignal>
#include <iomanip>
#include <iostream>
#include <sstream>
#include <thread>
#include <nxpnfcfrontend.hpp>
bool stop = false;
void handleSigInt(int sig) {
std::cout << "Caught signal " << sig << " (Ctrl+C)" << std::endl;
stop = true;
}
int main(void) {
std::signal(SIGINT, handleSigInt);
auto callback = [](const std::pair<std::string, std::vector<std::uint8_t>>& reply) {
auto& [protocol, nfcid] = reply;
std::cout << "Detected Card\n Type : '" << protocol << "'\n";
std::cout << " Length: " << nfcid.size() << "\n";
std::cout << " UID : ";
for (std::uint16_t byte : nfcid) {
std::cout << std::setfill('0') << std::setw(2) << std::uppercase << std::hex << byte;
}
std::cout << std::endl;
};
auto error_callback = [](const std::string& error_message) {
std::cerr << "ERROR: " << error_message << std::endl;
};
std::cout << "NFC client:" << std::endl;
NxpNfcFrontendWrapper::NxpNfcFrontend frontend{};
frontend.setDetectionCallback(callback);
frontend.setErrorLogCallback(error_callback);
std::cout << "Starting the loop" << std::endl;
frontend.run();
while (!stop) {
std::this_thread::sleep_for(std::chrono::milliseconds(200));
}
// destructor of NxpNfcFrontend will stop the internal threads
return 0;
}

View File

@@ -0,0 +1,33 @@
#
# AUTO GENERATED - MARKED REGIONS WILL BE KEPT
# template version 3
#
# module setup:
# - ${MODULE_NAME}: module name
ev_setup_cpp_module()
# ev@bcc62523-e22b-41d7-ba2f-825b493a3c97:v1
add_subdirectory(pn532_serial)
target_include_directories(${MODULE_NAME}
PRIVATE
"common"
"pn532_serial"
)
target_link_libraries(${MODULE_NAME}
PRIVATE
everest::helpers
pn532_serial
)
# ev@bcc62523-e22b-41d7-ba2f-825b493a3c97:v1
target_sources(${MODULE_NAME}
PRIVATE
"main/auth_token_providerImpl.cpp"
)
# ev@c55432ab-152c-45a9-9d2e-7281d50c69c3:v1
# insert other things like install cmds etc here
# ev@c55432ab-152c-45a9-9d2e-7281d50c69c3:v1

View File

@@ -0,0 +1,15 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright 2022 - 2022 Pionix GmbH and Contributors to EVerest
#include "PN532TokenProvider.hpp"
namespace module {
void PN532TokenProvider::init() {
invoke_init(*p_main);
}
void PN532TokenProvider::ready() {
invoke_ready(*p_main);
}
} // namespace module

View File

@@ -0,0 +1,58 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright Pionix GmbH and Contributors to EVerest
#ifndef PN532TOKEN_PROVIDER_HPP
#define PN532TOKEN_PROVIDER_HPP
//
// AUTO GENERATED - MARKED REGIONS WILL BE KEPT
// template version 2
//
#include "ld-ev.hpp"
// headers for provided interface implementations
#include <generated/interfaces/auth_token_provider/Implementation.hpp>
// ev@4bf81b14-a215-475c-a1d3-0a484ae48918:v1
// insert your custom include headers here
// ev@4bf81b14-a215-475c-a1d3-0a484ae48918:v1
namespace module {
struct Conf {};
class PN532TokenProvider : public Everest::ModuleBase {
public:
PN532TokenProvider() = delete;
PN532TokenProvider(const ModuleInfo& info, std::unique_ptr<auth_token_providerImplBase> p_main, Conf& config) :
ModuleBase(info), p_main(std::move(p_main)), config(config){};
const std::unique_ptr<auth_token_providerImplBase> p_main;
const Conf& config;
// ev@1fce4c5e-0ab8-41bb-90f7-14277703d2ac:v1
// insert your public definitions here
// ev@1fce4c5e-0ab8-41bb-90f7-14277703d2ac:v1
protected:
// ev@4714b2ab-a24f-4b95-ab81-36439e1478de:v1
// insert your protected definitions here
// ev@4714b2ab-a24f-4b95-ab81-36439e1478de:v1
private:
friend class LdEverest;
void init();
void ready();
// ev@211cfdbe-f69a-4cd6-a4ec-f8aaa3d1b6c8:v1
// insert your private definitions here
// ev@211cfdbe-f69a-4cd6-a4ec-f8aaa3d1b6c8:v1
};
// ev@087e516b-124c-48df-94fb-109508c7cda9:v1
// insert other definitions here
// ev@087e516b-124c-48df-94fb-109508c7cda9:v1
} // namespace module
#endif // PN532TOKEN_PROVIDER_HPP

View File

@@ -0,0 +1,84 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright Pionix GmbH and Contributors to EVerest
#include "auth_token_providerImpl.hpp"
#include <everest/helpers/helpers.hpp>
#include <fmt/core.h>
namespace module {
namespace main {
void auth_token_providerImpl::init() {
// initialize serial driver
if (config.debug) {
serial.enableDebug();
EVLOG_info << "Serial port: " << config.serial_port << " baud rate: " << config.baud_rate;
}
if (!serial.openDevice(config.serial_port.c_str(), config.baud_rate)) {
if (!this->error_state_monitor->is_error_active("generic/CommunicationFault", "Communication timed out")) {
auto error_message =
fmt::format("Could not open serial port {} with baud rate {}", config.serial_port, config.baud_rate);
auto error = this->error_factory->create_error("generic/CommunicationFault", "Communication timed out",
error_message);
raise_error(error);
}
return;
}
}
void auth_token_providerImpl::ready() {
serial.run();
serial.reset();
// configure Secure Access Module (SAM)
auto configure_sam_future = serial.configureSAM();
while (configure_sam_future.wait_for(std::chrono::milliseconds(100)) != std::future_status::ready) {
EVLOG_verbose << "Retrying to configure SAM";
configure_sam_future = serial.configureSAM();
}
auto configure_sam = configure_sam_future.get();
if (configure_sam) {
EVLOG_debug << "Configured SAM";
}
auto firmware_version_future = serial.getFirmwareVersion();
while (firmware_version_future.wait_for(std::chrono::milliseconds(100)) != std::future_status::ready) {
EVLOG_verbose << "Retrying to get firmware version";
firmware_version_future = serial.getFirmwareVersion();
}
auto firmware_version = firmware_version_future.get();
if (firmware_version.valid) {
std::shared_ptr<FirmwareVersion> fv = std::dynamic_pointer_cast<FirmwareVersion>(firmware_version.message);
EVLOG_info << "PN532 firmware version: " << std::to_string(fv->ver) << "." << std::to_string(fv->rev);
}
while (true) {
auto in_list_passive_target_response_future = serial.inListPassiveTarget();
while (in_list_passive_target_response_future.wait_for(std::chrono::seconds(5)) != std::future_status::ready) {
EVLOG_verbose << "Retrying to get target";
in_list_passive_target_response_future = serial.inListPassiveTarget();
}
auto in_list_passive_target_response = in_list_passive_target_response_future.get();
if (in_list_passive_target_response.valid) {
std::shared_ptr<InListPassiveTargetResponse> in_list_passive_target_response_message =
std::dynamic_pointer_cast<InListPassiveTargetResponse>(in_list_passive_target_response.message);
auto target_data = in_list_passive_target_response_message->target_data;
for (auto entry : target_data) {
types::authorization::ProvidedIdToken provided_token;
provided_token.id_token = {entry.getNFCID(), types::authorization::IdTokenType::ISO14443};
provided_token.authorization_type = types::authorization::AuthorizationType::RFID;
if (config.debug) {
EVLOG_info << "Publishing new rfid/nfc token: " << everest::helpers::redact(provided_token);
}
this->publish_provided_token(provided_token);
}
}
std::this_thread::sleep_for(std::chrono::seconds(config.read_timeout));
}
}
} // namespace main
} // namespace module

View File

@@ -0,0 +1,68 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright Pionix GmbH and Contributors to EVerest
#ifndef MAIN_AUTH_TOKEN_PROVIDER_IMPL_HPP
#define MAIN_AUTH_TOKEN_PROVIDER_IMPL_HPP
//
// AUTO GENERATED - MARKED REGIONS WILL BE KEPT
// template version 3
//
#include <generated/interfaces/auth_token_provider/Implementation.hpp>
#include "../PN532TokenProvider.hpp"
// ev@75ac1216-19eb-4182-a85c-820f1fc2c091:v1
// insert your custom include headers here
#include "pn532_serial/PN532Serial.h"
// ev@75ac1216-19eb-4182-a85c-820f1fc2c091:v1
namespace module {
namespace main {
struct Conf {
std::string serial_port;
int baud_rate;
int read_timeout;
bool debug;
};
class auth_token_providerImpl : public auth_token_providerImplBase {
public:
auth_token_providerImpl() = delete;
auth_token_providerImpl(Everest::ModuleAdapter* ev, const Everest::PtrContainer<PN532TokenProvider>& mod,
Conf& config) :
auth_token_providerImplBase(ev, "main"), mod(mod), config(config){};
// ev@8ea32d28-373f-4c90-ae5e-b4fcc74e2a61:v1
// insert your public definitions here
// ev@8ea32d28-373f-4c90-ae5e-b4fcc74e2a61:v1
protected:
// no commands defined for this interface
// ev@d2d1847a-7b88-41dd-ad07-92785f06f5c4:v1
// insert your protected definitions here
// ev@d2d1847a-7b88-41dd-ad07-92785f06f5c4:v1
private:
const Everest::PtrContainer<PN532TokenProvider>& mod;
const Conf& config;
virtual void init() override;
virtual void ready() override;
// ev@3370e4dd-95f4-47a9-aaec-ea76f34a66c9:v1
// insert your private definitions here
PN532Serial serial;
// ev@3370e4dd-95f4-47a9-aaec-ea76f34a66c9:v1
};
// ev@3d7da0ad-02c2-493d-9920-0bbbd56b9876:v1
// insert other definitions here
// ev@3d7da0ad-02c2-493d-9920-0bbbd56b9876:v1
} // namespace main
} // namespace module
#endif // MAIN_AUTH_TOKEN_PROVIDER_IMPL_HPP

View File

@@ -0,0 +1,33 @@
description: PN532 RFID/NFC token provider returning the token as soon as the tag can be read by the reader
provides:
main:
description: Implementation of PN532 RFID/NFC token provider
interface: auth_token_provider
config:
serial_port:
description: Serial port the PN532 hardware is connected to
type: string
default: /dev/ttyS0
baud_rate:
description: Serial baud rate to use when communicating with PN532 hardware
type: integer
minimum: 9600
maximum: 230400
default: 115200
read_timeout:
description: Time between subsequent card reads (in s)
type: integer
minimum: 0
maximum: 120
default: 5
debug:
description: Show debug output on command line.
type: boolean
default: false
metadata:
license: https://opensource.org/licenses/Apache-2.0
authors:
- Cornelius Claussen
- Kai-Uwe Hermann
- Thilo Molitor
- Anton Wöllert

View File

@@ -0,0 +1,18 @@
cmake_minimum_required(VERSION 3.10)
# set the project name
project(pn532_serial VERSION 0.1)
# specify the C++ standard
set(CMAKE_CXX_STANDARD 14)
set(CMAKE_CXX_STANDARD_REQUIRED True)
set(THREADS_PREFER_PTHREAD_FLAG ON)
find_package(Threads REQUIRED)
# add the executable
add_library(pn532_serial STATIC PN532Serial.cpp)
ev_register_library_target(pn532_serial)
target_include_directories(pn532_serial PUBLIC "${PROJECT_BINARY_DIR}")
target_link_libraries(pn532_serial PRIVATE Threads::Threads everest::framework)

View File

@@ -0,0 +1,331 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright 2020 - 2022 Pionix GmbH and Contributors to EVerest
#include "PN532Serial.h"
#include <errno.h>
#include <fcntl.h>
#include <fstream>
#include <iostream>
#include <string.h>
#include <string>
#include <thread>
#include <unistd.h>
#include <everest/logging.hpp>
constexpr size_t FIRMWARE_VERSION_IC_POS = 0;
constexpr size_t FIRMWARE_VERSION_VER_POS = 1;
constexpr size_t FIRMWARE_VERSION_REV_POS = 2;
constexpr size_t FIRMWARE_VERSION_SUPPORT_POS = 3;
constexpr size_t IN_LIST_PASSIVE_TARGET_NBTG = 0;
constexpr size_t IN_LIST_PASSIVE_TARGET_TG = 1;
constexpr size_t IN_LIST_PASSIVE_TARGET_SENS_RES_MSB = 2;
constexpr size_t IN_LIST_PASSIVE_TARGET_SENS_RES_LSB = 3;
constexpr size_t IN_LIST_PASSIVE_TARGET_SEL_RES = 4;
constexpr size_t IN_LIST_PASSIVE_TARGET_NFCID_LENGTH = 5;
// command codes
constexpr uint8_t COMMAND_GET_FIRMWARE_VERSION = 0x02;
constexpr uint8_t COMMAND_GET_FIRMWARE_VERSION_RESPONSE = 0x03;
constexpr uint8_t COMMAND_SAM_CONFIGURATION = 0x14;
constexpr uint8_t COMMAND_SAM_CONFIGURATION_RESPONSE = 0x15;
constexpr uint8_t COMMAND_IN_LIST_PASSIVE_TARGET = 0x4a;
constexpr uint8_t COMMAND_IN_LIST_PASSIVE_TARGET_RESPONSE = 0x4b;
void PN532Serial::run() {
readThreadHandle = std::thread(&PN532Serial::readThread, this);
}
void PN532Serial::readThread() {
uint8_t buf[2048];
size_t n = 0;
ssize_t first_start_code_offset;
while (true) {
if (readThreadHandle.shouldExit()) {
break;
}
auto c = read(fd, &buf[n], sizeof(buf) - n);
if (c == -1) {
EVLOG_error << "Read failed: " << strerror(errno) << " (" << errno << ")";
break;
}
if (c == 0) {
continue;
}
if (this->debug) {
EVLOG_info << "Received: " << hexdump(buf + n, c);
}
n += c;
restart_buffer_analysis:
EVLOG_verbose << "buffer content (size: " << n << "): " << hexdump(buf, n);
// packet minimum size is 6 byte for ACK or NACK, other frames are larger
if (n < 6) {
continue;
}
first_start_code_offset = -1;
// we cannot assume that we receive the whole response in one read call
// because of different driver/interfaces, so we have to scan for well-known
// patterns or check whether it looks like a valid frame after a start code
// pattern; if we find one, we can delete it from the buffer and move the
// left-over buffer content to the front, then we must restart analyzing
// to be sure to handle any following frame immediately and don't wait
// until the next read call runs/returns
for (ssize_t i = 0; i <= n - 6; ++i) {
// check for ACK or NACKs
if (memcmp(&buf[i], ACK_FRAME.data(), ACK_FRAME.size()) == 0) {
EVLOG_debug << "Received ACK";
n = n - i - ACK_FRAME.size();
memmove(buf, buf + i + ACK_FRAME.size(), n);
goto restart_buffer_analysis;
}
if (memcmp(&buf[i], NACK_FRAME.data(), NACK_FRAME.size()) == 0) {
EVLOG_debug << "Received NACK";
n = n - i - NACK_FRAME.size();
memmove(buf, buf + i + NACK_FRAME.size(), n);
goto restart_buffer_analysis;
}
// check for start_code
if (memcmp(&buf[i], START_CODE.data(), START_CODE.size()) == 0) {
if (first_start_code_offset == -1) {
first_start_code_offset = i;
}
auto len = buf[i + START_CODE.size()];
auto lcs = buf[i + START_CODE.size() + 1];
if (((len + lcs) & 0xff) != 0) {
EVLOG_verbose << "package length checksum mismatch";
continue;
}
// offset + start code size + len and lcs byte + data length + dcs and postamble
if (i + START_CODE.size() + 2 + len + 2 > n) {
EVLOG_verbose << "frame still too short or length bogus";
continue;
}
// accesses beyond i are safe below since we ensure that above
auto tfi = buf[i + START_CODE.size() + 2];
if (tfi != PN532_TO_HOST) {
EVLOG_verbose << "frame is not a response";
continue;
}
if (buf[i + START_CODE.size() + 2 + len + 1] != 0x00) {
EVLOG_verbose << "postamble check failed";
continue;
}
auto dcs_compl = 0;
for (size_t j = 0; j < len; ++j) {
dcs_compl += buf[i + START_CODE.size() + 2 + j];
}
auto dcs = buf[i + START_CODE.size() + 2 + len];
if (((dcs_compl + dcs) & 0xff) != 0) {
EVLOG_verbose << "package data checksum does not match";
continue;
}
// all checks so far indicate that frame/packet looks good
command_code = buf[i + START_CODE.size() + 2 + 1];
data = std::vector<uint8_t>(&buf[i + START_CODE.size() + 2 + 1 + 1],
&buf[i + START_CODE.size() + 2 + len]);
parseData();
// discard processed data, the processed size is:
// offset (incl. preamble) + start code size + len and lcs byte + data length + dcs and postamble
auto processed_size = i + START_CODE.size() + 1 + 1 + data.size() + 1 + 1;
n = n - processed_size;
memmove(buf, buf + processed_size, n);
goto restart_buffer_analysis;
}
}
if (first_start_code_offset == -1) {
// no start code found so far: continue with outer loop and receive more data
} else {
// use first start code offset found and assume garbage before -> discard this
n -= first_start_code_offset;
memmove(buf, buf + first_start_code_offset, n);
}
}
}
void PN532Serial::parseData() {
if (command_code == COMMAND_GET_FIRMWARE_VERSION_RESPONSE && this->get_firmware_version_promise) {
PN532Response response;
if (data.size() == 4) {
EVLOG_debug << "Sending ACK";
serialWrite(ACK_FRAME);
response.valid = true;
response.message = std::make_shared<FirmwareVersion>(
data.at(FIRMWARE_VERSION_IC_POS), data.at(FIRMWARE_VERSION_VER_POS), data.at(FIRMWARE_VERSION_REV_POS),
data.at(FIRMWARE_VERSION_SUPPORT_POS));
this->get_firmware_version_promise->set_value(response);
} else {
EVLOG_debug << "Sending NACK";
serialWrite(NACK_FRAME);
}
} else if (command_code == COMMAND_SAM_CONFIGURATION_RESPONSE && this->configure_sam_promise) {
EVLOG_debug << "Sending ACK";
serialWrite(ACK_FRAME);
this->configure_sam_promise->set_value(true);
} else if (command_code == COMMAND_IN_LIST_PASSIVE_TARGET_RESPONSE && this->in_list_passive_target_promise) {
// always send ACK for now
EVLOG_debug << "Sending ACK";
serialWrite(ACK_FRAME);
parseInListPassiveTargetResponse();
}
}
void PN532Serial::parseInListPassiveTargetResponse() {
PN532Response response;
auto in_list_passive_target_response = std::make_shared<InListPassiveTargetResponse>();
TargetData target_data;
if (data.size() >= 6) {
in_list_passive_target_response->nbtg = data.at(IN_LIST_PASSIVE_TARGET_NBTG);
if (in_list_passive_target_response->nbtg == 1) {
target_data.tg = data.at(IN_LIST_PASSIVE_TARGET_TG);
target_data.sens_res_msb = data.at(IN_LIST_PASSIVE_TARGET_SENS_RES_MSB);
target_data.sens_res_lsb = data.at(IN_LIST_PASSIVE_TARGET_SENS_RES_LSB);
target_data.sens_res = (target_data.sens_res_msb << 8) + target_data.sens_res_lsb;
target_data.sel_res = data.at(IN_LIST_PASSIVE_TARGET_SEL_RES);
target_data.nfcid_length = data.at(IN_LIST_PASSIVE_TARGET_NFCID_LENGTH);
if (this->debug) {
EVLOG_info << "Target data: " << std::right << std::hex << "\ntg: 0x" << std::setfill('0')
<< std::setw(2) << (int)target_data.tg << "\nsens_res_msb: 0x" << std::setfill('0')
<< std::setw(2) << (int)target_data.sens_res_msb << "\nsens_res_lsb: 0x" << std::setfill('0')
<< std::setw(2) << (int)target_data.sens_res_lsb << "\nsens_res: 0x" << std::setfill('0')
<< std::setw(4) << (int)target_data.sens_res << "\nsel_res: 0x" << std::setfill('0')
<< std::setw(2) << (int)target_data.sel_res << "\nnfcid_length: 0x" << std::setfill('0')
<< std::setw(2) << (int)target_data.nfcid_length;
}
if (data.size() >= 6 + target_data.nfcid_length) {
response.valid = true;
for (ssize_t i = 6; i < 6 + target_data.nfcid_length; i++) {
target_data.nfcid.push_back(data.at(i));
}
if (this->debug) {
std::stringstream nfcid_stream;
nfcid_stream << hexdump(target_data.nfcid);
nfcid_stream << " (length: " << std::dec << target_data.nfcid.size() << ")";
EVLOG_info << "NFCID: " << nfcid_stream.str();
}
if (data.size() >= 6 + target_data.nfcid_length + 1) {
auto ats_length = data.at(6 + target_data.nfcid_length);
if (data.size() >= 6 + target_data.nfcid_length + ats_length) {
for (size_t i = 6 + target_data.nfcid_length; i < 6 + target_data.nfcid_length + ats_length;
i++) {
target_data.ats.push_back(data.at(i));
}
}
if (this->debug) {
std::stringstream ats_stream;
ats_stream << hexdump(target_data.ats);
ats_stream << " (length: " << std::dec << target_data.ats.size() << ")";
EVLOG_info << "ATS: " << ats_stream.str();
}
}
}
in_list_passive_target_response->target_data.push_back(target_data);
}
}
response.message = in_list_passive_target_response;
this->in_list_passive_target_promise->set_value(response);
}
std::future<bool> PN532Serial::configureSAM() {
this->configure_sam_promise = std::make_unique<std::promise<bool>>();
this->serialWriteCommand({
COMMAND_SAM_CONFIGURATION, // command code
0x01, // normal mode
0x00, // no timeout
0x01 // P70_IRQ pin driven by PN532
});
return this->configure_sam_promise->get_future();
}
std::future<PN532Response> PN532Serial::getFirmwareVersion() {
this->get_firmware_version_promise = std::make_unique<std::promise<PN532Response>>();
this->serialWriteCommand({COMMAND_GET_FIRMWARE_VERSION});
return this->get_firmware_version_promise->get_future();
}
std::future<PN532Response> PN532Serial::inListPassiveTarget() {
this->in_list_passive_target_promise = std::make_unique<std::promise<PN532Response>>();
this->serialWriteCommand({
COMMAND_IN_LIST_PASSIVE_TARGET, // command code
0x01, // one target
0x00 // 105 kbps type A (ISO/IEC1443 Type A)
});
return this->in_list_passive_target_promise->get_future();
}
bool PN532Serial::serialWrite(const std::vector<uint8_t>& data) {
auto rv = write(fd, data.data(), data.size());
if (rv != data.size()) {
EVLOG_error << "Write failed: " << strerror(errno) << " (" << errno << ")";
return false;
}
return true;
}
bool PN532Serial::serialWriteCommand(const std::vector<uint8_t>& data) {
// calculate packet length checksum
uint8_t lcs = data.size() + 1;
lcs = (uint8_t)-lcs;
// calculate data check sum
uint8_t dcs = HOST_TO_PN532;
for (auto element : data) {
dcs += element;
}
dcs = (uint8_t)-dcs;
std::vector<uint8_t> serial_data;
// size: preamble + start code + LEN + LCS + TFI + data + DCS + postamble
serial_data.reserve(1 + START_CODE.size() + 1 + 1 + 1 + data.size() + 1 + 1);
serial_data.push_back(PREAMBLE);
serial_data.insert(serial_data.end(), START_CODE.begin(), START_CODE.end());
serial_data.push_back(data.size() + 1);
serial_data.push_back(lcs);
serial_data.push_back(HOST_TO_PN532);
serial_data.insert(serial_data.end(), data.begin(), data.end());
serial_data.push_back(dcs);
serial_data.push_back(POSTAMBLE);
if (this->debug) {
EVLOG_info << "Sending bytes: " << hexdump(serial_data);
}
return this->serialWrite(serial_data);
}
bool PN532Serial::reset() {
return this->serialWrite(
{0x55, 0x55, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00});
}
void PN532Serial::enableDebug() {
this->debug = true;
}

View File

@@ -0,0 +1,103 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright 2020 - 2022 Pionix GmbH and Contributors to EVerest
#ifndef PN532_SERIAL
#define PN532_SERIAL
#include <future>
#include <iomanip>
#include <iostream>
#include <sstream>
#include <stdint.h>
#include <termios.h>
#include <utils/serial.hpp>
#include <utils/thread.hpp>
#include <vector>
enum class PN532Command {
SAMConfiguration,
GetFirmwareVersion
};
struct PN532Message {
virtual ~PN532Message() = default;
};
struct PN532Response {
bool valid = false;
std::shared_ptr<PN532Message> message;
};
struct FirmwareVersion : public PN532Message {
uint8_t ic;
uint8_t ver; // TODO: also pre-parsed version string of this
uint8_t rev;
uint8_t support; // TODO: bool flags
FirmwareVersion(uint8_t ic, uint8_t ver, uint8_t rev, uint8_t support) :
ic(ic), ver(ver), rev(rev), support(support) {
}
};
struct TargetData {
uint8_t tg;
uint8_t sens_res_msb;
uint8_t sens_res_lsb;
uint16_t sens_res;
uint8_t sel_res;
uint8_t nfcid_length;
std::vector<uint8_t> nfcid;
std::vector<uint8_t> ats;
std::string getNFCID() {
std::stringstream ss;
for (auto it = nfcid.begin(); it != nfcid.end(); it++) {
int id = *it;
ss << std::setfill('0') << std::setw(2) << std::hex << id;
}
return ss.str();
};
};
struct InListPassiveTargetResponse : public PN532Message {
uint8_t nbtg = 0;
std::vector<TargetData> target_data;
};
class PN532Serial : public Everest::Serial {
public:
PN532Serial() = default;
virtual ~PN532Serial() = default;
void readThread();
void run() override;
bool reset();
bool serialWrite(const std::vector<uint8_t>& data);
bool serialWriteCommand(const std::vector<uint8_t>& data);
std::future<bool> configureSAM();
std::future<PN532Response> getFirmwareVersion();
std::future<PN532Response> inListPassiveTarget();
void enableDebug();
private:
static constexpr uint8_t PREAMBLE = 0x00;
static constexpr uint8_t POSTAMBLE = 0x00;
static constexpr uint8_t HOST_TO_PN532 = 0xd4;
static constexpr uint8_t PN532_TO_HOST = 0xd5;
const std::vector<uint8_t> START_CODE{0x00, 0xff};
const std::vector<uint8_t> ACK_FRAME{0x00, 0x00, 0xff, 0x00, 0xff, 0x00};
const std::vector<uint8_t> NACK_FRAME{0x00, 0x00, 0xff, 0xff, 0x00, 0x00};
std::unique_ptr<std::promise<bool>> configure_sam_promise;
std::unique_ptr<std::promise<PN532Response>> get_firmware_version_promise;
std::unique_ptr<std::promise<PN532Response>> in_list_passive_target_promise;
uint8_t command_code = 0;
std::vector<uint8_t> data;
bool debug = false;
void parseData();
void parseInListPassiveTargetResponse();
// Read thread for serial port
Everest::Thread readThreadHandle;
};
#endif

View File

@@ -0,0 +1,40 @@
#
# AUTO GENERATED - MARKED REGIONS WILL BE KEPT
# template version 3
#
# module setup:
# - ${MODULE_NAME}: module name
ev_setup_cpp_module()
# ev@bcc62523-e22b-41d7-ba2f-825b493a3c97:v1
target_include_directories(${MODULE_NAME}
PRIVATE
"common"
)
target_sources(${MODULE_NAME}
PRIVATE
"main/libnfc_handler.cpp"
)
target_link_libraries(${MODULE_NAME}
PRIVATE
"libnfc_nci"
)
# ev@bcc62523-e22b-41d7-ba2f-825b493a3c97:v1
target_sources(${MODULE_NAME}
PRIVATE
"main/auth_token_providerImpl.cpp"
)
# ev@c55432ab-152c-45a9-9d2e-7281d50c69c3:v1
install(FILES
"libnfc-nci_config/libnfc-nxp.conf"
"libnfc-nci_config/libnfc-nci.conf"
DESTINATION
"${CMAKE_INSTALL_SYSCONFDIR}/everest/libnfc_config/")
# ev@c55432ab-152c-45a9-9d2e-7281d50c69c3:v1

View File

@@ -0,0 +1,15 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright 2022 - 2024 Pionix GmbH and Contributors to EVerest
#include "PN7160TokenProvider.hpp"
namespace module {
void PN7160TokenProvider::init() {
invoke_init(*p_main);
}
void PN7160TokenProvider::ready() {
invoke_ready(*p_main);
}
} // namespace module

View File

@@ -0,0 +1,58 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright Pionix GmbH and Contributors to EVerest
#ifndef PN7160TOKEN_PROVIDER_HPP
#define PN7160TOKEN_PROVIDER_HPP
//
// AUTO GENERATED - MARKED REGIONS WILL BE KEPT
// template version 2
//
#include "ld-ev.hpp"
// headers for provided interface implementations
#include <generated/interfaces/auth_token_provider/Implementation.hpp>
// ev@4bf81b14-a215-475c-a1d3-0a484ae48918:v1
// insert your custom include headers here
// ev@4bf81b14-a215-475c-a1d3-0a484ae48918:v1
namespace module {
struct Conf {};
class PN7160TokenProvider : public Everest::ModuleBase {
public:
PN7160TokenProvider() = delete;
PN7160TokenProvider(const ModuleInfo& info, std::unique_ptr<auth_token_providerImplBase> p_main, Conf& config) :
ModuleBase(info), p_main(std::move(p_main)), config(config){};
const std::unique_ptr<auth_token_providerImplBase> p_main;
const Conf& config;
// ev@1fce4c5e-0ab8-41bb-90f7-14277703d2ac:v1
// insert your public definitions here
// ev@1fce4c5e-0ab8-41bb-90f7-14277703d2ac:v1
protected:
// ev@4714b2ab-a24f-4b95-ab81-36439e1478de:v1
// insert your protected definitions here
// ev@4714b2ab-a24f-4b95-ab81-36439e1478de:v1
private:
friend class LdEverest;
void init();
void ready();
// ev@211cfdbe-f69a-4cd6-a4ec-f8aaa3d1b6c8:v1
// insert your private definitions here
// ev@211cfdbe-f69a-4cd6-a4ec-f8aaa3d1b6c8:v1
};
// ev@087e516b-124c-48df-94fb-109508c7cda9:v1
// insert other definitions here
// ev@087e516b-124c-48df-94fb-109508c7cda9:v1
} // namespace module
#endif // PN7160TOKEN_PROVIDER_HPP

View File

@@ -0,0 +1,27 @@
.. _everest_modules_handwritten_PN7160TokenProvider:
.. *******************
.. PN7160TokenProvider
.. *******************
This module provides authentication tokens obtained from RFID cards via the NXP PN7160 NFC chip.
It uses a modified *libnfc-nci* as external dependency to interface the chip via I²C or SPI, either from user space or via a kernel module.
Hardware Interface Configuration
================================
Configuration of the hardware interface is possible at runtime.
The module installs two configuration files:
* ``libnfc-nci_config/libnfc-nci.conf``: define NFC options
* ``libnfc-nci_config/libnfc-nxp.conf``: choose the hardware interface (kernel module vs. userspace; I²C vs. SPI, ...)
Module Configuration
====================
The EVerest module can be adjusted in its behaviour as follows:
* ``token_debounce_interval_ms``: Publish tokens in minimum intervall of this timespan in order not to flood subscribers.
* ``disable_nfc_rfid``: Allows to load the module without actually initializing the hardware.

View File

@@ -0,0 +1,121 @@
##############################################################################
#
# Note by PIONIX GmbH
# ===================
#
# Original file distributed NXP
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
##############################################################################
########################### PN7160 libnfc-nci.conf ############################
###############################################################################
# Application options
APPL_TRACE_LEVEL=0xFF
PROTOCOL_TRACE_LEVEL=0xFFFFFFFF
NFC_DEBUG_ENABLED=0x00
###############################################################################
# File used for NFA storage
NFA_STORAGE="/data/vendor/nfc"
###############################################################################
# Forcing HOST to listen for a selected protocol
# 0x00 : Disable Host Listen
# 0x01 : Enable Host to Listen (A) for ISO-DEP tech A
# 0x02 : Enable Host to Listen (B) for ISO-DEP tech B
# 0x04 : Enable Host to Listen (F) for T3T Tag Type Protocol tech F
# 0x07 : Enable Host to Listen (ABF)for ISO-DEP tech AB & T3T Tag Type Protocol tech F
HOST_LISTEN_TECH_MASK=0x07
###############################################################################
# When screen is turned off, specify the desired power state of the controller.
# 0: power-off-sleep state; DEFAULT
# 1: full-power state
# 2: screen-off card-emulation (CE4/CE3/CE1 modes are used)
SCREEN_OFF_POWER_STATE=1
###############################################################################
# NCI Hal Module name
NCI_HAL_MODULE="nfc_nci.pn54x"
###############################################################################
# Force tag polling for the following technology(s).
# The bits are defined as tNFA_TECHNOLOGY_MASK in nfa_api.h.
# Default is NFA_TECHNOLOGY_MASK_A | NFA_TECHNOLOGY_MASK_B |
# NFA_TECHNOLOGY_MASK_F | NFA_TECHNOLOGY_MASK_ISO15693 |
# NFA_TECHNOLOGY_MASK_KOVIO | NFA_TECHNOLOGY_MASK_A_ACTIVE |
# NFA_TECHNOLOGY_MASK_F_ACTIVE
#
# Notable bits:
# NFA_TECHNOLOGY_MASK_A 0x01 /* NFC Technology A */
# NFA_TECHNOLOGY_MASK_B 0x02 /* NFC Technology B */
# NFA_TECHNOLOGY_MASK_F 0x04 /* NFC Technology F */
# NFA_TECHNOLOGY_MASK_ISO15693 0x08 /* Proprietary Technology */
# NFA_TECHNOLOGY_MASK_KOVIO 0x20 /* Proprietary Technology */
# NFA_TECHNOLOGY_MASK_A_ACTIVE 0x40 /* NFC Technology A active mode */
# NFA_TECHNOLOGY_MASK_F_ACTIVE 0x80 /* NFC Technology F active mode */
# This flag when set to zero will disable Reader mode.
POLLING_TECH_MASK=0xCF
###############################################################################
# Force P2P to only listen for the following technology(s).
# The bits are defined as tNFA_TECHNOLOGY_MASK in nfa_api.h.
# Default is NFA_TECHNOLOGY_MASK_A | NFA_TECHNOLOGY_MASK_F |
# NFA_TECHNOLOGY_MASK_A_ACTIVE | NFA_TECHNOLOGY_MASK_F_ACTIVE
#
# Notable bits:
# NFA_TECHNOLOGY_MASK_A 0x01 /* NFC Technology A */
# NFA_TECHNOLOGY_MASK_F 0x04 /* NFC Technology F */
# NFA_TECHNOLOGY_MASK_A_ACTIVE 0x40 /* NFC Technology A active mode */
# NFA_TECHNOLOGY_MASK_F_ACTIVE 0x80 /* NFC Technology F active mode */
# This flag when set to zero will disable P2P Listen mode.
P2P_LISTEN_TECH_MASK=0xC5
PRESERVE_STORAGE=0x01
###############################################################################
# AID_MATCHING constants
# AID_MATCHING_EXACT_ONLY 0x00
# AID_MATCHING_EXACT_OR_PREFIX 0x01
# AID_MATCHING_PREFIX_ONLY 0x02
# AID_MATCHING_EXACT_OR_SUBSET_OR_PREFIX 0x03
AID_MATCHING_MODE=0x03
###############################################################################
# Override the stack default for NFA_EE_MAX_EE_SUPPORTED set in nfc_target.h.
# Maximum EE supported number
NFA_MAX_EE_SUPPORTED=0x01
###############################################################################
#Set the OffHost AID supported power state:
OFFHOST_AID_ROUTE_PWR_STATE=0x3B
###############################################################################
# Vendor Specific Proprietary Protocol & Discovery Configuration
# Set to 0xFF if unsupported
# byte[0] NCI_PROTOCOL_18092_ACTIVE
# byte[1] NCI_PROTOCOL_B_PRIME
# byte[2] NCI_PROTOCOL_DUAL
# byte[3] NCI_PROTOCOL_15693
# byte[4] NCI_PROTOCOL_KOVIO
# byte[5] NCI_PROTOCOL_MIFARE
# byte[6] NCI_DISCOVERY_TYPE_POLL_KOVIO
# byte[7] NCI_DISCOVERY_TYPE_POLL_B_PRIME
# byte[8] NCI_DISCOVERY_TYPE_LISTEN_B_PRIME
NFA_PROPRIETARY_CFG={05:FF:FF:06:81:80:70:FF:FF}
###############################################################################

View File

@@ -0,0 +1,221 @@
##############################################################################
#
# Note by PIONIX GmbH
# ===================
#
# Original file distributed NXP
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
# --------------------------------------------------------
# This file has been changed by PIONIX GmbH in 11-2024
# Changes are marked below
# --------------------------------------------------------
#
##############################################################################
########################### PN7160 libnfc-nxp.conf ############################
###############################################################################
# Logging Levels. Suggested value for debugging is 0x03.
# NXPLOG_GLOBAL_LOGLEVEL - Configuration for Global logging level
# NXPLOG_EXTNS_LOGLEVEL - Configuration for extns logging level
# NXPLOG_NCIHAL_LOGLEVEL - Configuration for enabling logging of HAL
# NXPLOG_NCIX_LOGLEVEL - Configuration for enabling logging of NCI TX packets
# NXPLOG_NCIR_LOGLEVEL - Configuration for enabling logging of NCI RX packets
# NXPLOG_FWDNLD_LOGLEVEL - Configuration for enabling logging of FW download functionality
# NXPLOG_TML_LOGLEVEL - Configuration for enabling logging of TML
# Logging Levels
# NXPLOG_DEFAULT_LOGLEVEL 0x01
# NXPLOG_DEBUG_LOGLEVEL 0x03
# NXPLOG_WARN_LOGLEVEL 0x02
# NXPLOG_ERROR_LOGLEVEL 0x01
# NXPLOG_SILENT_LOGLEVEL 0x00
NXPLOG_EXTNS_LOGLEVEL=0x00
NXPLOG_NCIHAL_LOGLEVEL=0x00
NXPLOG_NCIX_LOGLEVEL=0x00
NXPLOG_NCIR_LOGLEVEL=0x00
NXPLOG_FWDNLD_LOGLEVEL=0x00
NXPLOG_TML_LOGLEVEL=0x00
###############################################################################
# TRANSPORT Type
# 0x00 - I2C /SPI for noraml nxpnfc driver
# 0x01 - Not Used, kept to align with Android code
# 0x02 - ALT_I2C
# 0x03 - ALT_SPI
NXP_TRANSPORT=0x02
###############################################################################
# Nfc Device Node name
NXP_NFC_DEV_NODE="/dev/nxpnfc"
# Modification by PIONIX GmbH 2024 vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
###############################################################################
# ALT_I2C/SPI Interface Configuration
# [PINs defined as GPIO23/24/25 on RPi5]
PIN_INT=594
PIN_ENABLE=595
PIN_FWDNLD=596
I2C_ADDRESS=0x28
I2C_BUS="/dev/i2c-1"
SPI_BUS="/dev/spidev0.0"
# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
###############################################################################
# Extension for Mifare reader enable
MIFARE_READER_ENABLE=0x01
###############################################################################
# Firmware file type
#.so file 0x01
#.bin file 0x02
NXP_FW_TYPE=0x01
###############################################################################
# System clock source selection configuration
#define CLK_SRC_XTAL 1
#define CLK_SRC_PLL 2
NXP_SYS_CLK_SRC_SEL=0x01
###############################################################################
# Dynamic RSSI feature enable
# Disable 0x00
# Enable 0x01
NXP_AGC_DEBUG_ENABLE=0x00
###############################################################################
# NXP proprietary settings
NXP_ACT_PROP_EXTN={2F, 02, 00}
###############################################################################
# NFC forum profile settings
NXP_NFC_PROFILE_EXTN={20, 02, 05, 01, A0, 44, 01, 00}
###############################################################################
# To enable i2c fragmentation set i2c fragmentation enable 0x01 to disable set
# to 0x00
NXP_I2C_FRAGMENTATION_ENABLED=0x00
###############################################################################
# System clock frequency selection configuration
#define CLK_FREQ_13MHZ 1
#define CLK_FREQ_19_2MHZ 2
#define CLK_FREQ_24MHZ 3
#define CLK_FREQ_26MHZ 4
#define CLK_FREQ_38_4MHZ 5
#define CLK_FREQ_52MHZ 6
NXP_SYS_CLK_FREQ_SEL=0x02
###############################################################################
# The timeout value to be used for clock request acknowledgment
# min value = 0x01 to max = 0x06
NXP_SYS_CLOCK_TO_CFG=0x06
###############################################################################
# TVDD configurations settings
# Allow NFCC to configure External TVDD
# There are two possible configurations (0x01 or 0x02):
# CFG1: Vbat is used to generate the VDD(TX) through TXLDO
# CFG2: external 5V is used to generate the VDD(TX) through TXLDO
NXP_EXT_TVDD_CFG=0x02
# CFG1: 3.3V for both Reader and Card modes
NXP_EXT_TVDD_CFG_1={20, 02, 0F, 01, A0, 0E, 0B, 31, 01, 01, 31, 00, 00, 00, 01, 00, D0, 0C}
# CFG2: VBAT2 to 5V and 4.7V for both Reader and Card modes
NXP_EXT_TVDD_CFG_2={20, 02, 0F, 01, A0, 0E, 0B, 11, 01, C2, B2, 00, B2, 1E, 1F, 00, D0, 0C}
###############################################################################
# Core configuration settings
NXP_CORE_CONF={ 20, 02, 31, 0F,
85, 01, 01,
28, 01, 00,
21, 01, 00,
30, 01, 08,
31, 01, 03,
32, 01, 60,
38, 01, 01,
33, 04, 01, 02, 03, 04,
54, 01, 06,
50, 01, 02,
5B, 01, 00,
80, 01, 01,
81, 01, 01,
82, 01, 0E,
18, 01, 01
}
###############################################################################
# NXP Proprietary core configuration extensions
# For more details refer to the NFC Controller User Manual
NXP_CORE_CONF_EXTN={20, 02, 09, 02,
A0, 5E, 01, 01,
A0, 40, 01, 00
}
###############################################################################
# RF configuration settings
# Below settings relates to OM5578 demo kit RF performance optimization
#NXP_RF_CONF_BLK_1={ 20, 02, A3, 13,
# A0, 0D, 06, 04, 35, 90, 01, F4, 01,
# A0, 0D, 06, 06, 44, 01, 90, 03, 00,
# A0, 0D, 06, 06, 30, B0, 01, 10, 00,
# A0, 0D, 06, 06, 42, 02, 00, FF, FF,
# A0, 0D, 03, 06, 3F, 04,
# A0, 0D, 06, 20, 42, 88, 00, FF, FF,
# A0, 0D, 04, 22, 44, 22, 00,
# A0, 0D, 06, 22, 2D, 50, 34, 0C, 00,
# A0, 0D, 06, 32, 42, F8, 00, FF, FF,
# A0, 0D, 06, 34, 2D, 24, 37, 0C, 00,
# A0, 0D, 06, 34, 33, 86, 80, 00, 70,
# A0, 0D, 04, 34, 44, 22, 00,
# A0, 0D, 06, 42, 2D, 15, 45, 0D, 00,
# A0, 0D, 04, 46, 44, 22, 00,
# A0, 0D, 06, 46, 2D, 05, 59, 0E, 00,
# A0, 0D, 06, 44, 42, 88, 00, FF, FF,
# A0, 0D, 06, 56, 2D, 05, 9F, 0C, 00,
# A0, 0D, 06, 54, 42, 88, 00, FF, FF,
# A0, 0D, 06, 0A, 33, 80, 86, 00, 70
#}
###############################################################################
# Extended APDU length for ISO_DEP
ISO_DEP_MAX_TRANSCEIVE=0xFEFF
###############################################################################
# Choose the presence-check algorithm for type-4 tag. If not defined, the default value is 1.
# 0 NFA_RW_PRES_CHK_DEFAULT; Let stack selects an algorithm
# 1 NFA_RW_PRES_CHK_I_BLOCK; ISO-DEP protocol's empty I-block
# 2 NFA_RW_PRES_CHK_ISO_DEP_NAK; ISO-DEP protocol's nak presence check command
PRESENCE_CHECK_ALGORITHM=2
###############################################################################
#T4T NFCEE ENABLE
#bit pos 0 = Enable T4T NFCEE from NFCC (Only wired R/W activated, RF read only activated)
NXP_T4T_NFCEE_ENABLE=0x01
###############################################################################
#Set the T4TNfcee AID Power state :
#This settings will be used when application does not set this parameter
# bit pos 0 = Switch On
# bit pos 1 = Switch Off
# bit pos 2 = Battery Off
# bit pos 3 = Screen off unlock
# bit pos 4 = Screen On lock
# bit pos 5 = Screen Off lock
DEFAULT_T4TNFCEE_AID_POWER_STATE=0x3B
###############################################################################

View File

@@ -0,0 +1,87 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright Pionix GmbH and Contributors to EVerest
#include "auth_token_providerImpl.hpp"
#include <filesystem>
std::string rfid_to_string(char const rfid[], size_t length) {
std::stringstream ss;
for (size_t i = 0; i < length; ++i) {
ss << std::setfill('0') << std::setw(2) << std::uppercase << std::hex << static_cast<uint16_t>(rfid[i]);
}
return ss.str();
};
namespace module {
namespace main {
void auth_token_providerImpl::init() {
if (config.disable_nfc_rfid) {
return;
}
std::filesystem::path config_path = mod->info.paths.etc / "libnfc_config";
EVLOG_info << "Using configuration path " << config_path << " to look for 'libnfc-nci.conf' and 'libnfc-nxp.conf'";
try {
this->nfc_handler = std::make_unique<NfcHandler>(config_path);
} catch (const std::exception& e) {
EVLOG_error << "Failed to initialize libnfc handler: " << e.what();
}
}
void auth_token_providerImpl::new_rfid_token_callback(char* uid, size_t length, NfcHandler::Protocol protocol) {
// debounce
const auto now = std::chrono::steady_clock::now();
const auto debounce_interval = std::chrono::milliseconds(config.token_debounce_interval_ms);
if (now < this->last_rfid_submit + debounce_interval) {
// nothing to do, just debounce
return;
}
if (uid == nullptr || length == 0 || length > 32) {
// NOTE (aw): invalid data?, can this even happen?
// NOTE (aw): we should probably log here?
return;
}
// convert token to string and publish ist
types::authorization::ProvidedIdToken token;
token.id_token.type = [](NfcHandler::Protocol const in) {
switch (in) {
case NfcHandler::Protocol::ISO_IEC_15693:
return types::authorization::IdTokenType::ISO15693;
case NfcHandler::Protocol::MIFARE:
return types::authorization::IdTokenType::ISO14443;
case NfcHandler::Protocol::UNKNOWN:
return types::authorization::IdTokenType::Local;
}
// FIXME (aw): default would be unknown, what to do here?
// choosing Local here, although this is not the proper way
return types::authorization::IdTokenType::Local;
}(protocol);
token.id_token.value = rfid_to_string(uid, length);
token.authorization_type = types::authorization::AuthorizationType::RFID;
if (config.debug) {
EVLOG_info << "Publishing new rfid/nfc token: " << token;
}
this->publish_provided_token(token);
this->last_rfid_submit = now;
}
void auth_token_providerImpl::ready() {
if (this->nfc_handler) {
this->nfc_handler->start(
[this](auto&&... args) { this->new_rfid_token_callback(std::forward<decltype(args)>(args)...); });
}
}
} // namespace main
} // namespace module

View File

@@ -0,0 +1,71 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright Pionix GmbH and Contributors to EVerest
#ifndef MAIN_AUTH_TOKEN_PROVIDER_IMPL_HPP
#define MAIN_AUTH_TOKEN_PROVIDER_IMPL_HPP
//
// AUTO GENERATED - MARKED REGIONS WILL BE KEPT
// template version 3
//
#include <generated/interfaces/auth_token_provider/Implementation.hpp>
#include "../PN7160TokenProvider.hpp"
// ev@75ac1216-19eb-4182-a85c-820f1fc2c091:v1
// insert your custom include headers here
#include "libnfc_handler.hpp"
// ev@75ac1216-19eb-4182-a85c-820f1fc2c091:v1
namespace module {
namespace main {
struct Conf {
int token_debounce_interval_ms;
bool disable_nfc_rfid;
bool debug;
};
class auth_token_providerImpl : public auth_token_providerImplBase {
public:
auth_token_providerImpl() = delete;
auth_token_providerImpl(Everest::ModuleAdapter* ev, const Everest::PtrContainer<PN7160TokenProvider>& mod,
Conf& config) :
auth_token_providerImplBase(ev, "main"), mod(mod), config(config){};
// ev@8ea32d28-373f-4c90-ae5e-b4fcc74e2a61:v1
// insert your public definitions here
// ev@8ea32d28-373f-4c90-ae5e-b4fcc74e2a61:v1
protected:
// no commands defined for this interface
// ev@d2d1847a-7b88-41dd-ad07-92785f06f5c4:v1
// insert your protected definitions here
// ev@d2d1847a-7b88-41dd-ad07-92785f06f5c4:v1
private:
const Everest::PtrContainer<PN7160TokenProvider>& mod;
const Conf& config;
virtual void init() override;
virtual void ready() override;
// ev@3370e4dd-95f4-47a9-aaec-ea76f34a66c9:v1
std::unique_ptr<NfcHandler> nfc_handler{nullptr};
void new_rfid_token_callback(char*, size_t, NfcHandler::Protocol);
std::chrono::steady_clock::time_point last_rfid_submit{};
// ev@3370e4dd-95f4-47a9-aaec-ea76f34a66c9:v1
};
// ev@3d7da0ad-02c2-493d-9920-0bbbd56b9876:v1
// insert other definitions here
// ev@3d7da0ad-02c2-493d-9920-0bbbd56b9876:v1
} // namespace main
} // namespace module
#endif // MAIN_AUTH_TOKEN_PROVIDER_IMPL_HPP

View File

@@ -0,0 +1,90 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright Pionix GmbH and Contributors to EVerest
#include <cstdio>
#include <iomanip>
#include <stdexcept>
#include <thread>
extern "C" {
#include <linux_nfc_api.h>
#include <linux_nfc_api_compatibility.h>
}
#include "libnfc_handler.hpp"
// NOTE (aw): access to this variable is not thread safe
// but for the current "one-shot" use, this should not be necessary
static NfcHandler* nfc_handler_instance{nullptr};
static nfcTagCallback_t nfc_callbacks;
NfcHandler::NfcHandler(const std::filesystem::path& config_path) {
// we could have also used a singleton instance,
if (nfc_handler_instance) {
throw std::runtime_error("Only one nfc handler instance allowed");
}
setConfigPath(config_path.c_str());
InitializeLogLevel();
if (doInitialize() != 0) {
throw std::runtime_error("Failed to initialize libnfc_nci library");
}
nfc_callbacks.onTagArrival = [](nfc_tag_info_t* tag_info) { nfc_handler_instance->on_tag_arrival(tag_info); };
nfc_callbacks.onTagDeparture = []() { nfc_handler_instance->on_tag_departure(); };
nfc_handler_instance = this;
}
bool NfcHandler::start(Callback callback_) {
if (this->callback) {
return false;
}
this->callback = std::move(callback_);
registerTagCallback(&nfc_callbacks);
// enable discovery in reader-only mody, no host-routing/host-card-emulation and force a restart
// doEnableDiscovery (int technologies_mask,
// int reader_only_mode,
// int enable_host_routing,
// int restart)
doEnableDiscovery(DEFAULT_NFA_TECH_MASK, 0x01, 0x0, 0x1);
return true;
}
void NfcHandler::on_tag_arrival(void* tag_info_) {
// unfortunately, typedefs can't be forward declared, therefor we need to do it here
const auto tag_info = reinterpret_cast<nfc_tag_info_t*>(tag_info_);
const auto protocol = [](tNFC_PROTOCOL const in) {
if (in == NFA_PROTOCOL_MIFARE) {
return Protocol::MIFARE;
} else if (in == NFA_PROTOCOL_15693) {
return Protocol::ISO_IEC_15693;
}
return Protocol::UNKNOWN;
}(tag_info->protocol);
if (this->callback) {
this->callback(tag_info->uid, tag_info->uid_length, protocol);
} else {
// this should not happen
// assert(false);
}
}
void NfcHandler::on_tag_departure() {
// handle tag departure
}
NfcHandler::~NfcHandler() {
disableDiscovery();
deregisterTagCallback();
doDeinitialize();
}

View File

@@ -0,0 +1,33 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright Pionix GmbH and Contributors to EVerest
#pragma once
#include <chrono>
#include <filesystem>
#include <memory>
#include <vector>
#include <generated/interfaces/auth_token_provider/Implementation.hpp>
class NfcHandler {
public:
enum class Protocol {
UNKNOWN,
MIFARE,
ISO_IEC_15693,
};
using Callback = std::function<void(char* uid, size_t length, Protocol)>;
NfcHandler(const std::filesystem::path& config_path);
~NfcHandler();
bool start(Callback);
private:
void on_tag_arrival(void* pTagInfo);
void on_tag_departure();
Callback callback{nullptr};
};

View File

@@ -0,0 +1,28 @@
description: PN7160 RFID/NFC token provider returning the token as soon as the tag can be read by the reader
provides:
main:
description: Implementation of PN7160 RFID/NFC token provider
interface: auth_token_provider
config:
token_debounce_interval_ms:
description: Minimal wait time in ms until next token will be published (debounce interval).
type: integer
default: 3000
minimum: 1000
maximum: 10000
disable_nfc_rfid:
description: Disable NFC RFID reader
type: boolean
default: false
debug:
description: Show debug output on command line.
type: boolean
default: false
metadata:
license: https://opensource.org/licenses/Apache-2.0
authors:
- Cornelius Claussen
- Kai-Uwe Hermann
- Thilo Molitor
- Anton Wöllert
- Christoph Burandt

View File

@@ -0,0 +1 @@
Drivers for NFC readers