changeset 395:3852a10a088f

more nim progress on rfid reader Ignore-this: 762e256b911e74db2b2103b509250e9f
author drewp@bigasterisk.com
date Thu, 21 Feb 2019 09:58:56 -0800
parents ff588658de31
children 66f1ed94c2e4
files service/rfid_pn532/Dockerfile service/rfid_pn532/Dockerfile.pi service/rfid_pn532/index.html service/rfid_pn532/makefile service/rfid_pn532/nfc-nim/freefare.h service/rfid_pn532/nfc-nim/nfc.h service/rfid_pn532/nim.cfg service/rfid_pn532/rfid.nim service/rfid_pn532/tags.nim
diffstat 9 files changed, 1387 insertions(+), 15 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/service/rfid_pn532/Dockerfile	Thu Feb 21 09:58:56 2019 -0800
@@ -0,0 +1,18 @@
+FROM bang6:5000/base_nim_x86
+
+WORKDIR /opt
+
+RUN apt-get install -y libnfc5 libfreefare0 libnfc-dev libfreefare-dev && \
+  ln -sf libnfc.so.5 /usr/lib/x86_64-linux-gnu/libnfc.so && \
+  ln -sf libfreefare.so.0 /usr/lib/x86_64-linux-gnu/libfreefare.so
+
+COPY *.nim *.cfg ./
+COPY nfc-nim/ nfc-nim/
+
+RUN nim c -d:nimDebugDlOpen rfid.nim
+
+ENV LIBNFC_DEFAULT_DEVICE="pn532_i2c:/dev/i2c-1"
+
+EXPOSE 10012
+
+CMD ["./rfid"]
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/service/rfid_pn532/Dockerfile.pi	Thu Feb 21 09:58:56 2019 -0800
@@ -0,0 +1,21 @@
+FROM bang6:5000/base_nim_pi
+
+WORKDIR /opt
+
+RUN apt-get install -y libnfc5 libfreefare0 libnfc-dev libfreefare-dev && \
+  ln -sf libnfc.so.5 /usr/lib/arm-linux-gnueabihf/libnfc.so && \
+  ln -sf libfreefare.so.0 /usr/lib/arm-linux-gnueabihf/libfreefare.so
+
+COPY *.nim *.cfg ./
+COPY nfc-nim/ nfc-nim/
+
+RUN nim c -d:nimDebugDlOpen rfid.nim
+
+ENV LIBNFC_DEFAULT_DEVICE="pn532_i2c:/dev/i2c-1"
+
+EXPOSE 10012
+
+# i2c may not read right. might need to run 'pigs m 2 0; pigs m 3 0' first, or restart pigpiod?
+
+CMD ["./rfid"]
+# LIBNFC_DEFAULT_DEVICE="pn532_i2c:/dev/i2c-1" mifare-classic-read-ndef -o /tmp/card
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/service/rfid_pn532/index.html	Thu Feb 21 09:58:56 2019 -0800
@@ -0,0 +1,128 @@
+<!doctype html>
+<html>
+  <head>
+    <title>rfid</title>
+    <meta charset="utf-8" />
+    <meta name="mobile-web-app-capable" content="yes">
+    <meta name="viewport" content="width=device-width, initial-scale=1">
+    <script src="/lib/polymer/1.0.9/webcomponentsjs/webcomponents.min.js"></script>
+    <script src="/lib/require/require-2.3.3.js"></script>
+    <script>
+     requirejs.config({
+       paths: {
+         "streamed-graph": "/rdf/streamed-graph",
+         "quadstore": "/rdf/quadstore",
+         "async-module": "/lib/async/80f1793/async",
+         "async": "/lib/async/80f1793/async",
+         "jsonld-module": "/lib/jsonld.js/0.4.11/js/jsonld",
+         "jsonld": "/lib/jsonld.js/0.4.11/js/jsonld",
+         "rdfstore": "/lib/rdf_store/0.9.7/dist/rdfstore",
+         "moment": "/lib/moment.min",
+         "underscore": "/lib/underscore-1.5.2.min",
+       }
+     });
+    </script>
+    <script>
+     window.NS = {
+       dev: 'http://projects.bigasterisk.com/device/',
+       room: 'http://projects.bigasterisk.com/room/',
+       rdfs: 'http://www.w3.org/2000/01/rdf-schema#',
+       sensor: 'http://bigasterisk.com/homeauto/sensor/',
+     };
+    </script>
+    <link rel="import" href="/lib/polymer/1.0.9/iron-ajax/iron-ajax.html">
+    <link rel="import" href="/rdf/streamed-graph.html">
+    <link rel="import" href="/lib/polymer/1.0.9/polymer/polymer.html">
+    <link rel="import" href="/rdf/rdf-oneshot.html">
+    <link rel="import" href="/rdf/rdf-uri.html">
+  </head>
+  <body>
+    <dom-module id="rfid-control">
+      <style>
+       button {
+           min-width: 60px;
+           min-height: 40px;
+       }
+       table {
+           border-collapse: collapse;
+       }
+       
+       td, th {
+           border: 1px solid gray;
+       }
+      </style>
+      <template>
+        <div>
+          <streamed-graph url="graph/events" graph="{{graph}}"></streamed-graph>
+          <!-- also get a graph of users so we can look up cards -->
+        </div>
+        
+        <iron-ajax id="rewrite" url="rewrite" method="POST"></iron-ajax>
+        
+        Current reads: 
+        <table>
+          <tr><th>Card UID</th><th>Card text</th><th></th></tr>
+          <template is="dom-repeat" items="{{currentReads}}">
+            <tr>
+              <td>{{item.uidDisplay}}</td>
+              <td>{{item.text}}</td>
+              <td>
+                <div id="form">
+                  <button on-click="rewrite">Rewrite</button>
+                </div>
+              </td>
+            </tr>
+          </template>
+        </table>
+        
+      </template>
+      <script>
+       HTMLImports.whenReady(function () {
+         Polymer({
+           is: 'rfid-control',
+           properties: {
+             graph: { type: Object, notify: true, observer: "_onGraph" },
+             currentReads: { type: Array, value: [] },
+           },
+           behaviors: [BigastUri],
+           _onGraph: function(graph) {
+             if (!graph.graph) return;
+             const env = graph.graph.store.rdf;
+
+             this.splice('currentReads', 0, this.currentReads.length);
+             graph.graph.quadStore.quads(
+               {subject: env.createNamedNode('room:frontDoorWindowRfid'),
+                predicate: env.createNamedNode('room:reading'),
+               },
+               (q) => {
+                 graph.graph.quadStore.quads(
+                   {subject: q.object,
+                    predicate: env.createNamedNode('room:cardText'),
+                   },
+                   (q2) => {
+                     this.push(
+                       'currentReads', {
+                         'cardUid': q.object,
+                         'uidDisplay': q.object.toString().replace(/.*\//, ""),
+                         'text': q2.object.toString()
+                       });
+                   });
+               });
+           },
+           rewrite: function(ev) {
+             const cardUid = ev.model.item.cardUid;
+
+             // ask for user first
+
+             this.$.rewrite.contentType = "application/json";
+             this.$.rewrite.body = {'cardUid': cardUid.toString(),
+                                    'user': "some foaf"};
+             this.$.rewrite.generateRequest();
+           }
+         });
+       });
+      </script>
+    </dom-module>
+    <rfid-control></rfid-control>
+  </body>
+</html>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/service/rfid_pn532/makefile	Thu Feb 21 09:58:56 2019 -0800
@@ -0,0 +1,43 @@
+SERVICE=rfid_pn532
+
+nfc-nim/nfc.nim: nfc-nim/nfc.h
+	c2nim/c2nim  nfc-nim/nfc.h
+
+nfc-nim/freefare.nim: nfc-nim/freefare.h
+	c2nim/c2nim  nfc-nim/freefare.h
+
+freefare_demo: freefare_demo.nim nfc-nim/nfc.nim nfc-nim/freefare.nim
+	nim-0.19.4/bin/nim c -d:nimDebugDlOpen freefare_demo.nim
+
+freefare_demo_run: freefare_demo
+	./freefare_demo
+
+rfid: rfid.nim graphserver.nim nfc-nim/nfc.nim nfc-nim/freefare.nim
+	nim-0.19.4/bin/nim c -d:nimDebugDlOpen rfid.nim
+
+rfid_local_run: rfid
+	./rfid
+
+
+build_image:
+	rm -rf tmp_ctx
+	mkdir -p tmp_ctx
+	cp -a Dockerfile *.nim *.cfg nfc-nim tmp_ctx
+	docker build --network=host -t bang6:5000/$(SERVICE)_x86:latest tmp_ctx
+	docker push bang6:5000/$(SERVICE)_x86:latest
+	rm -rf tmp_ctx
+
+
+build_image_pi:
+	rm -rf tmp_ctx
+	mkdir -p tmp_ctx
+	cp -a Dockerfile.pi *.nim *.cfg nfc-nim tmp_ctx
+	docker build --file Dockerfile.pi --network=host -t bang6:5000/$(SERVICE)_pi:latest tmp_ctx
+	docker push bang6:5000/$(SERVICE)_pi:latest
+	rm -rf tmp_ctx
+
+shell: build_image
+	docker run --name rfid_shell --rm -it --cap-add SYS_PTRACE --net=host bang6:5000/$(SERVICE)_x86:latest  /bin/bash
+
+local_run: build_image
+	docker run --name rfid_local --rm -it --net=host bang6:5000/$(SERVICE)_x86:latest
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/service/rfid_pn532/nfc-nim/freefare.h	Thu Feb 21 09:58:56 2019 -0800
@@ -0,0 +1,578 @@
+
+#ifdef C2NIM
+#define freefareLib "libfreefare.so.0.0.0"
+#define nfcHeader "nfc/nfc.h"
+#define freefareHeader "freefare.h"
+#  mangle uint8_t uint8
+#  mangle uint16_t uint16
+#  mangle uint32_t uint32
+#  mangle int32_t int32
+#  mangle ssize_t int32
+#  mangle off_t uint32
+#  prefix nfc_
+#  dynlib freefareLib
+#  cdecl
+#  header nfcHeader
+#  header freefareHeader
+#@
+import nfc
+@#
+#endif
+
+
+
+#ifndef __FREEFARE_H__
+#define __FREEFARE_H__
+
+#include <sys/types.h>
+
+#include <stdint.h>
+
+#include <nfc/nfc.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif // __cplusplus
+
+enum freefare_tag_type {
+    FELICA,
+    MIFARE_MINI,
+    MIFARE_CLASSIC_1K,
+    MIFARE_CLASSIC_4K,
+    MIFARE_DESFIRE,
+//    MIFARE_PLUS_S2K,
+//    MIFARE_PLUS_S4K,
+//    MIFARE_PLUS_X2K,
+//    MIFARE_PLUS_X4K,
+    MIFARE_ULTRALIGHT,
+    MIFARE_ULTRALIGHT_C,
+    NTAG_21x,
+};
+
+struct freefare_tag;
+typedef struct freefare_tag *FreefareTag;
+
+/* Replace any MifareTag by the generic FreefareTag. */
+typedef struct freefare_tag *MifareTag;
+
+struct mifare_desfire_key;
+typedef struct mifare_desfire_key *MifareDESFireKey;
+
+struct ntag21x_key;
+typedef struct ntag21x_key *NTAG21xKey;
+
+typedef uint8_t MifareUltralightPageNumber;
+typedef unsigned char MifareUltralightPage[4];
+
+FreefareTag	*freefare_get_tags(nfc_device *device);
+FreefareTag	 freefare_tag_new(nfc_device *device, nfc_target target);
+enum freefare_tag_type freefare_get_tag_type(FreefareTag tag);
+const char	*freefare_get_tag_friendly_name(FreefareTag tag);
+char		*freefare_get_tag_uid(FreefareTag tag);
+void		 freefare_free_tag(FreefareTag tag);
+void		 freefare_free_tags(FreefareTag *tags);
+bool		 freefare_selected_tag_is_present(nfc_device *device);
+
+const char	*freefare_strerror(FreefareTag tag);
+int		 freefare_strerror_r(FreefareTag tag, char *buffer, size_t len);
+void		 freefare_perror(FreefareTag tag, const char *string);
+
+
+
+bool		 felica_taste(nfc_device *device, nfc_target target);
+
+#define FELICA_SC_RW 0x0009
+#define FELICA_SC_RO 0x000b
+
+FreefareTag	 felica_tag_new(nfc_device *device, nfc_target target);
+void		 felica_tag_free(FreefareTag tag);
+
+ssize_t		 felica_read(FreefareTag tag, uint16_t service, uint8_t block, uint8_t *data, size_t length);
+ssize_t		 felica_read_ex(FreefareTag tag, uint16_t service, uint8_t block_count, uint8_t blocks[], uint8_t *data, size_t length);
+ssize_t		 felica_write(FreefareTag tag, uint16_t service, uint8_t block, uint8_t *data, size_t length);
+ssize_t		 felica_write_ex(FreefareTag tag, uint16_t service, uint8_t block_count, uint8_t blocks[], uint8_t *data, size_t length);
+
+
+
+bool		 mifare_ultralight_taste(nfc_device *device, nfc_target target);
+bool		 mifare_ultralightc_taste(nfc_device *device, nfc_target target);
+FreefareTag	 mifare_ultralight_tag_new(nfc_device *device, nfc_target target);
+FreefareTag	 mifare_ultralightc_tag_new(nfc_device *device, nfc_target target);
+void		 mifare_ultralight_tag_free(FreefareTag tag);
+void		 mifare_ultralightc_tag_free(FreefareTag tag);
+
+int		 mifare_ultralight_connect(FreefareTag tag);
+int		 mifare_ultralight_disconnect(FreefareTag tag);
+
+int		 mifare_ultralight_read(FreefareTag tag, const MifareUltralightPageNumber page, MifareUltralightPage *data);
+int		 mifare_ultralight_write(FreefareTag tag, const MifareUltralightPageNumber page, const MifareUltralightPage data);
+
+int		 mifare_ultralightc_authenticate(FreefareTag tag, const MifareDESFireKey key);
+int		 mifare_ultralightc_set_key(FreefareTag tag, MifareDESFireKey key);
+bool		 is_mifare_ultralight(FreefareTag tag);
+bool		 is_mifare_ultralightc(FreefareTag tag);
+bool		 is_mifare_ultralightc_on_reader(nfc_device *device, nfc_iso14443a_info nai);
+
+
+
+bool		 ntag21x_taste(nfc_device *device, nfc_target target);
+uint8_t		 ntag21x_last_error(FreefareTag tag);
+
+/* NTAG21x access features */
+#define NTAG_PROT 0x80
+#define NTAG_CFGLCK 0x40
+#define NTAG_NFC_CNT_EN 0x20
+#define NTAG_NFC_CNT_PWD_PROT 0x10
+#define NTAG_AUTHLIM 0x07
+
+enum ntag_tag_subtype {
+    NTAG_UNKNOWN,
+    NTAG_213,
+    NTAG_215,
+    NTAG_216
+};
+
+FreefareTag	 ntag21x_tag_new(nfc_device *device, nfc_target target);
+FreefareTag	 ntag21x_tag_reuse(FreefareTag tag);  /* Copy data from Ultralight tag to new NTAG21x, don't forget to free your old tag */
+NTAG21xKey	 ntag21x_key_new(const uint8_t data[4], const uint8_t pack[2]); /* Create new key */
+void		 ntag21x_key_free(NTAG21xKey key);  /* Clear key from memory */
+void		 ntag21x_tag_free(FreefareTag tag);
+int		 ntag21x_connect(FreefareTag tag);
+int		 ntag21x_disconnect(FreefareTag tag);
+int		 ntag21x_get_info(FreefareTag tag);  /* Get all information about tag (size,vendor ...) */
+enum  ntag_tag_subtype ntag21x_get_subtype(FreefareTag tag);  /* Get subtype of tag */
+uint8_t		 ntag21x_get_last_page(FreefareTag tag);  /* Get last page address based on gathered info from function above */
+int		 ntag21x_read_signature(FreefareTag tag, uint8_t *data); /* Get tag signature */
+int		 ntag21x_set_pwd(FreefareTag tag, uint8_t data[4]);  /* Set password */
+int		 ntag21x_set_pack(FreefareTag tag, uint8_t data[2]);  /* Set pack */
+int		 ntag21x_set_key(FreefareTag tag, const NTAG21xKey key); /* Set key */
+int		 ntag21x_set_auth(FreefareTag tag, uint8_t byte); /* Set AUTH0 byte (from which page starts password protection) */
+int		 ntag21x_get_auth(FreefareTag tag, uint8_t *byte); /* Get AUTH0 byte */
+int		 ntag21x_access_enable(FreefareTag tag, uint8_t byte); /* Enable access feature in ACCESS byte */
+int		 ntag21x_access_disable(FreefareTag tag, uint8_t byte); /* Disable access feature in ACCESS byte */
+int		 ntag21x_get_access(FreefareTag tag, uint8_t *byte); /* Get ACCESS byte */
+int		 ntag21x_check_access(FreefareTag tag, uint8_t byte, bool *result); /* Check if access feature is enabled */
+int		 ntag21x_get_authentication_limit(FreefareTag tag, uint8_t *byte); /* Get authentication limit */
+int		 ntag21x_set_authentication_limit(FreefareTag tag, uint8_t byte); /* Set authentication limit (0x00 = disabled, [0x01,0x07] = valid range, > 0x07 invalid range) */
+int		 ntag21x_read(FreefareTag tag, uint8_t page, uint8_t *data); /* Read 16 bytes starting from page */
+int		 ntag21x_read4(FreefareTag tag, uint8_t page, uint8_t *data); /* Read 4 bytes on page */
+int		 ntag21x_fast_read(FreefareTag tag, uint8_t start_page, uint8_t end_page, uint8_t *data); /* Read n*4 bytes from range [start_page,end_page] */
+int		 ntag21x_fast_read4(FreefareTag tag, uint8_t page, uint8_t *data); /* Fast read certain page */
+int		 ntag21x_read_cnt(FreefareTag tag, uint8_t *data);  /* Read 3-byte NFC counter if enabled else it returns error */
+int		 ntag21x_write(FreefareTag tag, uint8_t page, uint8_t data[4]);  /* Write 4 bytes to page */
+int		 ntag21x_compatibility_write(FreefareTag tag, uint8_t page, uint8_t data[4]);  /* Writes 4 bytes to page with mifare classic write */
+int		 ntag21x_authenticate(FreefareTag tag, const NTAG21xKey key);  /* Authenticate with tag */
+bool		 is_ntag21x(FreefareTag tag);  /* Check if tag type is NTAG21x */
+bool		 ntag21x_is_auth_supported(nfc_device *device, nfc_iso14443a_info nai);  /* Check if tag supports 21x commands */
+
+
+
+bool             mifare_mini_taste(nfc_device *device, nfc_target target);
+bool		 mifare_classic1k_taste(nfc_device *device, nfc_target target);
+bool		 mifare_classic4k_taste(nfc_device *device, nfc_target target);
+FreefareTag      mifare_mini_tag_new(nfc_device *device, nfc_target target);
+FreefareTag	 mifare_classic1k_tag_new(nfc_device *device, nfc_target target);
+FreefareTag	 mifare_classic4k_tag_new(nfc_device *device, nfc_target target);
+void		 mifare_classic_tag_free(FreefareTag tag);
+
+typedef unsigned char MifareClassicBlock[16];
+
+typedef uint8_t MifareClassicSectorNumber;
+typedef unsigned char MifareClassicBlockNumber;
+
+typedef enum { MFC_KEY_A, MFC_KEY_B } MifareClassicKeyType;
+typedef unsigned char MifareClassicKey[6];
+
+/* NFC Forum public key */
+extern const MifareClassicKey mifare_classic_nfcforum_public_key_a;
+
+int		 mifare_classic_connect(FreefareTag tag);
+int		 mifare_classic_disconnect(FreefareTag tag);
+
+int		 mifare_classic_authenticate(FreefareTag tag, const MifareClassicBlockNumber block, const MifareClassicKey key, const MifareClassicKeyType key_type);
+int		 mifare_classic_read(FreefareTag tag, const MifareClassicBlockNumber block, MifareClassicBlock *data);
+int		 mifare_classic_init_value(FreefareTag tag, const MifareClassicBlockNumber block, const int32_t value, const MifareClassicBlockNumber adr);
+int		 mifare_classic_read_value(FreefareTag tag, const MifareClassicBlockNumber block, int32_t *value, MifareClassicBlockNumber *adr);
+int		 mifare_classic_write(FreefareTag tag, const MifareClassicBlockNumber block, const MifareClassicBlock data);
+
+int		 mifare_classic_increment(FreefareTag tag, const MifareClassicBlockNumber block, const uint32_t amount);
+int		 mifare_classic_decrement(FreefareTag tag, const MifareClassicBlockNumber block, const uint32_t amount);
+int		 mifare_classic_restore(FreefareTag tag, const MifareClassicBlockNumber block);
+int		 mifare_classic_transfer(FreefareTag tag, const MifareClassicBlockNumber block);
+
+int		 mifare_classic_get_trailer_block_permission(FreefareTag tag, const MifareClassicBlockNumber block, const uint16_t permission, const MifareClassicKeyType key_type);
+int		 mifare_classic_get_data_block_permission(FreefareTag tag, const MifareClassicBlockNumber block, const unsigned char permission, const MifareClassicKeyType key_type);
+
+int		 mifare_classic_format_sector(FreefareTag tag, const MifareClassicSectorNumber sector);
+
+void		 mifare_classic_trailer_block(MifareClassicBlock *block, const MifareClassicKey key_a, uint8_t ab_0, uint8_t ab_1, uint8_t ab_2, uint8_t ab_tb, const uint8_t gpb, const MifareClassicKey key_b);
+
+MifareClassicSectorNumber mifare_classic_block_sector(MifareClassicBlockNumber block);
+MifareClassicBlockNumber  mifare_classic_sector_first_block(MifareClassicSectorNumber sector);
+size_t		 mifare_classic_sector_block_count(MifareClassicSectorNumber sector);
+MifareClassicBlockNumber  mifare_classic_sector_last_block(MifareClassicSectorNumber sector);
+
+#define C_000 0
+#define C_001 1
+#define C_010 2
+#define C_011 3
+#define C_100 4
+#define C_101 5
+#define C_110 6
+#define C_111 7
+#define C_DEFAULT 255
+
+/* MIFARE Classic Access Bits */
+#define MCAB_R 0x8
+#define MCAB_W 0x4
+#define MCAB_D 0x2
+#define MCAB_I 0x1
+
+#define MCAB_READ_KEYA         0x400
+#define MCAB_WRITE_KEYA        0x100
+#define MCAB_READ_ACCESS_BITS  0x040
+#define MCAB_WRITE_ACCESS_BITS 0x010
+#define MCAB_READ_KEYB         0x004
+#define MCAB_WRITE_KEYB        0x001
+
+struct mad_aid {
+    uint8_t application_code;
+    uint8_t function_cluster_code;
+};
+typedef struct mad_aid MadAid;
+
+struct mad;
+typedef struct mad *Mad;
+
+/* MAD Public read key A */
+extern const MifareClassicKey mad_public_key_a;
+
+/* AID - Adminisration codes */
+extern const MadAid mad_free_aid;
+extern const MadAid mad_defect_aid;
+extern const MadAid mad_reserved_aid;
+extern const MadAid mad_card_holder_aid;
+extern const MadAid mad_not_applicable_aid;
+
+/* NFC Forum AID */
+extern const MadAid mad_nfcforum_aid;
+
+Mad		 mad_new(const uint8_t version);
+Mad		 mad_read(FreefareTag tag);
+int		 mad_write(FreefareTag tag, Mad mad, const MifareClassicKey key_b_sector_00, const MifareClassicKey key_b_sector_10);
+int		 mad_get_version(Mad mad);
+void		 mad_set_version(Mad mad, const uint8_t version);
+MifareClassicSectorNumber mad_get_card_publisher_sector(Mad mad);
+int		 mad_set_card_publisher_sector(Mad mad, const MifareClassicSectorNumber cps);
+int		 mad_get_aid(Mad mad, const MifareClassicSectorNumber sector, MadAid *aid);
+int		 mad_set_aid(Mad mad, const MifareClassicSectorNumber sector, MadAid aid);
+bool		 mad_sector_reserved(const MifareClassicSectorNumber sector);
+void		 mad_free(Mad mad);
+
+MifareClassicSectorNumber *mifare_application_alloc(Mad mad, const MadAid aid, const size_t size);
+ssize_t		 mifare_application_read(FreefareTag tag, Mad mad, const MadAid aid, void *buf, size_t nbytes, const MifareClassicKey key, const MifareClassicKeyType key_type);
+ssize_t		 mifare_application_write(FreefareTag tag, Mad mad, const MadAid aid, const void *buf, size_t nbytes, const MifareClassicKey key, const MifareClassicKeyType key_type);
+int		 mifare_application_free(Mad mad, const MadAid aid);
+
+MifareClassicSectorNumber *mifare_application_find(Mad mad, const MadAid aid);
+
+
+
+bool		 mifare_desfire_taste(nfc_device *device, nfc_target target);
+
+/* File types */
+
+enum mifare_desfire_file_types {
+    MDFT_STANDARD_DATA_FILE             = 0x00,
+    MDFT_BACKUP_DATA_FILE               = 0x01,
+    MDFT_VALUE_FILE_WITH_BACKUP         = 0x02,
+    MDFT_LINEAR_RECORD_FILE_WITH_BACKUP = 0x03,
+    MDFT_CYCLIC_RECORD_FILE_WITH_BACKUP = 0x04
+};
+
+/* Communication mode */
+
+#define MDCM_PLAIN      0x00
+#define MDCM_MACED      0x01
+#define MDCM_ENCIPHERED 0x03
+
+/* Mifare DESFire master key settings
+bit 7 - 4: Always 0.
+bit 3: PICC master key settings frozen = 0 (WARNING - this is irreversible); PICC master key settings changeable when authenticated with PICC master key = 1
+bit 2: PICC master key authentication required for creating or deleting applications = 0; Authentication not required = 1
+bit 1: PICC master key authentication required for listing of applications or reading key settings = 0; Free listing of applications and reading key settings = 1
+bit 0: PICC master key frozen (reversible with configuration change or when formatting card) = 0; PICC master key changeable = 1
+*/
+
+#define MDMK_SETTINGS(picc_master_key_settings_changeable,free_create_delete_application,free_listing_apps_and_key_settings,picc_master_key_changeable) ( \
+	(picc_master_key_settings_changeable << 3) | \
+	(free_create_delete_application << 2) | \
+	(free_listing_apps_and_key_settings << 1) | \
+	(picc_master_key_changeable) \
+																			)
+
+/* Mifare DESFire EV1 Application crypto operations */
+
+#define APPLICATION_CRYPTO_DES    0x00
+#define APPLICATION_CRYPTO_3K3DES 0x40
+#define APPLICATION_CRYPTO_AES    0x80
+
+/* Mifare DESFire Application settings
+ * bit 7 - 4: Number of key needed to change application keys (key 0 - 13; 0 = master key; 14 = key itself required for key change; 15 = all keys are frozen)
+ * bit 3: Application configuration frozen = 0; Application configuration changeable when authenticated with application master key = 1
+ * bit 2: Application master key authentication required for create/delete files = 0; Authentication not required = 1
+ * bit 1: GetFileIDs, GetFileSettings and GetKeySettings behavior: Master key authentication required = 0; No authentication required = 1
+ * bit 0 = Application master key frozen = 0; Application master key changeable = 1
+ */
+
+#define MDAPP_SETTINGS(key_no_for_key_changing,config_changeable,free_create_delete_files,free_listing_contents,app_master_key_changeable) ( \
+	(key_no_for_key_changing << 4) | \
+	(config_changeable << 3) | \
+	(free_create_delete_files << 2) | \
+	(free_listing_contents << 1) | \
+	(app_master_key_changeable) \
+																	   )
+
+/* Access right */
+
+#define MDAR(read,write,read_write,change_access_rights) ( \
+	(read << 12) | \
+	(write << 8) | \
+	(read_write << 4) | \
+	(change_access_rights) \
+							 )
+
+#define MDAR_READ(ar)       (((ar) >> 12) & 0x0f)
+#define MDAR_WRITE(ar)      (((ar) >>  8) & 0x0f)
+#define MDAR_READ_WRITE(ar) (((ar) >>  4) & 0x0f)
+#define MDAR_CHANGE_AR(ar)  ((ar)         & 0x0f)
+
+#define MDAR_KEY0  0x0
+#define MDAR_KEY1  0x1
+#define MDAR_KEY2  0x2
+#define MDAR_KEY3  0x3
+#define MDAR_KEY4  0x4
+#define MDAR_KEY5  0x5
+#define MDAR_KEY6  0x6
+#define MDAR_KEY7  0x7
+#define MDAR_KEY8  0x8
+#define MDAR_KEY9  0x9
+#define MDAR_KEY10 0xa
+#define MDAR_KEY11 0xb
+#define MDAR_KEY12 0xc
+#define MDAR_KEY13 0xd
+#define MDAR_FREE  0xE
+#define MDAR_DENY  0xF
+
+/* Status and error codes */
+
+#define	OPERATION_OK		0x00
+#define	NO_CHANGES		0x0C
+#define	OUT_OF_EEPROM_ERROR	0x0E
+#define	ILLEGAL_COMMAND_CODE	0x1C
+#define	INTEGRITY_ERROR		0x1E
+#define	NO_SUCH_KEY		0x40
+#define	LENGTH_ERROR		0x7E
+#define	PERMISSION_ERROR	0x9D
+#define	PARAMETER_ERROR		0x9E
+#define	APPLICATION_NOT_FOUND	0xA0
+#define	APPL_INTEGRITY_ERROR	0xA1
+#define	AUTHENTICATION_ERROR	0xAE
+#define	ADDITIONAL_FRAME	0xAF
+#define	BOUNDARY_ERROR		0xBE
+#define	PICC_INTEGRITY_ERROR	0xC1
+#define	COMMAND_ABORTED		0xCA
+#define	PICC_DISABLED_ERROR	0xCD
+#define	COUNT_ERROR		0xCE
+#define	DUPLICATE_ERROR		0xDE
+#define	EEPROM_ERROR		0xEE
+#define	FILE_NOT_FOUND		0xF0
+#define	FILE_INTEGRITY_ERROR	0xF1
+
+/* Error code managed by the library */
+
+#define CRYPTO_ERROR            0x01
+#define TAG_INFO_MISSING_ERROR	0xBA
+#define UNKNOWN_TAG_TYPE_ERROR	0xBB
+
+struct mifare_desfire_aid;
+typedef struct mifare_desfire_aid *MifareDESFireAID;
+
+struct mifare_desfire_df {
+    uint32_t aid;
+    uint16_t fid;
+    uint8_t df_name[16];
+    size_t df_name_len;
+};
+typedef struct mifare_desfire_df MifareDESFireDF;
+
+MifareDESFireAID mifare_desfire_aid_new(uint32_t aid);
+MifareDESFireAID mifare_desfire_aid_new_with_mad_aid(MadAid mad_aid, uint8_t n);
+uint32_t	 mifare_desfire_aid_get_aid(MifareDESFireAID aid);
+
+uint8_t		 mifare_desfire_last_pcd_error(FreefareTag tag);
+uint8_t		 mifare_desfire_last_picc_error(FreefareTag tag);
+
+#pragma pack (push)
+#pragma pack (1)
+struct mifare_desfire_version_info {
+    struct {
+	uint8_t vendor_id;
+	uint8_t type;
+	uint8_t subtype;
+	uint8_t version_major;
+	uint8_t version_minor;
+	uint8_t storage_size;
+	uint8_t protocol;
+    } hardware;
+    struct {
+	uint8_t vendor_id;
+	uint8_t type;
+	uint8_t subtype;
+	uint8_t version_major;
+	uint8_t version_minor;
+	uint8_t storage_size;
+	uint8_t protocol;
+    } software;
+    uint8_t uid[7];
+    uint8_t batch_number[5];
+    uint8_t production_week;
+    uint8_t production_year;
+};
+#pragma pack (pop)
+
+struct mifare_desfire_file_settings {
+    uint8_t file_type;
+    uint8_t communication_settings;
+    uint16_t access_rights;
+    union {
+	struct {
+	    uint32_t file_size;
+	} standard_file;
+	struct {
+	    int32_t lower_limit;
+	    int32_t upper_limit;
+	    int32_t limited_credit_value;
+	    uint8_t limited_credit_enabled;
+	} value_file;
+	struct {
+	    uint32_t record_size;
+	    uint32_t max_number_of_records;
+	    uint32_t current_number_of_records;
+	} linear_record_file;
+    } settings;
+};
+
+FreefareTag	 mifare_desfire_tag_new(nfc_device *device, nfc_target target);
+void		 mifare_desfire_tag_free(FreefareTag tags);
+
+int		 mifare_desfire_connect(FreefareTag tag);
+int		 mifare_desfire_disconnect(FreefareTag tag);
+
+int		 mifare_desfire_authenticate(FreefareTag tag, uint8_t key_no, MifareDESFireKey key);
+int		 mifare_desfire_authenticate_iso(FreefareTag tag, uint8_t key_no, MifareDESFireKey key);
+int		 mifare_desfire_authenticate_aes(FreefareTag tag, uint8_t key_no, MifareDESFireKey key);
+int		 mifare_desfire_change_key_settings(FreefareTag tag, uint8_t settings);
+int		 mifare_desfire_get_key_settings(FreefareTag tag, uint8_t *settings, uint8_t *max_keys);
+int		 mifare_desfire_change_key(FreefareTag tag, uint8_t key_no, MifareDESFireKey new_key, MifareDESFireKey old_key);
+int		 mifare_desfire_get_key_version(FreefareTag tag, uint8_t key_no, uint8_t *version);
+int		 mifare_desfire_create_application(FreefareTag tag, MifareDESFireAID aid, uint8_t settings, uint8_t key_no);
+int		 mifare_desfire_create_application_3k3des(FreefareTag tag, MifareDESFireAID aid, uint8_t settings, uint8_t key_no);
+int		 mifare_desfire_create_application_aes(FreefareTag tag, MifareDESFireAID aid, uint8_t settings, uint8_t key_no);
+
+int		 mifare_desfire_create_application_iso(FreefareTag tag, MifareDESFireAID aid, uint8_t settings, uint8_t key_no, int want_iso_file_identifiers, uint16_t iso_file_id, uint8_t *iso_file_name, size_t iso_file_name_len);
+int		 mifare_desfire_create_application_3k3des_iso(FreefareTag tag, MifareDESFireAID aid, uint8_t settings, uint8_t key_no, int want_iso_file_identifiers, uint16_t iso_file_id, uint8_t *iso_file_name, size_t iso_file_name_len);
+int		 mifare_desfire_create_application_aes_iso(FreefareTag tag, MifareDESFireAID aid, uint8_t settings, uint8_t key_no, int want_iso_file_identifiers, uint16_t iso_file_id, uint8_t *iso_file_name, size_t iso_file_name_len);
+
+int		 mifare_desfire_delete_application(FreefareTag tag, MifareDESFireAID aid);
+int		 mifare_desfire_get_application_ids(FreefareTag tag, MifareDESFireAID *aids[], size_t *count);
+int		 mifare_desfire_get_df_names(FreefareTag tag, MifareDESFireDF *dfs[], size_t *count);
+void		 mifare_desfire_free_application_ids(MifareDESFireAID aids[]);
+int		 mifare_desfire_select_application(FreefareTag tag, MifareDESFireAID aid);
+int		 mifare_desfire_format_picc(FreefareTag tag);
+int		 mifare_desfire_get_version(FreefareTag tag, struct mifare_desfire_version_info *version_info);
+int		 mifare_desfire_free_mem(FreefareTag tag, uint32_t *size);
+int		 mifare_desfire_set_configuration(FreefareTag tag, bool disable_format, bool enable_random_uid);
+int		 mifare_desfire_set_default_key(FreefareTag tag, MifareDESFireKey key);
+int		 mifare_desfire_set_ats(FreefareTag tag, uint8_t *ats);
+int		 mifare_desfire_get_card_uid(FreefareTag tag, char **uid);
+int		 mifare_desfire_get_card_uid_raw(FreefareTag tag, uint8_t uid[7]);
+int		 mifare_desfire_get_file_ids(FreefareTag tag, uint8_t **files, size_t *count);
+int		 mifare_desfire_get_iso_file_ids(FreefareTag tag, uint16_t **files, size_t *count);
+int		 mifare_desfire_get_file_settings(FreefareTag tag, uint8_t file_no, struct mifare_desfire_file_settings *settings);
+int		 mifare_desfire_change_file_settings(FreefareTag tag, uint8_t file_no, uint8_t communication_settings, uint16_t access_rights);
+int		 mifare_desfire_create_std_data_file(FreefareTag tag, uint8_t file_no, uint8_t communication_settings, uint16_t access_rights, uint32_t file_size);
+int		 mifare_desfire_create_std_data_file_iso(FreefareTag tag, uint8_t file_no, uint8_t communication_settings, uint16_t access_rights, uint32_t file_size, uint16_t iso_file_id);
+int		 mifare_desfire_create_backup_data_file(FreefareTag tag, uint8_t file_no, uint8_t communication_settings, uint16_t access_rights, uint32_t file_size);
+int		 mifare_desfire_create_backup_data_file_iso(FreefareTag tag, uint8_t file_no, uint8_t communication_settings, uint16_t access_rights, uint32_t file_size, uint16_t iso_file_id);
+int		 mifare_desfire_create_value_file(FreefareTag tag, uint8_t file_no, uint8_t communication_settings, uint16_t access_rights, int32_t lower_limit, int32_t upper_limit, int32_t value, uint8_t limited_credit_enable);
+int		 mifare_desfire_create_linear_record_file(FreefareTag tag, uint8_t file_no, uint8_t communication_settings, uint16_t access_rights, uint32_t record_size, uint32_t max_number_of_records);
+int		 mifare_desfire_create_linear_record_file_iso(FreefareTag tag, uint8_t file_no, uint8_t communication_settings, uint16_t access_rights, uint32_t record_size, uint32_t max_number_of_records, uint16_t iso_file_id);
+int		 mifare_desfire_create_cyclic_record_file(FreefareTag tag, uint8_t file_no, uint8_t communication_settings, uint16_t access_rights, uint32_t record_size, uint32_t max_number_of_records);
+int		 mifare_desfire_create_cyclic_record_file_iso(FreefareTag tag, uint8_t file_no, uint8_t communication_settings, uint16_t access_rights, uint32_t record_size, uint32_t max_number_of_records, uint16_t iso_file_id);
+int		 mifare_desfire_delete_file(FreefareTag tag, uint8_t file_no);
+
+ssize_t		 mifare_desfire_read_data(FreefareTag tag, uint8_t file_no, off_t offset, size_t length, void *data);
+ssize_t		 mifare_desfire_read_data_ex(FreefareTag tag, uint8_t file_no, off_t offset, size_t length, void *data, int cs);
+ssize_t		 mifare_desfire_write_data(FreefareTag tag, uint8_t file_no, off_t offset, size_t length, const void *data);
+ssize_t		 mifare_desfire_write_data_ex(FreefareTag tag, uint8_t file_no, off_t offset, size_t length, const void *data, int cs);
+int		 mifare_desfire_get_value(FreefareTag tag, uint8_t file_no, int32_t *value);
+int		 mifare_desfire_get_value_ex(FreefareTag tag, uint8_t file_no, int32_t *value, int cs);
+int		 mifare_desfire_credit(FreefareTag tag, uint8_t file_no, int32_t amount);
+int		 mifare_desfire_credit_ex(FreefareTag tag, uint8_t file_no, int32_t amount, int cs);
+int		 mifare_desfire_debit(FreefareTag tag, uint8_t file_no, int32_t amount);
+int		 mifare_desfire_debit_ex(FreefareTag tag, uint8_t file_no, int32_t amount, int cs);
+int		 mifare_desfire_limited_credit(FreefareTag tag, uint8_t file_no, int32_t amount);
+int		 mifare_desfire_limited_credit_ex(FreefareTag tag, uint8_t file_no, int32_t amount, int cs);
+ssize_t		 mifare_desfire_write_record(FreefareTag tag, uint8_t file_no, off_t offset, size_t length, void *data);
+ssize_t		 mifare_desfire_write_record_ex(FreefareTag tag, uint8_t file_no, off_t offset, size_t length, void *data, int cs);
+ssize_t		 mifare_desfire_read_records(FreefareTag tag, uint8_t file_no, off_t offset, size_t length, void *data);
+ssize_t		 mifare_desfire_read_records_ex(FreefareTag tag, uint8_t file_no, off_t offset, size_t length, void *data, int cs);
+int		 mifare_desfire_clear_record_file(FreefareTag tag, uint8_t file_no);
+int		 mifare_desfire_commit_transaction(FreefareTag tag);
+int		 mifare_desfire_abort_transaction(FreefareTag tag);
+
+MifareDESFireKey mifare_desfire_des_key_new(const uint8_t value[8]);
+MifareDESFireKey mifare_desfire_3des_key_new(const uint8_t value[16]);
+MifareDESFireKey mifare_desfire_des_key_new_with_version(const uint8_t value[8]);
+MifareDESFireKey mifare_desfire_3des_key_new_with_version(const uint8_t value[16]);
+MifareDESFireKey mifare_desfire_3k3des_key_new(const uint8_t value[24]);
+MifareDESFireKey mifare_desfire_3k3des_key_new_with_version(const uint8_t value[24]);
+MifareDESFireKey mifare_desfire_aes_key_new(const uint8_t value[16]);
+MifareDESFireKey mifare_desfire_aes_key_new_with_version(const uint8_t value[16], uint8_t version);
+uint8_t		 mifare_desfire_key_get_version(MifareDESFireKey key);
+void		 mifare_desfire_key_set_version(MifareDESFireKey key, uint8_t version);
+void		 mifare_desfire_key_free(MifareDESFireKey key);
+
+uint8_t		*tlv_encode(const uint8_t type, const uint8_t *istream, uint16_t isize, size_t *osize);
+uint8_t		*tlv_decode(const uint8_t *istream, uint8_t *type, uint16_t *size);
+size_t		tlv_record_length(const uint8_t *istream, size_t *field_length_size, size_t *field_value_size);
+uint8_t		*tlv_append(uint8_t *a, uint8_t *b);
+
+typedef enum mifare_key_type {
+    MIFARE_KEY_DES,
+    MIFARE_KEY_2K3DES,
+    MIFARE_KEY_3K3DES,
+    MIFARE_KEY_AES128,
+
+    MIFARE_KEY_LAST = MIFARE_KEY_AES128
+} MifareKeyType;
+
+struct mifare_key_deriver;
+typedef struct mifare_key_deriver *MifareKeyDeriver;
+
+MifareKeyDeriver mifare_key_deriver_new_an10922(MifareDESFireKey master_key, MifareKeyType output_key_type);
+int		 mifare_key_deriver_begin(MifareKeyDeriver deriver);
+int		 mifare_key_deriver_update_data(MifareKeyDeriver deriver, const uint8_t *data, size_t len);
+int		 mifare_key_deriver_update_uid(MifareKeyDeriver deriver, FreefareTag tag);
+int		 mifare_key_deriver_update_aid(MifareKeyDeriver deriver, MifareDESFireAID aid);
+int		 mifare_key_deriver_update_cstr(MifareKeyDeriver deriver, const char *cstr);
+MifareDESFireKey mifare_key_deriver_end(MifareKeyDeriver deriver);
+int		 mifare_key_deriver_end_raw(MifareKeyDeriver deriver, uint8_t* diversified_bytes, size_t data_max_len);
+void		 mifare_key_deriver_free(MifareKeyDeriver state);
+
+#ifdef __cplusplus
+}
+#endif // __cplusplus
+
+#endif /* !__FREEFARE_H__ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/service/rfid_pn532/nfc-nim/nfc.h	Thu Feb 21 09:58:56 2019 -0800
@@ -0,0 +1,523 @@
+/*-
+ * Free/Libre Near Field Communication (NFC) library
+ *
+ * Libnfc historical contributors:
+ * Copyright (C) 2009      Roel Verdult
+ * Copyright (C) 2009-2013 Romuald Conty
+ * Copyright (C) 2010-2012 Romain Tartière
+ * Copyright (C) 2010-2013 Philippe Teuwen
+ * Copyright (C) 2012-2013 Ludovic Rousseau
+ * See AUTHORS file for a more comprehensive list of contributors.
+ * Additional contributors of this file:
+ *
+ * This program is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by the
+ * Free Software Foundation, either version 3 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>
+ */
+
+#ifdef C2NIM
+#define nfcLib "libnfc.so.5.0.1"
+#  mangle uint8_t uint8
+#  mangle uint32_t uint32
+#  prefix nfc_
+#  dynlib nfcLib
+#  cdecl
+#endif
+
+/**
+ * @file nfc.h
+ * @brief libnfc interface
+ *
+ * Provide all usefull functions (API) to handle NFC devices.
+ */
+
+
+#  include <sys/time.h>
+
+#  include <stdint.h>
+#  include <stdbool.h>
+
+
+/*-
+ * Free/Libre Near Field Communication (NFC) library
+ *
+ * Libnfc historical contributors:
+ * Copyright (C) 2009      Roel Verdult
+ * Copyright (C) 2009-2013 Romuald Conty
+ * Copyright (C) 2010-2012 Romain Tartière
+ * Copyright (C) 2010-2013 Philippe Teuwen
+ * Copyright (C) 2012-2013 Ludovic Rousseau
+ * See AUTHORS file for a more comprehensive list of contributors.
+ * Additional contributors of this file:
+ *
+ * This program is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by the
+ * Free Software Foundation, either version 3 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>
+ */
+/**
+ * @file nfc-types.h
+ * @brief Define NFC types
+ */
+
+
+#include <stddef.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <stdio.h>
+
+
+#define NFC_BUFSIZE_CONNSTRING 1024
+
+
+/**
+ * NFC context
+ */
+struct nfc_context;
+typedef struct nfc_context nfc_context;
+
+/**
+ * NFC device
+ */
+struct nfc_device;
+typedef struct nfc_device nfc_device;
+
+/**
+ * NFC device driver
+ */
+struct nfc_driver;
+typedef struct nfc_driver nfc_driver;
+
+/**
+ * Connection string
+ */
+typedef char nfc_connstring[NFC_BUFSIZE_CONNSTRING];
+
+/**
+ * Properties
+ */
+typedef enum {
+  /**
+   * Default command processing timeout
+   * Property value's (duration) unit is ms and 0 means no timeout (infinite).
+   * Default value is set by driver layer
+   */
+  NP_TIMEOUT_COMMAND,
+  /**
+   * Timeout between ATR_REQ and ATR_RES
+   * When the device is in initiator mode, a target is considered as mute if no
+   * valid ATR_RES is received within this timeout value.
+   * Default value for this property is 103 ms on PN53x based devices.
+   */
+  NP_TIMEOUT_ATR,
+  /**
+   * Timeout value to give up reception from the target in case of no answer.
+   * Default value for this property is 52 ms).
+   */
+  NP_TIMEOUT_COM,
+  /** Let the PN53X chip handle the CRC bytes. This means that the chip appends
+  * the CRC bytes to the frames that are transmitted. It will parse the last
+  * bytes from received frames as incoming CRC bytes. They will be verified
+  * against the used modulation and protocol. If an frame is expected with
+  * incorrect CRC bytes this option should be disabled. Example frames where
+  * this is useful are the ATQA and UID+BCC that are transmitted without CRC
+  * bytes during the anti-collision phase of the ISO14443-A protocol. */
+  NP_HANDLE_CRC,
+  /** Parity bits in the network layer of ISO14443-A are by default generated and
+   * validated in the PN53X chip. This is a very convenient feature. On certain
+   * times though it is useful to get full control of the transmitted data. The
+   * proprietary MIFARE Classic protocol uses for example custom (encrypted)
+   * parity bits. For interoperability it is required to be completely
+   * compatible, including the arbitrary parity bits. When this option is
+   * disabled, the functions to communicating bits should be used. */
+  NP_HANDLE_PARITY,
+  /** This option can be used to enable or disable the electronic field of the
+   * NFC device. */
+  NP_ACTIVATE_FIELD,
+  /** The internal CRYPTO1 co-processor can be used to transmit messages
+   * encrypted. This option is automatically activated after a successful MIFARE
+   * Classic authentication. */
+  NP_ACTIVATE_CRYPTO1,
+  /** The default configuration defines that the PN53X chip will try indefinitely
+   * to invite a tag in the field to respond. This could be desired when it is
+   * certain a tag will enter the field. On the other hand, when this is
+   * uncertain, it will block the application. This option could best be compared
+   * to the (NON)BLOCKING option used by (socket)network programming. */
+  NP_INFINITE_SELECT,
+  /** If this option is enabled, frames that carry less than 4 bits are allowed.
+   * According to the standards these frames should normally be handles as
+   * invalid frames. */
+  NP_ACCEPT_INVALID_FRAMES,
+  /** If the NFC device should only listen to frames, it could be useful to let
+   * it gather multiple frames in a sequence. They will be stored in the internal
+   * FIFO of the PN53X chip. This could be retrieved by using the receive data
+   * functions. Note that if the chip runs out of bytes (FIFO = 64 bytes long),
+   * it will overwrite the first received frames, so quick retrieving of the
+   * received data is desirable. */
+  NP_ACCEPT_MULTIPLE_FRAMES,
+  /** This option can be used to enable or disable the auto-switching mode to
+   * ISO14443-4 is device is compliant.
+   * In initiator mode, it means that NFC chip will send RATS automatically when
+   * select and it will automatically poll for ISO14443-4 card when ISO14443A is
+   * requested.
+   * In target mode, with a NFC chip compliant (ie. PN532), the chip will
+   * emulate a 14443-4 PICC using hardware capability */
+  NP_AUTO_ISO14443_4,
+  /** Use automatic frames encapsulation and chaining. */
+  NP_EASY_FRAMING,
+  /** Force the chip to switch in ISO14443-A */
+  NP_FORCE_ISO14443_A,
+  /** Force the chip to switch in ISO14443-B */
+  NP_FORCE_ISO14443_B,
+  /** Force the chip to run at 106 kbps */
+  NP_FORCE_SPEED_106,
+} nfc_property;
+
+// Compiler directive, set struct alignment to 1 uint8_t for compatibility
+#  pragma pack(1)
+
+/**
+ * @enum nfc_dep_mode
+ * @brief NFC D.E.P. (Data Exchange Protocol) active/passive mode
+ */
+typedef enum {
+  NDM_UNDEFINED = 0,
+  NDM_PASSIVE,
+  NDM_ACTIVE,
+} nfc_dep_mode;
+
+/**
+ * @struct nfc_dep_info
+ * @brief NFC target information in D.E.P. (Data Exchange Protocol) see ISO/IEC 18092 (NFCIP-1)
+ */
+typedef struct {
+  /** NFCID3 */
+  uint8_t  abtNFCID3[10];
+  /** DID */
+  uint8_t  btDID;
+  /** Supported send-bit rate */
+  uint8_t  btBS;
+  /** Supported receive-bit rate */
+  uint8_t  btBR;
+  /** Timeout value */
+  uint8_t  btTO;
+  /** PP Parameters */
+  uint8_t  btPP;
+  /** General Bytes */
+  uint8_t  abtGB[48];
+  size_t  szGB;
+  /** DEP mode */
+  nfc_dep_mode ndm;
+} nfc_dep_info;
+
+/**
+ * @struct nfc_iso14443a_info
+ * @brief NFC ISO14443A tag (MIFARE) information
+ */
+typedef struct {
+  uint8_t  abtAtqa[2];
+  uint8_t  btSak;
+  size_t  szUidLen;
+  uint8_t  abtUid[10];
+  size_t  szAtsLen;
+  uint8_t  abtAts[254]; // Maximal theoretical ATS is FSD-2, FSD=256 for FSDI=8 in RATS
+} nfc_iso14443a_info;
+
+/**
+ * @struct nfc_felica_info
+ * @brief NFC FeLiCa tag information
+ */
+typedef struct {
+  size_t  szLen;
+  uint8_t  btResCode;
+  uint8_t  abtId[8];
+  uint8_t  abtPad[8];
+  uint8_t  abtSysCode[2];
+} nfc_felica_info;
+
+/**
+ * @struct nfc_iso14443b_info
+ * @brief NFC ISO14443B tag information
+ */
+typedef struct {
+  /** abtPupi store PUPI contained in ATQB (Answer To reQuest of type B) (see ISO14443-3) */
+  uint8_t abtPupi[4];
+  /** abtApplicationData store Application Data contained in ATQB (see ISO14443-3) */
+  uint8_t abtApplicationData[4];
+  /** abtProtocolInfo store Protocol Info contained in ATQB (see ISO14443-3) */
+  uint8_t abtProtocolInfo[3];
+  /** ui8CardIdentifier store CID (Card Identifier) attributted by PCD to the PICC */
+  uint8_t ui8CardIdentifier;
+} nfc_iso14443b_info;
+
+/**
+ * @struct nfc_iso14443bi_info
+ * @brief NFC ISO14443B' tag information
+ */
+typedef struct {
+  /** DIV: 4 LSBytes of tag serial number */
+  uint8_t abtDIV[4];
+  /** Software version & type of REPGEN */
+  uint8_t btVerLog;
+  /** Config Byte, present if long REPGEN */
+  uint8_t btConfig;
+  /** ATR, if any */
+  size_t szAtrLen;
+  uint8_t  abtAtr[33];
+} nfc_iso14443bi_info;
+
+/**
+ * @struct nfc_iso14443b2sr_info
+ * @brief NFC ISO14443-2B ST SRx tag information
+ */
+typedef struct {
+  uint8_t abtUID[8];
+} nfc_iso14443b2sr_info;
+
+/**
+ * @struct nfc_iso14443b2ct_info
+ * @brief NFC ISO14443-2B ASK CTx tag information
+ */
+typedef struct {
+  uint8_t abtUID[4];
+  uint8_t btProdCode;
+  uint8_t btFabCode;
+} nfc_iso14443b2ct_info;
+
+/**
+ * @struct nfc_jewel_info
+ * @brief NFC Jewel tag information
+ */
+typedef struct {
+  uint8_t  btSensRes[2];
+  uint8_t  btId[4];
+} nfc_jewel_info;
+
+/**
+ * @union nfc_target_info
+ * @brief Union between all kind of tags information structures.
+ */
+typedef union {
+  nfc_iso14443a_info nai;
+  nfc_felica_info nfi;
+  nfc_iso14443b_info nbi;
+  nfc_iso14443bi_info nii;
+  nfc_iso14443b2sr_info nsi;
+  nfc_iso14443b2ct_info nci;
+  nfc_jewel_info nji;
+  nfc_dep_info ndi;
+} nfc_target_info;
+
+/**
+ * @enum nfc_baud_rate
+ * @brief NFC baud rate enumeration
+ */
+typedef enum {
+  NBR_UNDEFINED = 0,
+  NBR_106,
+  NBR_212,
+  NBR_424,
+  NBR_847,
+} nfc_baud_rate;
+
+/**
+ * @enum nfc_modulation_type
+ * @brief NFC modulation type enumeration
+ */
+typedef enum {
+  NMT_ISO14443A = 1,
+  NMT_JEWEL,
+  NMT_ISO14443B,
+  NMT_ISO14443BI, // pre-ISO14443B aka ISO/IEC 14443 B' or Type B'
+  NMT_ISO14443B2SR, // ISO14443-2B ST SRx
+  NMT_ISO14443B2CT, // ISO14443-2B ASK CTx
+  NMT_FELICA,
+  NMT_DEP,
+} nfc_modulation_type;
+
+/**
+ * @enum nfc_mode
+ * @brief NFC mode type enumeration
+ */
+typedef enum {
+  N_TARGET,
+  N_INITIATOR,
+} nfc_mode;
+
+/**
+ * @struct nfc_modulation
+ * @brief NFC modulation structure
+ */
+typedef struct {
+  nfc_modulation_type nmt;
+  nfc_baud_rate nbr;
+} nfc_modulation;
+
+/**
+ * @struct nfc_target
+ * @brief NFC target structure
+ */
+typedef struct {
+  nfc_target_info nti;
+  nfc_modulation nm;
+} nfc_target;
+
+// Reset struct alignment to default
+#  pragma pack()
+
+
+/* Library initialization/deinitialization */
+void nfc_init(nfc_context **context);
+void nfc_exit(nfc_context *context);
+int nfc_register_driver(const nfc_driver *driver);
+
+/* NFC Device/Hardware manipulation */
+nfc_device *nfc_open(nfc_context *context, const nfc_connstring connstring);
+void nfc_close(nfc_device *pnd);
+int nfc_abort_command(nfc_device *pnd);
+size_t nfc_list_devices(nfc_context *context, nfc_connstring connstrings[], size_t connstrings_len);
+int nfc_idle(nfc_device *pnd);
+
+/* NFC initiator: act as "reader" */
+int nfc_initiator_init(nfc_device *pnd);
+int nfc_initiator_init_secure_element(nfc_device *pnd);
+int nfc_initiator_select_passive_target(nfc_device *pnd, const nfc_modulation nm, const uint8_t *pbtInitData, const size_t szInitData, nfc_target *pnt);
+int nfc_initiator_list_passive_targets(nfc_device *pnd, const nfc_modulation nm, nfc_target ant[], const size_t szTargets);
+int nfc_initiator_poll_target(nfc_device *pnd, const nfc_modulation *pnmTargetTypes, const size_t szTargetTypes, const uint8_t uiPollNr, const uint8_t uiPeriod, nfc_target *pnt);
+int nfc_initiator_select_dep_target(nfc_device *pnd, const nfc_dep_mode ndm, const nfc_baud_rate nbr, const nfc_dep_info *pndiInitiator, nfc_target *pnt, const int timeout);
+int nfc_initiator_poll_dep_target(nfc_device *pnd, const nfc_dep_mode ndm, const nfc_baud_rate nbr, const nfc_dep_info *pndiInitiator, nfc_target *pnt, const int timeout);
+int nfc_initiator_deselect_target(nfc_device *pnd);
+int nfc_initiator_transceive_bytes(nfc_device *pnd, const uint8_t *pbtTx, const size_t szTx, uint8_t *pbtRx, const size_t szRx, int timeout);
+int nfc_initiator_transceive_bits(nfc_device *pnd, const uint8_t *pbtTx, const size_t szTxBits, const uint8_t *pbtTxPar, uint8_t *pbtRx, const size_t szRx, uint8_t *pbtRxPar);
+int nfc_initiator_transceive_bytes_timed(nfc_device *pnd, const uint8_t *pbtTx, const size_t szTx, uint8_t *pbtRx, const size_t szRx, uint32_t *cycles);
+int nfc_initiator_transceive_bits_timed(nfc_device *pnd, const uint8_t *pbtTx, const size_t szTxBits, const uint8_t *pbtTxPar, uint8_t *pbtRx, const size_t szRx, uint8_t *pbtRxPar, uint32_t *cycles);
+int nfc_initiator_target_is_present(nfc_device *pnd, const nfc_target *pnt);
+
+/* NFC target: act as tag (i.e. MIFARE Classic) or NFC target device. */
+int nfc_target_init(nfc_device *pnd, nfc_target *pnt, uint8_t *pbtRx, const size_t szRx, int timeout);
+int nfc_target_send_bytes(nfc_device *pnd, const uint8_t *pbtTx, const size_t szTx, int timeout);
+int nfc_target_receive_bytes(nfc_device *pnd, uint8_t *pbtRx, const size_t szRx, int timeout);
+int nfc_target_send_bits(nfc_device *pnd, const uint8_t *pbtTx, const size_t szTxBits, const uint8_t *pbtTxPar);
+int nfc_target_receive_bits(nfc_device *pnd, uint8_t *pbtRx, const size_t szRx, uint8_t *pbtRxPar);
+
+/* Error reporting */
+const char *nfc_strerror(const nfc_device *pnd);
+int nfc_strerror_r(const nfc_device *pnd, char *buf, size_t buflen);
+void nfc_perror(const nfc_device *pnd, const char *s);
+int nfc_device_get_last_error(const nfc_device *pnd);
+
+/* Special data accessors */
+const char *nfc_device_get_name(nfc_device *pnd);
+const char *nfc_device_get_connstring(nfc_device *pnd);
+int nfc_device_get_supported_modulation(nfc_device *pnd, const nfc_mode mode,  const nfc_modulation_type **const supported_mt);
+int nfc_device_get_supported_baud_rate(nfc_device *pnd, const nfc_modulation_type nmt, const nfc_baud_rate **const supported_br);
+
+/* Properties accessors */
+int nfc_device_set_property_int(nfc_device *pnd, const nfc_property property, const int value);
+int nfc_device_set_property_bool(nfc_device *pnd, const nfc_property property, const bool bEnable);
+
+/* Misc. functions */
+void iso14443a_crc(uint8_t *pbtData, size_t szLen, uint8_t *pbtCrc);
+void iso14443a_crc_append(uint8_t *pbtData, size_t szLen);
+void iso14443b_crc(uint8_t *pbtData, size_t szLen, uint8_t *pbtCrc);
+void iso14443b_crc_append(uint8_t *pbtData, size_t szLen);
+uint8_t *iso14443a_locate_historical_bytes(uint8_t *pbtAts, size_t szAts, size_t *pszTk);
+
+void nfc_free(void *p);
+const char *nfc_version(void);
+int nfc_device_get_information_about(nfc_device *pnd, char **buf);
+
+/* String converter functions */
+const char *str_nfc_modulation_type(const nfc_modulation_type nmt);
+const char *str_nfc_baud_rate(const nfc_baud_rate nbr);
+int str_nfc_target(char **buf, const nfc_target *pnt, bool verbose);
+
+/* Error codes */
+/** @ingroup error
+ * @hideinitializer
+ * Success (no error)
+ */
+#define NFC_SUCCESS			 0
+/** @ingroup error
+ * @hideinitializer
+ * Input / output error, device may not be usable anymore without re-open it
+ */
+#define NFC_EIO				-1
+/** @ingroup error
+ * @hideinitializer
+ * Invalid argument(s)
+ */
+#define NFC_EINVARG			-2
+/** @ingroup error
+ * @hideinitializer
+ *  Operation not supported by device
+ */
+#define NFC_EDEVNOTSUPP			-3
+/** @ingroup error
+ * @hideinitializer
+ * No such device
+ */
+#define NFC_ENOTSUCHDEV			-4
+/** @ingroup error
+ * @hideinitializer
+ * Buffer overflow
+ */
+#define NFC_EOVFLOW			-5
+/** @ingroup error
+ * @hideinitializer
+ * Operation timed out
+ */
+#define NFC_ETIMEOUT			-6
+/** @ingroup error
+ * @hideinitializer
+ * Operation aborted (by user)
+ */
+#define NFC_EOPABORTED			-7
+/** @ingroup error
+ * @hideinitializer
+ * Not (yet) implemented
+ */
+#define NFC_ENOTIMPL			-8
+/** @ingroup error
+ * @hideinitializer
+ * Target released
+ */
+#define NFC_ETGRELEASED			-10
+/** @ingroup error
+ * @hideinitializer
+ * Error while RF transmission
+ */
+#define NFC_ERFTRANS			-20
+/** @ingroup error
+ * @hideinitializer
+ * MIFARE Classic: authentication failed
+ */
+#define NFC_EMFCAUTHFAIL		-30
+/** @ingroup error
+ * @hideinitializer
+ * Software error (allocation, file/pipe creation, etc.)
+ */
+#define NFC_ESOFT			-80
+/** @ingroup error
+ * @hideinitializer
+ * Device's internal chip error
+ */
+#define NFC_ECHIP			-90
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/service/rfid_pn532/nim.cfg	Thu Feb 21 09:58:56 2019 -0800
@@ -0,0 +1,3 @@
+path="/opt"
+cincludes="/usr/include"
+threads="on"
--- a/service/rfid_pn532/rfid.nim	Tue Feb 19 12:08:22 2019 -0800
+++ b/service/rfid_pn532/rfid.nim	Thu Feb 21 09:58:56 2019 -0800
@@ -1,18 +1,36 @@
 # make rfid && make build_image_pi
 # docker pull bang6:5000/rfid_pn532_pi && docker run --rm -it --name rfid --net=host --privileged bang6:5000/rfid_pn532_pi
 
+# i2c keeps dropping. kernel from 1.20180313 to 1.201811112.1
+
 import nfc-nim/freefare
 import strformat
 import strutils
 import graphserver
 import tags
+import threadpool
+import sets
 
-var nn = newNfcDevice()
+type CardEvent = object of RootObj
+  uid: cstring
+  body: cstring
+  appeared: bool
+type CardEventChannel = Channel[CardEvent]
+
+
+var events: CardEventChannel
 
-while true:
-  echo "loop"
+type TagWatcher = object of RootObj
+  dev: NfcDevice
+  nearbyUids: var HashSet[cstring]
 
-  nn.forAllTags proc (tag: NfcTag) = 
+proc initTagWatcher(): var TagWatcher =
+  result.nearbyUids.init()
+  
+proc oneScan(self: TagWatcher) =
+  var nearThisPass = initSet[cstring]()
+
+  self.dev.forAllTags proc (tag: NfcTag) = 
     if tag.tagType() == freefare.MIFARE_CLASSIC_1K:
       echo &"found mifare 1k"
     else:
@@ -21,21 +39,61 @@
 
     echo &"  uid {tag.uid()}"
 
+    nearThisPass.incl(tag.uid())
+
+    if tag.uid() in self.nearbyUids:
+      return
+
     tag.connect()
     try:
       echo &" block1: {tag.readBlock(1).escape}"
+      events.send(CardEvent(uid: tag.uid(), body: tag.readBlock(1),
+                            appeared: true))
       #tag.writeBlock(1, toBlock("helloworld"))
     finally:
       tag.disconnect()
 
-    if false:
-      var data: freefare.MifareClassicBlock
-      data[0] = cast[cuchar](5)
-      data[1] = cast[cuchar](6)
-      data[2] = cast[cuchar](7)
-      tag.writeBlock(1, data)
+  for uid in self.nearbyUids.difference(nearThisPass):
+    events.send(CardEvent(uid: uid, appeared: false))
+
+  self.nearbyUids = nearThisPass
+
+
+proc scanTags(self: TagWatcher) =
+  self.dev = newNfcDevice()
+  try:
+    while true:
+      self.oneScan()
+  finally:
+    self.dev.destroy()
 
-nn.destroy()
+  
+proc watchForever*(self: TagWatcher) {.thread.} =
+  while true:
+    try:
+      self.scanTags()
+    except IOError:
+      echo "IOError: restarting nfc now"
+  
+
+proc tagsToGraph() {.thread.} =
+  while true:
+    echo "wait for event"
+    echo &"ev {events.recv()}"
+  
 
-let server = newGraphServer(port = 10012)
-server.run()
+proc main() =
+  events.open()
+
+  var tw = initTagWatcher()
+  var thr: Thread[void]
+  thr.createThread(tw.watchForever)
+
+  var t2: Thread[void]
+  t2.createThread(tagsToGraph)
+  
+
+  let server = newGraphServer(port = 10012)
+  server.run()
+
+main()
--- a/service/rfid_pn532/tags.nim	Tue Feb 19 12:08:22 2019 -0800
+++ b/service/rfid_pn532/tags.nim	Thu Feb 21 09:58:56 2019 -0800
@@ -22,7 +22,7 @@
 proc check(ret: int, msg: string) =
   check(ret == 0, &"{msg} ({ret})")
 
-type NfcDevice = ref object of RootObj
+type NfcDevice* = ref object of RootObj
   context: ptr nfc.context
   dev*: ptr nfc.device
   
@@ -69,7 +69,7 @@
 
 # freefare lib wants to free all the tag memory, so process them in a
 # callback and don't keep them outside that.
-proc forAllTags*(self: var NfcDevice, onTag: (NfcTag) -> void) =
+proc forAllTags*(self: NfcDevice, onTag: (NfcTag) -> void) =
   var ret = getTags(self.dev)
   var tagList = cast[TagArray](ret)
   for tagp in tagList: