techniq / node-pn532

Native Node.js driver for the PN532 NFC chip
70 stars 31 forks source link

Card emulation #12

Open Zhairgling opened 7 years ago

Zhairgling commented 7 years ago

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

Zhairgling commented 7 years ago

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 commented 7 years ago

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 commented 7 years ago

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 commented 7 years ago

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 commented 7 years ago

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 commented 7 years ago

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 commented 7 years ago

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 commented 7 years ago

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).

Zhairgling commented 7 years ago

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 commented 7 years ago

I would definitely use the master branch and not the old branch. Will make merging easier.

On Wed, Jan 25, 2017, 5:35 AM Zhairgling notifications@github.com wrote:

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?

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/techniq/node-pn532/issues/12#issuecomment-275074312, or mute the thread https://github.com/notifications/unsubscribe-auth/AAK1RIPxRZdO1CJa84nGKkqECvfEzQ6eks5rVyWIgaJpZM4LsF1P .

Zhairgling commented 7 years ago

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 commented 7 years ago

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 commented 7 years ago

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 commented 7 years ago

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 commented 7 years ago

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 commented 7 years ago

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 commented 7 years ago

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 commented 7 years ago

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 commented 7 years ago

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 commented 7 years ago

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 commented 7 years ago

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 commented 7 years ago

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 commented 7 years ago

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

techniq commented 7 years ago

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)

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


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 commented 7 years ago

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 commented 7 years ago

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:

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 commented 7 years ago

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 commented 7 years ago

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:

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 commented 7 years ago

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:

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 commented 7 years ago

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 commented 7 years ago

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 commented 7 years ago

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

techniq commented 7 years ago

@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 commented 7 years ago

@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 commented 7 years ago

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 commented 7 years ago

@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 commented 7 years ago

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

Zhairgling commented 7 years ago

@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 commented 7 years ago

@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 commented 7 years ago

@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 commented 7 years ago

Awesome. Glad you were able to figure it out. Can you commit your changes to your fork so I can see them?

On Mon, Mar 13, 2017, 5:18 AM Zhairgling notifications@github.com wrote:

@techniq https://github.com/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

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/techniq/node-pn532/issues/12#issuecomment-286052946, or mute the thread https://github.com/notifications/unsubscribe-auth/AAK1RHSty_Fl6mW4r0MkSM_GDAaZT1Cxks5rlQnLgaJpZM4LsF1P .

Coollision commented 6 years ago

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 commented 6 years ago

@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 commented 6 years ago

@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 .