SNEP server ack timeout with WP8 and PN532

Asked by thenextreclaimer

Hi,
I'm trying to create a python based application that will transfer data between a PN532 and WP8.
I'm testing this out with snep-test-server.py before I start to code myself, however I'm getting a few problems I wanted to clear up first.

I've changed the run_once function in examples cli.py to go to tty:AMA0:pn53x, which is where my PN532 is connected via UART (and this works). But, when I run the snep-test-server program, the results seem a bit hit and miss.

Sometimes when I run it and tap my phone on the NFC module I get:

[nfc.clf] searching for reader with path 'tty:AMA0:pn53x'
[nfc.clf] using NXP PN532 at /dev/ttyAMA0
[nfc.snep.server] snep server bound to port 4
[nfc.snep.server] snep server bound to port 16
[nfc.dev.pn53x] activated a p2p target in 424 kbps active mode
[nfc.llcp.llc] LLCP Link established as NFC-DEP Initiator
Local LLCP Settings
  LLCP Version: 1.1
  Link Timeout: 500 ms
  Max Inf Unit: 1024 octet
  Service List: 0000000000010011
Remote LLCP Settings
  LLCP Version: 1.1
  Link Timeout: 1000 ms
  Max Inf Unit: 1024 octet
  Service List: 0000000000000001
[nfc.llcp.tco] accepting CONNECT from SAP 32
[nfc.snep.server] serving snep client on remote sap 32

Which I believe indicates a successful link, though no data was set to be transferred.

A few times I've tried it with NFC interactor (an app on the windows phone store) and was able to get this response:

sudo python snep-test-server.py
[nfc.clf] searching for reader with path 'tty:AMA0:pn53x'
[nfc.clf] using NXP PN532 at /dev/ttyAMA0
[nfc.snep.server] snep server bound to port 4
[nfc.snep.server] snep server bound to port 16
[nfc.dev.pn53x] activated a p2p target in 424 kbps active mode
[nfc.llcp.llc] LLCP Link established as NFC-DEP Initiator
Local LLCP Settings
  LLCP Version: 1.1
  Link Timeout: 500 ms
  Max Inf Unit: 1024 octet
  Service List: 0000000000010011
Remote LLCP Settings
  LLCP Version: 1.1
  Link Timeout: 1000 ms
  Max Inf Unit: 1024 octet
  Service List: 0000000000000001
[nfc.llcp.tco] accepting CONNECT from SAP 32
[nfc.snep.server] serving snep client on remote sap 32
[main] default snep server got put request
[main] ndef message length is 18 octets
[main] record 1
  type = 'urn:nfc:wkt:T'
  name = ''
  data = '\x02enhello world'

Indicating I was able to successfully transmit an NDEF record. However for the majority of other tries (seemingly randomly) I get something along the lines of (it varies):

sudo python snep-test-server.py
[nfc.clf] searching for reader with path 'tty:AMA0:pn53x'
[nfc.clf] using NXP PN532 at /dev/ttyAMA0
[nfc.snep.server] snep server bound to port 4
[nfc.snep.server] snep server bound to port 16

[nfc.dev.pn53x] activated as target in 106 kbps active mode
[nfc.dev.pn53x] [PN53x Error 0x29] Released by Initiator while operating as Target
[nfc.dev.pn53x] timeout while waiting for ack
[nfc.dev.pn53x] [Errno 5] Input/output error
[nfc.clf] [Errno 5] Input/output error
[nfc.dev.pn53x] timeout while waiting for ack

I'm really not sure what is causing this erratic behaviour. I would like to use nfcpy as opposed to e.g. libnfc as I believe WP8 requires NDEF, SNEP and LLCP to communicate with another active NFC device, and I don't think libnfc currently supports this?

What can I do to solve this problem? At a basic level I really just want to be able to pass strings between the two active devices. I'm happy to provide more information if necessary, just ask!

As an aside, should this be successful, will the nfc.snep module documentation be updated any time soon? It would be most appreciated, as it would be a big help with this.

Question information

Language:
English Edit question
Status:
Solved
For:
nfcpy Edit question
Assignee:
No assignee Edit question
Solved by:
thenextreclaimer
Solved:
Last query:
Last reply:
Revision history for this message
Stephen Tiedemann (stephen-tiedemann) said :
#1

The NFC-DEP layer that sits below LLCP has a master/slave communication style where the master is called "Initiator" and the slave is the "Target". To get connected, the Target waits to receive an initialization sequence from the Inititiator. Both peer devices randomly toggle the role between Initiator and Target until communication is established.

With the examples you provided it looks like the successful cases are when nfcpy plays the Master and WP8 is the Target. In the bad case the sign of error is in [PN53x Error 0x29] when the WP8 Initiator has given up the target. The reason can still be on both sides, for example the nfcpy/PN532 could have failed to respond fast enough.

To nail this down I'd recommed that you first run a couple of tests with the role fixed on nfcpy side using the command line flag "--mode i" to force Initiator and "--mode t" to force Target mode. If this shows significant difference, next step should be to inspect the time stamps around the error. Time stamps are added when logging to a file, with "-f <logfile-name>".

Revision history for this message
thenextreclaimer (tnr) said :
#3

Scratch that last post, I was able to test it as you described.

On the whole I think you were right. When forcing nfcpy as initiator I am 80% of the time successfully able to send an NDEF message from the app on my phone and view it in the console. Sometimes I do get this error though:

WARNING [nfc.dev.pn53x] [PN53x Error 0x13] Format error during RF communication

When forcing nfcpy as target, it did occasionally work, but most of the time I got (same as before):

[nfc.dev.pn53x] timeout while waiting for ack
[nfc.dev.pn53x] [Errno 5] Input/output error
[nfc.clf] [Errno 5] Input/output error

This is the resulting log file of the command "sudo python snep-test-server.py --mode i --loop -f log.log"

2013-09-09 16:36:33,484 INFO [nfc.clf] searching for reader with path 'tty:AMA0:pn53x'
2013-09-09 16:36:33,560 INFO [nfc.clf] using NXP PN532 at /dev/ttyAMA0
2013-09-09 16:36:33,567 INFO [nfc.snep.server] snep server bound to port 4
2013-09-09 16:36:33,575 INFO [nfc.snep.server] snep server bound to port 16
2013-09-09 16:36:42,469 INFO [nfc.dev.pn53x] activated a p2p target in 424 kbps active mode
2013-09-09 16:36:42,474 INFO [nfc.llcp.llc] LLCP Link established as NFC-DEP Initiator
Local LLCP Settings
  LLCP Version: 1.1
  Link Timeout: 500 ms
  Max Inf Unit: 1024 octet
  Service List: 0000000000010011
Remote LLCP Settings
  LLCP Version: 1.1
  Link Timeout: 1000 ms
  Max Inf Unit: 1024 octet
  Service List: 0000000000000001
2013-09-09 16:36:42,534 INFO [nfc.llcp.tco] accepting CONNECT from SAP 32
2013-09-09 16:36:42,542 INFO [nfc.snep.server] serving snep client on remote sap 32
2013-09-09 16:36:42,631 INFO [main] default snep server got put request
2013-09-09 16:36:42,635 INFO [main] ndef message length is 14 octets
2013-09-09 16:36:42,665 INFO [main] record 1
  type = 'urn:nfc:wkt:T'
  name = ''
  data = '\x02entesting'
2013-09-09 16:36:45,401 INFO [main] *** RESTART ***
2013-09-09 16:36:45,412 INFO [nfc.clf] searching for reader with path 'tty:AMA0:pn53x'
2013-09-09 16:36:45,442 INFO [nfc.clf] using NXP PN532 at /dev/ttyAMA0
2013-09-09 16:36:45,449 INFO [nfc.snep.server] snep server bound to port 4
2013-09-09 16:36:45,456 INFO [nfc.snep.server] snep server bound to port 16
2013-09-09 16:36:45,510 INFO [nfc.dev.pn53x] activated a p2p target in 424 kbps active mode
2013-09-09 16:36:45,515 INFO [nfc.llcp.llc] LLCP Link established as NFC-DEP Initiator
Local LLCP Settings
  LLCP Version: 1.1
  Link Timeout: 500 ms
  Max Inf Unit: 1024 octet
  Service List: 0000000000010011
Remote LLCP Settings
  LLCP Version: 1.1
  Link Timeout: 1000 ms
  Max Inf Unit: 1024 octet
  Service List: 0000000000000001
2013-09-09 16:36:46,099 WARNING [nfc.dev.pn53x] [PN53x Error 0x13] Format error during RF communication
2013-09-09 16:36:46,224 INFO [main] *** RESTART ***
2013-09-09 16:36:46,226 INFO [nfc.clf] searching for reader with path 'tty:AMA0:pn53x'
2013-09-09 16:36:46,254 INFO [nfc.clf] using NXP PN532 at /dev/ttyAMA0
2013-09-09 16:36:46,261 INFO [nfc.snep.server] snep server bound to port 4
2013-09-09 16:36:46,269 INFO [nfc.snep.server] snep server bound to port 16
2013-09-09 16:37:07,203 INFO [nfc.dev.pn53x] activated a p2p target in 424 kbps active mode
2013-09-09 16:37:07,208 INFO [nfc.llcp.llc] LLCP Link established as NFC-DEP Initiator
Local LLCP Settings
  LLCP Version: 1.1
  Link Timeout: 500 ms
  Max Inf Unit: 1024 octet
  Service List: 0000000000010011
Remote LLCP Settings
  LLCP Version: 1.1
  Link Timeout: 1000 ms
  Max Inf Unit: 1024 octet
  Service List: 0000000000000001
2013-09-09 16:37:07,272 INFO [nfc.llcp.tco] accepting CONNECT from SAP 32
2013-09-09 16:37:07,279 INFO [nfc.snep.server] serving snep client on remote sap 32
2013-09-09 16:37:07,367 INFO [main] default snep server got put request
2013-09-09 16:37:07,371 INFO [main] ndef message length is 14 octets
2013-09-09 16:37:07,376 INFO [main] record 1
  type = 'urn:nfc:wkt:T'
  name = ''
  data = '\x02entesting'
2013-09-09 16:37:09,496 WARNING [nfc.dev.pn53x] [PN53x Error 0x13] Format error during RF communication
2013-09-09 16:37:09,625 INFO [main] *** RESTART ***
2013-09-09 16:37:09,628 INFO [nfc.clf] searching for reader with path 'tty:AMA0:pn53x'
2013-09-09 16:37:09,666 INFO [nfc.clf] using NXP PN532 at /dev/ttyAMA0
2013-09-09 16:37:09,673 INFO [nfc.snep.server] snep server bound to port 4
2013-09-09 16:37:09,682 INFO [nfc.snep.server] snep server bound to port 16
2013-09-09 16:37:12,053 INFO [nfc.dev.pn53x] activated a p2p target in 424 kbps active mode
2013-09-09 16:37:12,058 INFO [nfc.llcp.llc] LLCP Link established as NFC-DEP Initiator
Local LLCP Settings
  LLCP Version: 1.1
  Link Timeout: 500 ms
  Max Inf Unit: 1024 octet
  Service List: 0000000000010011
Remote LLCP Settings
  LLCP Version: 1.1
  Link Timeout: 1000 ms
  Max Inf Unit: 1024 octet
  Service List: 0000000000000001
2013-09-09 16:37:12,283 INFO [nfc.llcp.tco] accepting CONNECT from SAP 32
2013-09-09 16:37:12,310 INFO [nfc.snep.server] serving snep client on remote sap 32
2013-09-09 16:37:12,386 INFO [main] default snep server got put request
2013-09-09 16:37:12,390 INFO [main] ndef message length is 14 octets
2013-09-09 16:37:12,395 INFO [main] record 1
  type = 'urn:nfc:wkt:T'
  name = ''
  data = '\x02entesting'
2013-09-09 16:37:18,445 INFO [main] *** RESTART ***
2013-09-09 16:37:18,449 INFO [nfc.clf] searching for reader with path 'tty:AMA0:pn53x'
2013-09-09 16:37:18,478 INFO [nfc.clf] using NXP PN532 at /dev/ttyAMA0
2013-09-09 16:37:18,485 INFO [nfc.snep.server] snep server bound to port 4
2013-09-09 16:37:18,493 INFO [nfc.snep.server] snep server bound to port 16
2013-09-09 16:37:23,618 INFO [nfc.dev.pn53x] activated a p2p target in 424 kbps active mode
2013-09-09 16:37:23,631 INFO [nfc.llcp.llc] LLCP Link established as NFC-DEP Initiator
Local LLCP Settings
  LLCP Version: 1.1
  Link Timeout: 500 ms
  Max Inf Unit: 1024 octet
  Service List: 0000000000010011
Remote LLCP Settings
  LLCP Version: 1.1
  Link Timeout: 1000 ms
  Max Inf Unit: 1024 octet
  Service List: 0000000000000001
2013-09-09 16:37:23,771 ERROR [nfc.dev.pn53x] timeout while waiting for ack
2013-09-09 16:37:23,887 ERROR [nfc.dev.pn53x] timeout while waiting for ack

For some reason (don't know if its because of the looping?) I eventually got the timeout error while initiator was forced. Maybe the loop does not consider the mode argument on subsequent iterations?

I'm not sure what else to look for in the log, can you shed some light on this?

Revision history for this message
Stephen Tiedemann (stephen-tiedemann) said :
#4

Please try the following modification (on line 171 in nfc/dev/pn53x.py):

=== modified file 'nfc/dev/pn53x.py'
--- nfc/dev/pn53x.py 2013-07-05 02:33:21 +0000
+++ nfc/dev/pn53x.py 2013-09-10 16:14:52 +0000
@@ -168,7 +168,7 @@

         try:
             self.write_frame(frame)
- frame = self.read_frame(timeout=100)
+ frame = self.read_frame(timeout)
         except IOError as error:
             log.error("timeout while waiting for ack")
             raise IOError(errno.EIO, os.strerror(errno.EIO))

This will set the timeout for chip acks to the same value as expected for the response. The guess is that acks will sometimes be missing and then cause the error. If the guess is true there should then be "missing ack frame from pn53x" warnings issued.

In general, to get more detailed logs you can enable debugging for individual modules (directories) or files with "-d nfc.dev" or "-d nfc.dev.pn53x", respectively.

I'd appreciate if you could describe your HW/SW setup, such that potentially I could try a similar setup.

Revision history for this message
thenextreclaimer (tnr) said :
#5

I made the change you specified, but unfortunately it doesn't appear to have made any difference.
Running variations on the command a few times I get the following (in chronological order). This was all done as soon as I my hardware had been switched on:

sudo python snep-test-server.py --mode i
[nfc.clf] searching for reader with path 'tty:AMA0:pn53x'
[nfc.clf] using NXP PN532 at /dev/ttyAMA0
[nfc.snep.server] snep server bound to port 4
[nfc.snep.server] snep server bound to port 16
[nfc.dev.pn53x] timeout while waiting for ack
[nfc.clf] [Errno 5] Input/output error
[nfc.dev.pn53x] timeout while waiting for ack

sudo python snep-test-server.py --mode i
[nfc.clf] searching for reader with path 'tty:AMA0:pn53x'
[nfc.clf] using NXP PN532 at /dev/ttyAMA0
[nfc.snep.server] snep server bound to port 4
[nfc.snep.server] snep server bound to port 16
[nfc.dev.pn53x] timeout while waiting for ack
[nfc.clf] [Errno 5] Input/output error
[nfc.dev.pn53x] timeout while waiting for ack

sudo python snep-test-server.py --mode i -d nfc.dev.pn53x
[main] enable debug output for module 'nfc.dev.pn53x'
[nfc.clf] searching for reader with path 'tty:AMA0:pn53x'
[nfc.dev.pn53x] GetFirmwareVersion command with timeout 100 ms
[nfc.dev.pn53x] chipset is a PN532 version 1.6
[nfc.dev.pn53x] Diagnose command with timeout 100 ms
[nfc.dev.pn53x] timeout while waiting for ack
[nfc.clf] no reader found at 'tty:AMA0:pn53x'
[main] no contactless reader found

sudo python snep-test-server.py --mode i -d nfc.dev.pn53x -d nfc.dev
[main] enable debug output for module 'nfc.dev.pn53x'
[main] enable debug output for module 'nfc.dev'
[nfc.clf] searching for reader with path 'tty:AMA0:pn53x'
[nfc.dev] trying pn53x on 'tty:AMA0:pn53x'
[nfc.dev] import nfc.dev.pn53x
[nfc.dev.transport] >>> 0000ff00ff00
[nfc.dev.pn53x] GetFirmwareVersion command with timeout 100 ms
[nfc.dev.transport] >>> 0000ff02fed4022a00
[nfc.dev.pn53x] timeout while waiting for ack
[nfc.clf] no reader found at 'tty:AMA0:pn53x'
[main] no contactless reader found

sudo python snep-test-server.py --mode i
[nfc.clf] searching for reader with path 'tty:AMA0:pn53x'
[nfc.clf] using NXP PN532 at /dev/ttyAMA0
[nfc.snep.server] snep server bound to port 4
[nfc.snep.server] snep server bound to port 16
[nfc.dev.pn53x] timeout while waiting for ack
[nfc.clf] [Errno 5] Input/output error
[nfc.dev.pn53x] timeout while waiting for ack

I find these results odd, as on some runs the module is detected, but others it is not, yet it always fails. Running libnfcs "nfc-scan-device" I get:

sudo nfc-scan-device
nfc-scan-device uses libnfc 1.7.0
1 NFC device(s) found:
- pn532_uart:/dev/ttyAMA0:
    pn532_uart:/dev/ttyAMA0

So it is definitely connected.

All the successful results I have mentioned already eventually start occurring after what I can only explain as waiting a while. As I was typing this I tried again and it suddenly worked??

sudo python snep-test-server.py --mode i --loop
[nfc.clf] searching for reader with path 'tty:AMA0:pn53x'
[nfc.clf] using NXP PN532 at /dev/ttyAMA0
[nfc.snep.server] snep server bound to port 4
[nfc.snep.server] snep server bound to port 16
[nfc.dev.pn53x] activated a p2p target in 424 kbps active mode
[nfc.llcp.llc] LLCP Link established as NFC-DEP Initiator
Local LLCP Settings
  LLCP Version: 1.1
  Link Timeout: 500 ms
  Max Inf Unit: 1024 octet
  Service List: 0000000000010011
Remote LLCP Settings
  LLCP Version: 1.1
  Link Timeout: 1000 ms
  Max Inf Unit: 1024 octet
  Service List: 0000000000000001
[nfc.llcp.tco] accepting CONNECT from SAP 32
[nfc.snep.server] serving snep client on remote sap 32
[nfc.dev.pn53x] [PN53x Error 0x13] Format error during RF communication
[main] *** RESTART ***
[nfc.clf] searching for reader with path 'tty:AMA0:pn53x'
[nfc.clf] using NXP PN532 at /dev/ttyAMA0
[nfc.snep.server] snep server bound to port 4
[nfc.snep.server] snep server bound to port 16
[nfc.dev.pn53x] activated a p2p target in 424 kbps active mode
[nfc.llcp.llc] LLCP Link established as NFC-DEP Initiator
Local LLCP Settings
  LLCP Version: 1.1
  Link Timeout: 500 ms
  Max Inf Unit: 1024 octet
  Service List: 0000000000010011
Remote LLCP Settings
  LLCP Version: 1.1
  Link Timeout: 1000 ms
  Max Inf Unit: 1024 octet
  Service List: 0000000000000001
[nfc.llcp.tco] accepting CONNECT from SAP 32
[nfc.snep.server] serving snep client on remote sap 32
[nfc.dev.pn53x] [PN53x Error 0x13] Format error during RF communication
[main] *** RESTART ***
[nfc.clf] searching for reader with path 'tty:AMA0:pn53x'
[nfc.clf] using NXP PN532 at /dev/ttyAMA0
[nfc.snep.server] snep server bound to port 4
[nfc.snep.server] snep server bound to port 16
[nfc.dev.pn53x] activated a p2p target in 424 kbps active mode
[nfc.llcp.llc] LLCP Link established as NFC-DEP Initiator
Local LLCP Settings
  LLCP Version: 1.1
  Link Timeout: 500 ms
  Max Inf Unit: 1024 octet
  Service List: 0000000000010011
Remote LLCP Settings
  LLCP Version: 1.1
  Link Timeout: 1000 ms
  Max Inf Unit: 1024 octet
  Service List: 0000000000000001
[nfc.llcp.tco] accepting CONNECT from SAP 32
[nfc.snep.server] serving snep client on remote sap 32
[main] *** RESTART ***
[nfc.clf] searching for reader with path 'tty:AMA0:pn53x'
[nfc.clf] using NXP PN532 at /dev/ttyAMA0
[nfc.snep.server] snep server bound to port 4
[nfc.snep.server] snep server bound to port 16
[nfc.dev.pn53x] activated a p2p target in 424 kbps active mode
[nfc.llcp.llc] LLCP Link established as NFC-DEP Initiator
Local LLCP Settings
  LLCP Version: 1.1
  Link Timeout: 500 ms
  Max Inf Unit: 1024 octet
  Service List: 0000000000010011
Remote LLCP Settings
  LLCP Version: 1.1
  Link Timeout: 1000 ms
  Max Inf Unit: 1024 octet
  Service List: 0000000000000001
[nfc.llcp.tco] accepting CONNECT from SAP 32
[nfc.snep.server] serving snep client on remote sap 32
[nfc.dev.pn53x] [PN53x Error 0x13] Format error during RF communication

Once it starts working it seems to be fine.
The "Format Error" does not seem to be causing a problem.

In terms of what I'm using, I have an Elechouse PN532 NFC module, connected via UART (HSU) to a raspberry pi (model B) I'm then accessing that via SSH. I'm using a Lumia 920 to communicate with the Pi by NFC.

Between the errors, I have managed to start putting together my own small nfcpy program to implement my own SNEP server functionality. I understand you haven't got around to fully documenting it yet, but I was hoping you could answer: how do you actually use the SnepServer override to create a socket and then exchange data between the devices? I have created a clf object, and called connect with llcp as its argument, and amongst other things "'on-connect': self.on_llcp_connect" in the llcp dictionary. What do I need to do in on_llcp_connect though?
I've looked through the example, but I can't work out where the actual data exchange occurs. (I haven't overridden put and get on my server class, but I believe I need to?)

Revision history for this message
thenextreclaimer (tnr) said :
#6

More findings: after starting up the pi from off, trying to run the snep server example gives an ack timeout error. However, after running libnfcs nfc-scan-device, the nfcpy examples work fine...

Are you able to offer any more information concerning my other queries? Thanks for your help.

Revision history for this message
Stephen Tiedemann (stephen-tiedemann) said :
#7

Sounds like there's some initialization sequence missing. I'll compare this with my serial readers next week.

There'll be SNEP documentation coming soon. Until then, please have a look at examples/snep-test-server.py. For a server you typically need to implement callbacks for "on-startup" and "on-connect". During "on-startup" the server instance is created and as part of the nfc.snep.Server logic the service name gets registered. When "on-connect" is called just start the server thread. You need to override put and get, otherwise its just printed to log. This should be easy to see in snep-test-server.py

Revision history for this message
thenextreclaimer (tnr) said :
#8

I see, that's good to hear. Most of what you have said I have already done, so I think I'm getting close. In my on_llcp_connect I create an instance of my class MainServer, which is an override of SnepServer (it registers 'urn:nfc:sn:snep' as its service name and calls
`super(MainServer, self).__init__(llc, service_name)` )

then, in my on_llcp_connect, this server object is started. This all works and I'm able to publish an NDEF message from WP8, and see it on the RPi console. I achieved this (as you said) by overriding put, and printing/working with the received record there.

The big problem is I cant send data from the Pi and see it on the WP8 side. I'm unclear as to whether its a limitation of WP8s (very restricted) NFC, or a problem with my nfcpy program, but assuming that because WP8 can send NDEF messages it can receive them, I'm guessing its a problem with my program.

I'm confused as to what to do with get in my server override because as far as I can see, "DefaultServer" in snep-test-server.py does not override get, and whenever I have run it, ValidationServers get has never been hit, so I assumed it was not relevant to my case.

All my get override does it return an ndef_message that I hardcoded (just to see if i can get it to WP8). I tried to call the method manually from on_llcp_connect, but it seems to fire before put, and the end result is that I get no data transferred to my phone.

I guess what I want to know is: what do I need to make get do to transfer data, and where/when do I need to call it?

Revision history for this message
Stephen Tiedemann (stephen-tiedemann) said :
#9

Please see the all-new documentation at http://nfcpy.readthedocs.org/en/latest/api/snep.html, it should answer your questions. Bottom line is that you don't have to care about SNEP GET but use a SNEP client to send to WP8. For WP8 also a client app must always run a SNEP server at "urn:nfc:sn:snep", otherwise the phone gets stuck.

Revision history for this message
Stephen Tiedemann (stephen-tiedemann) said :
#10

One further remark, if you're heading for command line program it might not be a bad idea to base that on examples/cli.py and use examples/snep-test-server.py and examples/snep-test-client.py as templates. Just forget everything about the validation server - it's only made for testing SNEP layer implementations.

Revision history for this message
thenextreclaimer (tnr) said :
#11

Thank you for updating the documentation, it has provided a lot of insight into what I'm doing, however I just wanted to clarify a couple of points, as I'm still not sure I understand entirely

Just to be clear about what I'm trying to achieve; I want to be able to send an NDEF message from wp8 to the Pi, have it analyse the message, and crucially send an NDEF message back to the phone for it to evaluate and display the result on the phone to the user (the Pi is intended to be headless).

Based on the new documentation and what you have just said, is this logic correct? (this is what I have currently, and as I mentioned I'm able to send from the phone, but not receive. The phone is subscribed to NDEF messages):

On executing the program a ContactlessFrontEnd object is obtained, including arguments 'tty:AMA0:pn53x' and 'initiator'.
if this is successful, clf.connect is called, including llcp "on-startup" and "on-connect" callbacks
"on-startup" is called, Which gets an instance of my MainServer like this : super(MainServer, self).__init__(llc,'urn:nfc:sn:snep')
The program now stops and waits for a device.
When device is detected, on-connect is hit, which does this:
self.main_snep_server.start()
self.phone_client_server = nfc.snep.SnepClient(llc)
threading.Thread(target=self.send_ndef_message, args=()).start()

(where self is an instance of the actual program class)
 this executes send_ndef_message on another thread using the SnepClient:

def send_ndef_message(self):
        sp = nfc.ndef.Record('urn:nfc:wkt:T', 'id', b'enTest Send') #hardcoded NDEF message I want to see on the phone
        self.phone_client_server.put( nfc.ndef.Message(sp) )

        print "*** get whatever the server has ***"
        print self.phone_client_server.get().pretty()

Trying to run all this, I get the following output:

MAIN SERVER INIT HIT
LLCP STARTUP COMPLETE
LLCP CONNECT HIT
Exception in thread Thread-5:
Traceback (most recent call last):
  File "/usr/lib/python2.7/threading.py", line 552, in __bootstrap_inner
    self.run()
  File "/usr/lib/python2.7/threading.py", line 505, in run
    self.__target(*self.__args, **self.__kwargs)
  File "NFCDoorControl.py", line 121, in send_ndef_message
    self.phone_client_server.put( nfc.ndef.Message(sp) )
  File "/home/pi/nfcpy/nfcpy/nfc/snep/client.py", line 111, in put
    self.connect('urn:nfc:sn:snep')
  File "/home/pi/nfcpy/nfcpy/nfc/snep/client.py", line 72, in connect
    self.socket.connect(service_name)
  File "/home/pi/nfcpy/nfcpy/nfc/llcp/socket.py", line 86, in connect
    return self.llc.connect(self._tco, address)
  File "/home/pi/nfcpy/nfcpy/nfc/llcp/llc.py", line 519, in connect
    socket.connect(dest)
  File "/home/pi/nfcpy/nfcpy/nfc/llcp/tco.py", line 423, in connect
    raise ConnectRefused(pdu.reason)
ConnectRefused: nfc.llcp.ConnectRefused: [ECONNREFUSED] Connection refused with reason 2

main snep server got put request
ndef message length is 33 octets
record 1
  type = 'urn:nfc:ext:L\x00o\x00c\x00k\x00'
  name = ''
  data = 'H\x00e\x00l\x00l\x00o\x00 \x00W\x00o\x00r\x00l\x00d\x00'
Message: Hello World
INVALID
True

On the phone side, I made an app that in this case sent an NDEF message with payload "Hello World" in byte array form. The phones "on-message-transmitted" event is raised when this is sent (as expected), and it then immediately subscribes to NDEF messages in return, but this event is never raised i.e. is never is sent a response

By "use a SNEP client to send to WP8", do you mean actually create an nfcpy SnepClient object on the phone (which I'm not sure is possible?) or create an instance of SnepClient in my python program for the phone (which I think I have attempted here)

Should I get this basic two way communication to work I will definitely look into implementing a more robust and complete solution based on cli.py. I just wanted to see if it was possible first!

Revision history for this message
Stephen Tiedemann (stephen-tiedemann) said :
#12

You're almost there. Replace the Text record in send_ndef_message with a URI record like this "nfc.ndef.UriRecord("http://nfcpy.org")" and delete the "self.phone_client_server.get().pretty()" part. You should the see that you receive the "Hello World" from the phone and that the opens the web page at http://nfcpy.org.

What you have attempted then are two independent SNEP connections: One from a SNEP client on the phone to your SNEP server and one from your client to the phone's server. For the application you intend the only thing left is then to make the message sent as SNEP client depend on the message received in the SNEP server.

The exception ConnectRefused looks like the WP8 SNEP server implementation doesn't accept a subsequent connection attempt, which is what is caused by nfc.snep.SnepClient.put() followed by nfc.snep.SnepClient.get(). That would be an implementation error and I'll verify if the theory is correct. But you want to put only one message anyway; if that ever changes you might need to use nfc.snep.SnepClient.connect("urn:nfc:sn:snep") to let all put()s use the same connection.

Revision history for this message
thenextreclaimer (tnr) said :
#13

Result! I made your changes, and messed around with it for a bit and I now seem to be able to send records from the server to my phone. (I've only tested Uri and Text, hope it all works after a restart!) Thanks for all the guidance!

Some observations:
After connection between the two devices, the log on my phone indicates that the record from the server is being sent and received before my phone sends its record. Is this the default? Can this/should this be switched around, or should the server always make the first transmission?

Concerning your last point, the endgame for this (based on my understanding of NFC when I started this) was that I would be able to send multiple messages over the same link during one connection. Could you be a bit more specific on where I would need to call connect, and if its a good option to do so. I tried calling it in on_llcp_connect just before I create the thread for send_ndef_message, but it seems to just make the program to hang, and I had to force close it.

Revision history for this message
thenextreclaimer (tnr) said :
#14

If multiple messages during one link is possible, then it also means that checks will be needed between the server and client to make sure they are both in sync, and can detect errors such as if the client moved away to early, the server needs to be able to reset and recover. Is any of that taken into account by the llcp layer/are there events that callbacks can be assigned to to handle them?

Revision history for this message
Stephen Tiedemann (stephen-tiedemann) said :
#15

A bit on architecture: The basic communication layer between two NFC devices (P2P mode) is the Logical Link Control Protocol (LLCP). This is pretty much like IP in the Internet world, just without host adressing (as there are only two) and no routing. Similar to IP there can be connection-less (like UDP) and connection-mode (like TCP) traffic and for the latter a connection setup procedure must be run . SNEP uses connection-mode transport and so a SNEP client must setup first a data-link-connection (that's how it's called in LLCP) with a SNEP server. LLCP data-link-connections are reliable, data sent is guaranteed to arrive unless the LLCP Link gets broken which is the case if the devices do no longer touch.

The nfc.snep.SnepClient connects automatically when you use put() or get() and closes the connection on return. This is a convinience function and restricts the choice of server to the Default SNEP Server (service name "urn:nfc:sn:snep"). To address a differnt SNEP server or to exceute multiple put() or get() calls over the same data-link-connection, the nfc.snep.SnepClient.connect(service_name) call must be issued before and nfc.snep.SnepClient.close() after the put()/get() calls. Replace service_name with "urn:nfc:sn:snep" to continue interaction with a Default SNEP Server on the peer device.

That's for one direction. In your scenario you'll have a second data-link-connection from the WP8 SNEP client to the RasPi Default SNEP Server. It's automaticall set-up by WP8 every time you touch and you'll receive the NDEF message sent (put) by the phone over that connection.

Revision history for this message
thenextreclaimer (tnr) said :
#16

Great! Thank you! That all makes sense. Using all of what you have said I think I am able to transmit messages in both directions.

I have one last question though (sorry!), in on_llcp_connect I create a thread for communication. In this thread I have called SnepClient.connect, then SnepClient.put with an ndef message. This is received by the phone which sends an ndef message back. This is being picked up by SnepServer.put. I'm I correct in saying I have to handle the phones response in this SnepServer.put? My idea was that I would get the response, process it, and then send another message back to the phone either as confirmation or to query more data. However I don't think I can call SnepClient.put within SnepServer.put. Is this right? If so, I'll devise another structure to transfer all the data I want. Thanks again!

Revision history for this message
thenextreclaimer (tnr) said :
#17

I'm assuming I'm at least partially wrong, as while trying to handle responses in the way I mentioned, I'm getting threading errors:

Exception in thread Thread-3:
Traceback (most recent call last):
  File "/usr/lib/python2.7/threading.py", line 552, in __bootstrap_inner
    self.run()
  File "/usr/lib/python2.7/threading.py", line 505, in run
    self.__target(*self.__args, **self.__kwargs)
  File "NFCDoorControl.py", line 120, in begin_communication
    self.phone_client_server.connect('urn:nfc:sn:snep')
  File "/home/pi/nfcpy/nfcpy/nfc/snep/client.py", line 72, in connect
    self.socket.connect(service_name)
  File "/home/pi/nfcpy/nfcpy/nfc/llcp/socket.py", line 86, in connect
    return self.llc.connect(self._tco, address)
  File "/home/pi/nfcpy/nfcpy/nfc/llcp/llc.py", line 519, in connect
    socket.connect(dest)
  File "/home/pi/nfcpy/nfcpy/nfc/llcp/tco.py", line 419, in connect
    pdu = super(DataLinkConnection, self).recv()
  File "/home/pi/nfcpy/nfcpy/nfc/llcp/tco.py", line 129, in recv
    return self.recv_queue.popleft()
IndexError: pop from an empty deque

Revision history for this message
Stephen Tiedemann (stephen-tiedemann) said :
#18

Can you post your code to Gist or Pastebin and let me know the link?

Revision history for this message
thenextreclaimer (tnr) said :
#19

put up on a pastebin here: http://pastebin.com/BG47md3y

Revision history for this message
Stephen Tiedemann (stephen-tiedemann) said :
#20

I've put together a working example of what I think you try to accomplish at http://pastebin.com/up6d7H9b . It's tested to work with a WP8 phone.

The snep put() is done directly in the server's put() receive method. That's just the lazy way, the probably cleaner architecture might be to add the received message into a threading.queue and evaluate it in a separate thread.

I based the code on examples/cli.py to save me typing generic code. You should be able to run that example with "--device tty:AMA0:pn53x" and with "-d nfc.llcp.llc --nolog-symm" you'll also get a trace of the LLCP packets back and forth.

Revision history for this message
thenextreclaimer (tnr) said :
#21

Once again thank you. Given that example I have been able to create the sort of program I was aiming for.
Should you ever need beta testers for a future release let me know and i'll see if I can help!