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:
@@ -0,0 +1,6 @@
|
||||
ev_add_module(NxpNfcFrontendTokenProvider)
|
||||
ev_add_module(PN532TokenProvider)
|
||||
|
||||
if(EVEREST_DEPENDENCY_ENABLED_LIBNFC_NCI)
|
||||
ev_add_module(PN7160TokenProvider)
|
||||
endif()
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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``.
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
@@ -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})
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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
|
||||
@@ -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)
|
||||
@@ -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 |
|
||||
|
||||

|
||||
@@ -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 |
@@ -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
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
)
|
||||
@@ -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
|
||||
@@ -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 */
|
||||
@@ -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
|
||||
)
|
||||
@@ -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 */
|
||||
@@ -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 */
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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
|
||||
)
|
||||
@@ -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 {};
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
@@ -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_
|
||||
@@ -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};
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
@@ -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)
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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)
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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.
|
||||
|
||||
@@ -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}
|
||||
|
||||
###############################################################################
|
||||
@@ -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
|
||||
|
||||
###############################################################################
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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();
|
||||
}
|
||||
@@ -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};
|
||||
};
|
||||
@@ -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
|
||||
@@ -0,0 +1 @@
|
||||
Drivers for NFC readers
|
||||
Reference in New Issue
Block a user