From 70ede60e304584313b04b8b2b119100b831a441c Mon Sep 17 00:00:00 2001 From: Romuald Conty Date: Thu, 3 Sep 2009 13:47:26 +0000 Subject: [PATCH] Add NFCIP (NDEP) as experimental feature (Thanks to Fkooman). --- src/Makefile.am | 8 +++- src/initiator.c | 37 +++++++++++++++++ src/libnfc.c | 108 +++++++++++++++++++++++++++++++++++++++++++++++- src/libnfc.h | 41 ++++++++++++++++++ src/target.c | 31 ++++++++++++++ src/types.h | 16 ++++++- 6 files changed, 238 insertions(+), 3 deletions(-) create mode 100644 src/initiator.c create mode 100644 src/target.c diff --git a/src/Makefile.am b/src/Makefile.am index d105999..bd74061 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1,6 +1,6 @@ enable_pcsc_lite = @enable_pcsc_lite@ -bin_PROGRAMS = nfc-anticol nfc-list nfc-mftool nfc-mfultool nfc-relay nfc-emulate +bin_PROGRAMS = nfc-anticol nfc-list nfc-mftool nfc-mfultool nfc-relay nfc-emulate nfcip-target nfcip-initiator # set the include path found by configure INCLUDES= $(all_includes) @@ -38,6 +38,12 @@ nfc_relay_LDADD = libnfc.la nfc_emulate_SOURCES = emulate.c nfc_emulate_LDADD = libnfc.la +nfcip_target_SOURCES = target.c +nfcip_target_LDADD = libnfc.la + +nfcip_initiator_SOURCES = initiator.c +nfcip_initiator_LDADD = libnfc.la + dist_man_MANS = nfc-anticol.1 nfc-emulate.1 nfc-list.1 nfc-mftool.1 nfc-relay.1 #dist_man_MANS = $(man_MANS) #EXTRA_DIST = $(man_MANS) diff --git a/src/initiator.c b/src/initiator.c new file mode 100644 index 0000000..c3e4d95 --- /dev/null +++ b/src/initiator.c @@ -0,0 +1,37 @@ +#include +#include +#include "libnfc.h" + +int main(int argc, const char *argv[]) +{ + dev_info *pdi; + tag_info ti; + byte_t abtRecv[MAX_FRAME_LEN]; + uint32_t uiRecvBits; + byte_t send[] = "Hello World!"; + + pdi = nfc_connect(); + if (!pdi || !nfc_initiator_init(pdi) + || !nfc_initiator_select_dep_target(pdi, IM_PASSIVE_DEP, NULL, 0, + NULL, 0, NULL, 0, &ti)) { + printf + ("unable to connect, initialize, or select the target\n"); + return 1; + } + + printf("Sending : %s\n", send); + if (!nfc_initiator_transceive_dep_bytes(pdi, + send, + strlen(send), abtRecv, + &uiRecvBits)) { + printf("unable to send data\n"); + return 1; + } + + abtRecv[uiRecvBits] = 0; + printf("Received: %s\n", abtRecv); + + nfc_initiator_deselect_tag(pdi); + nfc_disconnect(pdi); + return 0; +} diff --git a/src/libnfc.c b/src/libnfc.c index 8fa477a..5237382 100644 --- a/src/libnfc.c +++ b/src/libnfc.c @@ -72,6 +72,8 @@ byte_t pncmd_rf_configure_retry_select [ 6] = { 0xD4,0x32,0x05 }; // Reader byte_t pncmd_reader_list_passive [264] = { 0xD4,0x4A }; + +byte_t pncmd_reader_jump_for_dep [ 68] = { 0xD4,0x56 }; byte_t pncmd_reader_select [ 3] = { 0xD4,0x54 }; byte_t pncmd_reader_deselect [ 3] = { 0xD4,0x44,0x00 }; byte_t pncmd_reader_release [ 3] = { 0xD4,0x52,0x00 }; @@ -81,6 +83,7 @@ byte_t pncmd_reader_auto_poll [ 5] = { 0xD4,0x60 }; // Target byte_t pncmd_target_get_data [ 2] = { 0xD4,0x86 }; +byte_t pncmd_target_set_data [264] = { 0xD4,0x8E }; byte_t pncmd_target_init [ 39] = { 0xD4,0x8C }; byte_t pncmd_target_virtual_card [ 4] = { 0xD4,0x14 }; byte_t pncmd_target_receive [ 2] = { 0xD4,0x88 }; @@ -384,6 +387,53 @@ bool nfc_initiator_init(const dev_info* pdi) return true; } +bool nfc_initiator_select_dep_target(const dev_info* pdi, const init_modulation im, const byte_t* pbtPidData, const uint32_t uiPidDataLen, const byte_t* pbtNFCID3i, const uint32_t uiNFCID3iDataLen, const byte_t *pbtGbData, const uint32_t uiGbDataLen, tag_info* pti) +{ + if(im == IM_ACTIVE_DEP) { + pncmd_reader_jump_for_dep[2] = 0x01; /* active DEP */ + } + pncmd_reader_jump_for_dep[3] = 0x00; /* baud rate = 106kbps */ + + uint32_t offset = 5; + if(pbtPidData && im != IM_ACTIVE_DEP) { /* can't have passive initiator data when using active mode */ + pncmd_reader_jump_for_dep[4] |= 0x01; + memcpy(pncmd_reader_jump_for_dep+offset,pbtPidData,uiPidDataLen); + offset+= uiPidDataLen; + } + + if(pbtNFCID3i) { + pncmd_reader_jump_for_dep[4] |= 0x02; + memcpy(pncmd_reader_jump_for_dep+offset,pbtNFCID3i,uiNFCID3iDataLen); + offset+= uiNFCID3iDataLen; + } + + if(pbtGbData) { + pncmd_reader_jump_for_dep[4] |= 0x04; + memcpy(pncmd_reader_jump_for_dep+offset,pbtGbData,uiGbDataLen); + offset+= uiGbDataLen; + } + + // Try to find a target, call the transceive callback function of the current device + uiRxLen = MAX_FRAME_LEN; + if (!pdi->pdc->transceive(pdi->ds,pncmd_reader_jump_for_dep,5+uiPidDataLen+uiNFCID3iDataLen+uiGbDataLen,abtRx,&uiRxLen)) return false; + + // some error occurred... + if (abtRx[0] != 0) return false; + + // Make sure one target has been found, the PN53X returns 0x00 if none was available + if (abtRx[1] != 1) return false; + + // Is a target info struct available + if (pti) + { + memcpy(pti->tid.NFCID3i,abtRx+2,10); + pti->tid.btDID = abtRx[12]; + pti->tid.btBSt = abtRx[13]; + pti->tid.btBRt = abtRx[14]; + } + return true; +} + bool nfc_initiator_select_tag(const dev_info* pdi, const init_modulation im, const byte_t* pbtInitData, const uint32_t uiInitDataLen, tag_info* pti) { // Make sure we are dealing with a active device @@ -539,11 +589,36 @@ bool nfc_initiator_transceive_bits(const dev_info* pdi, const byte_t* pbtTx, con return true; } +bool nfc_initiator_transceive_dep_bytes(const dev_info* pdi, const byte_t* pbtTx, const uint32_t uiTxLen, byte_t* pbtRx, uint32_t* puiRxLen) { + // We can not just send bytes without parity if while the PN53X expects we handled them + if (!pdi->bPar) return false; + + // Copy the data into the command frame + pncmd_reader_exchange_data[2] = 1; /* target number */ + memcpy(pncmd_reader_exchange_data+3,pbtTx,uiTxLen); + + // To transfer command frames bytes we can not have any leading bits, reset this to zero + if (!pn53x_set_tx_bits(pdi,0)) return false; + + // Send the frame to the PN53X chip and get the answer + // We have to give the amount of bytes + (the two command bytes 0xD4, 0x42) + if (!pn53x_transceive(pdi,pncmd_reader_exchange_data,uiTxLen+3)) return false; + + // Save the received byte count + *puiRxLen = uiRxLen-1; + + // Copy the received bytes + memcpy(pbtRx,abtRx+1,*puiRxLen); + + // Everything went successful + return true; +} + bool nfc_initiator_transceive_bytes(const dev_info* pdi, const byte_t* pbtTx, const uint32_t uiTxLen, byte_t* pbtRx, uint32_t* puiRxLen) { // We can not just send bytes without parity if while the PN53X expects we handled them if (!pdi->bPar) return false; - + // Copy the data into the command frame memcpy(pncmd_exchange_raw_data+2,pbtTx,uiTxLen); @@ -700,6 +775,21 @@ bool nfc_target_receive_bits(const dev_info* pdi, byte_t* pbtRx, uint32_t* puiRx return true; } +bool nfc_target_receive_dep_bytes(const dev_info* pdi, byte_t* pbtRx, uint32_t* puiRxLen) +{ + // Try to gather a received frame from the reader + if (!pn53x_transceive(pdi,pncmd_target_get_data,2)) return false; + + // Save the received byte count + *puiRxLen = uiRxLen-1; + + // Copy the received bytes + memcpy(pbtRx,abtRx+1,*puiRxLen); + + // Everyting seems ok, return true + return true; +} + bool nfc_target_receive_bytes(const dev_info* pdi, byte_t* pbtRx, uint32_t* puiRxLen) { // Try to gather a received frame from the reader @@ -764,3 +854,19 @@ bool nfc_target_send_bytes(const dev_info* pdi, const byte_t* pbtTx, const uint3 // Everyting seems ok, return true return true; } + +bool nfc_target_send_dep_bytes(const dev_info* pdi, const byte_t* pbtTx, const uint32_t uiTxLen) +{ + // We can not just send bytes without parity if while the PN53X expects we handled them + if (!pdi->bPar) return false; + + // Copy the data into the command frame + memcpy(pncmd_target_set_data+2,pbtTx,uiTxLen); + + // Try to send the bits to the reader + if (!pn53x_transceive(pdi,pncmd_target_set_data,uiTxLen+2)) return false; + + // Everyting seems ok, return true + return true; +} + diff --git a/src/libnfc.h b/src/libnfc.h index a4916b1..5780eb5 100644 --- a/src/libnfc.h +++ b/src/libnfc.h @@ -91,6 +91,20 @@ bool nfc_initiator_init(const dev_info* pdi); */ bool nfc_initiator_select_tag(const dev_info* pdi, const init_modulation im, const byte_t* pbtInitData, const uint32_t uiInitDataLen, tag_info* pti); +/** + * @fn nfc_initiator_select_dep_target(const dev_info *pdi, const init_modulation im, const byte_t *pbtPidData, const uint32_t uiPidDataLen, const byte_t *pbtNFCID3i, const uint32_t uiNFCID3iDataLen, const byte_t *pbtGbData, const uint32_t uiGbDataLen, tag_info * pti); + * @brief Select a target and request active or passive mode for DEP (Data Exchange Protocol) + * @return Returns true if action was successfully performed; otherwise returns false. + * @param pdi dev_info struct pointer that represent currently used device + * @param im Desired modulation (IM_ACTIVE_DEP or IM_PASSIVE_DEP for active, respectively passive mode) + * @param pbtPidData passive initiator data, 4 or 5 bytes long, (optional, only for IM_PASSIVE_DEP, can be NULL) + * @param pbtNFCID3i the NFCID3, 10 bytes long, of the initiator (optional, can be NULL) + * @param pbtGbData generic data of the initiator, max 48 bytes long, (optional, can be NULL) + * + * The NFC device will try to find the available target. The standards (ISO18092 and ECMA-340) describe the modulation that can be used for reader to passive communications. + * @note tag_info_dep will be returned when the target was acquired successfully. + */ +bool nfc_initiator_select_dep_target(const dev_info* pdi, const init_modulation im, const byte_t* pbtPidData, const uint32_t uiPidDataLen, const byte_t* pbtNFCID3i, const uint32_t uiNFCID3iDataLen, const byte_t *pbtGbData, const uint32_t uiGbDataLen, tag_info* pti); /** * @fn nfc_initiator_deselect_tag(const dev_info* pdi); * @brief Deselect a selected passive or emulated tag @@ -126,6 +140,15 @@ bool nfc_initiator_transceive_bits(const dev_info* pdi, const byte_t* pbtTx, con */ bool nfc_initiator_transceive_bytes(const dev_info* pdi, const byte_t* pbtTx, const uint32_t uiTxLen, byte_t* pbtRx, uint32_t* puiRxLen); +/** + * @fn nfc_initiator_transceive_dep_bytes(const dev_info* pdi, const byte_t* pbtTx, const uint32_t uiTxLen, byte_t* pbtRx, uint32_t* puiRxLen) + * @brief Transceive data + * @return Returns true if action was successfully performed; otherwise returns false. + * + * The reader will transmit the supplied (data) bytes in pbtTx to the target (tag). It waits for the response and stores the received bytes in the pbtRx byte array. The difference between this function and nfc_initiator_transceive_bytes is that here pbtTx and pbtRx contain *only* the data sent and received and not any additional commands, that is all handled internally by the PN53X. + */ +bool nfc_initiator_transceive_dep_bytes(const dev_info* pdi, const byte_t* pbtTx, const uint32_t uiTxLen, byte_t* pbtRx, uint32_t* puiRxLen); + /** * @fn nfc_initiator_mifare_cmd(const dev_info* pdi, const mifare_cmd mc, const uint8_t ui8Block, mifare_param* pmp) * @brief Execute a MIFARE Classic Command @@ -168,6 +191,15 @@ bool nfc_target_receive_bits(const dev_info* pdi, byte_t* pbtRx, uint32_t* puiRx */ bool nfc_target_receive_bytes(const dev_info* pdi, byte_t* pbtRx, uint32_t* puiRxLen); +/** + * @fn nfc_target_receive_dep_bytes(const dev_info* pdi, byte_t* pbtRx, uint32_t* puiRxLen) + * @brief Receive data + * @return Returns true if action was successfully performed; otherwise returns false. + * + * The main receive function that returns the received data from a nearby reader. The difference between this function and nfc_target_receive_bytes is that here pbtRx contains *only* the data received and not any additional commands, that is all handled internally by the PN53X. + */ +bool nfc_target_receive_dep_bytes(const dev_info* pdi, byte_t* pbtRx, uint32_t* puiRxLen); + /** * @fn nfc_target_send_bits(const dev_info* pdi, const byte_t* pbtTx, const uint32_t uiTxBits, const byte_t* pbtTxPar) * @brief Send raw bit-frames @@ -186,5 +218,14 @@ bool nfc_target_send_bits(const dev_info* pdi, const byte_t* pbtTx, const uint32 */ bool nfc_target_send_bytes(const dev_info* pdi, const byte_t* pbtTx, const uint32_t uiTxLen); +/** + * @fn nfc_target_send_dep_bytes(const dev_info* pdi, const byte_t* pbtTx, const uint32_t uiTxLen) + * @brief Send data + * @return Returns true if action was successfully performed; otherwise returns false. + * + * To communicate data to the reader, this function could be used. The difference between this function and nfc_target_send_bytes is that here pbtTx contains *only* the data sent and not any additional commands, that is all handled internally by the PN53X. + */ +bool nfc_target_send_dep_bytes(const dev_info* pdi, const byte_t* pbtTx, const uint32_t uiTxLen); + #endif // _LIBNFC_H_ diff --git a/src/target.c b/src/target.c new file mode 100644 index 0000000..fe65aa2 --- /dev/null +++ b/src/target.c @@ -0,0 +1,31 @@ +#include +#include "libnfc.h" + +int main(int argc, const char *argv[]) +{ + byte_t abtRecv[MAX_FRAME_LEN]; + uint32_t uiRecvBits; + byte_t send[] = "Hello Mars!"; + dev_info *pdi = nfc_connect(); + + if (!pdi || !nfc_target_init(pdi, abtRecv, &uiRecvBits)) { + printf("unable to connect or initialize\n"); + return 1; + } + + if (!nfc_target_receive_dep_bytes(pdi, abtRecv, &uiRecvBits)) { + printf("unable to receive data\n"); + return 1; + } + abtRecv[uiRecvBits] = 0; + printf("Received: %s\n", abtRecv); + printf("Sending : %s\n", send); + + if (!nfc_target_send_dep_bytes(pdi, send, 11)) { + printf("unable to send data\n"); + return 1; + } + + nfc_disconnect(pdi); + return 0; +} diff --git a/src/types.h b/src/types.h index 2ce5bdf..fcb5809 100644 --- a/src/types.h +++ b/src/types.h @@ -122,9 +122,22 @@ typedef enum { /** ISO14443-B http://en.wikipedia.org/wiki/ISO/IEC_14443 */ IM_ISO14443B_106 = 0x03, /** Jewel Topaz (Innovision Research & Development) */ - IM_JEWEL_106 = 0x04 + IM_JEWEL_106 = 0x04, +/** Active DEP */ + IM_ACTIVE_DEP = 0x05, +/** Passive DEP */ + IM_PASSIVE_DEP = 0x06, + + }init_modulation; +typedef struct { + byte_t NFCID3i[10]; + byte_t btDID; + byte_t btBSt; + byte_t btBRt; +}tag_info_dep; + typedef struct { byte_t abtAtqa[2]; byte_t btSak; @@ -164,6 +177,7 @@ typedef union { tag_info_felica tif; tag_info_iso14443b tib; tag_info_jewel tij; + tag_info_dep tid; }tag_info; ////////////////////////////////////////////////////////////////////