Using PN532 to WRITE to a TYPE 4 TAG

Hello all, 

I have scoured the devzone and other blogspots to find an answer to this but so far have come up short. 

in short i want to use one NRF552-DK with the adafruit PN532 shield to read and write another data from another nrf52dk acting as a regular type 4 NFC tag.

Looking at the drivers for the shield and for the PN532 chip directly it seems like the chip should be able to write to a tag of this type but there is not a prewritten function in the driver. I'm fine with writing this on m own I just want to know if its indeed possible for the PN532 to write data to the tag. So far I know the following:

  1. The PN532 shield can successfully READ data from the T4T
  2. a phone app "NFC" for iOS can WRITE data to the T4T (more specifically the NFC_T4T_EVENT_NDEF_UPDATED event is raised on the nordic chip acting as a tag)
  3. The PN52 shield can successfully write RAW data to the T4T (the NFC_T4T_EVENT_DATA_IND event is raised when running the nfc uart examples on the respective dev kits)

My goal is to send a custom binary data in the form of an ndef message from the reader to the T4T but when I use the "adafruit_pn532_in_data_exchange()" function the error_code it returns is zero however the NFC_T4T_EVENT_NDEF_UPDATED event is never raised on the tag side.

I know this is not so much a question about the nordic chip as it is the PN532 but I find it strange there is not a working example on the poller side for how to write an NDEF message, this makes me think that maybe its not possible with the PN532? if so i'm happy to buy a different reader board

Thanks,

Patjshan

  • What library are your using with the PN532? Does your lib supports ISO1443-4 APDUs? 

  • I'm using the adafruit_pn532 files that come with the SDK in the adafruit_tag_reader example. According to the documentation for the PN532 itself it does support ISO1443-4 

    PN532 Manual (page 131 has info on using the INDATAEXCHANGE command with ISO1443-3 tags) : www.nxp.com/.../141520.pdf

    /** @brief Function for exchanging an Application Protocol Data Unit (APDU) with the currently enlisted peer.
     *
     *   @param[in]     p_send                 Pointer to the data to send.
     *   @param[in]     send_len               Length of the data to send.
     *   @param[out]    p_response             Pointer to the buffer for response data.
     *   @param[in,out] p_response_len         Pointer to the variable that stores
     *                                         the length of the p_response buffer (as
     *                                         input) and the length of the response data
     *                                         (as output).
     *
     *   @retval        NRF_SUCCESS            If the function completed successfully. Otherwise,
     *                                         an error code is returned.
     */
    ret_code_t adafruit_pn532_in_data_exchange(uint8_t * p_send,
                                               uint8_t   send_len,
                                               uint8_t * p_response,
                                               uint8_t * p_response_len);

    and this is the declaration of the function from the drivers from Nordic. maybe I'm mistaken but this would have me believe that I just need to pass the output of the ndef_message_encode() function as the "p_send" argument and specify the length and give it a response buffer and this should update the value on the tag but the event is not being raised.

  • UPDATE: I haven't tried it yet but i did find what I believe will solve the issue. I was not first wrapping my ndef message in the correct capability container before sending the message. Using the function "nfc_t4t_ndef_update()" (in nfc_t4t_hl_detection_procedures.c/h") and passing argument 1 as the cc_file of the target,, followed by the ndef message you wish to send and the size of that message should do the trick I think, but I will update once I try it out

  • ANSWER: I totally missed this page in the infocenter 

    https://infocenter.nordicsemi.com/topic/sdk_nrf5_v17.1.0/nfc_t4t_hl_detection_procedures_dox.html

    which documents how to update an nfc type 4 tag. I will say the documentation for the functions is subpar but it seems like this is intentional to keep the specification behind the NFC forum paywall. the procedure outlined here works, but for anyone else that might find it helpful, I separated out the nfc_t4t_update function from the detection (reading) of the tag and call it in a separate function. this works so long as you still instantiate the cc_file and go through the process of selecting the file and whatnot before actually writing you're message to the ndef file. And it would seem you have to prepend the NLEN value to the ndef message yourself as it is not, as I thought it was, generated automatically by the nfc_ndef_msg_encode() function.

    ret_code_t t4t_data_update(uint8_t * ndef_message, uint8_t ndef_message_size){
       NFC_T4T_CC_DESC_DEF(cc_file, MAX_TLV_BLOCKS);
       uint32_t err_code;
       static uint8_t updated_ndef_file[MAX_TLV_BLOCKS][TAG_TYPE_4_NDEF_FILE_SIZE];
    
       err_code = nfc_t4t_ndef_tag_app_select();
       T4T_ERROR_HANDLE(err_code, "Error (0x%X) during NDEF Tag Application Select Procedure.");
    
       err_code = nfc_t4t_cc_select();
       T4T_ERROR_HANDLE(err_code, "Error (0x%X) during CC Select Procedure.");
    
       nfc_t4t_capability_container_t * cc_file = &NFC_T4T_CC_DESC(cc_file);
       err_code = nfc_t4t_cc_read(cc_file);
       T4T_ERROR_HANDLE(err_code, "Error (0x%X) during CC Read Procedure.");
    
        nfc_t4t_tlv_block_t * p_tlv_block = cc_file->p_tlv_block_array;
        uint32_t              i;
      
        p_tlv_block = cc_file->p_tlv_block_array;
        
        // this only runs once in my case, but yours may be different
        for (i = 0; i < cc_file->tlv_count; i++)
        {
        // set the NLEN field value
           memset(updated_ndef_file[i], 0, 1);
           memset(&updated_ndef_file[i][1], ndef_message, 1);
           
        // now copy the ndef message into the ndef file
           memcpy(&updated_ndef_file[i][2], ndef_message, ndef_message_size);
           
           if ((p_tlv_block->type == NDEF_FILE_CONTROL_TLV) ||
           (p_tlv_block->value.write_access == CONTROL_FILE_WRITE_ACCESS_GRANTED))
           {
           err_code = nfc_t4t_file_select(p_tlv_block->value.file_id);
           if (err_code != NRF_SUCCESS)
           {
           //Error during NDEF Select Procedure.
           return err_code;
           }
           err_code = nfc_t4t_ndef_update(cc_file, updated_ndef_msg[i], ndef_message_size + NLEN_FIELD_SIZE);
           if (err_code != NRF_SUCCESS)
           {
           //Error during NDEF update procedure.
           return err_code;
           }
           }
           p_tlv_block++;
          }
          return NRF_SUCCESS;
    }

    after using this code I now receive the NFC_T4T_EVENT_NDEF_UPDATED event on the tag side

  • Thanks! This code really helped me to my solution. I did have some difficulty with setting up the ndef_file message. If you use the function nfc_ndef_file_encode you don't need to use the memset functions, and you can just use nfc_t4t_ndef_update without adding the NLEN_FIELD_SIZE.

    The memcpy and nfc_t4t_ndef_update would then look like this:

    memcpy(&updated_ndef_file[i][0], ndef_message, ndef_message_size);
    
    err_code = nfc_t4t_ndef_update(cc_file, updated_ndef_msg[i], ndef_message_size);

    And for completion, this is an example of what i used to setup my ndef file:

    #define LANG_LEN 2
    #define EXAMPLE_SIZE 7
    static const uint8_t en_code[LANG_LEN] = {'e', 'n'};
    static const uint8_t exampleWrite[EXAMPLE_SIZE] = {'e','x','a','m','p','l','e'};
    
    static int ndef_write_message(uint8_t *ndef_message, uint32_t *ndef_message_size)
    {
        int err;
    	*ndef_message_size  = nfc_t4t_ndef_file_msg_size_get(*ndef_message_size);
    
    	NFC_NDEF_TEXT_RECORD_DESC_DEF(nfc_text_example,
    								  UTF_8,
    								  en_code,
    								  sizeof(en_code),
    									exampleWrite,
    								  sizeof(exampleWrite));					  					  
    
    	NFC_NDEF_MSG_DEF(nfc_text_msg, 1);
    
    	err = nfc_ndef_msg_record_add(&NFC_NDEF_MSG(nfc_text_msg),
    				   &NFC_NDEF_TEXT_RECORD_DESC(nfc_text_example));
    	if (err) {
    		printk("Cannot add record!\n");
    		return err;
    	}		   
    				  							  
    	err = nfc_ndef_msg_encode(&NFC_NDEF_MSG(nfc_text_msg),
    				      nfc_t4t_ndef_file_msg_get(ndef_message),
    				      ndef_message_size);
    	if (err)
    	{
    		printk("Cannot encode NDEF message!\n");
    		return err;
    	}
    	err = nfc_t4t_ndef_file_encode(ndef_message, ndef_message_size);
    	if (err)
    	{
    		printk("Cannot encode NDEF file, err: %d!\n",err);
    		return err;
    	}
    	return 0;
    }

Related