diff options
author | Matt Ranostay <matt.ranostay@konsulko.com> | 2018-05-24 22:57:13 -0700 |
---|---|---|
committer | Matt Ranostay <matt.ranostay@konsulko.com> | 2018-07-04 23:18:45 -0700 |
commit | 6eb99ceb647cf35c39dc97292f00040fbb821170 (patch) | |
tree | 1db97cb18370f6b25902bb06b2e01a74aae169e2 | |
parent | f9e5259d74c8cf521921a96377c64691b5b3c3ae (diff) |
binding: nfc: new initial binding
Slight rewrite to use libnfc initially for getting tag uid's for
user settings.
Bug-AGL: SPEC-1554
Change-Id: I7b8c30102b82e86a92c89909bcbfba9ab7164c1f
Signed-off-by: Matt Ranostay <matt.ranostay@konsulko.com>
-rw-r--r-- | CMakeLists.txt | 16 | ||||
-rw-r--r-- | README.md | 90 | ||||
-rw-r--r-- | binding/CMakeLists.txt | 35 | ||||
-rw-r--r-- | binding/afm-nfc-binding.c | 200 | ||||
m--------- | conf.d/app-templates | 0 | ||||
-rwxr-xr-x | conf.d/autobuild/agl/autobuild | 67 | ||||
-rwxr-xr-x | conf.d/autobuild/linux/autobuild | 67 | ||||
-rw-r--r-- | conf.d/cmake/config.cmake | 100 | ||||
-rw-r--r-- | conf.d/wgt/config.xml.in | 35 | ||||
-rw-r--r-- | htdocs/nfc/AFB-websock.js | 174 | ||||
-rw-r--r-- | htdocs/nfc/binding-debug.css | 61 | ||||
-rw-r--r-- | htdocs/nfc/index.html | 25 | ||||
-rw-r--r-- | htdocs/nfc/nfc-binding.js | 156 | ||||
-rw-r--r-- | src/CMakeLists.txt | 77 | ||||
-rw-r--r-- | src/api.c | 63 | ||||
-rw-r--r-- | src/libnfc_reader.c | 478 | ||||
-rw-r--r-- | src/libnfc_reader.h | 12 | ||||
-rw-r--r-- | src/nfc-binding.c | 134 | ||||
-rw-r--r-- | src/nfc-binding.h | 17 | ||||
-rw-r--r-- | src/stringutils.h | 41 |
20 files changed, 427 insertions, 1421 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index 1511ac0..b485097 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,7 +1,7 @@ ########################################################################### # Copyright 2015, 2016, 2017 IoT.bzh # -# author: Loïc Collignon <loic.collignon@iot.bzh> +# author: Romain Forlot <romain.forlot@iot.bzh> # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -18,18 +18,4 @@ CMAKE_MINIMUM_REQUIRED(VERSION 3.3) -option(USE_LIBNFC "Enable or disable the 'libnfc' usage." ON) -option(LIBNFC_POLL_ALL "Enable all modulation when polling." OFF) -option(LIBNFC_POLL_NMT_ISO14443A "Enable ISO-14443A modulation when polling." ON) -option(LIBNFC_POLL_NMT_ISOJEWEL "Enable ISO-JEWEL modulation when polling." OFF) -option(LIBNFC_POLL_NMT_ISO14443B "Enable ISO-14443B modulation when polling." OFF) -option(LIBNFC_POLL_NMT_ISO14443BI "Enable ISO-14443BI modulation when polling." OFF) -option(LIBNFC_POLL_NMT_ISO14443B2SR "Enable ISO-14443B2SR modulation when polling." OFF) -option(LIBNFC_POLL_NMT_ISO14443B2CT "Enable ISO-14443B2CT modulation when polling." OFF) -option(LIBNFC_POLL_NMT_FELICA "Enable Felica modulation when polling." OFF) - include(${CMAKE_CURRENT_SOURCE_DIR}/conf.d/cmake/config.cmake) - -install(DIRECTORY htdocs/nfc DESTINATION htdocs) -install(DIRECTORY etc DESTINATION ./) - @@ -1,84 +1,18 @@ -# nfc-binding -Binding to handle NFC devices and tags. -It currently use the libnfc, but we would like to support neard. -Unfortunatly, neard seem not mature enough right now. +# NFC Service -# Devices and Tags compatibilities +## Overview -Those tags were tested with both SCL3711 (pn533) and ACS122U (pn532). -ACS122U is currently not working using neard and have also some issues with libnfc. -Expect random error, but seem to stay stable and working. +NFC service uses the respective libnfc package to detect the presence of NFC tags and singal via an event -|Tag type |Protocol |libnfc|neard| -|---------------------------|----------------|------|-----| -|Alien H3 + FM1108 |ISO/IEC 14443A |yes |no² | -|FM1108 |ISO/IEC 14443A |yes |no² | -|Hitag2 |ISO/IEC 14443A |yes |no | -|Mifaire Ultralight |ISO/IEC 14443A |yes |yes | -|Mifare 1K S50 |ISO/IEC 14443A |yes |no² | -|Mifare Plus S2K |ISO/IEC 14443A |yes |no² | -|Mifare Desfire D41 |ISO/IEC 14443A |yes |yes | -|NTag 213 |ISO/IEC 14443A |yes |yes | -|Hellfest Cashless |ISO/IEC 14443A |yes |no² | -|French biometric passeport¹|ISO/IEC 14443A |yes |no² | -|French Credit Card |ISO/IEC 14443-4B|yes |no² | -|Alien H3 |N/A |no |no | -|Alien H3 9654 |N/A |no |no | -|Alien H3 9662 |N/A |no |no | -|Alien H3 + TK4100 |N/A |no |no | -|EM4450 |N/A |no |no | -|ICODE SLI |N/A |no |no | -|Picopass 2KS |N/A |no |no | -|SRI512 |N/A |no |no | -|Tag-it HF-I (TI2048) |N/A |no |no | -|TK4100 |N/A |no |no | +## Verbs -¹ UID is randomly generated so the tag is detected as a new one on each poll. +| Name | Description | JSON Parameters | +|--------------------|:-------------------------------------|:-----------------------------------------------------------------------| +| subscribe | subscribe to NFC events | *Request:* {"value": "presence"} | +| unsubscribe | unsubscribe to NFC events | *Request:* {"value": "presence"} | -² Polling is stopped at detection but no tag is exposed. +## Events -# UDev rules - -You may want to add some UDev's rule for nfc device to make things easier. -You can put those lines into /etc/udev/rules.d/99-nfc.rules -```Shell -ACTION!="add", GOTO="nfc_pn53x_end" - -# Advanced Card Systems, Ltd ACR122U -ATTRS{idVendor}=="072f", ATTRS{idProduct}=="2200", MODE="0666", SYMLINK+="nfc%n" - -# SCM Microsystems, Inc. SCL3711-NFC&RW -ATTRS{idVendor}=="04e6", ATTRS{idProduct}=="5591", MODE="0666", SYMLINK+="nfc%n" - -LABEL="nfc_pn53x_end" -``` - -# Kernel module -The SCL3711 is supported by the kernel and neard, so it takes the device and prevent the libnfc to use it. -If you have an error saying that the device is busy, it's probably the reason why. - -You have to unload nfc kernel modules to get it work using libnfc. -```ShellSession -root@localhost# rmmod pn533_usb -root@localhost# rmmod pn533 -root@localhost# rmmod nfc -``` - -To make it permanent you can add this file: /etc/modprobe.d/blacklist-nfc.conf -``` -blacklist nfc -blacklist pn533 -blacklist pn533_usb -``` - -# Compilation option - -* USE_LIBNFC - Enable or disable the 'libnfc' usage. Default is ON. - * LIBNFC_POLL_ALL Enable all modulation when polling. Default is OFF. - * LIBNFC_POLL_NMT_ISO14443A - Enable ISO-14443A modulation when polling. Default is ON. - * LIBNFC_POLL_NMT_ISOJEWEL - Enable ISO-JEWEL modulation when polling. Default is OFF. - * LIBNFC_POLL_NMT_ISO14443B - Enable ISO-14443B modulation when polling. Default is OFF. - * LIBNFC_POLL_NMT_ISO14443BI - Enable ISO-14443BI modulation when polling. Default is OFF. - * LIBNFC_POLL_NMT_ISO14443B2SR - Enable ISO-14443B2SR modulation when polling. Default is OFF. - * LIBNFC_POLL_NMT_ISO14443B2CT - Enable ISO-14443B2CT modulation when polling. Default is OFF. - * LIBNFC_POLL_NMT_FELICA - Enable Felica modulation when polling. Default is OFF.
\ No newline at end of file +| Name | Description | JSON Response | +|--------------------|:-------------------------------------|:------------------------------------------ ----------------------------| +| presence | event that reports NFC tag presence | *Response:* {"status": "detected", "uid": "042eb3628e4981"} | diff --git a/binding/CMakeLists.txt b/binding/CMakeLists.txt new file mode 100644 index 0000000..512cede --- /dev/null +++ b/binding/CMakeLists.txt @@ -0,0 +1,35 @@ +########################################################################### +# Copyright 2015, 2016, 2017 IoT.bzh +# +# author: Fulup Ar Foll <fulup@iot.bzh> +# contrib: Romain Forlot <romain.forlot@iot.bzh> +# +# 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. +########################################################################### + +# Add target to project dependency list +PROJECT_TARGET_ADD(afm-nfc-binding) + + # Define project Targets + add_library(afm-nfc-binding MODULE afm-nfc-binding.c) + + # Binder exposes a unique public entry point + SET_TARGET_PROPERTIES(${TARGET_NAME} PROPERTIES + PREFIX "lib" + LABELS "BINDING" + LINK_FLAGS ${BINDINGS_LINK_FLAG} + OUTPUT_NAME ${TARGET_NAME} + ) + + # Library dependencies (include updates automatically) + TARGET_LINK_LIBRARIES(${TARGET_NAME} ${link_libraries}) diff --git a/binding/afm-nfc-binding.c b/binding/afm-nfc-binding.c new file mode 100644 index 0000000..c92c36c --- /dev/null +++ b/binding/afm-nfc-binding.c @@ -0,0 +1,200 @@ +/* + * Copyright (C) 2018 Konsulko Group + * Author: Matt Ranostay <matt.ranostay@konsulko.com> + * + * 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. + * + * TODO: add support for NFC p2p transactions + */ + +#define _GNU_SOURCE +#include <errno.h> +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <stdbool.h> +#include <unistd.h> +#include <pthread.h> +#include <glib.h> +#include <glib-object.h> +#include <json-c/json.h> +#include <nfc/nfc.h> +#include <nfc/nfc-types.h> + +#define AFB_BINDING_VERSION 2 +#include <afb/afb-binding.h> + +#define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0])) +#define WAIT_FOR_REMOVE(dev) { while (0 == nfc_initiator_target_is_present(dev, NULL)) {} } + +static struct afb_event presence_event; +static char *current_uid = NULL; +static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; + +static const nfc_modulation modulations[] = { + { .nmt = NMT_ISO14443A, .nbr = NBR_106 }, +}; + +static char *to_hex_string(unsigned char *data, size_t size) +{ + char *buffer = malloc((2 * size) + 1); + char *tmp = buffer; + int i; + + if (buffer == NULL) + return buffer; + + for (i = 0; i < size; i++) { + tmp += sprintf(tmp, "%.2x", data[i]); + } + + return buffer; +} + +static char *get_tag_uid(nfc_target *nt) +{ + if (nt->nm.nmt == NMT_ISO14443A) + return to_hex_string((unsigned char *) &nt->nti.nai.abtUid, nt->nti.nai.szUidLen); + + return NULL; +} + +static void send_detect_event(char *current_id) +{ + json_object *jresp; + + if (current_id == NULL) + return; + + jresp = json_object_new_object(); + + json_object_object_add(jresp, "status", json_object_new_string("detected")); + json_object_object_add(jresp, "uid", json_object_new_string(current_uid)); + + afb_event_push(presence_event, jresp); +} + +static void *nfc_loop_thread(void *ptr) +{ + nfc_context *ctx = NULL; + nfc_device *dev = NULL; + + nfc_init(&ctx); + + dev = nfc_open(ctx, NULL); + + if (dev == NULL) { + AFB_ERROR("Cannot get context for libnfc"); + nfc_exit(ctx); + exit(EXIT_FAILURE); + } + + if (nfc_initiator_init(dev) < 0) { + AFB_ERROR("Cannot get initiator mode from libnfc"); + nfc_close(dev); + nfc_exit(ctx); + exit(EXIT_FAILURE); + } + + while (1) { + nfc_target nt; + json_object *jresp; + int res = nfc_initiator_poll_target(dev, modulations, ARRAY_SIZE(modulations), 0xff, 2, &nt); + + if (res < 0) + break; + + pthread_mutex_lock(&mutex); + + current_uid = get_tag_uid(&nt); + send_detect_event(current_uid); + + pthread_mutex_unlock(&mutex); + + WAIT_FOR_REMOVE(dev); + + pthread_mutex_lock(&mutex); + + jresp = json_object_new_object(); + json_object_object_add(jresp, "status", json_object_new_string("removed")); + json_object_object_add(jresp, "uid", json_object_new_string(current_uid)); + afb_event_push(presence_event, jresp); + + free(current_uid); + current_uid = NULL; + + pthread_mutex_unlock(&mutex); + } + + nfc_close(dev); + nfc_exit(ctx); + + return NULL; +} + +static int init() +{ + pthread_t thread_id; + + presence_event = afb_daemon_make_event("presence"); + + return pthread_create(&thread_id, NULL, nfc_loop_thread, NULL); +} + +static void subscribe(struct afb_req request) +{ + const char *value = afb_req_value(request, "value"); + + if (value && !strcasecmp(value, "presence")) { + afb_req_subscribe(request, presence_event); + afb_req_success(request, NULL, NULL); + + // send initial tag if exists + pthread_mutex_lock(&mutex); + send_detect_event(current_uid); + pthread_mutex_unlock(&mutex); + + return; + } + + afb_req_fail(request, "failed", "Invalid event"); +} + +static void unsubscribe(struct afb_req request) +{ + const char *value = afb_req_value(request, "value"); + + if (value && !strcasecmp(value, "presence")) { + afb_req_unsubscribe(request, presence_event); + afb_req_success(request, NULL, NULL); + return; + } + + afb_req_fail(request, "failed", "Invalid event"); +} + +static const struct afb_verb_v2 binding_verbs[] = { + { .verb = "subscribe", .callback = subscribe, .info = "Subscribe to NFC events" }, + { .verb = "unsubscribe", .callback = unsubscribe, .info = "Unsubscribe to NFC events" }, + { } +}; + +/* + * binder API description + */ +const struct afb_binding_v2 afbBindingV2 = { + .api = "nfc", + .specification = "NFC service API", + .verbs = binding_verbs, + .init = init, +}; diff --git a/conf.d/app-templates b/conf.d/app-templates -Subproject 8c2b05967a3237e624a2cc78e13fcd1c5e72991 +Subproject e400fb3543217ccd4e2b2a67b018bc947f09bd2 diff --git a/conf.d/autobuild/agl/autobuild b/conf.d/autobuild/agl/autobuild new file mode 100755 index 0000000..83097ab --- /dev/null +++ b/conf.d/autobuild/agl/autobuild @@ -0,0 +1,67 @@ +#!/usr/bin/make -f +# Copyright (C) 2015, 2016 "IoT.bzh" +# Author "Romain Forlot" <romain.forlot@iot.bzh> +# +# 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. + +THISFILE := $(lastword $(MAKEFILE_LIST)) +BUILD_DIR := $(abspath $(dir $(THISFILE)/../../../../..)/build) +DEST := ${BUILD_DIR}/target + +.PHONY: all clean distclean configure build package help update + +all: help + +help: + @echo "List of targets available:" + @echo "" + @echo "- all" + @echo "- clean" + @echo "- distclean" + @echo "- configure" + @echo "- build: compilation, link and prepare files for package into a widget" + @echo "- package: output a widget file '*.wgt'" + @echo "- install: install in your ${CMAKE_INSTALL_DIR} directory" + @echo "" + @echo "Usage: ./conf.d/autobuild/agl/autobuild package DEST=${HOME}/opt" + @echo "Don't use your build dir as DEST as wgt file is generated at this location" + +update: configure + @cmake --build ${BUILD_DIR} --target autobuild + +clean: + @([ -d ${BUILD_DIR} ] && make -C ${BUILD_DIR} clean) || echo Nothing to clean + +distclean: + @rm -rf ${BUILD_DIR} + +configure: ${BUILD_DIR}/Makefile + +build: configure + @cmake --build ${BUILD_DIR} ${BUILD_ARGS} --target all + +package: build + @mkdir -p ${BUILD_DIR}/$@/bin + @mkdir -p ${BUILD_DIR}/$@/etc + @mkdir -p ${BUILD_DIR}/$@/lib + @mkdir -p ${BUILD_DIR}/$@/htdocs + @mkdir -p ${BUILD_DIR}/$@/var + @cmake --build ${BUILD_DIR} --target widget + @mkdir -p ${DEST} && cp ${BUILD_DIR}/*wgt ${DEST} + +install: build + @cmake --build ${BUILD_DIR} --target install + +${BUILD_DIR}/Makefile: + @[ -d ${BUILD_DIR} ] || mkdir -p ${BUILD_DIR} + @[ -f ${BUILD_DIR}/Makefile ] || (cd ${BUILD_DIR} && cmake ${CONFIGURE_ARGS} ..) diff --git a/conf.d/autobuild/linux/autobuild b/conf.d/autobuild/linux/autobuild new file mode 100755 index 0000000..83097ab --- /dev/null +++ b/conf.d/autobuild/linux/autobuild @@ -0,0 +1,67 @@ +#!/usr/bin/make -f +# Copyright (C) 2015, 2016 "IoT.bzh" +# Author "Romain Forlot" <romain.forlot@iot.bzh> +# +# 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. + +THISFILE := $(lastword $(MAKEFILE_LIST)) +BUILD_DIR := $(abspath $(dir $(THISFILE)/../../../../..)/build) +DEST := ${BUILD_DIR}/target + +.PHONY: all clean distclean configure build package help update + +all: help + +help: + @echo "List of targets available:" + @echo "" + @echo "- all" + @echo "- clean" + @echo "- distclean" + @echo "- configure" + @echo "- build: compilation, link and prepare files for package into a widget" + @echo "- package: output a widget file '*.wgt'" + @echo "- install: install in your ${CMAKE_INSTALL_DIR} directory" + @echo "" + @echo "Usage: ./conf.d/autobuild/agl/autobuild package DEST=${HOME}/opt" + @echo "Don't use your build dir as DEST as wgt file is generated at this location" + +update: configure + @cmake --build ${BUILD_DIR} --target autobuild + +clean: + @([ -d ${BUILD_DIR} ] && make -C ${BUILD_DIR} clean) || echo Nothing to clean + +distclean: + @rm -rf ${BUILD_DIR} + +configure: ${BUILD_DIR}/Makefile + +build: configure + @cmake --build ${BUILD_DIR} ${BUILD_ARGS} --target all + +package: build + @mkdir -p ${BUILD_DIR}/$@/bin + @mkdir -p ${BUILD_DIR}/$@/etc + @mkdir -p ${BUILD_DIR}/$@/lib + @mkdir -p ${BUILD_DIR}/$@/htdocs + @mkdir -p ${BUILD_DIR}/$@/var + @cmake --build ${BUILD_DIR} --target widget + @mkdir -p ${DEST} && cp ${BUILD_DIR}/*wgt ${DEST} + +install: build + @cmake --build ${BUILD_DIR} --target install + +${BUILD_DIR}/Makefile: + @[ -d ${BUILD_DIR} ] || mkdir -p ${BUILD_DIR} + @[ -f ${BUILD_DIR}/Makefile ] || (cd ${BUILD_DIR} && cmake ${CONFIGURE_ARGS} ..) diff --git a/conf.d/cmake/config.cmake b/conf.d/cmake/config.cmake index f625321..35da628 100644 --- a/conf.d/cmake/config.cmake +++ b/conf.d/cmake/config.cmake @@ -18,14 +18,11 @@ # Project Info # ------------------ -set(PROJECT_NAME nfc-binding) -set(PROJECT_VERSION "0.1") -set(PROJECT_PRETTY_NAME "NFC Binding") -set(PROJECT_DESCRIPTION "Abstract NFC readers.") -set(PROJECT_URL "https://gerrit.automotivelinux.org/gerrit/apps/app-templates") +set(PROJECT_NAME agl-service-nfc) +set(PROJECT_PRETTY_NAME "AFM binding for NFC") +set(PROJECT_DESCRIPTION "Binding for handling NFC access controls") +set(PROJECT_VERSION "1.0") set(PROJECT_ICON "icon.png") -set(PROJECT_AUTHOR "Collignon, Loïc") -set(PROJECT_AUTHOR_MAIL "loic.collignon@iot.bzh") set(PROJECT_LICENSE "APL2.0") set(PROJECT_LANGUAGES,"C") @@ -45,6 +42,7 @@ set(PROJECT_APP_TEMPLATES_DIR "conf.d/app-templates") # Compilation Mode (DEBUG, RELEASE) # ---------------------------------- +set(CMAKE_BUILD_TYPE "DEBUG") # Kernel selection if needed. You can choose between a # mandatory version to impose a minimal version. @@ -57,8 +55,8 @@ set(PROJECT_APP_TEMPLATES_DIR "conf.d/app-templates") # NOTE*** FOR NOW IT CHECKS KERNEL Yocto environment and # Yocto SDK Kernel version. # ----------------------------------------------- -#set (kernel_mandatory_version 4.8) -#set (kernel_minimal_version 4.8) +#set(kernel_mandatory_version 4.8) +set(kernel_minimal_version 4.8) # Compiler selection if needed. Impose a minimal version. # ----------------------------------------------- @@ -68,71 +66,26 @@ set (gcc_minimal_version 4.9) # ----------------------------- set (PKG_REQUIRED_LIST json-c + glib-2.0 + libnfc libsystemd>=222 afb-daemon - libnfc ) -# Prefix path where will be installed the files -# Default: /usr/local (need root permission to write in) -# ------------------------------------------------------ -#set(CMAKE_INSTALL_PREFIX $ENV{HOME}/opt) - # Customize link option # ----------------------------- -list(APPEND link_libraries -lnfc) - -# Compilation options definition -# Use CMake generator expressions to specify only for a specific language -# Values are prefilled with default options that is currently used. -# Either separate options with ";", or each options must be quoted separately -# DO NOT PUT ALL OPTION QUOTED AT ONCE , COMPILATION COULD FAILED ! -# ---------------------------------------------------------------------------- -#set(COMPILE_OPTIONS -# -Wall -# -Wextra -# -Wconversion -# -Wno-unused-parameter -# -Wno-sign-compare -# -Wno-sign-conversion -# -Werror=maybe-uninitialized -# -Werror=implicit-function-declaration -# -ffunction-sections -# -fdata-sections -# -fPIC -# CACHE STRING "Compilation flags") -#set(C_COMPILE_OPTIONS "" CACHE STRING "Compilation flags for C language.") -#set(CXX_COMPILE_OPTIONS "" CACHE STRING "Compilation flags for C++ language.") -#set(PROFILING_COMPILE_OPTIONS -# -g -# -O0 -# -pg -# -Wp,-U_FORTIFY_SOURCE -# CACHE STRING "Compilation flags for PROFILING build type.") -#set(DEBUG_COMPILE_OPTIONS -# -g -# -ggdb -# -Wp,-U_FORTIFY_SOURCE -# CACHE STRING "Compilation flags for DEBUG build type.") -#set(CCOV_COMPILE_OPTIONS -# -g -# -O2 -# --coverage -# CACHE STRING "Compilation flags for CCOV build type.") -#set(RELEASE_COMPILE_OPTIONS -# -g -# -O2 -# CACHE STRING "Compilation flags for RELEASE build type.") +list (APPEND link_libraries -pthread) # (BUG!!!) as PKG_CONFIG_PATH does not work [should be an env variable] # --------------------------------------------------------------------- +set(CMAKE_INSTALL_PREFIX $ENV{HOME}/opt) set(CMAKE_PREFIX_PATH ${CMAKE_INSTALL_PREFIX}/lib64/pkgconfig ${CMAKE_INSTALL_PREFIX}/lib/pkgconfig) set(LD_LIBRARY_PATH ${CMAKE_INSTALL_PREFIX}/lib64 ${CMAKE_INSTALL_PREFIX}/lib) # Optional location for config.xml.in # ----------------------------------- -#set(WIDGET_ICON conf.d/wgt/${PROJECT_ICON} CACHE PATH "Path to the widget icon") -set(WIDGET_CONFIG_TEMPLATE ${CMAKE_CURRENT_SOURCE_DIR}/conf.d/wgt/config.xml.in CACHE PATH "Path to widget config file template (config.xml.in)") +set(WIDGET_CONFIG_TEMPLATE ${CMAKE_CURRENT_SOURCE_DIR}/conf.d/wgt/config.xml.in) + # Mandatory widget Mimetype specification of the main unit # -------------------------------------------------------------------------- @@ -156,7 +109,12 @@ set(WIDGET_TYPE application/vnd.agl.service) # This is the file that will be executed, loaded, # at launch time by the application framework. # -set(WIDGET_ENTRY_POINT config.xml) +set(WIDGET_ENTRY_POINT lib/libafm-nfc-binding.so) + +# Print a helper message when every thing is finished +# ---------------------------------------------------- +set(CLOSING_MESSAGE "Test with: afb-daemon --rootdir=\$\$(pwd)/package --binding=\$\$(pwd)/package/${WIDGET_ENTRY_POINT} --port=1234 --tracereq=common --token=\"1\" --verbose") +set(PACKAGE_MESSAGE "Install widget file using in the target : afm-util install ${PROJECT_NAME}.wgt") # Optional dependencies order # --------------------------- @@ -170,6 +128,10 @@ set(WIDGET_ENTRY_POINT config.xml) # ------------------------- #set(EXTRA_LINK_LIBRARIES) +# Optional force binding installation +# ------------------------------------ +# set(BINDINGS_INSTALL_PREFIX PrefixPath ) + # Optional force binding Linking flag # ------------------------------------ # set(BINDINGS_LINK_FLAG LinkOptions ) @@ -181,20 +143,8 @@ set(WIDGET_ENTRY_POINT config.xml) # Optional Application Framework security token # and port use for remote debugging. #------------------------------------------------------------ -set(AFB_TOKEN "" CACHE PATH "Default binder security token") -set(AFB_REMPORT "1234" CACHE PATH "Default binder listening port") - -# Print a helper message when every thing is finished -# ---------------------------------------------------- -set(CLOSING_MESSAGE "Typical binding launch: afb-daemon --port=${AFB_REMPORT} --workdir=${CMAKE_BINARY_DIR}/package --ldpaths=lib --roothttp=htdocs --token=\"${AFB_TOKEN}\" --tracereq=common --verbose") -set(PACKAGE_MESSAGE "Install widget file using in the target : afm-util install ${PROJECT_NAME}.wgt") - -# Optional schema validator about now only XML, LUA and JSON -# are supported -#------------------------------------------------------------ -#set(LUA_CHECKER "luac" "-p" CACHE STRING "LUA compiler") -#set(XML_CHECKER "xmllint" CACHE STRING "XML linter") -#set(JSON_CHECKER "json_verify" CACHE STRING "JSON linter") +#set(AFB_TOKEN "" CACHE PATH "Default AFB_TOKEN") +#set(AFB_REMPORT "1234" CACHE PATH "Default AFB_TOKEN") # This include is mandatory and MUST happens at the end # of this file, else you expose you to unexpected behavior diff --git a/conf.d/wgt/config.xml.in b/conf.d/wgt/config.xml.in index e518d20..d19e60f 100644 --- a/conf.d/wgt/config.xml.in +++ b/conf.d/wgt/config.xml.in @@ -1,18 +1,23 @@ <?xml version="1.0" encoding="UTF-8"?> <widget xmlns="http://www.w3.org/ns/widgets" id="@PROJECT_NAME@" version="@PROJECT_VERSION@"> - <name>@PROJECT_NAME@</name> - <icon src="@PROJECT_ICON@"/> - <content src="@WIDGET_ENTRY_POINT@" type="@WIDGET_TYPE@"/> - <description>@PROJECT_DESCRIPTION@</description> - <author>@PROJECT_AUTHOR@ <@PROJECT_AUTHOR_MAIL@></author> - <license>@PROJECT_LICENSE@</license> - <feature name="urn:AGL:widget:required-permission"> - <param name="urn:AGL:permission::public:hidden" value="required" /> - </feature> - <feature name="urn:AGL:widget:required-api"> - <param name="lib/afb-nfc-binding.so" value="local" /> - </feature> - <feature name="urn:AGL:widget:provided-api"> - <param name="nfc" value="ws" /> - </feature> + <name>@PROJECT_NAME@</name> + <icon src="@PROJECT_ICON@"/> + <content src="@WIDGET_ENTRY_POINT@" type="@WIDGET_TYPE@"/> + <description>@PROJECT_DESCRIPTION@</description> + <author>@PROJECT_AUTHOR@ <@PROJECT_AUTHOR_MAIL@></author> + <license>@PROJECT_LICENSE@</license> + + <feature name="urn:AGL:widget:required-permission"> + <param name="urn:AGL:permission::public:hidden" value="required" /> + <param name="urn:AGL:permission::public:no-htdocs" value="required" /> + <param name="urn:AGL:permission::system:run-by-default" value="required" /> + </feature> + + <feature name="urn:AGL:widget:provided-api"> + <param name="nfc" value="ws" /> + </feature> + + <feature name="urn:AGL:widget:required-api"> + <param name="@WIDGET_ENTRY_POINT@" value="local" /> + </feature> </widget> diff --git a/htdocs/nfc/AFB-websock.js b/htdocs/nfc/AFB-websock.js deleted file mode 100644 index 08a7ffe..0000000 --- a/htdocs/nfc/AFB-websock.js +++ /dev/null @@ -1,174 +0,0 @@ -AFB = function(base, initialtoken){ - -var urlws = "ws://"+window.location.host+"/"+base; -var urlhttp = "http://"+window.location.host+"/"+base; - -/*********************************************/ -/**** ****/ -/**** AFB_context ****/ -/**** ****/ -/*********************************************/ -var AFB_context; -{ - var UUID = undefined; - var TOKEN = initialtoken; - - var context = function(token, uuid) { - this.token = token; - this.uuid = uuid; - } - - context.prototype = { - get token() {return TOKEN;}, - set token(tok) {if(tok) TOKEN=tok;}, - get uuid() {return UUID;}, - set uuid(id) {if(id) UUID=id;} - }; - - AFB_context = new context(); -} -/*********************************************/ -/**** ****/ -/**** AFB_websocket ****/ -/**** ****/ -/*********************************************/ -var AFB_websocket; -{ - var CALL = 2; - var RETOK = 3; - var RETERR = 4; - var EVENT = 5; - - var PROTO1 = "x-afb-ws-json1"; - - AFB_websocket = function(onopen, onabort) { - var u = urlws; - if (AFB_context.token) { - u = u + '?x-afb-token=' + AFB_context.token; - if (AFB_context.uuid) - u = u + '&x-afb-uuid=' + AFB_context.uuid; - } - this.ws = new WebSocket(u, [ PROTO1 ]); - this.pendings = {}; - this.awaitens = {}; - this.counter = 0; - this.ws.onopen = onopen.bind(this); - this.ws.onerror = onerror.bind(this); - this.ws.onclose = onclose.bind(this); - this.ws.onmessage = onmessage.bind(this); - this.onopen = onopen; - this.onabort = onabort; - this.onclose = onabort; - } - - function onerror(event) { - var f = this.onabort; - if (f) { - delete this.onopen; - delete this.onabort; - f && f(this); - } - this.onerror && this.onerror(this); - } - - function onopen(event) { - var f = this.onopen; - delete this.onopen; - delete this.onabort; - f && f(this); - } - - function onclose(event) { - for (var id in this.pendings) { - var ferr = this.pendings[id].onerror; - ferr && ferr(null, this); - } - this.pendings = {}; - this.onclose && this.onclose(); - } - - function fire(awaitens, name, data) { - var a = awaitens[name]; - if (a) - a.forEach(function(handler){handler(data);}); - var i = name.indexOf("/"); - if (i >= 0) { - a = awaitens[name.substring(0,i)]; - if (a) - a.forEach(function(handler){handler(data);}); - } - a = awaitens["*"]; - if (a) - a.forEach(function(handler){handler(data);}); - } - - function reply(pendings, id, ans, offset) { - if (id in pendings) { - var p = pendings[id]; - delete pendings[id]; - var f = p[offset]; - f(ans); - } - } - - function onmessage(event) { - var obj = JSON.parse(event.data); - var code = obj[0]; - var id = obj[1]; - var ans = obj[2]; - AFB_context.token = obj[3]; - switch (code) { - case RETOK: - reply(this.pendings, id, ans, 0); - break; - case RETERR: - reply(this.pendings, id, ans, 1); - break; - case EVENT: - default: - fire(this.awaitens, id, ans); - break; - } - } - - function close() { - this.ws.close(); - this.onabort(); - } - - function call(method, request) { - return new Promise((function(resolve, reject){ - var id, arr; - do { - id = String(this.counter = 4095 & (this.counter + 1)); - } while (id in this.pendings); - this.pendings[id] = [ resolve, reject ]; - arr = [CALL, id, method, request ]; - if (AFB_context.token) arr.push(AFB_context.token); - this.ws.send(JSON.stringify(arr)); - }).bind(this)); - } - - function onevent(name, handler) { - var id = name; - var list = this.awaitens[id] || (this.awaitens[id] = []); - list.push(handler); - } - - AFB_websocket.prototype = { - close: close, - call: call, - onevent: onevent - }; -} -/*********************************************/ -/**** ****/ -/**** ****/ -/**** ****/ -/*********************************************/ -return { - context: AFB_context, - ws: AFB_websocket -}; -}; - diff --git a/htdocs/nfc/binding-debug.css b/htdocs/nfc/binding-debug.css deleted file mode 100644 index f41c940..0000000 --- a/htdocs/nfc/binding-debug.css +++ /dev/null @@ -1,61 +0,0 @@ -#debug-panel { - float: right; -} - -#debug-panel.collapsed { - background-color: transparent; - overflow-x: hidden; -} - -#debug-panel.expanded { - background-color: lightyellow; - max-width: 25%; - overflow-x: scroll; -} - -#debug-panel.collapsed > #debug-panel-collapse { - display: none; -} - -#debug-panel.expanded > #debug-panel-collapse { - display: block; -} - -#debug-panel.collapsed > #debug-panel-expand { - display: block; -} - -#debug-panel.expanded > #debug-panel-expand { - display: none; -} - -#debug-panel.expanded > #debug-panel-content { - display: block; -} - -#debug-panel.collapsed > #debug-panel-content { - display: none; -} - -.json-key { - color: cornflowerblue; - font-weight: bold; -} - -.json-string { - color: crimson; -} - -.json-number { - color: sandybrown; -} - -.json-boolean { - color: fuchsia; - font-weight: bold; -} - -.json-null { - color: black; - font-weight: bold; -} diff --git a/htdocs/nfc/index.html b/htdocs/nfc/index.html deleted file mode 100644 index c7c049e..0000000 --- a/htdocs/nfc/index.html +++ /dev/null @@ -1,25 +0,0 @@ -<!doctype html> -<html> - <head> - <title>agl-service-nfc</title> - <meta charset="UTF-8"> - <script type="text/javascript" src="AFB-websock.js"></script> - <script type="text/javascript" src="nfc-binding.js"></script> - <link rel="stylesheet" type="text/css" href="binding-debug.css" /> - </head> - - <body onload="init();" id="app-body"> - <div id="debug-panel-container"></div> - <h1>agl-service-nfc</h1> - <p> - <ul> - <li><button onclick="subscribe();">Subscribe</button></li> - <li><button onclick="unsubscribe();">Unsubscribe</button></li> - <li><button onclick="list_devices();">list-devices</button></li> - <li><button onclick="list_devices_capabilities();">list-device-capabilities</button></li> - <li><button onclick="start_polling();">start-polling</button></li> - <li><button onclick="stop_polling();">stop-polling</button></li> - </ul> - </p> - </body> -</html> diff --git a/htdocs/nfc/nfc-binding.js b/htdocs/nfc/nfc-binding.js deleted file mode 100644 index 4241c26..0000000 --- a/htdocs/nfc/nfc-binding.js +++ /dev/null @@ -1,156 +0,0 @@ -var afb = new AFB("api", "HELLO"); -var ws; - -function add_debbug_panel() { - - if (document.getElementById("debug-panel")) - return; - - var itm = document.getElementById("debug-panel-container"); - if (itm) - { - var pnl = - "<div id=\"debug-panel\" class=\"expanded\">\n" + - " <button id=\"debug-panel-collapse\" onclick=\"debug_panel_collapse();\">></button>\n" + - " <button id=\"debug-panel-expand\" onclick=\"debug_panel_expand();\"><</button>\n" + - " <div id=\"debug-panel-content\">\n" + - " <h1>Debug</h1>\n" + - " <h2>Call</h2><div id=\"debug-panel-call\">\n" + - " <ul>\n" + - " <li><strong>api : </strong><span id=\"debug-panel-call-id\"></span></li>\n" + - " <li><strong>verb : </strong><span id=\"debug-panel-call-verb\"></span></li>\n" + - " <li><strong>query : </strong></li>\n" + - " </ul>\n" + - " <pre id=\"debug-panel-call-query\"></pre>\n" + - " </div>\n" + - " <h2>Response</h2><pre id=\"debug-panel-response\"></pre>\n" + - " <h2>Event</h2><pre id=\"debug-panel-event\"></pre>\n" + - " </div>\n" + - "</div>\n"; - itm.insertAdjacentHTML("afterbegin", pnl); - } -} - -function createClass(name,rules) { - var style = document.createElement('style'); - style.type = 'text/css'; - document.getElementsByTagName('head')[0].appendChild(style); - if(!(style.sheet||{}).insertRule) - (style.styleSheet || style.sheet).addRule(name, rules); - else - style.sheet.insertRule(name+"{"+rules+"}",0); -} - -function syntaxHighlight(json) { - if (typeof json != 'string') - json = JSON.stringify(json, undefined, 2); - - json = json.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>'); - return json.replace(/("(\\u[a-zA-Z0-9]{4}|\\[^u]|[^\\"])*"(\s*:)?|\b(true|false|null)\b|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?)/g, function (match) { - var cls = 'json-number'; - if (/^"/.test(match)) { - if (/:$/.test(match)) { - cls = 'json-key'; - } else { - cls = 'json-string'; - } - } else if (/true|false/.test(match)) { - cls = 'json-boolean'; - } else if (/null/.test(match)) { - cls = 'json-null'; - } - return '<span class="' + cls + '">' + match + '</span>'; - }); -} - -function set_item_html(id, text) -{ - var itm = document.getElementById(id); - if (itm) itm.innerHTML = text; -} - -function set_item_text(id, text) -{ - var itm = document.getElementById(id); - if (itm) itm.innerText = text; -} - -function debug_panel_collapse() { - var pnl = document.getElementById('debug-panel'); - if (pnl) - { - pnl.classList.remove('expanded'); - pnl.classList.add('collapsed'); - } -} - -function debug_panel_expand() { - var pnl = document.getElementById('debug-panel'); - if (pnl) - { - pnl.classList.remove('collapsed'); - pnl.classList.add('expanded'); - } -} - -function init() { - add_debbug_panel(); - ws = new afb.ws(onopen, onabort); -} - -function onopen() { - //callbinder("ll-auth", "getuser", ""); - ws.onevent("*", gotevent); -} - -function onabort() { -} - -function replyok(obj) { - console.log("replyok:" + JSON.stringify(obj)); - set_item_html("debug-panel-response", syntaxHighlight(JSON.stringify(obj, null, 4))); -} - -function replyerr(obj) { - console.log("replyerr:" + JSON.stringify(obj)); - set_item_html("debug-panel-response", syntaxHighlight(JSON.stringify(obj, null, 4))); -} - -function gotevent(obj) { - console.log("gotevent:" + JSON.stringify(obj)); - set_item_html("debug-panel-event", syntaxHighlight(JSON.stringify(obj, null, 4))); -} - -function callbinder(api, verb, query) { - console.log ("subscribe api="+api+" verb="+verb+" query=" +query); - - set_item_text("debug-panel-call-api", api); - set_item_text("debug-panel-call-verb", verb); - set_item_html("debug-panel-call-query", syntaxHighlight(JSON.stringify(query, null, 4))); - - ws.call(api+"/"+verb, query).then(replyok, replyerr); -} - -function subscribe() { - callbinder("nfc", "subscribe", {}); -} - -function unsubscribe() { - callbinder("nfc", "unsubscribe", {}); -} - -function list_devices() { - callbinder("nfc", "list-devices", {}); -} - -function list_devices_capabilities() { - callbinder("nfc", "list-devices-capabilities", {}); -} - -function start_polling() { - callbinder("nfc", "start-polling", {}); -} - -function stop_polling() { - callbinder("nfc", "stop-polling", {}); -} diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt deleted file mode 100644 index ba35037..0000000 --- a/src/CMakeLists.txt +++ /dev/null @@ -1,77 +0,0 @@ -########################################################################### -# Copyright 2015, 2016, 2017 IoT.bzh -# -# author: Loïc Collignon <loic.collignon@iot.bzh> -# -# 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. -########################################################################### - -CMAKE_MINIMUM_REQUIRED(VERSION 3.3) - -PROJECT_TARGET_ADD(nfc-binding) - -set(NFC_BINDING_SOURCES api.c nfc-binding.c) - -if (USE_LIBNFC) - set(NFC_BINDING_SOURCES ${NFC_BINDING_SOURCES} libnfc_reader.c) - add_definitions(-DUSE_LIBNFC=1) - - if(LIBNFC_POLL_ALL) - add_definitions(-DLIBNFC_POLL_ALL=1) - endif() - - if(LIBNFC_POLL_NMT_ISO14443A) - add_definitions(-DLIBNFC_POLL_NMT_ISO14443A=1) - endif() - - if(LIBNFC_POLL_NMT_ISOJEWEL) - add_definitions(-DLIBNFC_POLL_NMT_ISOJEWEL=1) - endif() - - if(LIBNFC_POLL_NMT_ISO14443B) - add_definitions(-DLIBNFC_POLL_NMT_ISO14443B=1) - endif() - - if(LIBNFC_POLL_NMT_ISO14443BI) - add_definitions(-DLIBNFC_POLL_NMT_ISO14443BI=1) - endif() - - if(LIBNFC_POLL_NMT_ISO14443B2SR) - add_definitions(-DLIBNFC_POLL_NMT_ISO14443B2SR=1) - endif() - - if(LIBNFC_POLL_NMT_ISO14443B2CT) - add_definitions(-DLIBNFC_POLL_NMT_ISO14443B2CT=1) - endif() - - if(LIBNFC_POLL_NMT_FELICA) - add_definitions(-DLIBNFC_POLL_NMT_FELICA=1) - endif() -endif() - -message(STATUS "libnfc enabled: ${USE_LIBNFC}") - -add_library(${TARGET_NAME} MODULE ${NFC_BINDING_SOURCES}) -target_link_libraries(${TARGET_NAME} ${link_libraries}) - -add_custom_command(TARGET ${TARGET_NAME} - PRE_BUILD - COMMAND mkdir -p ${CMAKE_CURRENT_BINARY_DIR}/../package/htdocs - COMMAND cp -rv ${CMAKE_CURRENT_SOURCE_DIR}/../htdocs ${CMAKE_CURRENT_BINARY_DIR}/../package/) - -SET_TARGET_PROPERTIES(${TARGET_NAME} PROPERTIES - PREFIX "afb-" - LABELS "BINDING" - LINK_FLAGS ${BINDINGS_LINK_FLAG} - OUTPUT_NAME ${TARGET_NAME}) - diff --git a/src/api.c b/src/api.c deleted file mode 100644 index 8e928fd..0000000 --- a/src/api.c +++ /dev/null @@ -1,63 +0,0 @@ -#include "nfc-binding.h" - -/* -static const struct afb_auth nfc_auths[] = { -}; -*/ - -static const struct afb_verb_v2 nfc_verbs[] = { - { - .verb = "subscribe", - .callback = verb_subscribe, - .auth = NULL, - .info = NULL, - .session = AFB_SESSION_NONE_V2 - }, - { - .verb = "unsubscribe", - .callback = verb_unsubscribe, - .auth = NULL, - .info = NULL, - .session = AFB_SESSION_NONE_V2 - }, - { - .verb = "list-devices", - .callback = verb_list_devices, - .auth = NULL, - .info = NULL, - .session = AFB_SESSION_NONE_V2 - }, - { - .verb = "list-devices-capabilities", - .callback = verb_list_devices_capabilities, - .auth = NULL, - .info = NULL, - .session = AFB_SESSION_NONE_V2 - }, - { - .verb = "start", - .callback = verb_start, - .auth = NULL, - .info = NULL, - .session = AFB_SESSION_NONE_V2 - }, - { - .verb = "stop", - .callback = verb_stop, - .auth = NULL, - .info = NULL, - .session = AFB_SESSION_NONE_V2 - }, - { .verb = NULL } -}; - -const struct afb_binding afbBindingV2 = { - .api = "nfc", - .specification = NULL, - .info = NULL, - .verbs = nfc_verbs, - .preinit = NULL, - .init = init, - .onevent = NULL, - .noconcurrency = 0 -}; diff --git a/src/libnfc_reader.c b/src/libnfc_reader.c deleted file mode 100644 index 78269db..0000000 --- a/src/libnfc_reader.c +++ /dev/null @@ -1,478 +0,0 @@ -#include "nfc-binding.h" - -#include <signal.h> -#include <string.h> -#include <sys/types.h> -#include <pthread.h> - -// FIXME: It compile without these lines, but KDevelop complains about pthread_t being undeclared. -#ifndef _BITS_PTHREADTYPES -typedef unsigned long int pthread_t; -#endif - -#include <nfc/nfc.h> -#include "libnfc_reader.h" -#include "stringutils.h" - -extern struct afb_event on_nfc_target_add_event; -extern struct afb_event on_nfc_target_remove_event; - -#define MAX_NFC_DEVICE_COUNT 8 -#define MAX_NFC_MODULATIONS 8 -#define MAX_NFC_BAUDRATES 8 -#define POLL_NUMBER 0x1 -#define POLL_PERIOD 0x7 - -typedef struct libnfc_device_tag -{ - pthread_t poller; - nfc_device* device; - nfc_connstring name; - - nfc_modulation* modulations; - size_t modulations_count; -} libnfc_device; - -typedef struct libnfc_context_tag -{ - nfc_context* context; - libnfc_device* devices; - size_t devices_count; - struct json_object* last_target; -} libnfc_context; - -static libnfc_context libnfc; - -void libnfc_polling_error(int code) -{ - switch(code) - { - case NFC_EIO: - AFB_ERROR("libnfc: polling failed with NFC_EIO (%d) code: Input / output error, device may not be usable anymore without re-open it!", code); - break; - case NFC_EINVARG: - AFB_ERROR("libnfc: polling failed with NFC_EINVARG (%d) code: Invalid argument(s)!", code); - break; - case NFC_EDEVNOTSUPP: - AFB_ERROR("libnfc: polling failed with NFC_EDEVNOTSUPP (%d) code: Operation not supported by device!", code); - break; - case NFC_ENOTSUCHDEV: - AFB_ERROR("libnfc: polling failed with NFC_ENOTSUCHDEV (%d) code: No such device!", code); - break; - case NFC_EOVFLOW: - AFB_ERROR("libnfc: polling failed with NFC_EOVFLOW (%d) code: Buffer overflow!", code); - break; - case NFC_ETIMEOUT: - AFB_ERROR("libnfc: polling failed with NFC_ETIMEOUT (%d) code: Operation timed out!", code); - break; - case NFC_EOPABORTED: - AFB_ERROR("libnfc: polling failed with NFC_EOPABORTED (%d) code: Operation aborted (by user)!", code); - break; - case NFC_ENOTIMPL: - AFB_ERROR("libnfc: polling failed with NFC_ENOTIMPL (%d) code: Not (yet) implemented!", code); - break; - case NFC_ETGRELEASED: - AFB_ERROR("libnfc: polling failed with NFC_ETGRELEASED (%d) code: Target released!", code); - break; - case NFC_ERFTRANS: - AFB_ERROR("libnfc: polling failed with NFC_ERFTRANS (%d) code: Error while RF transmission!", code); - break; - case NFC_EMFCAUTHFAIL: - AFB_ERROR("libnfc: polling failed with NFC_EMFCAUTHFAIL (%d) code: MIFARE Classic: authentication failed!", code); - break; - case NFC_ESOFT: - AFB_ERROR("libnfc: polling failed with NFC_ESOFT (%d) code: Software error (allocation, file/pipe creation, etc.)!", code); - break; - case NFC_ECHIP: - //AFB_ERROR("libnfc: polling failed with NFC_ECHIP (%d) code: Device's internal chip error!", code); - break; - default: - AFB_ERROR("libnfc: polling failed with unknown code: %d!", code); - break; - } -} - -void add_nfc_field(struct json_object* parent, const char* field, const void* src, size_t sz) -{ - char* data; - - if (parent && field && src && sz) - { - data = to_hex_string(src, sz); - if (data) - { - json_object_object_add(parent, field, json_object_new_string(data)); - free(data); - } - } -} - -struct json_object* read_target(const nfc_target* target) -{ - struct json_object* result; - const char* mt; - - if (!target) - { - AFB_WARNING("libnfc: No target to read!"); - return NULL; - } - - result = json_object_new_object(); - mt = str_nfc_modulation_type(target->nm.nmt); - json_object_object_add(result, "Type", json_object_new_string(mt)); - - switch(target->nm.nmt) - { - case NMT_ISO14443A: - add_nfc_field(result, "ATQA", target->nti.nai.abtAtqa, 2); - add_nfc_field(result, "SAK", &target->nti.nai.btSak, 1); - add_nfc_field(result, "UID", target->nti.nai.abtUid, target->nti.nai.szUidLen); - add_nfc_field(result, "ATS", target->nti.nai.abtAts, target->nti.nai.szAtsLen); - - break; - case NMT_ISO14443B: - add_nfc_field(result, "PUPI", target->nti.nbi.abtPupi, 4); - add_nfc_field(result, "Application Data", target->nti.nbi.abtApplicationData, 4); - add_nfc_field(result, "Protocol Info", target->nti.nbi.abtProtocolInfo, 3); - add_nfc_field(result, "Card Id", &target->nti.nbi.ui8CardIdentifier, 1); - - break; - default: - AFB_WARNING("libnfc: unsupported modulation type: %s.", mt); - json_object_object_add(result, "error", json_object_new_string("unsupported tag type")); - break; - } - return result; -} - -void* libnfc_reader_main(void* arg) -{ - libnfc_device* device; - nfc_target nt; - int polled_target_count; - nfc_modulation mods[MAX_NFC_MODULATIONS]; - struct json_object* result; - size_t i, j; - - device = (libnfc_device*)arg; - - memset(mods, 0, sizeof(nfc_modulation) * MAX_NFC_MODULATIONS); - for(i = 0, j = 0; i < device->modulations_count; ++i, ++j) - { - switch(device->modulations[i].nmt) - { -#if defined(LIBNFC_POLL_ALL) || defined(LIBNFC_POLL_NMT_ISO14443A) - case NMT_ISO14443A: -#endif -#if defined(LIBNFC_POLL_ALL) || defined(LIBNFC_POLL_NMT_ISOJEWEL) - case NMT_JEWEL: -#endif -#if defined(LIBNFC_POLL_ALL) || defined(LIBNFC_POLL_NMT_ISO14443B) - case NMT_ISO14443B: -#endif -#if defined(LIBNFC_POLL_ALL) || defined(LIBNFC_POLL_NMT_ISO14443BI) - case NMT_ISO14443BI: -#endif -#if defined(LIBNFC_POLL_ALL) || defined(LIBNFC_POLL_NMT_ISO14443B2SR) - case NMT_ISO14443B2SR: -#endif -#if defined(LIBNFC_POLL_ALL) || defined(LIBNFC_POLL_NMT_ISO14443B2CT) - case NMT_ISO14443B2CT: -#endif -#if defined(LIBNFC_POLL_ALL) || defined(LIBNFC_POLL_NMT_FELICA) - case NMT_FELICA: -#endif - mods[j] = device->modulations[i]; - AFB_NOTICE("libnfc: polling for %s at %s is ENABLED.", str_nfc_modulation_type(device->modulations[i].nmt), str_nfc_baud_rate(device->modulations[i].nbr)); - break; - default: - --j; - // NMT_DEP is always disabled because it can't be polled - AFB_NOTICE("libnfc: polling for %s at %s is DISABLED.", str_nfc_modulation_type(device->modulations[i].nmt), str_nfc_baud_rate(device->modulations[i].nbr)); - break; - } - } - - while(device->device) - { - polled_target_count = nfc_initiator_poll_target - ( - device->device, - mods, - j, - POLL_NUMBER, - POLL_PERIOD, - &nt - ); - - switch(polled_target_count) - { - case 0: - // No target detected - AFB_INFO("libnfc: polling done with no result."); - if (libnfc.last_target) - { - AFB_NOTICE("libnfc: tag removed = %s", json_object_to_json_string(libnfc.last_target)); - afb_event_push(on_nfc_target_remove_event, libnfc.last_target); - libnfc.last_target = NULL; - } - break; - - case 1: - AFB_INFO("libnfc: polling done with one result."); - // One target detected - result = read_target(&nt); - - if (libnfc.last_target) - { - if (strcmp(json_object_to_json_string(result), json_object_to_json_string(libnfc.last_target))) - { - AFB_NOTICE("libnfc: tag removed = %s", json_object_to_json_string(libnfc.last_target)); - afb_event_push(on_nfc_target_remove_event, libnfc.last_target); - libnfc.last_target = NULL; - } - } - - if (!libnfc.last_target) - { - json_object_get(result); - libnfc.last_target = result; - - AFB_NOTICE("libnfc: tag added = %s", json_object_to_json_string(result)); - afb_event_push(on_nfc_target_add_event, result); - } - break; - - default: - if (polled_target_count < 0) libnfc_polling_error(polled_target_count); - else AFB_WARNING("libnfc: polling done with unsupported result count: %d.", polled_target_count); - - // Consider target is removed - if (libnfc.last_target) - { - AFB_NOTICE("libnfc: tag removed = %s", json_object_to_json_string(libnfc.last_target)); - afb_event_push(on_nfc_target_remove_event, libnfc.last_target); - libnfc.last_target = NULL; - } - break; - } - } - return NULL; -} - -void exit_handler() -{ - size_t i; - nfc_device* dev; - for(i = 0; i < libnfc.devices_count; ++i) - { - if (libnfc.devices[i].device) - { - dev = libnfc.devices[i].device; - libnfc.devices[i].device = NULL; - nfc_close(dev); - } - } - nfc_exit(libnfc.context); - libnfc.context = NULL; -} - -void sigterm_handler(int sig) -{ - if (sig == SIGTERM && libnfc.context && libnfc.devices_count) - { - exit_handler(); - } -} - -/// @brief Start the libnfc context. -/// @return An exit code, @c EXIT_LIBNFC_SUCCESS (zero) on success. -int libnfc_init() -{ - nfc_device* dev; - const nfc_modulation_type* modulations; - const nfc_baud_rate* baudrates; - size_t modulation_idx; - nfc_connstring connstrings[MAX_NFC_DEVICE_COUNT]; - size_t ref_device_count; - size_t device_idx; - - atexit(exit_handler); - - memset(&libnfc, 0, sizeof(libnfc_context)); - - nfc_init(&libnfc.context); - if (libnfc.context == NULL) - { - AFB_ERROR("[libnfc] Initialization failed (malloc)!"); - return EXIT_LIBNFC_NOT_INITIALIZED; - } - - AFB_NOTICE("[libnfc] Using libnfc version: %s.", nfc_version()); - - // Find and register devices - ref_device_count = nfc_list_devices(libnfc.context, connstrings, MAX_NFC_DEVICE_COUNT); - if (!ref_device_count) - { - AFB_ERROR("libnfc: No NFC device found!"); - return EXIT_LIBNFC_NO_DEVICE_FOUND; - } - libnfc.devices_count = ref_device_count; - libnfc.devices = malloc(sizeof(libnfc_device) * libnfc.devices_count); - memset(libnfc.devices, 0, sizeof(libnfc_device) * libnfc.devices_count); - - signal(SIGTERM, sigterm_handler); - - for(device_idx = 0; device_idx < ref_device_count; ++device_idx) - { - AFB_NOTICE("libnfc: NFC Device found: \"%s\".", connstrings[device_idx]); - strcpy(libnfc.devices[device_idx].name, connstrings[device_idx]); - - // Find and register modulations - dev = nfc_open(libnfc.context, connstrings[device_idx]); - if (dev) - { - if (nfc_device_get_supported_modulation(dev, N_INITIATOR, &modulations)) - { - AFB_ERROR("libnfc: Failed to get supported modulations from '%s'!", connstrings[device_idx]); - } - else - { - // Find and register modulations - modulation_idx = 0; - while(modulations[modulation_idx]) ++modulation_idx; - libnfc.devices[device_idx].modulations_count = modulation_idx; - if (modulation_idx) - { - libnfc.devices[device_idx].modulations = malloc(sizeof(nfc_modulation) * modulation_idx); - memset(libnfc.devices[device_idx].modulations, 0, sizeof(nfc_modulation) * modulation_idx); - - modulation_idx = 0; - while(modulations[modulation_idx]) - { - libnfc.devices[device_idx].modulations[modulation_idx].nmt = modulations[modulation_idx]; - if (!nfc_device_get_supported_baud_rate(dev, modulations[modulation_idx], &baudrates)) - { - // Keep only the first speed which is supposed to be the fastest - libnfc.devices[device_idx].modulations[modulation_idx].nbr = baudrates[0]; - } - - AFB_NOTICE("libnfc: - Modulation '%s' supported at '%s'." - , str_nfc_modulation_type(libnfc.devices[device_idx].modulations[modulation_idx].nmt) - , str_nfc_baud_rate(libnfc.devices[device_idx].modulations[modulation_idx].nbr)); - ++modulation_idx; - } - } - } - nfc_close(dev); - } - } - - return EXIT_LIBNFC_SUCCESS; -} - -/// @brief List devices founds by libnfc. -/// @param[in] result A json object array into which found devices are added. -/// @return An exit code, @c EXIT_LIBNFC_SUCCESS (zero) on success. -int libnfc_list_devices(struct json_object* result) -{ - struct json_object* device; - size_t i; - - for(i = 0; i < libnfc.devices_count; ++i) - { - device = json_object_new_object(); - json_object_object_add(device, "source", json_object_new_string("libnfc")); - json_object_object_add(device, "name", json_object_new_string(libnfc.devices[i].name)); - json_object_array_add(result, device); - } - - return EXIT_LIBNFC_SUCCESS; -} - -int libnfc_list_devices_capabilities(struct json_object* result, struct json_object* devices) -{ - struct json_object* device; - struct json_object* mods; - struct json_object* mod; - size_t i, j; - - for(i = 0; i < libnfc.devices_count; ++i) - { - device = json_object_new_object(); - json_object_object_add(device, "source", json_object_new_string("libnfc")); - json_object_object_add(device, "name", json_object_new_string(libnfc.devices[i].name)); - mods = json_object_new_array(); - - for(j = 0; j < libnfc.devices[i].modulations_count; ++j) - { - mod = json_object_new_object(); - json_object_object_add(mod, "modulation", json_object_new_string(str_nfc_modulation_type(libnfc.devices[i].modulations[j].nmt))); - json_object_object_add(mod, "baudrate", json_object_new_string(str_nfc_baud_rate(libnfc.devices[i].modulations[j].nbr))); - json_object_array_add(mods, mod); - } - - json_object_object_add(device, "modulations", mods); - json_object_array_add(result, device); - } - - return EXIT_LIBNFC_SUCCESS; -} - -int libnfc_start_polling(struct json_object* result, struct json_object* devices) -{ - struct json_object* device; - size_t i; - int r; - - for(i = 0; i < libnfc.devices_count; ++i) - { - device = json_object_new_object(); - json_object_object_add(device, "source", json_object_new_string("libnfc")); - json_object_object_add(device, "name", json_object_new_string(libnfc.devices[i].name)); - if (libnfc.devices[i].device) - { - json_object_object_add(device, "status", json_object_new_string("already polling")); - AFB_NOTICE("libnfc: Device '%s' is already polling.", libnfc.devices[i].name); - } - else - { - libnfc.devices[i].device = nfc_open(libnfc.context, libnfc.devices[i].name); - if (libnfc.devices[i].device) - { - if (nfc_initiator_init(libnfc.devices[i].device) < 0) - { - nfc_close(libnfc.devices[i].device); - libnfc.devices[i].device = NULL; - json_object_object_add(device, "status", json_object_new_string("failed to set initiator mode")); - AFB_ERROR("libnfc: nfc_initiator_init failedfor device '%s'!", libnfc.devices[i].name); - } - else - { - r = pthread_create(&libnfc.devices[i].poller, NULL, libnfc_reader_main, (void*)&libnfc.devices[i]); - if (r) - { - nfc_close(libnfc.devices[i].device); - libnfc.devices[i].device = NULL; - json_object_object_add(device, "status", json_object_new_string("failed to create the polling thread")); - AFB_ERROR("libnfc: pthread_create failed!"); - } - else - { - json_object_object_add(device, "status", json_object_new_string("polling")); - AFB_NOTICE("libnfc: Polling the device '%s'.", libnfc.devices[i].name); - } - } - } - else - { - json_object_object_add(device, "status", json_object_new_string("failed to open device")); - AFB_ERROR("libnfc: Failed to open device '%s'!", libnfc.devices[i].name); - } - } - json_object_array_add(result, device); - } - - return EXIT_LIBNFC_SUCCESS; -} diff --git a/src/libnfc_reader.h b/src/libnfc_reader.h deleted file mode 100644 index 1209fda..0000000 --- a/src/libnfc_reader.h +++ /dev/null @@ -1,12 +0,0 @@ -#pragma once - -#include <json-c/json.h> - -#define EXIT_LIBNFC_SUCCESS 0 -#define EXIT_LIBNFC_NOT_INITIALIZED 1 -#define EXIT_LIBNFC_NO_DEVICE_FOUND 2 - -int libnfc_init(); -int libnfc_list_devices(struct json_object* result); -int libnfc_list_devices_capabilities(struct json_object* result, struct json_object* devices); -int libnfc_start_polling(struct json_object* result, struct json_object* devices); diff --git a/src/nfc-binding.c b/src/nfc-binding.c deleted file mode 100644 index c5f14c6..0000000 --- a/src/nfc-binding.c +++ /dev/null @@ -1,134 +0,0 @@ -#include "nfc-binding.h" - -#if USE_LIBNFC == 1 -#include "libnfc_reader.h" -#endif - -struct afb_event on_nfc_target_add_event; -struct afb_event on_nfc_target_remove_event; - -/// @brief Binding's initialization. -/// @return Exit code, zero on success, non-zero otherwise. -int init() -{ - on_nfc_target_add_event = afb_daemon_make_event("on-nfc-target-add"); - on_nfc_target_remove_event = afb_daemon_make_event("on-nfc-target-remove"); - if (!afb_event_is_valid(on_nfc_target_add_event) || !afb_event_is_valid(on_nfc_target_remove_event)) - { - AFB_ERROR("Failed to create a valid event!"); - return 1; - } - -#if USE_LIBNFC == 1 - if (libnfc_init()) - { - AFB_ERROR("Failed start libnfc reader!"); - return 2; - } -#endif - - return 0; -} - -/// @brief Get a list of devices. -/// @param[in] req The query. -void verb_subscribe(struct afb_req req) -{ - if (!afb_req_subscribe(req, on_nfc_target_remove_event)) - { - if (!afb_req_subscribe(req, on_nfc_target_add_event)) - { - afb_req_success(req, NULL, "Subscription success!"); - return; - } - else afb_req_unsubscribe(req, on_nfc_target_remove_event); - } - - afb_req_fail(req, NULL, "Subscription failure!"); -} - -/// @brief Get a list of devices. -/// @param[in] req The query. -void verb_unsubscribe(struct afb_req req) -{ - if (!afb_req_unsubscribe(req, on_nfc_target_add_event)) - { - if (!afb_req_unsubscribe(req, on_nfc_target_remove_event)) - { - afb_req_success(req, NULL, "Unsubscription success!"); - return; - } - } - - afb_req_fail(req, NULL, "Unsubscription failure!"); -} - -/// @brief Get a list of devices. -/// @param[in] req The query. -void verb_list_devices(struct afb_req req) -{ - struct json_object* result; - - result = json_object_new_array(); - -#if USE_LIBNFC == 1 - if (libnfc_list_devices(result)) - { - afb_req_fail(req, "Failed to get devices list from libnfc!", NULL); - return; - } -#endif - - afb_req_success(req, result, NULL); -} - -/// @brief Get a list of devices capabilities. -/// @param[in] req The query. -void verb_list_devices_capabilities(struct afb_req req) -{ - struct json_object* result; - struct json_object* arg; - - arg = afb_req_json(req); - - result = json_object_new_array(); - -#if USE_LIBNFC == 1 - if (libnfc_list_devices_capabilities(result, arg)) - { - afb_req_fail(req, "Failed to get devices list from libnfc!", NULL); - return; - } -#endif - - afb_req_success(req, result, NULL); -} - -/// @brief Start polling. -/// @param[in] req The query. -void verb_start(struct afb_req req) -{ - struct json_object* result; - struct json_object* arg; - - arg = afb_req_json(req); - - result = json_object_new_array(); - -#if USE_LIBNFC == 1 - if (libnfc_start_polling(result, arg)) - { - afb_req_fail(req, "Failed to get devices list from libnfc!", NULL); - return; - } -#endif - - afb_req_success(req, result, NULL); -} - -/// @brief Stop polling. -/// @param[in] req The query. -void verb_stop(struct afb_req req) -{ - afb_req_fail(req, "Not implemented yet!", NULL); -} diff --git a/src/nfc-binding.h b/src/nfc-binding.h deleted file mode 100644 index 767a448..0000000 --- a/src/nfc-binding.h +++ /dev/null @@ -1,17 +0,0 @@ -#pragma once - -#include <json-c/json.h> - -#define AFB_BINDING_VERSION 2 -#include <afb/afb-binding.h> - -// Initializations -int init(); - -// Verbs -void verb_subscribe(struct afb_req req); -void verb_unsubscribe(struct afb_req req); -void verb_list_devices(struct afb_req req); -void verb_list_devices_capabilities(struct afb_req req); -void verb_start(struct afb_req req); -void verb_stop(struct afb_req req); diff --git a/src/stringutils.h b/src/stringutils.h deleted file mode 100644 index 824d09d..0000000 --- a/src/stringutils.h +++ /dev/null @@ -1,41 +0,0 @@ -#pragma once - -#include <stdlib.h> - -/** - * @brief Get a hexadecimal string representation from memory buffer. - * @param[in] src Buffer's pointer. - * @param[in] sz Buffer's size. - * @return A pointer to the result string. Caller is responsible for the result lifetime. - */ -static inline char* to_hex_string(const void* src, long unsigned int sz) -{ - static const char lookup[] = - { - '0', '1', '2', '3', - '4', '5', '6', '7', - '8', '9', 'a', 'b', - 'c', 'd', 'e', 'f' - }; - - const char* source; - char* result; - long unsigned int i; - - result = NULL; - if (src && sz) - { - source = (const char*)src; - result = (char*)malloc(sz * 2 + 1); - if (result) - { - result[sz * 2] = 0; - for (i = 0; i < sz; ++i) - { - result[i * 2] = lookup[(source[i] & 0xf0) >> 4]; - result[i * 2 + 1] = lookup[source[i] & 0x0f]; - } - } - } - return result; -} |