Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Card emulation #12

Open
Zhairgling opened this issue Jan 24, 2017 · 44 comments
Open

Card emulation #12

Zhairgling opened this issue Jan 24, 2017 · 44 comments

Comments

@Zhairgling
Copy link

Zhairgling commented Jan 24, 2017

Can we transfer data between 2 pn532 ? like android beam ? I have a raspberry pi 3 and Pn532 from adafruit in uart mode.

@Zhairgling
Copy link
Author

I saw here (https://github.com/techniq/node-pn532/blob/emulate-tag/src/pn532.js) that there was a function intended to make emulation of code but when I test I am a little lost.

I want to clarify that I already manage to read and write on tags.

@techniq
Copy link
Owner

techniq commented Jan 24, 2017

Hi @Zhairgling. The PN532 has the ability to be a writer as well as a reader, and I spent some time on the emulate-tag branch trying to get writing to work, but ultimately never had time to finish it. I also wasn't sure if being a simple writer was the same as Android Beam (if the later is more bi-directional communication). I do see Seeed Studios C library supports card emulation and snep (which I believe relates to Android Beam). I don't see me getting time to look at this for a while, but I accept PRs :). Between the User Guide and Datasheet (linked at the bottom of the README) and looking at Seeed Studio's implementation, it might not be too difficult to finish up.

@Zhairgling
Copy link
Author

First of all thank you @techniq for the answer. I do not want to communicate with an android device. I refer to this system of operation only as an example. I am only trying to exchange a json object between two pn532. Can you tell me what was not working when you were working.

@techniq
Copy link
Owner

techniq commented Jan 24, 2017

I also see Adafruit's PN532 C++ library has a PR to add tag emulation. You might take a look at the changes and see what needs to be done. Most of it comes down to getting the command structure correct.

@techniq
Copy link
Owner

techniq commented Jan 24, 2017

To be honest, I don't remember exactly (it's been a little while). I remember I was trying to use my Android phone with NFC Tools to scan my pn532 breakout board but I think I was having trouble understanding how to attach the payload of the data to send.

@Zhairgling
Copy link
Author

Thank you for the advices you gave me.
I'm a little lost though. I think I'll come back to you if I have any questions. But I confess that I am afraid of not being able to make it work.

@techniq
Copy link
Owner

techniq commented Jan 24, 2017

Looking at the SimpleTag.ino file within the test scripts on the Adafruit PR, it looks like you need to first initialize (nfc.TgInitAsTarget()) and then setup a response buffer/handler (nfc.TgGetData(...)) and then ultimately send the data (nfc.TgSetData(...))

#include <Adafruit_PN532.h>

#define SCK     (2)
#define MOSI    (3)
#define SS      (4)
#define MISO    (5)

boolean TgInit = false;

Adafruit_PN532 nfc(SCK, MISO, MOSI, SS);

void setup() {
  Serial.begin(115200);
  nfc.begin();

  uint8_t versiondata = nfc.getFirmwareVersion();
  if (! versiondata) {
    Serial.println("Didn't find PN532 on RX board!");
    while (1); //halt
  }

  nfc.SAMConfig();
  Serial.println("Boards initialized and ready...");
}

void loop() {
  uint8_t sendbuf[] = {0x04, 0x03, 0x02, 0x01};
  uint8_t resbuf[16];
  uint8_t reslen;
  if(nfc.TgInitAsTarget()) {
    Serial.println("Tag Emulation Successful");
    if(!nfc.TgGetData(resbuf, &reslen)) {
      Serial.println("GetData Fail");
    }
    nfc.TgSetData(sendbuf, sizeof(sendbuf));
    Serial.print("Response: ");
    nfc.PrintHex(resbuf, reslen);
    Serial.println("Sent data: ");
    nfc.PrintHex(sendbuf, sizeof(sendbuf));
//    while(1);
  }
  delay(1000);
}

I think I was on the right track with emulateTag (i.e. TgInitAsTarget), emulateGetData (i.e. TgGetData) and emulateSetData (i.e. TgSetData) but maybe not knowing I needed to call all 3 each time to setup the transfer...

Looking at what I had done, I think I was using Seeed Studio's emulatetag.cpp as reference, trying to figure it out. If you want to give it a shot, I would work from their impl. and see where `node-pn532' is lacking.

@techniq
Copy link
Owner

techniq commented Jan 24, 2017

Page 21 of the User Manual titled ISO/IEC14443-4 PICC emulation concept and pages 151-165 on TgInitAsTarget, TgGetData, and TgSetData might come in handy, but ultimately working by example (Seeed/Adafruit impl.) will probably give you the best idea on how to implement.

I wish I had more time to look at this, but as of right now, just giving comments/feedback is the best I can do (for a while at least).

@techniq techniq changed the title P2P between 2 pn532 Card emulation Jan 24, 2017
@Zhairgling
Copy link
Author

Hello, I bent over it tonight. I prepared two PI and two pn532. They work well both. I even was able to test the emulation function of tag in the shell with the examples of the libnfc.
I have needed a tip to choose the best way to implement it in the pn532 module. Should I load the old branch of your work or implement it myself in the latest version of the module?

@techniq
Copy link
Owner

techniq commented Jan 25, 2017 via email

@Zhairgling
Copy link
Author

I am currently working on it but I do not see very well the interest of the emulateSetData () function. Since there is one of the two configured as target the other just has to write on it, then reverse !?

@Zhairgling
Copy link
Author

Zhairgling commented Jan 25, 2017

Can you explain me the switch in the emulateGetData() function ?

emulateGetData() {
        logger.info('Emulate get data...');
        return this.sendCommand([c.COMMAND_TG_GET_DATA])
        .then((frame) => {
            var body = frame.getDataBody();
            logger.debug('Frame data from emulate get data read:', util.inspect(body));
            var status = body[0];
            if (status === 0x13) {
                logger.warn('The data format does not match to the specification.');
            }
            // var dataIn = body.slice(1, body.length - 1); // skip status byte and last byte (not part of memory)
            // 00 00 a4 04 00 07 d2 76 00 00 85 01 01 00 26
            var cla = body[1]
            var instruction = body[2];
            var parameter1 = body[3];
            var parameter2 = body[4];
            var commandLength = body[5];
            var data = body.slice(6, commandLength);
            logger.debug('instruction', instruction);
            logger.debug('parameter1', parameter1);
            logger.debug('parameter2', parameter2);
            logger.debug('commandLength', commandLength);
            logger.debug('data', util.inspect(data));
            switch(instruction) {          ////////              <==========================
                case c.ISO7816_SELECT_FILE:
                    logger.info('Select file');
                    if (parameter1 === 0x00) {
                        logger.info('Select by Id');
                    }
                    if (parameter1 === 0x04) {
                        logger.info('Select by name');
                    }
                 /*   case C_APDU_P1_SELECT_BY_ID:
                        if(p2 != 0x0c){
                            DMSG("C_APDU_P2 != 0x0c\n");
                           // setResponse(COMMAND_COMPLETE, rwbuf, &sendlen);
                        } else if(lc == 2 && rwbuf[C_APDU_DATA] == 0xE1 && (rwbuf[C_APDU_DATA+1] == 0x03 || rwbuf[C_APDU_DATA+1] == 0x04)){
                           // setResponse(COMMAND_COMPLETE, rwbuf, &sendlen);
                            if(rwbuf[C_APDU_DATA+1] == 0x03){
                                currentFile = CC;
                            } else if(rwbuf[C_APDU_DATA+1] == 0x04){
                                currentFile = NDEF;
                            }
                        } else {
                           // setResponse(TAG_NOT_FOUND, rwbuf, &sendlen);
                        }
                        break;
                        case C_APDU_P1_SELECT_BY_NAME:
                        const uint8_t ndef_tag_application_name_v2[] = {0, 0x7, 0xD2, 0x76, 0x00, 0x00, 0x85, 0x01, 0x01 };
                        if(0 == memcmp(ndef_tag_application_name_v2, rwbuf + C_APDU_P2, sizeof(ndef_tag_application_name_v2))){
                           // setResponse(COMMAND_COMPLETE, rwbuf, &sendlen);
                        } else{
                            DMSG("function not supported\n");
                          //  setResponse(FUNCTION_NOT_SUPPORTED, rwbuf, &sendlen);
                        }
                        break;
                    break;*/
                case c.ISO7816_READ_BINARY:
                    logger.info('Read binary');
                    break;
                case c.ISO7816_UPDATE_BINARY:
                    logger.info('Update binary');
                    break;
                default:
                    logger.warn('Command not supported');
            }
            return data;
        });
    }

@techniq
Copy link
Owner

techniq commented Jan 25, 2017

I'll be honest, I'm not sure what it does :D.

I think at the time I copied Seeed Studio's C++ implementation and was slowly trying to break it down to understand it, but I didn't get that far... :(

I think it would be best if we scraped that and looked at Adafruit's PR C++ implementation for TgGetData since it looks to be simpler (and we can build it out after we have a better understanding...).

@Zhairgling
Copy link
Author

Zhairgling commented Jan 26, 2017

I have worked on the emulateTag() function.

here is my work :

     emulateTag() {
        logger.info('Emulating tag...');
        var commAsTarget= 0x8C;
        var mode = 0x05; // PICC only, Passive Only
        var sens_res = [0x08, 0x00];
        var nfcId1t = [0x12, 0x34, 0x56];
        var sel_res = [0x60];
        var mifareParams = [].concat(sens_res, nfcId1t, sel_res);
        var felicaParams = [0,0,0,0,0,0,0,0,
                           0,0,0,0,0,0,0,0,
                           0,0];
        var nfcId3t = [0,0,0,0,0,0,0,0,0,0];
        var generalBytesLength = 0;
        var historicalBytesLength =  0;
        var commandBuffer = [
            commAsTarget,
            mode,
            mifareParams,
            felicaParams,
            nfcId3t,
            generalBytesLength,
            historicalBytesLength
        ];
        console.log('commandBuffer : '+ commandBuffer);
        return this.sendCommand(commandBuffer)
            .then((frame) => {

            var body = frame.getDataBody();
            logger.debug('body', util.inspect(body));
            var mode = body[0];
            console.log('mode', mode);
            logger.debug('mode', mode);
           
        });
    }
    

but i can't have any response by the pn532 after send the commandBuffer.

@techniq
Copy link
Owner

techniq commented Jan 26, 2017

Hmm, could you show me how you're calling emulateTag() and run your example with logging enabled:

PN532_LOGGING=debug node examples/emulate_tag.js

Replacing emulate_tag.js with whatever you called your file.

@Zhairgling
Copy link
Author

Zhairgling commented Jan 26, 2017

I'm simply calling it like that in my index.js file :


var SerialPort = require('serialport').SerialPort;

//ndef = require('ndef');
var serialPort = new SerialPort('/dev/ttyAMA0', { baudrate: 115200 });
var rfid = new pn532.PN532(serialPort);
rfid.on('ready', function() {
console.log('rfid ready');
rfid.emulateTag();
    });

when I run with logging enabled i get that :


DEPRECATION: Please use `require('serialport')` instead of `require('serialport').SerialPort`
debug: [frame-emitter] listening to data
debug: [hsu] Initializing serial port...
debug: [hsu] Serial port initialized.
info: [pn532] Configuring secure access module (SAM)...
debug: [pn532] Sending buffer: <Buffer 00 00 ff 05 fb d4 14 01 00 01 16 00>
debug: [hsu] Waking up PN532...
debug: [frame-emitter] Data received <Buffer 00 00 ff 00 ff 00 00 00 ff 02 fe d5 15 16 00>
debug: [frame-emitter] Processing buffer <Buffer 00 00 ff 00 ff 00 00 00 ff 02 fe d5 15 16 00>
debug: [frame-emitter] Frame found in buffer
info: [frame-emitter] Frame <AckFrame {"type":"Buffer","data":[0,0,255,0,255,0]}>
debug: [pn532] Response received for sendCommand <AckFrame {"type":"Buffer","data":[0,0,255,0,255,0]}>
info: [pn532] Command Acknowledged <AckFrame {"type":"Buffer","data":[0,0,255,0,255,0]}>
debug: [frame-emitter] AckFrame found in buffer
debug: [frame-emitter] Processing buffer <Buffer 00 00 ff 02 fe d5 15 16 00>
debug: [frame-emitter] Frame found in buffer
info: [frame-emitter] Frame <DataFrame {"data":{"command":21,"body":{"type":"Buffer","data":[22]}}}>
debug: [pn532] Response received for sendCommand <DataFrame {"data":{"command":21,"body":{"type":"Buffer","data":[22]}}}>
info: [pn532] Command Response <DataFrame {"data":{"command":21,"body":{"type":"Buffer","data":[22]}}}>
debug: [pn532] Removing listeners
debug: [frame-emitter] DataFrame found in buffer
rfid ready
info: [pn532] Emulating tag...
commandBuffer : 140,5,8,0,18,52,86,96,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
debug: [pn532] Sending buffer: <Buffer 00 00 ff 08 f8 d4 8c 05 00 00 00 00 00 01 00>

@techniq
Copy link
Owner

techniq commented Jan 26, 2017

Hmm, looking at the logs for the buffer being sent (last line)

00 00 ff 08 f8 d4 8c 05 00 00 00 00 00 01 00

The command is incorrect (or is being truncated). The command buffer we build for each different type of command (in this case, TgInitAsTarget) is passed to sendCommand and is wrapped into a frame, which adds things such as the PREAMBLE, START_CODE_1 / 2, calculates and appends the data length and the checksum of the data length, the direction of the communication (to/from the PN532), the actual data we're trying to send (commandBuffer), the checksum of that data, and the POSTAMBLE. You can see all of this by looking at DataFrame, and particularly these lines:

toBuffer() {
        var array = [].concat([
            PREAMBLE,
            START_CODE_1,
            START_CODE_2,
            this.getDataLength(),
            this.getDataLengthChecksum(),
            this.getDirection()
        ],  this._data, [
            this.getDataChecksum(),
            POSTAMBLE
        ]);
        return new Buffer(array);
    }

I think testing and fixing to make sure new DataFrame(commandBuffer) produces the correct output should get you past this issue. If you look at page 150 of the user manual you can see the structure of the frame for a TgInitAsTarget frame (this only shows the direction (D4) and then everything within the data part.

Also, when you paste code/logs, if you could wrap them in triple single quotes (`) it would make reading them much easier 😄.

Hopefully you can track down the flaw in the building of DataFrame. It's likely we're taking for granted the type of data we've sent up to this far and some adjustments / special handling for this frame needs to occur.

I've had it on my backlog for a while, but I really need to get around to setting up some testing infrastructure (jest, mocha, ...) to make this type of development easier. Early on I thought it would be difficult to test since it was dependent on hardware / physical setup, but there is a lot of the code that could be tested without hardware, most importantly the building of the frames.

@techniq
Copy link
Owner

techniq commented Jan 26, 2017

I think I might see the issue in your code...

var commandBuffer = [
  commAsTarget,
  mode,
  mifareParams,
  felicaParams,
  nfcId3t,
  generalBytesLength,
  historicalBytesLength
];

Things such as mifareParams, felicaParams, etc are arrays within the commandBuffer array, but commandBuffer should be a "flat array" of all the data. I think you need to concat all of this together so commandBuffer.length === 38 (doing a quick count, I could be off by 1 or 2). It looks like currently DataFrame saw 8 as indicated in the logs (00 00 ff 08...), and makes since as your commandBuffer is a length of 7 and getDataLength() adds 1 to the commandBuffer (I forgot exactly way, but I think maybe to account for the data checksum byte).

Anyways, try to concat all of your command buffer together and let me know.

@Zhairgling
Copy link
Author

Thanks..

I have concat my buffer command and it seems ok :

here the result of the emulate() function :

emulateTag() {
        logger.info('Emulating tag...');
        var commAsTarget= 0x8C;
        var mode = 0x05; // PICC only, Passive Only
        var sens_res = [0x08, 0x00];
        var nfcId1t = [0x12, 0x34, 0x56];
        var sel_res = [0x60];
        var mifareParams = [].concat(sens_res, nfcId1t, sel_res);

        var felicaParams = [0,0,0,0,0,0,0,0,
                           0,0,0,0,0,0,0,0,
                           0,0];

        var nfcId3t = [0,0,0,0,0,0,0,0,0,0];
        var generalBytesLength = 0;
        var historicalBytesLength =  0;
        var commandBuffer = [].concat(
            commAsTarget,
            mode,
            mifareParams,
            felicaParams,
            nfcId3t,
            generalBytesLength,
            historicalBytesLength
        );
        console.log('commandBuffer : '+ commandBuffer);
        return this.sendCommand(commandBuffer)
        .then((frame) => {
            var body = frame.getDataBody();
            logger.debug('body', util.inspect(body));
            var mode = body[0];
            console.log('mode', mode);
            logger.debug('mode', mode);
            // var initiatorCommand = ...
            // var numberOfTags = body[0];
            // if (numberOfTags === 1) {
            //     var tagNumber = body[1];
            //     var uidLength = body[5];
            //
            //     var uid = body.slice(6, 6 + uidLength)
            //     .toString('hex')
            //     .match(/.{1,2}/g)
            //     .join(':');
            //
            //     return {
            //         ATQA: body.slice(2, 4), // SENS_RES
            //         SAK: body[4],           // SEL_RES
            //         uid: uid
            //     };
            // }
        });
    }

and the result :

pi@raspberrypi:~/testNFCP2P $ PN532_LOGGING=debug node index.js
DEPRECATION: Please use `require('serialport')` instead of `require('serialport'                                                                               ).SerialPort`
debug: [frame-emitter] listening to data
debug: [hsu] Initializing serial port...
debug: [hsu] Serial port initialized.
info: [pn532] Configuring secure access module (SAM)...
debug: [pn532] Sending buffer: <Buffer 00 00 ff 05 fb d4 14 01 00 01 16 00>
debug: [hsu] Waking up PN532...
debug: [frame-emitter] Data received <Buffer 00 00 ff 00 ff 00 00 00 ff 02 fe d5                                                                                15 16 00>
debug: [frame-emitter] Processing buffer <Buffer 00 00 ff 00 ff 00 00 00 ff 02 f                                                                               e d5 15 16 00>
debug: [frame-emitter] Frame found in buffer
info: [frame-emitter] Frame <AckFrame {"type":"Buffer","data":[0,0,255,0,255,0]}                                                                               >
debug: [pn532] Response received for sendCommand <AckFrame {"type":"Buffer","dat                                                                               a":[0,0,255,0,255,0]}>
info: [pn532] Command Acknowledged <AckFrame {"type":"Buffer","data":[0,0,255,0,                                                                               255,0]}>
debug: [frame-emitter] AckFrame found in buffer
debug: [frame-emitter] Processing buffer <Buffer 00 00 ff 02 fe d5 15 16 00>
debug: [frame-emitter] Frame found in buffer
info: [frame-emitter] Frame <DataFrame {"data":{"command":21,"body":{"type":"Buf                                                                               fer","data":[22]}}}>
debug: [pn532] Response received for sendCommand <DataFrame {"data":{"command":2                                                                               1,"body":{"type":"Buffer","data":[22]}}}>
info: [pn532] Command Response <DataFrame {"data":{"command":21,"body":{"type":"                                                                               Buffer","data":[22]}}}>
debug: [pn532] Removing listeners
debug: [frame-emitter] DataFrame found in buffer
rfid ready
info: [pn532] Emulating tag...
commandBuffer : 140,5,8,0,18,52,86,96,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,                                                                               0,0,0,0,0,0,0,0,0
debug: [pn532] Sending buffer: <Buffer 00 00 ff 27 d9 d4 8c 05 08 00 12 34 56 60                                                                                00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0                                                                               0 00 00 00 97 00>
debug: [frame-emitter] Data received <Buffer 00 00 ff 00 ff 00>
debug: [frame-emitter] Processing buffer <Buffer 00 00 ff 00 ff 00>
debug: [frame-emitter] Frame found in buffer
info: [frame-emitter] Frame <AckFrame {"type":"Buffer","data":[0,0,255,0,255,0]}                                                                               >
debug: [pn532] Response received for sendCommand <AckFrame {"type":"Buffer","dat                                                                               a":[0,0,255,0,255,0]}>
info: [pn532] Command Acknowledged <AckFrame {"type":"Buffer","data":[0,0,255,0,                                                                               255,0]}>
debug: [frame-emitter] AckFrame found in buffer

when i use NFCTOOL from my phone i can read datas :D

@Zhairgling
Copy link
Author

Hi ,

I'm now working on the emulateGetData() fonction:

    emulateGetData() {
        logger.info('Emulate get data...');

        return this.sendCommand([c.COMMAND_TG_GET_DATA])//0x86
        .then((frame) => {
            var body = frame.getDataBody();
            logger.debug('Frame data from emulate get data read:', util.inspect(body));
            var status = body[0];
            if (status === 0x13) {
                logger.warn('The data format does not match to the specification.');
            }
            // var dataIn = body.slice(1, body.length - 1); // skip status byte and last byte (not part of memory)
            // 00 00 a4 04 00 07 d2 76 00 00 85 01 01 00 26
            var cla = body[1]
            var instruction = body[2];
            var parameter1 = body[3];
            var parameter2 = body[4];
            var commandLength = body[5];
            var data = body.slice(6, commandLength);
            logger.debug('instruction', instruction);
            logger.debug('parameter1', parameter1);
            logger.debug('parameter2', parameter2);
            logger.debug('commandLength', commandLength);
            logger.debug('data', util.inspect(data));
            console.log('Final data read : '+data);
            return data;
        });
    }

used like that :

var pn532 = require('pn532');
var SerialPort = require('serialport').SerialPort;
//ndef = require('ndef');

var serialPort = new SerialPort('/dev/ttyAMA0', { baudrate: 115200 });
var rfid = new pn532.PN532(serialPort);

rfid.on('ready', function() {
	console.log('rfid ready');


	rfid.emulateTag()
	 rfid.emulateGetData().then(function(data) {
        console.log('dataRead : ', data);
    });
});

The output is :

pi@raspberrypi:~/testNFCP2P $ sudo PN532_LOGGING=debug node index.js
DEPRECATION: Please use `require('serialport')` instead of `require('serialport').SerialPort`
debug: [frame-emitter] listening to data
debug: [hsu] Initializing serial port...
debug: [hsu] Serial port initialized.
info: [pn532] Configuring secure access module (SAM)...
debug: [pn532] Sending buffer: <Buffer 00 00 ff 05 fb d4 14 01 00 01 16 00>
debug: [hsu] Waking up PN532...
debug: [frame-emitter] Data received <Buffer 00 00 ff 00 ff 00 00 00 ff 02 fe d5 15 16 00>
debug: [frame-emitter] Processing buffer <Buffer 00 00 ff 00 ff 00 00 00 ff 02 fe d5 15 16 00>
debug: [frame-emitter] Frame found in buffer
info: [frame-emitter] Frame <AckFrame {"type":"Buffer","data":[0,0,255,0,255,0]}>
debug: [pn532] Response received for sendCommand <AckFrame {"type":"Buffer","data":[0,0,255,0,255,0]}>
info: [pn532] Command Acknowledged <AckFrame {"type":"Buffer","data":[0,0,255,0,255,0]}>
debug: [frame-emitter] AckFrame found in buffer
debug: [frame-emitter] Processing buffer <Buffer 00 00 ff 02 fe d5 15 16 00>
debug: [frame-emitter] Frame found in buffer
info: [frame-emitter] Frame <DataFrame {"data":{"command":21,"body":{"type":"Buffer","data":[22]}}}>
debug: [pn532] Response received for sendCommand <DataFrame {"data":{"command":21,"body":{"type":"Buffer","data":[22]}}}>
info: [pn532] Command Response <DataFrame {"data":{"command":21,"body":{"type":"Buffer","data":[22]}}}>
debug: [pn532] Removing listeners
debug: [frame-emitter] DataFrame found in buffer
rfid ready
info: [pn532] Emulating tag...
commandBuffer : 140,5,8,0,18,52,86,96,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
debug: [pn532] Sending buffer: <Buffer 00 00 ff 27 d9 d4 8c 05 08 00 12 34 56 60 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 97 00>
info: [pn532] Emulate get data...
debug: [pn532] Sending buffer: <Buffer 00 00 ff 02 fe d4 00 01 00>
debug: [frame-emitter] Data received <Buffer 00 00 ff 00 ff 00>
debug: [frame-emitter] Processing buffer <Buffer 00 00 ff 00 ff 00>
debug: [frame-emitter] Frame found in buffer
info: [frame-emitter] Frame <AckFrame {"type":"Buffer","data":[0,0,255,0,255,0]}>
debug: [pn532] Response received for sendCommand <AckFrame {"type":"Buffer","data":[0,0,255,0,255,0]}>
info: [pn532] Command Acknowledged <AckFrame {"type":"Buffer","data":[0,0,255,0,255,0]}>
debug: [pn532] Response received for sendCommand <AckFrame {"type":"Buffer","data":[0,0,255,0,255,0]}>
info: [pn532] Command Acknowledged <AckFrame {"type":"Buffer","data":[0,0,255,0,255,0]}>
debug: [frame-emitter] AckFrame found in buffer

What's wrong ? the AckFrame is not good ?

@techniq
Copy link
Owner

techniq commented Jan 27, 2017

You should wait for emulateTag()'s promise to resolve (wait on its ACK) before sending emulateGetData().

rfid.emulateTag().then(function() {
  console.log('emulateTag initialized');
  rfid.emulateGetData().then(function(data) {
  console.log('dataRead : ', data);
});

@Zhairgling
Copy link
Author

Zhairgling commented Jan 27, 2017

Ok when i use ur code, I can't write with NFCTOOLS, that say " error when writing".
When i use the rfid.writeNdefData(data) function :

var pn532 = require('pn532');
var SerialPort = require('serialport').SerialPort;
var ndef = require('ndef');

var serialPort = new SerialPort('/dev/ttyAMA0', { baudrate: 115200 });
var rfid = new pn532.PN532(serialPort);

rfid.on('ready', function() {
console.log('rfid ready');
 rfid.scanTag().then(function(tag) {
 	console.log('scan du taf');
        var messages = [
            ndef.uriRecord('http://www.google.com'),
            ndef.textRecord('test')
        ];
        console.log('messages: ',messages);
        var data = ndef.encodeMessage(messages);
        console.log('data: ',data);

        rfid.writeNdefData(data).then(function(response) {
            console.log('Write successful');
        });
    });
});

i get :

pi@raspberrypi:~/testNFCWrite $ PN532_LOGGING=debug node index.js
DEPRECATION: Please use `require('serialport')` instead of `require('serialport').SerialPort`
debug: [frame-emitter] listening to data
debug: [hsu] Initializing serial port...
debug: [hsu] Serial port initialized.
info: [pn532] Configuring secure access module (SAM)...
debug: [pn532] Sending buffer: <Buffer 00 00 ff 05 fb d4 14 01 00 01 16 00>
debug: [hsu] Waking up PN532...
debug: [frame-emitter] Data received <Buffer 00 00 ff 00 ff 00 00 00 ff 02 fe d5 15 16 00>
debug: [frame-emitter] Processing buffer <Buffer 00 00 ff 00 ff 00 00 00 ff 02 fe d5 15 16 00>
debug: [frame-emitter] Frame found in buffer
info: [frame-emitter] Frame <AckFrame {"type":"Buffer","data":[0,0,255,0,255,0]}>
debug: [pn532] Response received for sendCommand <AckFrame {"type":"Buffer","data":[0,0,255,0,255,0]}>
info: [pn532] Command Acknowledged <AckFrame {"type":"Buffer","data":[0,0,255,0,255,0]}>
debug: [frame-emitter] AckFrame found in buffer
debug: [frame-emitter] Processing buffer <Buffer 00 00 ff 02 fe d5 15 16 00>
debug: [frame-emitter] Frame found in buffer
info: [frame-emitter] Frame <DataFrame {"data":{"command":21,"body":{"type":"Buffer","data":[22]}}}>
debug: [pn532] Response received for sendCommand <DataFrame {"data":{"command":21,"body":{"type":"Buffer","data":[22]}}}>
info: [pn532] Command Response <DataFrame {"data":{"command":21,"body":{"type":"Buffer","data":[22]}}}>
debug: [pn532] Removing listeners
debug: [frame-emitter] DataFrame found in buffer
rfid ready
info: [pn532] Scanning tag...
debug: [pn532] Sending buffer: <Buffer 00 00 ff 04 fc d4 4a 01 00 e1 00>
debug: [frame-emitter] Data received <Buffer 00 00 ff 00 ff 00>
debug: [frame-emitter] Processing buffer <Buffer 00 00 ff 00 ff 00>
debug: [frame-emitter] Frame found in buffer
info: [frame-emitter] Frame <AckFrame {"type":"Buffer","data":[0,0,255,0,255,0]}>
debug: [pn532] Response received for sendCommand <AckFrame {"type":"Buffer","data":[0,0,255,0,255,0]}>
info: [pn532] Command Acknowledged <AckFrame {"type":"Buffer","data":[0,0,255,0,255,0]}>
debug: [frame-emitter] AckFrame found in buffer
debug: [frame-emitter] Data received <Buffer 00 00 ff 11 ef d5 4b 01>
debug: [frame-emitter] Processing buffer <Buffer 00 00 ff 11 ef d5 4b 01>
debug: [frame-emitter] Data received <Buffer 01 00 08 60 04 08 12 34 56 05 75 33 92 03 8c 00>
debug: [frame-emitter] Processing buffer <Buffer 00 00 ff 11 ef d5 4b 01 01 00 08 60 04 08 12 34 56 05 75 33 92 03 8c 00>
debug: [frame-emitter] Frame found in buffer
info: [frame-emitter] Frame <DataFrame {"data":{"command":75,"body":{"type":"Buffer","data":[1,1,0,8,96,4,8,18,52,86,5,117,51,146,3,140]}}}>
debug: [pn532] Response received for sendCommand <DataFrame {"data":{"command":75,"body":{"type":"Buffer","data":[1,1,0,8,96,4,8,18,52,86,5,117,51,146,3,140]}}}>
info: [pn532] Command Response <DataFrame {"data":{"command":75,"body":{"type":"Buffer","data":[1,1,0,8,96,4,8,18,52,86,5,117,51,146,3,140]}}}>
debug: [pn532] Removing listeners
debug: [frame-emitter] DataFrame found in buffer
debug: [pn532] body <Buffer 01 01 00 08 60 04 08 12 34 56 05 75 33 92 03 8c>
scan du taf
messages:  [ { tnf: 1,
    type: 'U',
    id: [],
    payload: [ 1, 103, 111, 111, 103, 108, 101, 46, 99, 111, 109 ],
    value: 'http://www.google.com' },
  { tnf: 1,
    type: 'T',
    id: [],
    payload: [ 2, 101, 110, 116, 101, 115, 116 ],
    value: 'test' } ]
data:  [ 145,
  1,
  11,
  85,
  1,
  103,
  111,
  111,
  103,
  108,
  101,
  46,
  99,
  111,
  109,
  81,
  1,
  7,
  84,
  2,
  101,
  110,
  116,
  101,
  115,
  116 ]
info: [pn532] Writing data...
debug: [pn532] block: <Buffer 03 1a 91 01 0b 55 01 67 6f 6f 67 6c 65 2e 63 6f 6d 51 01 07 54 02 65 6e 74 65 73 74 fe>
debug: [pn532] Writing block: 0 at blockAddress: 4
debug: [pn532] pageData: <Buffer 03 1a 91 01>
info: [pn532] Writing block...
debug: [pn532] Sending buffer: <Buffer 00 00 ff 09 f7 d4 40 01 a2 04 03 1a 91 01 96 00>
debug: [frame-emitter] Data received <Buffer 00 00 ff 00 ff 00>
debug: [frame-emitter] Processing buffer <Buffer 00 00 ff 00 ff 00>
debug: [frame-emitter] Frame found in buffer
info: [frame-emitter] Frame <AckFrame {"type":"Buffer","data":[0,0,255,0,255,0]}>
debug: [pn532] Response received for sendCommand <AckFrame {"type":"Buffer","data":[0,0,255,0,255,0]}>
info: [pn532] Command Acknowledged <AckFrame {"type":"Buffer","data":[0,0,255,0,255,0]}>
debug: [frame-emitter] AckFrame found in buffer

and on the target i have :

pi@raspberrypi:~/testNFCP2P $ PN532_LOGGING=debug node index.js
DEPRECATION: Please use `require('serialport')` instead of `require('serialport').SerialPort`
debug: [frame-emitter] listening to data
debug: [hsu] Initializing serial port...
debug: [hsu] Serial port initialized.
info: [pn532] Configuring secure access module (SAM)...
debug: [pn532] Sending buffer: <Buffer 00 00 ff 05 fb d4 14 01 00 01 16 00>
debug: [hsu] Waking up PN532...
debug: [frame-emitter] Data received <Buffer 00 00 ff 00 ff 00 00 00 ff 02 fe d5 15 16 00>
debug: [frame-emitter] Processing buffer <Buffer 00 00 ff 00 ff 00 00 00 ff 02 fe d5 15 16 00>
debug: [frame-emitter] Frame found in buffer
info: [frame-emitter] Frame <AckFrame {"type":"Buffer","data":[0,0,255,0,255,0]}>
debug: [pn532] Response received for sendCommand <AckFrame {"type":"Buffer","data":[0,0,255,0,255,0]}>
info: [pn532] Command Acknowledged <AckFrame {"type":"Buffer","data":[0,0,255,0,255,0]}>
debug: [frame-emitter] AckFrame found in buffer
debug: [frame-emitter] Processing buffer <Buffer 00 00 ff 02 fe d5 15 16 00>
debug: [frame-emitter] Frame found in buffer
info: [frame-emitter] Frame <DataFrame {"data":{"command":21,"body":{"type":"Buffer","data":[22]}}}>
debug: [pn532] Response received for sendCommand <DataFrame {"data":{"command":21,"body":{"type":"Buffer","data":[22]}}}>
info: [pn532] Command Response <DataFrame {"data":{"command":21,"body":{"type":"Buffer","data":[22]}}}>
debug: [pn532] Removing listeners
debug: [frame-emitter] DataFrame found in buffer
info: [pn532] Emulating tag...
commandBuffer : 140,5,8,0,18,52,86,96,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
debug: [pn532] Sending buffer: <Buffer 00 00 ff 27 d9 d4 8c 05 08 00 12 34 56 60 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 97 00>
debug: [frame-emitter] Data received <Buffer 00 00 ff 00 ff 00>
debug: [frame-emitter] Processing buffer <Buffer 00 00 ff 00 ff 00>
debug: [frame-emitter] Frame found in buffer
info: [frame-emitter] Frame <AckFrame {"type":"Buffer","data":[0,0,255,0,255,0]}>
debug: [pn532] Response received for sendCommand <AckFrame {"type":"Buffer","data":[0,0,255,0,255,0]}>
info: [pn532] Command Acknowledged <AckFrame {"type":"Buffer","data":[0,0,255,0,255,0]}>
debug: [frame-emitter] AckFrame found in buffer
debug: [frame-emitter] Data received <Buffer 00 00 ff 05 fb d5 8d 08>
debug: [frame-emitter] Processing buffer <Buffer 00 00 ff 05 fb d5 8d 08>
debug: [frame-emitter] Data received <Buffer e0 50 66 00>
debug: [frame-emitter] Processing buffer <Buffer 00 00 ff 05 fb d5 8d 08 e0 50 66 00>
debug: [frame-emitter] Frame found in buffer
info: [frame-emitter] Frame <DataFrame {"data":{"command":141,"body":{"type":"Buffer","data":[8,224,80,102]}}}>
debug: [pn532] Response received for sendCommand <DataFrame {"data":{"command":141,"body":{"type":"Buffer","data":[8,224,80,102]}}}>
info: [pn532] Command Response <DataFrame {"data":{"command":141,"body":{"type":"Buffer","data":[8,224,80,102]}}}>
debug: [pn532] Removing listeners
debug: [frame-emitter] DataFrame found in buffer
debug: [pn532] body <Buffer 08 e0 50 66>
mode 8
debug: [pn532] mode 8
emulateTag initialized
info: [pn532] Emulate get data...
debug: [pn532] Sending buffer: <Buffer 00 00 ff 02 fe d4 00 01 00>

It look like the target isn't waiting the good type of data.

@Zhairgling
Copy link
Author

screenshot_2017-01-27-15-01-57
here is a screen of reading the target with nfcTool from android phone

@techniq
Copy link
Owner

techniq commented Jan 27, 2017

Nothing is jumping out at me so far. Receiving the 8D (141) command after the 8C (140) looks correct.

8C command mode (request): 5 (00000101)

  • not used (0000)
  • PICC only: yes (1)
  • DEP only: no (0)
  • Passive only: yes (1)

8D command mode (response): 8 (00001000):

  • not used (0)
  • Baudrate: 106 kbps (000)
  • ISO/IEC 14443-4 PICC: yes (1)
  • DEP: no (0)
  • Framing type : Mifare (00)

Actually as I've been looking at a bunch of other things, something just stood out at me. The last command...

debug: [pn532] Sending buffer: <Buffer 00 00 ff 02 fe d4 00 01 00>

It looks like it's sending 00 as the command for TgGetData instead of 86.


Actually it looks like:

emulateGetData() {
  return this.sendCommand([c.COMMAND_TG_GET_DATA]) //0x86

should be

emulateGetData() {
  return this.sendCommand([c.TG_GET_DATA]) //0x86

Sorry for the noise in the comment, I thought I would leave my train of thought (and I had already typed things before I figured more of it out) 😄

Btw, another Github comment tip: If you add js after the first triple backtick, it will add javascript syntax highlighting to your pasted code (ignore the ., I had to add it so it wouldn't be parsed and prematurely close the example:

.```js
// code here
.```

It supports a lot of other languages as well (I wouldn't put the js on our log output)

@Zhairgling
Copy link
Author

Zhairgling commented Jan 27, 2017

Thank you for all advices you give me :)
You are right, that was the wrong command. But when i provide the good one, it fail :
And freez my pi

pi@raspberrypi:~/testNFCP2P $ PN532_LOGGING=debug node index.js
DEPRECATION: Please use `require('serialport')` instead of `require('serialport').SerialPort`
debug: [frame-emitter] listening to data
debug: [hsu] Initializing serial port...
debug: [hsu] Serial port initialized.
info: [pn532] Configuring secure access module (SAM)...
debug: [pn532] Sending buffer: <Buffer 00 00 ff 05 fb d4 14 01 00 01 16 00>
debug: [hsu] Waking up PN532...
debug: [frame-emitter] Data received <Buffer 00 00 ff 00 ff 00 00 00 ff 02 fe d5 15 16 00>
debug: [frame-emitter] Processing buffer <Buffer 00 00 ff 00 ff 00 00 00 ff 02 fe d5 15 16 00>
debug: [frame-emitter] Frame found in buffer
info: [frame-emitter] Frame <AckFrame {"type":"Buffer","data":[0,0,255,0,255,0]}>
debug: [pn532] Response received for sendCommand <AckFrame {"type":"Buffer","data":[0,0,255,0,255,0]}>
info: [pn532] Command Acknowledged <AckFrame {"type":"Buffer","data":[0,0,255,0,255,0]}>
debug: [frame-emitter] AckFrame found in buffer
debug: [frame-emitter] Processing buffer <Buffer 00 00 ff 02 fe d5 15 16 00>
debug: [frame-emitter] Frame found in buffer
info: [frame-emitter] Frame <DataFrame {"data":{"command":21,"body":{"type":"Buffer","data":[22]}}}>
debug: [pn532] Response received for sendCommand <DataFrame {"data":{"command":21,"body":{"type":"Buffer","data":[22]}}}>
info: [pn532] Command Response <DataFrame {"data":{"command":21,"body":{"type":"Buffer","data":[22]}}}>
debug: [pn532] Removing listeners
debug: [frame-emitter] DataFrame found in buffer
info: [pn532] Emulating tag...
commandBuffer : 140,5,8,0,18,52,86,96,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
debug: [pn532] Sending buffer: <Buffer 00 00 ff 27 d9 d4 8c 05 08 00 12 34 56 60 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 97 00>
debug: [frame-emitter] Data received <Buffer 00 00 ff 00 ff 00>
debug: [frame-emitter] Processing buffer <Buffer 00 00 ff 00 ff 00>
debug: [frame-emitter] Frame found in buffer
info: [frame-emitter] Frame <AckFrame {"type":"Buffer","data":[0,0,255,0,255,0]}>
debug: [pn532] Response received for sendCommand <AckFrame {"type":"Buffer","data":[0,0,255,0,255,0]}>
info: [pn532] Command Acknowledged <AckFrame {"type":"Buffer","data":[0,0,255,0,255,0]}>
debug: [frame-emitter] AckFrame found in buffer
debug: [frame-emitter] Data received <Buffer 00 00 ff 05 fb d5 8d 08>
debug: [frame-emitter] Processing buffer <Buffer 00 00 ff 05 fb d5 8d 08>
debug: [frame-emitter] Data received <Buffer e0 50 66 00>
debug: [frame-emitter] Processing buffer <Buffer 00 00 ff 05 fb d5 8d 08 e0 50 66 00>
debug: [frame-emitter] Frame found in buffer
info: [frame-emitter] Frame <DataFrame {"data":{"command":141,"body":{"type":"Buffer","data":[8,224,80,102]}}}>
debug: [pn532] Response received for sendCommand <DataFrame {"data":{"command":141,"body":{"type":"Buffer","data":[8,224,80,102]}}}>
info: [pn532] Command Response <DataFrame {"data":{"command":141,"body":{"type":"Buffer","data":[8,224,80,102]}}}>
debug: [pn532] Removing listeners
debug: [frame-emitter] DataFrame found in buffer
debug: [pn532] body <Buffer 08 e0 50 66>
mode 8
debug: [pn532] mode 8
emulateTag initialized
info: [pn532] Emulate get data...
debug: [pn532] Sending buffer: <Buffer 00 00 ff 02 fe d4 86 a6 00>
debug: [frame-emitter] Data received <Buffer 00 00 ff 00 ff 00>
debug: [frame-emitter] Processing buffer <Buffer 00 00 ff 00 ff 00>
debug: [frame-emitter] Frame found in buffer
info: [frame-emitter] Frame <AckFrame {"type":"Buffer","data":[0,0,255,0,255,0]}>
debug: [pn532] Response received for sendCommand <AckFrame {"type":"Buffer","data":[0,0,255,0,255,0]}>
info: [pn532] Command Acknowledged <AckFrame {"type":"Buffer","data":[0,0,255,0,255,0]}>
debug: [frame-emitter] AckFrame found in buffer
debug: [frame-emitter] Data received <Buffer 00 00 ff 09 f7 d5 87 00>
debug: [frame-emitter] Processing buffer <Buffer 00 00 ff 09 f7 d5 87 00>
debug: [frame-emitter] Data received <Buffer a2 04 03 1a 91 01 4f 00>
debug: [frame-emitter] Processing buffer <Buffer 00 00 ff 09 f7 d5 87 00 a2 04 03 1a 91 01 4f 00>
debug: [frame-emitter] Frame found in buffer
info: [frame-emitter] Frame <DataFrame {"data":{"command":135,"body":{"type":"Buffer","data":[0,162,4,3,26,145,1,79]}}}>
debug: [pn532] Response received for sendCommand <DataFrame {"data":{"command":135,"body":{"type":"Buffer","data":[0,162,4,3,26,145,1,79]}}}>
info: [pn532] Command Response <DataFrame {"data":{"command":135,"body":{"type":"Buffer","data":[0,162,4,3,26,145,1,79]}}}>
debug: [pn532] Removing listeners
debug: [frame-emitter] DataFrame found in buffer
debug: [pn532] Frame data from emulate get data read: <Buffer 00 a2 04 03 1a 91 01 4f>
debug: [pn532] instruction 4
debug: [pn532] parameter1 3
debug: [pn532] parameter2 26
debug: [pn532] commandLength 145
debug: [pn532] data <Buffer 01 4f>
Final data read : O
dataRead :  <Buffer 01 4f>

@techniq
Copy link
Owner

techniq commented Jan 27, 2017

Well, incremental progress 😄.

Hmm, so looking at the data of command 0x87 (135): 00 a2 04 03 1a 91 01 4f, it looks like the first byte is for status and is 00).

Looking at the User Manual, the following sections/pages look helpful:

  • 7.3.16 TgGetData (page 160)
  • 7.1 Error Handling (page 67)

I think a status of 00 is a good thing (otherwise it would be an error code from my understanding, but I just glossed over it).


It seems like you were breaking down the DataIn part of the 87 response (a2 04 03 1a 91 01 4f) into instruction, parameter1, etc. What exactly is failing (what are you expecting)?

@Zhairgling
Copy link
Author

Yes :)
For me it's failing because I can't get the data that i write with the other pn532,
i try to exchange datas in ndef format.
But i can't retrieve what i send

@techniq
Copy link
Owner

techniq commented Jan 27, 2017

You were writing the NDEF messages mentioned above right?

messages:  [ { tnf: 1,
    type: 'U',
    id: [],
    payload: [ 1, 103, 111, 111, 103, 108, 101, 46, 99, 111, 109 ],
    value: 'http://www.google.com' },
  { tnf: 1,
    type: 'T',
    id: [],
    payload: [ 2, 101, 110, 116, 101, 115, 116 ],
    value: 'test' } ]
data:  [ 145,
  1,
  11,
  85,
  1,
  103,
  111,
  111,
  103,
  108,
  101,
  46,
  99,
  111,
  109,
  81,
  1,
  7,
  84,
  2,
  101,
  110,
  116,
  101,
  115,
  116 ]

Looking at the user guide, it appears DataIn can be an array of data up to 262 bytes. Since you are trying to send more than this, I'm assuming it will need to come down in chunks/blocks, probably similarly to how readNdefData does. I do see 145 1 (or 91 01 in hex) in the your response, so that looks promising.

I don't fully understand what TgGetData and TgSetData are doing exactly TBH, although I think maybe TgSetData is used to confirm the receipt of the TgGetData.


In fact, looking at our data (response of ndef.encodeMessage(messages);, the length of the data array to send is 26, or 1a. Our response is:

  • 0x00/00: Status
  • 0xa2/162: Instruction (C_APDU_INS)
  • 0x04/4: Parameter 1 (C_APDU_P1)
    • C_APDU_P1_SELECT_BY_ID 0x00
    • C_APDU_P1_SELECT_BY_NAME 0x04
  • 0x03/3: Parameter 2 (C_APDU_P2)
  • 0x1a/26: Length command (C_APDU_LC)
  • 0x91/145: data[0]
  • 0x01/1: data[1]
  • 0x4f/79: checksum?

So my guess is we need to call TgSetData to acknowledge and probably TgGetData to get the next block of data. I don't know how we'll need to request the next block (maybe just calling TgGetData again. I think now's the time to break down how Seeed-Studio's EmulateTag::emulate works, with focus on the NDEF case statement (I saw ignore all the other case statements for now, just no-op them but leave placeholders so we know we need to handle them.

@techniq
Copy link
Owner

techniq commented Jan 27, 2017

I read a little more into Seeed-Studio's emulatetag.cpp and I don't believe the last byte (0x4f/79) is a checksum, but I'm not sure why it's not 11. It would be useful to:

  • Try sending a different NDEF message (and maybe 1 with a single message instead of 2)
  • Try to send the TgSetData command (8E). I'm not exactly sure of the payload for this command though.

I'm not sure how much more I can be right now. It would probably be helpful if you forked and committed your changes that way I can look at them as a whole (and maybe try to run it locally at some point if I get some time).

@techniq
Copy link
Owner

techniq commented Jan 27, 2017

Btw, I also have this spreadsheet that I created a while back to help me decipher NFC tag data / NDEF messages.

If you look at the second tab (NDEF Header) you'll see 91 in your data means this is the first of 2 records/messages, which is correct (since you're trying to send a url and a text record). The next byte 01 is the length of the record type indicator, which is typically always 1 (for well known types). The third byte should be the length of the NDEF message, which for the first message (google URL) is 11 (0x0B) but is in your logs as 4f, which I'm not sure why. It would be nice to capture logs a few times, a few with the same NDEF messages (to see if 4f changes) and a few with very simple payloads (maybe not even NDEF message, just a short byte array similar to Adafruit's test script mentioned above).

@Zhairgling
Copy link
Author

Hi,
I think you are right. the writer want send many buffers but reader read only one .

I will fork the project as you said.

here is what you requested last time, trying do send only one single message in NDEF data.

the writer code :

var pn532 = require('pn532');
var SerialPort = require('serialport').SerialPort;
var ndef = require('ndef');

var serialPort = new SerialPort('/dev/ttyAMA0', { baudrate: 115200 });
var rfid = new pn532.PN532(serialPort);

rfid.on('ready', function() {
console.log('rfid ready');
 rfid.scanTag().then(function(tag) {
        console.log('scan du taf');
        var messages = [
            ndef.textRecord('test')
        ];
        console.log('messages: ',messages);
        var data = ndef.encodeMessage(messages);
        console.log('data: ',data);

        rfid.writeNdefData(data).then(function(response) {
            console.log('Write successful');
        });
    });
});

the reader code as a target :

var pn532 = require('pn532');
var SerialPort = require('serialport').SerialPort;
//ndef = require('ndef');

var serialPort = new SerialPort('/dev/ttyAMA0', { baudrate: 115200 });
var rfid = new pn532.PN532(serialPort);

rfid.on('ready', function() {
	rfid.emulateTag().then(function() {
	  console.log('emulateTag initialized');
		  rfid.emulateGetData().then(function(data) {
		  console.log('dataRead : ', data);
		});
});
});

The output of the writer :

pi@raspberrypi:~/testNFCWrite $ PN532_LOGGING=debug node index.js
DEPRECATION: Please use `require('serialport')` instead of `require('serialport').SerialPort`
debug: [frame-emitter] listening to data
debug: [hsu] Initializing serial port...
debug: [hsu] Serial port initialized.
info: [pn532] Configuring secure access module (SAM)...
debug: [pn532] Sending buffer: <Buffer 00 00 ff 05 fb d4 14 01 00 01 16 00>
debug: [hsu] Waking up PN532...
debug: [frame-emitter] Data received <Buffer 00 00 ff 00 ff 00 00 00 ff 02 fe d5 15 16 00>
debug: [frame-emitter] Processing buffer <Buffer 00 00 ff 00 ff 00 00 00 ff 02 fe d5 15 16 00>
debug: [frame-emitter] Frame found in buffer
info: [frame-emitter] Frame <AckFrame {"type":"Buffer","data":[0,0,255,0,255,0]}>
debug: [pn532] Response received for sendCommand <AckFrame {"type":"Buffer","data":[0,0,255,0,255,0]}>
info: [pn532] Command Acknowledged <AckFrame {"type":"Buffer","data":[0,0,255,0,255,0]}>
debug: [frame-emitter] AckFrame found in buffer
debug: [frame-emitter] Processing buffer <Buffer 00 00 ff 02 fe d5 15 16 00>
debug: [frame-emitter] Frame found in buffer
info: [frame-emitter] Frame <DataFrame {"data":{"command":21,"body":{"type":"Buffer","data":[22]}}}>
debug: [pn532] Response received for sendCommand <DataFrame {"data":{"command":21,"body":{"type":"Buffer","data":[22]}}}>
info: [pn532] Command Response <DataFrame {"data":{"command":21,"body":{"type":"Buffer","data":[22]}}}>
debug: [pn532] Removing listeners
debug: [frame-emitter] DataFrame found in buffer
rfid ready
info: [pn532] Scanning tag...
debug: [pn532] Sending buffer: <Buffer 00 00 ff 04 fc d4 4a 01 00 e1 00>
debug: [frame-emitter] Data received <Buffer 00 00 ff 00 ff 00>
debug: [frame-emitter] Processing buffer <Buffer 00 00 ff 00 ff 00>
debug: [frame-emitter] Frame found in buffer
info: [frame-emitter] Frame <AckFrame {"type":"Buffer","data":[0,0,255,0,255,0]}>
debug: [pn532] Response received for sendCommand <AckFrame {"type":"Buffer","data":[0,0,255,0,255,0]}>
info: [pn532] Command Acknowledged <AckFrame {"type":"Buffer","data":[0,0,255,0,255,0]}>
debug: [frame-emitter] AckFrame found in buffer
debug: [frame-emitter] Data received <Buffer 00 00 ff 11 ef d5 4b 01>
debug: [frame-emitter] Processing buffer <Buffer 00 00 ff 11 ef d5 4b 01>
debug: [frame-emitter] Data received <Buffer 01 00 08 60 04 08 12 34 56 05 75 33 92 03 8c 00>
debug: [frame-emitter] Processing buffer <Buffer 00 00 ff 11 ef d5 4b 01 01 00 08 60 04 08 12 34 56 05 75 33 92 03 8c 00>
debug: [frame-emitter] Frame found in buffer
info: [frame-emitter] Frame <DataFrame {"data":{"command":75,"body":{"type":"Buffer","data":[1,1,0,8,96,4,8,18,52,86,5,117,51,146,3,140]}}}>
debug: [pn532] Response received for sendCommand <DataFrame {"data":{"command":75,"body":{"type":"Buffer","data":[1,1,0,8,96,4,8,18,52,86,5,117,51,146,3,140]}}}>
info: [pn532] Command Response <DataFrame {"data":{"command":75,"body":{"type":"Buffer","data":[1,1,0,8,96,4,8,18,52,86,5,117,51,146,3,140]}}}>
debug: [pn532] Removing listeners
debug: [frame-emitter] DataFrame found in buffer
debug: [pn532] body <Buffer 01 01 00 08 60 04 08 12 34 56 05 75 33 92 03 8c>
scan du taf
messages:  [ { tnf: 1,
    type: 'T',
    id: [],
    payload: [ 2, 101, 110, 116, 101, 115, 116 ],
    value: 'test' } ]
data:  [ 209, 1, 7, 84, 2, 101, 110, 116, 101, 115, 116 ]
info: [pn532] Writing data...
debug: [pn532] block: <Buffer 03 0b d1 01 07 54 02 65 6e 74 65 73 74 fe>
debug: [pn532] Writing block: 0 at blockAddress: 4
debug: [pn532] pageData: <Buffer 03 0b d1 01>
info: [pn532] Writing block...
debug: [pn532] Sending buffer: <Buffer 00 00 ff 09 f7 d4 40 01 a2 04 03 0b d1 01 65 00>
debug: [frame-emitter] Data received <Buffer 00 00 ff 00 ff 00>
debug: [frame-emitter] Processing buffer <Buffer 00 00 ff 00 ff 00>
debug: [frame-emitter] Frame found in buffer
info: [frame-emitter] Frame <AckFrame {"type":"Buffer","data":[0,0,255,0,255,0]}>
debug: [pn532] Response received for sendCommand <AckFrame {"type":"Buffer","data":[0,0,255,0,255,0]}>
info: [pn532] Command Acknowledged <AckFrame {"type":"Buffer","data":[0,0,255,0,255,0]}>
debug: [frame-emitter] AckFrame found in buffer
debug: [frame-emitter] Data received <Buffer 00 00 ff 03 fd d5 41 01>
debug: [frame-emitter] Processing buffer <Buffer 00 00 ff 03 fd d5 41 01>
debug: [frame-emitter] Data received <Buffer e9 00>
debug: [frame-emitter] Processing buffer <Buffer 00 00 ff 03 fd d5 41 01 e9 00>
debug: [frame-emitter] Frame found in buffer
info: [frame-emitter] Frame <DataFrame {"data":{"command":65,"body":{"type":"Buffer","data":[1,233]}}}>
debug: [pn532] Response received for sendCommand <DataFrame {"data":{"command":65,"body":{"type":"Buffer","data":[1,233]}}}>
info: [pn532] Command Response <DataFrame {"data":{"command":65,"body":{"type":"Buffer","data":[1,233]}}}>
debug: [pn532] Removing listeners
debug: [frame-emitter] DataFrame found in buffer
debug: [pn532] Frame data from block write: <Buffer 01 e9>
debug: [pn532] Writing block: 1 at blockAddress: 5
debug: [pn532] pageData: <Buffer 07 54 02 65>
info: [pn532] Writing block...
debug: [pn532] Sending buffer: <Buffer 00 00 ff 09 f7 d4 40 01 a2 05 07 54 02 65 82 00>
debug: [frame-emitter] Data received <Buffer 00 00 ff 00 ff 00>
debug: [frame-emitter] Processing buffer <Buffer 00 00 ff 00 ff 00>
debug: [frame-emitter] Frame found in buffer
info: [frame-emitter] Frame <AckFrame {"type":"Buffer","data":[0,0,255,0,255,0]}>
debug: [pn532] Response received for sendCommand <AckFrame {"type":"Buffer","data":[0,0,255,0,255,0]}>
info: [pn532] Command Acknowledged <AckFrame {"type":"Buffer","data":[0,0,255,0,255,0]}>
debug: [frame-emitter] AckFrame found in buffer
debug: [frame-emitter] Data received <Buffer 00 00 ff 03 fd d5 41 02>
debug: [frame-emitter] Processing buffer <Buffer 00 00 ff 03 fd d5 41 02>
debug: [frame-emitter] Data received <Buffer e8 00>
debug: [frame-emitter] Processing buffer <Buffer 00 00 ff 03 fd d5 41 02 e8 00>
debug: [frame-emitter] Frame found in buffer
info: [frame-emitter] Frame <DataFrame {"data":{"command":65,"body":{"type":"Buffer","data":[2,232]}}}>
debug: [pn532] Response received for sendCommand <DataFrame {"data":{"command":65,"body":{"type":"Buffer","data":[2,232]}}}>
info: [pn532] Command Response <DataFrame {"data":{"command":65,"body":{"type":"Buffer","data":[2,232]}}}>
debug: [pn532] Removing listeners
debug: [frame-emitter] DataFrame found in buffer
debug: [pn532] Frame data from block write: <Buffer 02 e8>
debug: [pn532] Writing block: 2 at blockAddress: 6
debug: [pn532] pageData: <Buffer 6e 74 65 73>
info: [pn532] Writing block...
debug: [pn532] Sending buffer: <Buffer 00 00 ff 09 f7 d4 40 01 a2 06 6e 74 65 73 89 00>
debug: [frame-emitter] Data received <Buffer 00 00 ff 00 ff 00>
debug: [frame-emitter] Processing buffer <Buffer 00 00 ff 00 ff 00>
debug: [frame-emitter] Frame found in buffer
info: [frame-emitter] Frame <AckFrame {"type":"Buffer","data":[0,0,255,0,255,0]}>
debug: [pn532] Response received for sendCommand <AckFrame {"type":"Buffer","data":[0,0,255,0,255,0]}>
info: [pn532] Command Acknowledged <AckFrame {"type":"Buffer","data":[0,0,255,0,255,0]}>
debug: [frame-emitter] AckFrame found in buffer
debug: [frame-emitter] Data received <Buffer 00 00 ff 03 fd d5 41 01 e9 00>
debug: [frame-emitter] Processing buffer <Buffer 00 00 ff 03 fd d5 41 01 e9 00>
debug: [frame-emitter] Frame found in buffer
info: [frame-emitter] Frame <DataFrame {"data":{"command":65,"body":{"type":"Buffer","data":[1,233]}}}>
debug: [pn532] Response received for sendCommand <DataFrame {"data":{"command":65,"body":{"type":"Buffer","data":[1,233]}}}>
info: [pn532] Command Response <DataFrame {"data":{"command":65,"body":{"type":"Buffer","data":[1,233]}}}>
debug: [pn532] Removing listeners
debug: [frame-emitter] DataFrame found in buffer
debug: [pn532] Frame data from block write: <Buffer 01 e9>
debug: [pn532] Writing block: 3 at blockAddress: 7
debug: [pn532] pageData: <Buffer 74 fe 00 00>
info: [pn532] Writing block...
debug: [pn532] Sending buffer: <Buffer 00 00 ff 09 f7 d4 40 01 a2 07 74 fe 00 00 d0 00>
debug: [frame-emitter] Data received <Buffer 00 00 ff 00 ff 00>
debug: [frame-emitter] Processing buffer <Buffer 00 00 ff 00 ff 00>
debug: [frame-emitter] Frame found in buffer
info: [frame-emitter] Frame <AckFrame {"type":"Buffer","data":[0,0,255,0,255,0]}>
debug: [pn532] Response received for sendCommand <AckFrame {"type":"Buffer","data":[0,0,255,0,255,0]}>
info: [pn532] Command Acknowledged <AckFrame {"type":"Buffer","data":[0,0,255,0,255,0]}>
debug: [frame-emitter] AckFrame found in buffer
debug: [frame-emitter] Data received <Buffer 00 00 ff 03 fd d5 41 01>
debug: [frame-emitter] Processing buffer <Buffer 00 00 ff 03 fd d5 41 01>
debug: [frame-emitter] Data received <Buffer e9 00>
debug: [frame-emitter] Processing buffer <Buffer 00 00 ff 03 fd d5 41 01 e9 00>
debug: [frame-emitter] Frame found in buffer
info: [frame-emitter] Frame <DataFrame {"data":{"command":65,"body":{"type":"Buffer","data":[1,233]}}}>
debug: [pn532] Response received for sendCommand <DataFrame {"data":{"command":65,"body":{"type":"Buffer","data":[1,233]}}}>
info: [pn532] Command Response <DataFrame {"data":{"command":65,"body":{"type":"Buffer","data":[1,233]}}}>
debug: [pn532] Removing listeners
debug: [frame-emitter] DataFrame found in buffer
debug: [pn532] Frame data from block write: <Buffer 01 e9>
Write successful
```

The output of the reader : 

``` 
pi@raspberrypi:~/testNFCP2P $ PN532_LOGGING=debug node index.js
DEPRECATION: Please use `require('serialport')` instead of `require('serialport').SerialPort`
debug: [frame-emitter] listening to data
debug: [hsu] Initializing serial port...
debug: [hsu] Serial port initialized.
info: [pn532] Configuring secure access module (SAM)...
debug: [pn532] Sending buffer: <Buffer 00 00 ff 05 fb d4 14 01 00 01 16 00>
debug: [hsu] Waking up PN532...
debug: [frame-emitter] Data received <Buffer 00 00 ff 00 ff 00 00 00 ff 02 fe d5 15 16 00>
debug: [frame-emitter] Processing buffer <Buffer 00 00 ff 00 ff 00 00 00 ff 02 fe d5 15 16 00>
debug: [frame-emitter] Frame found in buffer
info: [frame-emitter] Frame <AckFrame {"type":"Buffer","data":[0,0,255,0,255,0]}>
debug: [pn532] Response received for sendCommand <AckFrame {"type":"Buffer","data":[0,0,255,0,255,0]}>
info: [pn532] Command Acknowledged <AckFrame {"type":"Buffer","data":[0,0,255,0,255,0]}>
debug: [frame-emitter] AckFrame found in buffer
debug: [frame-emitter] Processing buffer <Buffer 00 00 ff 02 fe d5 15 16 00>
debug: [frame-emitter] Frame found in buffer
info: [frame-emitter] Frame <DataFrame {"data":{"command":21,"body":{"type":"Buffer","data":[22]}}}>
debug: [pn532] Response received for sendCommand <DataFrame {"data":{"command":21,"body":{"type":"Buffer","data":[22]}}}>
info: [pn532] Command Response <DataFrame {"data":{"command":21,"body":{"type":"Buffer","data":[22]}}}>
debug: [pn532] Removing listeners
debug: [frame-emitter] DataFrame found in buffer
info: [pn532] Emulating tag...
commandBuffer : 140,5,8,0,18,52,86,96,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
debug: [pn532] Sending buffer: <Buffer 00 00 ff 27 d9 d4 8c 05 08 00 12 34 56 60 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 97 00>
debug: [frame-emitter] Data received <Buffer 00 00 ff 00 ff 00>
debug: [frame-emitter] Processing buffer <Buffer 00 00 ff 00 ff 00>
debug: [frame-emitter] Frame found in buffer
info: [frame-emitter] Frame <AckFrame {"type":"Buffer","data":[0,0,255,0,255,0]}>
debug: [pn532] Response received for sendCommand <AckFrame {"type":"Buffer","data":[0,0,255,0,255,0]}>
info: [pn532] Command Acknowledged <AckFrame {"type":"Buffer","data":[0,0,255,0,255,0]}>
debug: [frame-emitter] AckFrame found in buffer
debug: [frame-emitter] Data received <Buffer 00 00 ff 05 fb d5 8d 08>
debug: [frame-emitter] Processing buffer <Buffer 00 00 ff 05 fb d5 8d 08>
debug: [frame-emitter] Data received <Buffer e0 50 66 00>
debug: [frame-emitter] Processing buffer <Buffer 00 00 ff 05 fb d5 8d 08 e0 50 66 00>
debug: [frame-emitter] Frame found in buffer
info: [frame-emitter] Frame <DataFrame {"data":{"command":141,"body":{"type":"Buffer","data":[8,224,80,102]}}}>
debug: [pn532] Response received for sendCommand <DataFrame {"data":{"command":141,"body":{"type":"Buffer","data":[8,224,80,102]}}}>
info: [pn532] Command Response <DataFrame {"data":{"command":141,"body":{"type":"Buffer","data":[8,224,80,102]}}}>
debug: [pn532] Removing listeners
debug: [frame-emitter] DataFrame found in buffer
debug: [pn532] body <Buffer 08 e0 50 66>
mode 8
debug: [pn532] mode 8
emulateTag initialized
info: [pn532] Emulate get data...
debug: [pn532] Sending buffer: <Buffer 00 00 ff 02 fe d4 86 a6 00>
debug: [frame-emitter] Data received <Buffer 00 00 ff 00 ff 00>
debug: [frame-emitter] Processing buffer <Buffer 00 00 ff 00 ff 00>
debug: [frame-emitter] Frame found in buffer
info: [frame-emitter] Frame <AckFrame {"type":"Buffer","data":[0,0,255,0,255,0]}>
debug: [pn532] Response received for sendCommand <AckFrame {"type":"Buffer","data":[0,0,255,0,255,0]}>
info: [pn532] Command Acknowledged <AckFrame {"type":"Buffer","data":[0,0,255,0,255,0]}>
debug: [frame-emitter] AckFrame found in buffer
debug: [frame-emitter] Data received <Buffer 00 00 ff 09 f7 d5 87 00>
debug: [frame-emitter] Processing buffer <Buffer 00 00 ff 09 f7 d5 87 00>
debug: [frame-emitter] Data received <Buffer a2 04 03 0b d1 01 1e 00>
debug: [frame-emitter] Processing buffer <Buffer 00 00 ff 09 f7 d5 87 00 a2 04 03 0b d1 01 1e 00>
debug: [frame-emitter] Frame found in buffer
info: [frame-emitter] Frame <DataFrame {"data":{"command":135,"body":{"type":"Buffer","data":[0,162,4,3,11,209,1,30]}}}>
debug: [pn532] Response received for sendCommand <DataFrame {"data":{"command":135,"body":{"type":"Buffer","data":[0,162,4,3,11,209,1,30]}}}>
info: [pn532] Command Response <DataFrame {"data":{"command":135,"body":{"type":"Buffer","data":[0,162,4,3,11,209,1,30]}}}>
debug: [pn532] Removing listeners
debug: [frame-emitter] DataFrame found in buffer
debug: [pn532] Frame data from emulate get data read: <Buffer 00 a2 04 03 0b d1 01 1e>
debug: [pn532] data <Buffer 01 1e>
debug: [pn532] instruction 4
debug: [pn532] parameter1 3
debug: [pn532] parameter2 11
debug: [pn532] commandLength 209
debug: [pn532] data <Buffer 01 1e>
Final data read :
dataRead :  <Buffer 01 1e>
```

@Zhairgling
Copy link
Author

Hi @techniq did you have any news ?
I am a little in trouble on my side .

@techniq
Copy link
Owner

techniq commented Feb 6, 2017

@Zhairgling Sorry, I haven't had a chance to look at this any more, and just picked up an overtime project at my work so I'm going to be pretty busy for a while. I'll let you know if I do get some time to look into it, but I wouldn't expect anything from me for a bit.

@Zhairgling
Copy link
Author

@techniq
Hi, I understand, I wish you success in your work.
Currently it happens that this project is for my work too.
I hope that I will find a solution too.

@danield12
Copy link

I have a question and am relative new to coding. I want to grab the data and compare it to a variable. For example if I want to read a block and store it as variable X then compare it to variable Y.

How would I store what nfc.PrintHexChar(data, 16); prints into variable X?

@techniq
Copy link
Owner

techniq commented Feb 14, 2017

@danield12, you would do the following:

var x = nfc.PrintHexChar(data, 16);

although this library does not have a PrintHexChar function so I'm not sure if you're in the right issues :)

@Zhairgling
Copy link
Author

Hi @techniq did you have any news ?
I'm stuck with this project.
Yet I feel that we are approaching the goal.

@Zhairgling
Copy link
Author

@techniq

I've worked on the 2 functions,

emulateTag and emulateGetData.

here is the code, could you please read and say what do you think about that.

'use strict';
var util = require('util');
//var Promise = require('bluebird');
var EventEmitter = require('events').EventEmitter;

var setupLogging = require('./logs');
setupLogging(process.env.PN532_LOGGING);
var logger = require('winston').loggers.get('pn532');

var FrameEmitter = require('./frame_emitter').FrameEmitter;
var frame = require('./frame');
var DataFrame = frame.DataFrame;
var AckFrame = frame.AckFrame;
var c = require('./constants');

class PN532 extends EventEmitter {
    /*
        @constructor
        @param {object} hal - An instance of node-serialport's SerialPort or node-i2c's i2c
    */
    constructor(hal, options) {
        super();
        options = options || {};
        this.pollInterval = options.pollInterval || 1000;

        if (hal.constructor.name === 'SerialPort') {
            var PN532_UART = require('./pn532_uart');
            this.hal = new PN532_UART(hal);
        } else if (hal.constructor.name === 'i2c') {
            var PN532_I2C = require('./pn532_i2c');
            this.hal = new PN532_I2C(hal);
        } else {
            throw new Error('Unknown hardware type: ', hal.constructor.name);
        }

        this.frameEmitter = new FrameEmitter(this.hal);
        this.hal.init().then(() => {
            this.configureSecureAccessModule().then(() => this.emit('ready'));
        });

        this.on('newListener', (event) => {
            // TODO: Only poll once (for each event type)
            if (event === 'tag') {
                logger.debug('Polling for tag scans...');
                var scanTag = () => {
                    this.scanTag().then((tag) => {
                        this.emit('tag', tag);
                        setTimeout(() => scanTag(), this.pollInterval);
                    });
                };
                scanTag();
            }
        });
    }

    sendCommand(commandBuffer) {
        return new Promise((resolve, reject) => {

            var removeListeners = () => {
                logger.debug('Removing listeners');
                this.frameEmitter.removeListener('frame', onFrame);
                this.frameEmitter.removeListener('error', onError);
            };

            // Wire up listening to wait for response (or error) from PN532
            var onFrame = (frame) => {
                logger.debug('Response received for sendCommand', util.inspect(frame));
                // TODO: If no ACK after 15ms, resend? (page 40 of user guide, UART only)?

                if (frame instanceof AckFrame) {
                    logger.info('Command Acknowledged', util.inspect(frame));
                } else if (frame instanceof DataFrame) {
                    logger.info('Command Response', util.inspect(frame));
                    removeListeners();
                    resolve(frame);
                }
            };
            this.frameEmitter.on('frame', onFrame);

            var onError = (error) => {
                logger.error('Error received for sendCommand', error);
                removeListeners();
                reject(error);
            };
            this.frameEmitter.on('error', onError);

            // Send command to PN532
            var dataFrame = new DataFrame(commandBuffer);
            var buffer = dataFrame.toBuffer();
            logger.debug('Sending buffer:', util.inspect(buffer));
            this.hal.write(buffer);
        });
    }

    configureSecureAccessModule() {
        logger.info('Configuring secure access module (SAM)...');

        // TODO: Test IRQ triggered reads

        var timeout = 0x00;  // 0x00-0xFF (12.75 seconds).  Only valid for Virtual card mode (SAMCONFIGURATION_MODE_VIRTUAL_CARD)

        var commandBuffer = [
            c.COMMAND_SAMCONFIGURATION,
            c.SAMCONFIGURATION_MODE_NORMAL,
            timeout,
            c.SAMCONFIGURATION_IRQ_ON // Use IRQ pin
        ];
        return this.sendCommand(commandBuffer);
    }

    getFirmwareVersion() {
        logger.info('Getting firmware version...');

        return this.sendCommand([c.COMMAND_GET_FIRMWARE_VERSION])
            .then((frame) => {
                var body = frame.getDataBody();
                return {
                    IC: body[0],
                    Ver: body[1],
                    Rev: body[2],
                    Support: body[3]
                };
            });
    }

    getGeneralStatus() {
        logger.info('Getting general status...');

        return this.sendCommand([c.COMMAND_GET_GENERAL_STATUS])
            .then((frame) => {
                var body = frame.getDataBody();
                return body;
            });
    }

    scanTag() {
        logger.info('Scanning tag...');

        var maxNumberOfTargets = 0x01;
        var baudRate = c.CARD_ISO14443A;

        var commandBuffer = [
            c.COMMAND_IN_LIST_PASSIVE_TARGET,
            maxNumberOfTargets,
            baudRate
        ];

        return this.sendCommand(commandBuffer)
            .then((frame) => {
                var body = frame.getDataBody();
                logger.debug('body', util.inspect(body));

                var numberOfTags = body[0];
                if (numberOfTags === 1) {
                    var tagNumber = body[1];
                    var uidLength = body[5];

                    var uid = body.slice(6, 6 + uidLength)
                                  .toString('hex')
                                  .match(/.{1,2}/g)
                                  .join(':');

                    return {
                        ATQA: body.slice(2, 4), // SENS_RES
                        SAK: body[4],           // SEL_RES
                        uid: uid
                    };
                }
            });
    }

    readBlock(options) {
        logger.info('Reading block...');

        var options = options || {};

        var tagNumber = options.tagNumber || 0x01;
        var blockAddress = options.blockAddress || 0x01;

        var commandBuffer = [
            c.COMMAND_IN_DATA_EXCHANGE,
            tagNumber,
            c.MIFARE_COMMAND_READ,
            blockAddress,
        ];

        return this.sendCommand(commandBuffer)
            .then((frame) => {
                var body = frame.getDataBody();
                logger.debug('Frame data from block read:', util.inspect(body));

                var status = body[0];

                if (status === 0x13) {
                    logger.warn('The data format does not match to the specification.');
                }
                var block = body.slice(1, body.length - 1); // skip status byte and last byte (not part of memory)
                // var unknown = body[body.length];

                return block;
        });
    }

    readNdefData() {
        logger.info('Reading data...');

        return this.readBlock({blockAddress: 0x04})
            .then((block) => {
                logger.debug('block:', util.inspect(block));

                // Find NDEF TLV (0x03) in block of data - See NFC Forum Type 2 Tag Operation Section 2.4 (TLV Blocks)
                var ndefValueOffset = null;
                var ndefLength = null;
                var blockOffset = 0;

                while (ndefValueOffset === null) {
                    logger.debug('blockOffset:', blockOffset, 'block.length:', block.length);
                    if (blockOffset >= block.length) {
                        throw new Error('Unable to locate NDEF TLV (0x03) byte in block:', block)
                    }

                    var type = block[blockOffset];       // Type of TLV
                    var length = block[blockOffset + 1]; // Length of TLV
                    logger.debug('blockOffset', blockOffset);
                    logger.debug('type', type, 'length', length);

                    if (type === c.TAG_MEM_NDEF_TLV) {
                        logger.debug('NDEF TLV found');
                        ndefLength = length;                  // Length proceeds NDEF_TLV type byte
                        ndefValueOffset = blockOffset + 2;    // Value (NDEF data) proceeds NDEV_TLV length byte
                        logger.debug('ndefLength:', ndefLength);
                        logger.debug('ndefValueOffset:', ndefValueOffset);
                    } else {
                        // Skip TLV (type byte, length byte, plus length of value)
                        blockOffset = blockOffset + 2 + length;
                    }
                }

                var ndefData = block.slice(ndefValueOffset, block.length);
                var additionalBlocks = Math.ceil((ndefValueOffset + ndefLength) / 16) - 1;
                logger.debug('Additional blocks needing to retrieve:', additionalBlocks);

                // Sequentially grab each additional 16-byte block (or 4x 4-byte pages) of data, chaining promises
                var self = this;
                var allDataPromise = (function retrieveBlock(blockNum) {
                    if (blockNum <= additionalBlocks) {
                        var blockAddress = 4 * (blockNum + 1);
                        logger.debug('Retrieving block:', blockNum, 'at blockAddress:', blockAddress);
                        return self.readBlock({blockAddress: blockAddress})
                            .then(function(block) {
                                blockNum++;
                                ndefData = Buffer.concat([ndefData, block]);
                                return retrieveBlock(blockNum);
                            });
                    }
                })(1);

                return allDataPromise.then(() => ndefData.slice(0, ndefLength));
            })
            .catch(function(error) {
                logger.error('ERROR:', error);
            });
    }

    writeBlock(block, options) {
        logger.info('Writing block...');

        var options = options || {};

        var tagNumber = options.tagNumber || 0x01;
        var blockAddress = options.blockAddress || 0x01;

        var commandBuffer = [].concat([
            c.COMMAND_IN_DATA_EXCHANGE,
            tagNumber,
            c.MIFARE_COMMAND_WRITE_4,
            blockAddress
        ],  block);

        return this.sendCommand(commandBuffer)
            .then((frame) => {
                var body = frame.getDataBody();
                logger.debug('Frame data from block write:', util.inspect(body));

                var status = body[0];

                if (status === 0x13) {
                    logger.warn('The data format does not match to the specification.');
                }
                var block = body.slice(1, body.length - 1); // skip status byte and last byte (not part of memory)
                // var unknown = body[body.length];

                return block;
            });
    }

    writeNdefData(data) {
        logger.info('Writing data...');

        // Prepend data with NDEF type and length (TLV) and append terminator TLV
        var block = [].concat([
            c.TAG_MEM_NDEF_TLV,
            data.length
        ],  data, [
            c.TAG_MEM_TERMINATOR_TLV
        ]);

        logger.debug('block:', util.inspect(new Buffer(block)));

        var PAGE_SIZE = 4;
        var totalBlocks = Math.ceil(block.length / PAGE_SIZE);

        // Sequentially write each additional 4-byte pages of data, chaining promises
        var self = this;
        var allPromises = (function writeBlock(blockNum) {
            if (blockNum < totalBlocks) {
                var blockAddress = 0x04 + blockNum;
                var pageData = block.splice(0, PAGE_SIZE);

                if (pageData.length < PAGE_SIZE) {
                    pageData.length = PAGE_SIZE; // Setting length will make sure NULL TLV (0x00) are written at the end of the page
                }

                logger.debug('Writing block:', blockNum, 'at blockAddress:', blockAddress);
                logger.debug('pageData:', util.inspect(new Buffer(pageData)));
                return self.writeBlock(pageData, {blockAddress: blockAddress})
                .then(function(block) {
                    blockNum++;
                    // ndefData = Buffer.concat([ndefData, block]);
                    return writeBlock(blockNum);
                });
            }
        })(0);

        // return allDataPromise.then(() => ndefData.slice(0, ndefLength));
        return allPromises;
    }

    // WIP
    authenticateBlock(uid, options) {
        logger.info('Authenticating block...');

        var options = options || {};

        var blockAddress = options.blockAddress || 0x04;
        var authType = options.authType || c.MIFARE_COMMAND_AUTH_A
        var authKey = options.authKey || [0xff, 0xff, 0xff, 0xff, 0xff, 0xff];
        var tagNumber = options.tagNumber || 0x01;
        var uidArray = uid.split(':').map(s => Number('0x' + s));

        var commandBuffer = [
            c.COMMAND_IN_DATA_EXCHANGE,
            tagNumber,
            authType,
            blockAddress
        ].concat(authKey).concat(uidArray);

        return this.sendCommand(commandBuffer)
        .then((frame) => {
            var body = frame.getDataBody();
            logger.info('Frame data from mifare classic authenticate', util.inspect(body));

            console.log('body', body);
            return body;

            // var status = body[0];
            // var tagData = body.slice(1, body.length);

            // return {
            //     status: status.toString(16),
            //     tagData: tagData
            // };
        });
    }

     emulateTag() {
        logger.info('Emulating tag...');
        var commAsTarget= 0x8C;
        var mode = 0x05; // PICC only, Passive Only
        var sens_res = [0x04, 0x00];
        var nfcId1t = [0x00, 0x00, 0x00];
        var sel_res = [0x20];
        var mifareParams = [].concat(sens_res, nfcId1t, sel_res);

        var felicaParams = [0x01,0xFE,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,
                           0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,
                           0xFF,0xFF];

        var nfcId3t = [0xAA,0x99,0x88,0x77,0x66,0x55,0x44,0x33,0x22,0x11];
        var generalBytesLength = 0;
        var historicalBytesLength =  0;
        var commandBuffer = [].concat(
            commAsTarget,
            mode,
            mifareParams,
            felicaParams,
            nfcId3t,
            generalBytesLength,
            historicalBytesLength
        );
        console.log('commandBuffer : '+ commandBuffer);
        return this.sendCommand(commandBuffer)
        .then((frame) => {
            var body = frame.getDataBody();
            logger.debug('body', util.inspect(body));
            var mode = body[0];
            console.log('mode', mode);
            logger.debug('mode', mode);
          /*   var initiatorCommand = 0x88;
             var numberOfTags = body[0];
             if (numberOfTags === 1) {
                 var tagNumber = body[1];
                 var uidLength = body[5];
            
                 var uid = body.slice(6, 6 + uidLength)
                 .toString('hex')
                 .match(/.{1,2}/g)
                 .join(':');
            
                 return {
                     ATQA: body.slice(2, 4), // SENS_RES
                     SAK: body[4],           // SEL_RES
                     uid: uid
                 };
             }*/
        });
    }
    
    emulateGetData() {
        logger.info('Emulate get data...');

        return this.sendCommand([c.TG_GET_DATA])//0x86
        .then((frame) => {
            var body = frame.getDataBody();
            logger.debug('Frame data from emulate get data read:', util.inspect(body));
            var status = body[0];
            if (status === 0x13) {
                logger.warn('The data format does not match to the specification.');
            }
            // var dataIn = body.slice(1, body.length - 1); // skip status byte and last byte (not part of memory)
            // 00 00 a4 04 00 07 d2 76 00 00 85 01 01 00 26
            var cla = body[1]
            var instruction = body[2];
            var parameter1 = body[3];
            var parameter2 = body[4];
            var commandLength = body[5];
            var data = body.slice(6, commandLength);
            logger.debug('status', status);

            logger.debug('instruction', instruction);
            logger.debug('parameter1', parameter1);
            logger.debug('parameter2', parameter2);
            logger.debug('commandLength', commandLength);
            logger.debug('data', util.inspect(data));
            logger.debug('Final data read : '+data);


  switch(instruction) {
                case c.ISO7816_SELECT_FILE:
                    logger.info('Select file');
                    if (parameter1 === 0x00) {
                        logger.info('Select by Id');
                    }
                    if (parameter1 === 0x04) {
                        logger.info('Select by name');
                    }
                case c.C_APDU_P1_SELECT_BY_ID:
                        if(parameter2 != 0x0c){
                          //  DMSG("C_APDU_P2 != 0x0c\n");
                           // setResponse(COMMAND_COMPLETE, rwbuf, &sendlen);
                        } else if(lc == 2 && rwbuf[c.C_APDU_DATA] == 0xE1 && (rwbuf[c.C_APDU_DATA+1] == 0x03 || rwbuf[c.C_APDU_DATA+1] == 0x04)){
                         //   setResponse(COMMAND_COMPLETE, rwbuf, &sendlen);
                            if(rwbuf[C_APDU_DATA+1] == 0x03){
                                currentFile = CC;
                            } else if(rwbuf[C_APDU_DATA+1] == 0x04){
                                currentFile = NDEF;
                            }
                        } else {
                          //  setResponse(TAG_NOT_FOUND, rwbuf, &sendlen);
                        }
                        break;
                case c.C_APDU_P1_SELECT_BY_NAME:
                        logger.info('c la ==============================================');
                     //   const uint8_t ndef_tag_application_name_v2[] = {0, 0x7, 0xD2, 0x76, 0x00, 0x00, 0x85, 0x01, 0x01 };
                        //if(0 == memcmp(ndef_tag_application_name_v2, rwbuf + c.C_APDU_P2, sizeof(ndef_tag_application_name_v2))){
                        logger.info('ca passe');

                          //  setResponse(COMMAND_COMPLETE, rwbuf, &sendlen);
                        return  this.sendCommand([c.R_APDU_SW1_COMMAND_COMPLETE,c.R_APDU_SW2_COMMAND_COMPLETE]);
                       // } else{
                       //     DMSG("function not supported\n");
                           // setResponse(FUNCTION_NOT_SUPPORTED, rwbuf, &sendlen);
                       // }
                        break;
                    break;
                case c.ISO7816_READ_BINARY:
                    logger.info('Read binary');
                    break;
                case c.ISO7816_UPDATE_BINARY:
                    logger.info('Update binary');
                    break;
                default:
                    logger.warn('Command not supported');
            }



            return data;
        });
    }

    emulateSetData(data) {
        logger.info('Writing data... bon code');
         // Prepend data with NDEF type and length (TLV) and append terminator TLV
         var block = [].concat([
             c.TAG_MEM_NDEF_TLV,
             data.length
             ],  data, [
             c.TAG_MEM_TERMINATOR_TLV
             ]);
        
             logger.debug('block:', util.inspect(new Buffer(block)));
        
             var PAGE_SIZE = 4;
             var totalBlocks = Math.ceil(block.length / PAGE_SIZE);
        
             // Sequentially write each additional 4-byte pages of data, chaining promises
             var self = this;
             var allPromises = (function writeBlock(blockNum) {
                 if (blockNum < totalBlocks) {
                     var blockAddress = 0x04 + blockNum;
                     var pageData = block.splice(0, PAGE_SIZE);
        
                     if (pageData.length < PAGE_SIZE) {
                         pageData.length = PAGE_SIZE; // Setting length will make sure NULL TLV (0x00) are written at the end of the page
                     }
        
                     logger.debug('Writing block:', blockNum, 'at blockAddress:', blockAddress);
                     logger.debug('pageData:', util.inspect(new Buffer(pageData)));
                     return self.writeBlock(pageData, {blockAddress: blockAddress})
                     .then(function(block) {
                         blockNum++;
                         // ndefData = Buffer.concat([ndefData, block]);
                         return writeBlock(blockNum);
                     });
                 }
             })(0);
        
             // return allDataPromise.then(() => ndefData.slice(0, ndefLength));
             return allPromises;
        // }
    }
    
}

exports.PN532 = PN532;
exports.I2C_ADDRESS = c.I2C_ADDRESS;

@techniq
Copy link
Owner

techniq commented Feb 23, 2017

@Zhairgling Sorry, I've just not had time to get back with you. I'm overcommitted as it is with my work/overtime I just don't have any time right now to help (at the level you need right now).

@Zhairgling
Copy link
Author

@techniq Hi can now make P2P exchange ;)
Thanks for all the help you give me. If you want more informations i let you come to me.
BTW you can now close this issue

@techniq
Copy link
Owner

techniq commented Mar 13, 2017 via email

@techniq techniq mentioned this issue May 22, 2017
@Coollision
Copy link

hi i am trying to get card emulation working, so my android phone can read some data from my rpi. I have had no luck in trying to get the my phone read anything from the card emulation..... while using nfc tools.... i can have my pn532 read some tags....

@techniq
Copy link
Owner

techniq commented Apr 24, 2018

@Coollision I never got around to merging in @Zhairgling branch and never received a PR. I'm pretty sure he had success with emulation, so maybe give his fork a try and if it works for you, would you care to send a PR this way and I'll cut a release?

@Zhairgling
Copy link
Author

@Coollision I don't have any time and ressources atm for that PR. you can use my fork and do the job if you want. I did not try with android but between 2 rpi it works pretty well .

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants