Skip to content

Commit

Permalink
New NFC modulation type NMT_BARCODE
Browse files Browse the repository at this point in the history
  • Loading branch information
doegox committed May 17, 2017
1 parent 9f1a685 commit dcdbff0
Show file tree
Hide file tree
Showing 16 changed files with 224 additions and 156 deletions.
3 changes: 2 additions & 1 deletion ChangeLog
Original file line number Diff line number Diff line change
Expand Up @@ -43,11 +43,12 @@ Improvements:
- nfc-mfultralight: add automatic modes and --check-magic
- nfc-mfultralight: add support for magic gen2 cards
- nfc-mfultralight: add option to specify UID
- nfc-barcode: new command to read NFC Barcodes (Tag-Talks-First)
- nfc-barcode: new command to read and decode NFC Barcodes (Tag-Talks-First)

Changes:
- nfc_get_supported_baud_rate() takes now a "mode" parameter
- New nfc_get_supported_baud_rate_target_mode()
- New NFC modulation type NMT_BARCODE to support Thinfilm NFC Barcode protocol

Special thanks to:
- Jim Anastassiou, Frédéric Bourgeois, Dario Carluccio, Emmanuel Dreyfus,
Expand Down
1 change: 0 additions & 1 deletion examples/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
SET(EXAMPLES-SOURCES
nfc-anticol
nfc-barcode
nfc-dep-initiator
nfc-dep-target
nfc-emulate-forum-tag2
Expand Down
6 changes: 0 additions & 6 deletions examples/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ SUBDIRS = pn53x-tamashell-scripts

bin_PROGRAMS = \
nfc-anticol \
nfc-barcode \
nfc-dep-initiator \
nfc-dep-target \
nfc-emulate-forum-tag2 \
Expand Down Expand Up @@ -36,10 +35,6 @@ nfc_anticol_SOURCES = nfc-anticol.c
nfc_anticol_LDADD = $(top_builddir)/libnfc/libnfc.la \
$(top_builddir)/utils/libnfcutils.la

nfc_barcode_SOURCES = nfc-barcode.c
nfc_barcode_LDADD = $(top_builddir)/libnfc/libnfc.la \
$(top_builddir)/utils/libnfcutils.la

nfc_relay_SOURCES = nfc-relay.c
nfc_relay_LDADD = $(top_builddir)/libnfc/libnfc.la \
$(top_builddir)/utils/libnfcutils.la
Expand Down Expand Up @@ -92,7 +87,6 @@ quick_start_example2_LDADD = $(top_builddir)/libnfc/libnfc.la \

dist_man_MANS = \
nfc-anticol.1 \
nfc-barcode.1 \
nfc-dep-initiator.1 \
nfc-dep-target.1 \
nfc-emulate-tag.1 \
Expand Down
11 changes: 11 additions & 0 deletions include/nfc/nfc-types.h
Original file line number Diff line number Diff line change
Expand Up @@ -261,6 +261,15 @@ typedef struct {
uint8_t btId[4];
} nfc_jewel_info;

/**
* @struct nfc_barcode_info
* @brief Thinfilm NFC Barcode information
*/
typedef struct {
size_t szDataLen;
uint8_t abtData[32];
} nfc_barcode_info;

/**
* @union nfc_target_info
* @brief Union between all kind of tags information structures.
Expand All @@ -273,6 +282,7 @@ typedef union {
nfc_iso14443b2sr_info nsi;
nfc_iso14443b2ct_info nci;
nfc_jewel_info nji;
nfc_barcode_info nti; // "t" for Thinfilm, "b" already used
nfc_dep_info ndi;
} nfc_target_info;

Expand All @@ -295,6 +305,7 @@ typedef enum {
typedef enum {
NMT_ISO14443A = 1,
NMT_JEWEL,
NMT_BARCODE, // Thinfilm NFC Barcode
NMT_ISO14443B,
NMT_ISO14443BI, // pre-ISO14443B aka ISO/IEC 14443 B' or Type B'
NMT_ISO14443B2SR, // ISO14443-2B ST SRx
Expand Down
140 changes: 140 additions & 0 deletions libnfc/chips/pn53x.c
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ const nfc_baud_rate pn533_iso14443a_supported_baud_rates[] = { NBR_847, NBR_424,
const nfc_baud_rate pn53x_felica_supported_baud_rates[] = { NBR_424, NBR_212, 0 };
const nfc_baud_rate pn53x_dep_supported_baud_rates[] = { NBR_424, NBR_212, NBR_106, 0 };
const nfc_baud_rate pn53x_jewel_supported_baud_rates[] = { NBR_106, 0 };
const nfc_baud_rate pn53x_barcode_supported_baud_rates[] = { NBR_106, 0 };
const nfc_baud_rate pn532_iso14443b_supported_baud_rates[] = { NBR_106, 0 };
const nfc_baud_rate pn533_iso14443b_supported_baud_rates[] = { NBR_847, NBR_424, NBR_212, NBR_106, 0 };
const nfc_modulation_type pn53x_supported_modulation_as_target[] = {NMT_ISO14443A, NMT_FELICA, NMT_DEP, 0};
Expand Down Expand Up @@ -107,6 +108,8 @@ pn53x_init(struct nfc_device *pnd)
if (CHIP_DATA(pnd)->type != PN531) {
CHIP_DATA(pnd)->supported_modulation_as_initiator[nbSupportedModulation] = NMT_JEWEL;
nbSupportedModulation++;
CHIP_DATA(pnd)->supported_modulation_as_initiator[nbSupportedModulation] = NMT_BARCODE;
nbSupportedModulation++;
}
CHIP_DATA(pnd)->supported_modulation_as_initiator[nbSupportedModulation] = NMT_DEP;
nbSupportedModulation++;
Expand Down Expand Up @@ -610,6 +613,10 @@ pn53x_decode_target_data(const uint8_t *pbtRawData, size_t szRawData, pn53x_type
pbtRawData += 2;
memcpy(pnti->nji.btId, pbtRawData, 4);
break;
case NMT_BARCODE:
pnti->nti.szDataLen = szRawData;
memcpy(pnti->nti.abtData, pbtRawData, szRawData);
break;
// Should not happend...
case NMT_DEP:
return NFC_ECHIP;
Expand Down Expand Up @@ -1147,6 +1154,87 @@ pn53x_initiator_select_passive_target_ext(struct nfc_device *pnd,
} while (pnd->bInfiniteSelect);
if (! found)
return 0;
} else if (nm.nmt == NMT_BARCODE) {
if (CHIP_DATA(pnd)->type == RCS360) {
// TODO add support for RC-S360, at the moment it refuses to send raw frames without a first select
pnd->last_error = NFC_ENOTIMPL;
return pnd->last_error;
}
// No native support in InListPassiveTarget so we do discovery by hand

// We turn RF field off first for a better detection rate but this doesn't work well with ASK LoGO
if ((! CHIP_DATA(pnd)->progressive_field) && (res = nfc_device_set_property_bool(pnd, NP_ACTIVATE_FIELD, false)) < 0) {
return res;
}
if ((res = nfc_device_set_property_bool(pnd, NP_HANDLE_CRC, false)) < 0) {
return res;
}
if ((res = nfc_device_set_property_bool(pnd, NP_HANDLE_PARITY, false)) < 0) {
return res;
}

bool found = false;
do {
uint8_t abtRx[PN53x_EXTENDED_FRAME__DATA_MAX_LEN];
uint8_t abtRxPar[PN53x_EXTENDED_FRAME__DATA_MAX_LEN];
if ((res = nfc_initiator_transceive_bits(pnd, NULL, 0, NULL, abtRx, sizeof(abtRx), abtRxPar)) < 0) {
if ((res == NFC_ERFTRANS) || (res == NFC_ECHIP)) { // Broken reception
continue;
} else {
nfc_device_set_property_bool(pnd, NP_HANDLE_CRC, true);
nfc_device_set_property_bool(pnd, NP_HANDLE_PARITY, true);
return res;
}
}

// Shuffle bits to produce NFC Barcode bitstream
uint8_t uRemainder;
size_t szPos;
size_t szBytes = res / 8;
size_t off = 0;
uint8_t i;
memset(abtTargetsData, 0x00, sizeof(abtTargetsData));
// Reinject S bit
abtTargetsData[off / 8] |= 1 << (7 - (off % 8));
off++;

for (szPos = 0; szPos < szBytes; szPos++) {
for (i = 0; i < 8; i++) {
abtTargetsData[off / 8] |= ((abtRx[szPos] >> i) & 1) << (7 - (off % 8));
off++;
}
abtTargetsData[off / 8] |= abtRxPar[szPos] << (7 - (off % 8));
off++;
}
uRemainder = res % 8;
for (i = 0; i < uRemainder; i++) {
abtTargetsData[off / 8] |= ((abtRx[szPos] >> i) & 1) << (7 - (off % 8));
off++;
}

if (off % 128 != 0) {
// NFC Barcode seems incomplete
continue;
}

szTargetsData = (size_t)off / 8;

// validate CRC
uint8_t pbtCrc[2];
iso14443a_crc(abtTargetsData, szTargetsData - 2, pbtCrc);
if ((pbtCrc[1] != abtTargetsData[szTargetsData - 2]) || (pbtCrc[0] != abtTargetsData[szTargetsData - 1])) {
continue;
}
nttmp.nm = nm;
if ((res = pn53x_decode_target_data(abtTargetsData, szTargetsData, CHIP_DATA(pnd)->type, nm.nmt, &(nttmp.nti))) < 0) {
return res;
}
found = true;
break;
} while (pnd->bInfiniteSelect);
if (! found) {
return 0;
}
} else {
const pn53x_modulation pm = pn53x_nm_to_pm(nm);
if ((PM_UNDEFINED == pm) || (NBR_UNDEFINED == nm.nbr)) {
Expand Down Expand Up @@ -1846,6 +1934,40 @@ static int pn53x_ISO14443A_Jewel_is_present(struct nfc_device *pnd)
return ret;
}

static int pn53x_ISO14443A_Barcode_is_present(struct nfc_device *pnd)
{
int ret;
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "%s", "target_is_present(): Ping Barcode");

// We turn RF field off first for a better detection rate but this doesn't work well with ASK LoGO
if ((! CHIP_DATA(pnd)->progressive_field) && (ret = nfc_device_set_property_bool(pnd, NP_ACTIVATE_FIELD, false)) < 0) {
return ret;
}
if ((ret = nfc_device_set_property_bool(pnd, NP_HANDLE_CRC, false)) < 0)
return ret;
if ((ret = nfc_device_set_property_bool(pnd, NP_HANDLE_PARITY, false)) < 0)
return ret;

int failures = 0;
while (failures < 3) {
if ((! CHIP_DATA(pnd)->progressive_field) && (ret = nfc_device_set_property_bool(pnd, NP_ACTIVATE_FIELD, false)) < 0) {
return ret;
}
uint8_t abtRx[PN53x_EXTENDED_FRAME__DATA_MAX_LEN];
uint8_t abtRxPar[PN53x_EXTENDED_FRAME__DATA_MAX_LEN];
if ((ret = nfc_initiator_transceive_bits(pnd, NULL, 0, NULL, abtRx, sizeof(abtRx), abtRxPar)) < 1) {
failures++;
} else {
nfc_device_set_property_bool(pnd, NP_HANDLE_CRC, true);
nfc_device_set_property_bool(pnd, NP_HANDLE_PARITY, true);
return NFC_SUCCESS;
}
}
nfc_device_set_property_bool(pnd, NP_HANDLE_CRC, true);
nfc_device_set_property_bool(pnd, NP_HANDLE_PARITY, true);
return NFC_ETGRELEASED;
}

static int pn53x_ISO14443A_MFUL_is_present(struct nfc_device *pnd)
{
int ret;
Expand Down Expand Up @@ -2081,6 +2203,9 @@ pn53x_initiator_target_is_present(struct nfc_device *pnd, const nfc_target *pnt)
case NMT_JEWEL:
ret = pn53x_ISO14443A_Jewel_is_present(pnd);
break;
case NMT_BARCODE:
ret = pn53x_ISO14443A_Barcode_is_present(pnd);
break;
case NMT_ISO14443B:
ret = pn53x_ISO14443B_4_is_present(pnd);
break;
Expand Down Expand Up @@ -2144,6 +2269,7 @@ pn53x_target_init(struct nfc_device *pnd, nfc_target *pnt, uint8_t *pbtRx, const
case NMT_ISO14443B2SR:
case NMT_ISO14443B2CT:
case NMT_JEWEL:
case NMT_BARCODE:
pnd->last_error = NFC_EDEVNOTSUPP;
return pnd->last_error;
}
Expand Down Expand Up @@ -2245,6 +2371,7 @@ pn53x_target_init(struct nfc_device *pnd, nfc_target *pnt, uint8_t *pbtRx, const
case NMT_ISO14443B2SR:
case NMT_ISO14443B2CT:
case NMT_JEWEL:
case NMT_BARCODE:
pnd->last_error = NFC_EDEVNOTSUPP;
return pnd->last_error;
}
Expand Down Expand Up @@ -2393,6 +2520,7 @@ pn53x_target_receive_bytes(struct nfc_device *pnd, uint8_t *pbtRx, const size_t
}
// NO BREAK
case NMT_JEWEL:
case NMT_BARCODE:
case NMT_ISO14443B:
case NMT_ISO14443BI:
case NMT_ISO14443B2SR:
Expand Down Expand Up @@ -2498,6 +2626,7 @@ pn53x_target_send_bytes(struct nfc_device *pnd, const uint8_t *pbtTx, const size
}
// NO BREAK
case NMT_JEWEL:
case NMT_BARCODE:
case NMT_ISO14443B:
case NMT_ISO14443BI:
case NMT_ISO14443B2SR:
Expand Down Expand Up @@ -2714,6 +2843,7 @@ pn53x_InListPassiveTarget(struct nfc_device *pnd,
}
break;
case PM_JEWEL_106:
case PM_BARCODE_106:
if (CHIP_DATA(pnd)->type == PN531) {
// These modulations are not supported by pn531
pnd->last_error = NFC_EDEVNOTSUPP;
Expand Down Expand Up @@ -3141,6 +3271,9 @@ pn53x_nm_to_pm(const nfc_modulation nm)
case NMT_JEWEL:
return PM_JEWEL_106;

case NMT_BARCODE:
return PM_BARCODE_106;

case NMT_FELICA:
switch (nm.nbr) {
case NBR_212:
Expand Down Expand Up @@ -3253,6 +3386,7 @@ pn53x_nm_to_ptt(const nfc_modulation nm)
case NMT_ISO14443BI:
case NMT_ISO14443B2SR:
case NMT_ISO14443B2CT:
case NMT_BARCODE:
case NMT_DEP:
// Nothing to do...
break;
Expand Down Expand Up @@ -3307,6 +3441,9 @@ pn53x_get_supported_baud_rate(nfc_device *pnd, const nfc_mode mode, const nfc_mo
case NMT_JEWEL:
*supported_br = (nfc_baud_rate *)pn53x_jewel_supported_baud_rates;
break;
case NMT_BARCODE:
*supported_br = (nfc_baud_rate *)pn53x_barcode_supported_baud_rates;
break;
case NMT_DEP:
*supported_br = (nfc_baud_rate *)pn53x_dep_supported_baud_rates;
break;
Expand Down Expand Up @@ -3560,6 +3697,9 @@ pn53x_data_new(struct nfc_device *pnd, const struct pn53x_io *io)

CHIP_DATA(pnd)->supported_modulation_as_target = NULL;

// Set default progressive field flag
CHIP_DATA(pnd)->progressive_field = false;

return pnd->chip_data;
}

Expand Down
3 changes: 3 additions & 0 deletions libnfc/chips/pn53x.h
Original file line number Diff line number Diff line change
Expand Up @@ -210,6 +210,7 @@ struct pn53x_data {
/** Supported modulation type */
nfc_modulation_type *supported_modulation_as_initiator;
nfc_modulation_type *supported_modulation_as_target;
bool progressive_field;
};

#define CHIP_DATA(pnd) ((struct pn53x_data*)(pnd->chip_data))
Expand All @@ -231,6 +232,8 @@ typedef enum {
PM_ISO14443B_106 = 0x03,
/** Jewel Topaz (Innovision Research & Development) (Not supported by PN531) */
PM_JEWEL_106 = 0x04,
/** Thinfilm NFC Barcode (Not supported by PN531) */
PM_BARCODE_106 = 0x05,
/** ISO14443-B http://en.wikipedia.org/wiki/ISO/IEC_14443 (Not supported by PN531 nor PN532) */
PM_ISO14443B_212 = 0x06,
/** ISO14443-B http://en.wikipedia.org/wiki/ISO/IEC_14443 (Not supported by PN531 nor PN532) */
Expand Down
1 change: 1 addition & 0 deletions libnfc/drivers/pn53x_usb.c
Original file line number Diff line number Diff line change
Expand Up @@ -474,6 +474,7 @@ pn53x_usb_open(const nfc_context *context, const nfc_connstring connstring)
// empirical tuning
case ASK_LOGO:
CHIP_DATA(pnd)->timer_correction = 50;
CHIP_DATA(pnd)->progressive_field = true;
break;
case SCM_SCL3711:
case SCM_SCL3712:
Expand Down
1 change: 1 addition & 0 deletions libnfc/nfc-internal.c
Original file line number Diff line number Diff line change
Expand Up @@ -201,6 +201,7 @@ prepare_initiator_data(const nfc_modulation nm, uint8_t **ppbtInitiatorData, siz
break;
case NMT_ISO14443A:
case NMT_JEWEL:
case NMT_BARCODE:
case NMT_DEP:
*ppbtInitiatorData = NULL;
*pszInitiatorData = 0;
Expand Down
7 changes: 5 additions & 2 deletions libnfc/nfc.c
Original file line number Diff line number Diff line change
Expand Up @@ -602,9 +602,10 @@ nfc_initiator_list_passive_targets(nfc_device *pnd,
break;
}
nfc_initiator_deselect_target(pnd);
// deselect has no effect on FeliCa and Jewel cards so we'll stop after one...
// deselect has no effect on FeliCa, Jewel and Thinfilm cards so we'll stop after one...
// ISO/IEC 14443 B' cards are polled at 100% probability so it's not possible to detect correctly two cards at the same time
if ((nm.nmt == NMT_FELICA) || (nm.nmt == NMT_JEWEL) || (nm.nmt == NMT_ISO14443BI) || (nm.nmt == NMT_ISO14443B2SR) || (nm.nmt == NMT_ISO14443B2CT)) {
if ((nm.nmt == NMT_FELICA) || (nm.nmt == NMT_JEWEL) || (nm.nmt == NMT_BARCODE) ||
(nm.nmt == NMT_ISO14443BI) || (nm.nmt == NMT_ISO14443B2SR) || (nm.nmt == NMT_ISO14443B2CT)) {
break;
}
}
Expand Down Expand Up @@ -1356,6 +1357,8 @@ str_nfc_modulation_type(const nfc_modulation_type nmt)
return "FeliCa";
case NMT_JEWEL:
return "Innovision Jewel";
case NMT_BARCODE:
return "Thinfilm NFC Barcode";
case NMT_DEP:
return "D.E.P.";
}
Expand Down
Loading

0 comments on commit dcdbff0

Please sign in to comment.