From 399800e461ad28e067a15c794f18843b48bfc919 Mon Sep 17 00:00:00 2001 From: Loïc Collignon Date: Wed, 25 Oct 2017 15:27:12 +0200 Subject: detect tag removing and raise an event MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Change-Id: I812c4f0b86f2f65c0d7561af95e531fd596bd45b Signed-off-by: Loïc Collignon --- src/libnfc_reader.c | 231 ++++++++++++++++++++++++++++++++++------------------ src/nfc-binding.c | 35 ++++++-- 2 files changed, 181 insertions(+), 85 deletions(-) diff --git a/src/libnfc_reader.c b/src/libnfc_reader.c index 8b11f0c..af51db5 100644 --- a/src/libnfc_reader.c +++ b/src/libnfc_reader.c @@ -1,5 +1,6 @@ #include "nfc-binding.h" +#include #include #include #include @@ -13,13 +14,14 @@ typedef unsigned long int pthread_t; #include "libnfc_reader.h" #include "stringutils.h" -extern struct afb_event on_nfc_read_event; +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 0xff -#define POLL_PERIOD 0x05 +#define POLL_NUMBER 0xA +#define POLL_PERIOD 0x7 typedef struct libnfc_device_tag { @@ -36,13 +38,10 @@ 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 = { - .context = NULL, - .devices = NULL, - .devices_count = 0 -}; +static libnfc_context libnfc; void libnfc_polling_error(int code) { @@ -93,104 +92,180 @@ void libnfc_polling_error(int code) } } +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; - - // Read datas - const char* mt; - char* field1; - char* field2; - char* field3; - char* field4; + 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) + { + if (device->modulations[i].nmt != NMT_DEP) + mods[j] = device->modulations[i]; + else --j; + } + while(device->device) { - polled_target_count = nfc_initiator_poll_target(device->device, device->modulations, device->modulations_count, POLL_NUMBER, POLL_PERIOD, &nt); + polled_target_count = nfc_initiator_poll_target + ( + device->device, + mods, + j, + POLL_NUMBER, + POLL_PERIOD, + &nt + ); + switch(polled_target_count) { - case 0: - AFB_INFO("libnfc: polling done with no result."); - break; - - case 1: - mt = str_nfc_modulation_type(nt.nm.nmt); - AFB_NOTICE("libnfc: polling done with one result of type %s.", mt); - switch(nt.nm.nmt) - { - case NMT_ISO14443A: - field1 = to_hex_string(nt.nti.nai.abtAtqa, 2); - field2 = to_hex_string(&nt.nti.nai.btSak, 1); - field3 = to_hex_string(nt.nti.nai.abtUid, nt.nti.nai.szUidLen); - field4 = to_hex_string(nt.nti.nai.abtAts, nt.nti.nai.szAtsLen); - - result = json_object_new_object(); - json_object_object_add(result, "Type", json_object_new_string(mt)); - if (field1) json_object_object_add(result, "ATQA", json_object_new_string(field1)); - if (field2) json_object_object_add(result, "SAK", json_object_new_string(field2)); - if (field3) json_object_object_add(result, "UID", json_object_new_string(field3)); - if (field4) json_object_object_add(result, "ATS", json_object_new_string(field4)); - - break; - case NMT_ISO14443B: - field1 = to_hex_string(nt.nti.nbi.abtPupi, 4); - field2 = to_hex_string(nt.nti.nbi.abtApplicationData, 4); - field3 = to_hex_string(nt.nti.nbi.abtProtocolInfo, 3); - field4 = to_hex_string(&nt.nti.nbi.ui8CardIdentifier, 1); - - result = json_object_new_object(); - json_object_object_add(result, "Type", json_object_new_string(mt)); - if (field1) json_object_object_add(result, "PUPI", json_object_new_string(field1)); - if (field2) json_object_object_add(result, "Application Data", json_object_new_string(field2)); - if (field3)json_object_object_add(result, "Protocol Info", json_object_new_string(field3)); - if (field4)json_object_object_add(result, "Card Id", json_object_new_string(field4)); - - break; - default: - AFB_WARNING("libnfc: unsupported modulation type: %s.", mt); - break; - } - - if (result) + 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: push tag read event=%s", json_object_to_json_string(result)); - afb_event_push(on_nfc_read_event, result); + 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 (field1) free(field1); - if (field2) free(field2); - if (field3) free(field3); - if (field4) free(field4); - - break; + } + + if (!libnfc.last_target) + { + json_object_get(result); + libnfc.last_target = result; - 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); - break; + 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 sigterm_handler(int sig) +{ + size_t i; + nfc_device* dev; + if (sig == SIGTERM && libnfc.context && libnfc.devices_count) + { + 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; + } +} + /// @brief Start the libnfc context. /// @return An exit code, @c EXIT_LIBNFC_SUCCESS (zero) on success. int libnfc_init() { nfc_device* dev; - nfc_connstring connstrings[MAX_NFC_DEVICE_COUNT]; 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; - size_t modulation_idx; + + + memset(&libnfc, 0, sizeof(libnfc_context)); nfc_init(&libnfc.context); if (libnfc.context == NULL) @@ -212,11 +287,13 @@ int libnfc_init() 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) diff --git a/src/nfc-binding.c b/src/nfc-binding.c index 3d96cbb..56aa211 100644 --- a/src/nfc-binding.c +++ b/src/nfc-binding.c @@ -4,14 +4,16 @@ #include "libnfc_reader.h" #endif -struct afb_event on_nfc_read_event; +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_read_event = afb_daemon_make_event("on-nfc-read"); - if (!afb_event_is_valid(on_nfc_read_event)) + 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; @@ -31,17 +33,34 @@ int init() /// @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_read_event)) afb_req_fail(req, NULL, "Subscription failure!"); - else afb_req_success(req, NULL, "Subscription success!"); +{ + 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_read_event)) afb_req_fail(req, NULL, "Unsubscription failure!"); - else afb_req_success(req, NULL, "Unsubscription success!"); + 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. -- cgit 1.2.3-korg