phdc: API documentation and sample code
authorOlivier Guiter <olivier.guiter@linux.intel.com>
Mon, 2 Sep 2013 10:32:18 +0000 (12:32 +0200)
committerSamuel Ortiz <sameo@linux.intel.com>
Mon, 2 Sep 2013 13:56:28 +0000 (15:56 +0200)
This sample code publishes two phdc Managers, to validate the phdc
driver. It relies on nfcpy test code for simulating a phdc thermometer.

Makefile.am
doc/phdc-api.txt [new file with mode: 0644]
test/phdc-simple-manager [new file with mode: 0755]

index 175cf07..175c09c 100644 (file)
@@ -72,7 +72,7 @@ build_plugindir = $(plugindir)
 endif
 
 doc_files = doc/manager-api.txt doc/tag-api.txt doc/device-api.txt \
-               doc/adapter-api.txt doc/agent-api.txt
+               doc/adapter-api.txt doc/agent-api.txt doc/phdc-api.txt
 
 EXTRA_DIST = src/genbuiltin $(doc_files)
 
@@ -81,7 +81,8 @@ dist_man_MANS = doc/neard.8 doc/neard.conf.5 doc/nfctool.1
 test_scripts = test/disable-adapter test/enable-adapter test/list-adapters \
                test/dump-device test/dump-tag test/dump-record \
                test/monitor-near test/start-poll test/stop-poll test/write-tag \
-               test/push-device test/bt-handover test/handover-agent
+               test/push-device test/bt-handover test/handover-agent \
+               test/phdc-simple-manager
 
 if TEST
 testdir = $(pkglibdir)/test
diff --git a/doc/phdc-api.txt b/doc/phdc-api.txt
new file mode 100644 (file)
index 0000000..1dc7983
--- /dev/null
@@ -0,0 +1,80 @@
+PHDC hierarchy
+==============
+Service                org.neard
+Interface      org.neard.PHDC
+Object path    /
+
+Methods                void RegisterAgent(dict values)
+
+                       Register new PHDC agent.
+
+                       PHDC Manager or Agent implementations calls this
+                       method in order to register themselves against neard.
+                       PHDC Managers will be notified through their
+                       NewConnection method of new PHDC Agents connections.
+                       PHDC Agents will be nnotified through their
+                       NewConnection method when a connection to a PHDC Manager
+                       succeeded.
+
+                       Possible Errors: org.neard.Error.OutOfMemory
+                                        org.neard.Error.InvalidArguments
+                                        org.neard.Error.AlreadyExists
+
+               void UnregisterAgent(object path, string role)
+
+                       Unregister an existing agent.
+
+                       Possible Errors: org.neard.Error.OutOfMemory
+                                        org.neard.Error.InvalidArguments
+
+
+Fields         string  Role
+
+                       "Agent" or "Manager" (mandatory)
+
+               object  Path
+
+                       Agent or Manager path (mandatory)
+
+               string  ServiceName
+
+                       NFC urn to connect or to listen to
+                       (default: "urn:nfc:sn:phdc").
+
+
+PHDC Manager hierarchy
+======================
+Service                unique name
+Interface      org.neard.PHDC.Manager
+Object path    freely definable
+
+
+Methods:       void NewConnection(fd agent)
+
+                       This method gets called when a PHDC Agent connects
+                       using the p2p service name. The Phdc Manager uses
+                       the given agent file descriptor to exchange data
+                       with the Agent.
+
+               void Disconnection(fd agent, error)
+
+                       This method is called when a PHDC Agent closes the
+                       file descriptoer.
+
+               void Release()
+
+                       This method is called when the service daemon
+                       unregisters the agent. An agent can use it to do
+                       cleanup tasks.
+                       There is no need to unregister the agent, because
+                       when this method gets called it has already been
+                       unregistered.
+
+
+PHDC Agent hierarchy
+====================
+Service                unique name
+Interface      org.neard.PHDC.Agent
+Object path    freely definable
+
+Methods:       NOT YET IMPLEMENTED
diff --git a/test/phdc-simple-manager b/test/phdc-simple-manager
new file mode 100755 (executable)
index 0000000..5317f25
--- /dev/null
@@ -0,0 +1,193 @@
+#!/usr/bin/env python2.7
+
+import sys
+import dbus
+import dbus.service
+import dbus.glib
+import gobject
+import socket
+import string
+import struct
+import threading
+from threading import Thread
+import time
+from dbus.mainloop.glib import DBusGMainLoop
+
+# IDs specific to Linux nfc
+AF_NFC = 39
+SOL_NFC = 280
+NFC_LLCP_MIUX = 1
+
+# Sample test code - compliant with nfcpy phdc test agent
+thermometer_assoc_req = \
+    "E200 0032 8000 0000" \
+    "0001 002A 5079 0026" \
+    "8000 0000 A000 8000" \
+    "0000 0000 0000 0080" \
+    "0000 0008 3132 3334" \
+    "3536 3738 0320 0001" \
+    "0100 0000 0000"
+
+thermometer_assoc_res = \
+    "E300 002C 0003 5079" \
+    "0026 8000 0000 8000" \
+    "8000 0000 0000 0000" \
+    "8000 0000 0008 3837" \
+    "3635 3433 3231 0000" \
+    "0000 0000 0000 0000" \
+
+assoc_release_req = "E40000020000"
+assoc_release_res = "E50000020000"
+
+#========================================
+# Display helper
+def hexdump( chars, sep, width ):
+       while chars:
+               line = chars[:width]
+               chars = chars[width:]
+               line = line.ljust( width, '\000' )
+               print "%s%s%s" % ( sep.join( "%02x" % ord(c) for c in line ),
+                        sep, quotechars( line ))
+
+
+def quotechars( chars ):
+       return ''.join( ['.', c][c.isalnum()] for c in chars )
+
+#========================================
+class PhdcPeerManager:
+    def __init__(self, agent_fd):
+       #Grab the agent ....
+       print 'Init PhdcPeerManager thread'
+       self.r_fd = agent_fd.take()
+       print 'Agent fd:', str(self.r_fd)
+
+    def run( self):
+       print 'Run PhdcPeerManager thread: ', str(self.r_fd)
+       self.sock = socket.fromfd(self.r_fd, AF_NFC, socket.SOCK_STREAM)
+        try:
+            while True:
+               miu = self.sock.getsockopt(SOL_NFC, NFC_LLCP_MIUX)
+               print 'MIU=', miu
+
+                while True:
+                    data = self.sock.recv(16)
+                    if data == None:
+                      print 'no data'
+                      break
+
+                   #analyze frame
+                    print 'analyze'
+                    size = struct.unpack(">H", data[0:2])[0]
+                    apdu = data[2:]
+
+                    #should i read more data ?
+                    while len(apdu) < size:
+                        data = self.sock.recv(10)
+                        if data == None: break
+                        hexdump(data, ':', 16)
+                        apdu += data
+                    print "[ieee] <<< {0}".format(str(apdu).encode("hex"))
+                    if apdu.startswith("\xE2\x00"):
+                        apdu = bytearray.fromhex(thermometer_assoc_res)
+                    elif apdu.startswith("\xE4\x00"):
+                        apdu = bytearray.fromhex(assoc_release_res)
+                    else:
+                        apdu = apdu[::-1]
+                    time.sleep(0.2)
+                    print "[ieee] >>> {0}".format(str(apdu).encode("hex"))
+                    data = struct.pack(">H", len(apdu)) + apdu
+                    for i in range(0, len(data), miu):
+                        self.sock.send(str(data[i:i+miu]))
+
+                print "remote peer {0} closed connection".format(agent_fd)
+                print "leaving ieee manager"
+                self.sock.close()
+
+        except IOError as e:
+               if e.errno == errno.EPIPE:
+                       print 'Remote disconnect'
+               else:
+                       print "I/O error({0}): {1}".format(e.errno, e.strerror)
+        finally:
+               print 'Finally exit'
+               stop()
+
+       def stop(self):
+               print 'Stop PhdcPeerManager:', str(self.r_fd)
+               self._Thread__stop()
+
+#===================================================
+''' Phdc Manager Class
+'''
+class SimplePhdcManager(dbus.service.Object):
+
+       @dbus.service.method('org.neard.PHDC.Manager',
+                                       in_signature='',
+                                       out_signature='')
+       def Release(self):
+               print 'Release'
+               mainloop.quit()
+
+
+       ''' Called on incoming agents
+       '''
+       @dbus.service.method('org.neard.PHDC.Manager',
+                                       in_signature='h',
+                                       out_signature='')
+       def NewConnection(self, agent_fd):
+               print'Launch Phdc Manager thread for fd:', str(agent_fd)
+               self.server = PhdcPeerManager(agent_fd)
+               print'Run Server'
+               self.server.run()
+               print'Leave Server'
+               return
+
+       ''' Called when the agent ends (from phdc_close)
+       '''
+       @dbus.service.method('org.neard.PHDC.Manager',
+                                       in_signature='hi', out_signature='')
+       def Disconnection(self,agent_fd, i_err):
+               print'Stop Phdc Manager thread'
+               self.server.stop()
+               return
+
+''' Main loop
+This sample installs two PHDC Managers:
+       * Simple: simulates a thermometer data exchange
+       * Validation: Validation Manager for NFC Forum PHDC)
+'''
+if "__main__" == __name__:
+       dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)
+
+       print 'PHDC Simple Manager Test'
+       bus = dbus.SystemBus()
+       neard_manager = dbus.Interface(bus.get_object('org.neard', '/'),
+                                                       'org.neard.PHDC')
+
+       simple_path = '/Simple'
+       valid_path = '/Validation'
+
+       print 'Creating & registering PHDC Simple Manager'
+       simpleobject = SimplePhdcManager(bus, simple_path)
+
+       d = dbus.Dictionary({'Role': 'Manager', 'Path': simple_path,
+                       'ServiceName': 'urn:nfc:sn:phdc' }, signature='sv')
+       neard_manager.RegisterAgent(d)
+
+       print 'Creating & Registering Validation Manager'
+
+       validationobj= SimplePhdcManager(bus, valid_path)
+       d = dbus.Dictionary({'Role': 'Manager', 'Path': valid_path,
+               'ServiceName': 'urn:nfc:xsn:nfc-forum.org:phdc-validation' },
+                signature='sv')
+       neard_manager.RegisterAgent(d)
+
+       mainloop = gobject.MainLoop()
+
+try:
+        mainloop.run()
+
+except(KeyboardInterrupt):
+       #Call for unregister...
+        neard_manager.UnregisterAgent(simple_path, 'Manager')
+        neard_manager.UnregisterAgent(valid_path, 'Manager')