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,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;
}