Merge c2fdab7f0cd1090d036b2dbfc4d44dfb53500378 into c9ac17c9f5e793d1cba877a33e4d8353beff94e6
This commit is contained in:
commit
c936be658f
1
.gitignore
vendored
1
.gitignore
vendored
@ -6,6 +6,7 @@
|
||||
*.la
|
||||
*.lo
|
||||
*.o
|
||||
*.stackdump
|
||||
*~
|
||||
Doxyfile
|
||||
INSTALL
|
||||
|
||||
@ -11,6 +11,7 @@ ELSE(WIN32)
|
||||
ENDIF(WIN32)
|
||||
SET(LIBNFC_DRIVER_PN532_UART ON CACHE BOOL "Enable PN532 UART support (Use serial port)")
|
||||
SET(LIBNFC_DRIVER_PN53X_USB ON CACHE BOOL "Enable PN531 and PN531 USB support (Depends on libusb)")
|
||||
SET(LIBNFC_DRIVER_RC522_UART ON CACHE BOOL "Enable MFRC522/FM17222 UART support (Use serial port)")
|
||||
|
||||
IF(LIBNFC_DRIVER_ACR122_PCSC)
|
||||
FIND_PACKAGE(PCSC REQUIRED)
|
||||
@ -61,4 +62,10 @@ IF(LIBNFC_DRIVER_PN53X_USB)
|
||||
SET(USB_REQUIRED TRUE)
|
||||
ENDIF(LIBNFC_DRIVER_PN53X_USB)
|
||||
|
||||
IF(LIBNFC_DRIVER_RC522_UART)
|
||||
ADD_DEFINITIONS("-DDRIVER_RC522_UART_ENABLED")
|
||||
SET(DRIVERS_SOURCES ${DRIVERS_SOURCES} "drivers/rc522_uart")
|
||||
SET(UART_REQUIRED TRUE)
|
||||
ENDIF(LIBNFC_DRIVER_RC522_UART)
|
||||
|
||||
INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}/libnfc/drivers)
|
||||
|
||||
@ -113,7 +113,7 @@ transmit_bits(const uint8_t *pbtTx, const size_t szTxBits)
|
||||
|
||||
|
||||
static bool
|
||||
transmit_bytes(const uint8_t *pbtTx, const size_t szTx)
|
||||
transmit_bytes(const uint8_t *pbtTx, const size_t szTx, bool wantsReply)
|
||||
{
|
||||
uint32_t cycles = 0;
|
||||
// Show transmitted command
|
||||
@ -124,13 +124,13 @@ transmit_bytes(const uint8_t *pbtTx, const size_t szTx)
|
||||
int res;
|
||||
// Transmit the command bytes
|
||||
if (timed) {
|
||||
if ((res = nfc_initiator_transceive_bytes_timed(pnd, pbtTx, szTx, abtRx, sizeof(abtRx), &cycles)) < 0)
|
||||
if ((res = nfc_initiator_transceive_bytes_timed(pnd, pbtTx, szTx, abtRx, wantsReply ? sizeof(abtRx) : 0, &cycles)) < 0)
|
||||
return false;
|
||||
if ((!quiet_output) && (res > 0)) {
|
||||
printf("Response after %u cycles\n", cycles);
|
||||
}
|
||||
} else {
|
||||
if ((res = nfc_initiator_transceive_bytes(pnd, pbtTx, szTx, abtRx, sizeof(abtRx), 0)) < 0)
|
||||
if ((res = nfc_initiator_transceive_bytes(pnd, pbtTx, szTx, abtRx, wantsReply ? sizeof(abtRx) : 0, -1)) < 0)
|
||||
return false;
|
||||
}
|
||||
szRx = res;
|
||||
@ -235,7 +235,7 @@ main(int argc, char *argv[])
|
||||
memcpy(abtAtqa, abtRx, 2);
|
||||
|
||||
// Anti-collision
|
||||
transmit_bytes(abtSelectAll, 2);
|
||||
transmit_bytes(abtSelectAll, 2, true);
|
||||
|
||||
// Check answer
|
||||
if ((abtRx[0] ^ abtRx[1] ^ abtRx[2] ^ abtRx[3] ^ abtRx[4]) != 0) {
|
||||
@ -248,7 +248,7 @@ main(int argc, char *argv[])
|
||||
//Prepare and send CL1 Select-Command
|
||||
memcpy(abtSelectTag + 2, abtRx, 5);
|
||||
iso14443a_crc_append(abtSelectTag, 7);
|
||||
transmit_bytes(abtSelectTag, 9);
|
||||
transmit_bytes(abtSelectTag, 9, true);
|
||||
abtSak = abtRx[0];
|
||||
|
||||
// Test if we are dealing with a CL2
|
||||
@ -267,7 +267,7 @@ main(int argc, char *argv[])
|
||||
abtSelectAll[0] = 0x95;
|
||||
|
||||
// Anti-collision
|
||||
transmit_bytes(abtSelectAll, 2);
|
||||
transmit_bytes(abtSelectAll, 2, true);
|
||||
|
||||
// Check answer
|
||||
if ((abtRx[0] ^ abtRx[1] ^ abtRx[2] ^ abtRx[3] ^ abtRx[4]) != 0) {
|
||||
@ -281,7 +281,7 @@ main(int argc, char *argv[])
|
||||
abtSelectTag[0] = 0x95;
|
||||
memcpy(abtSelectTag + 2, abtRx, 5);
|
||||
iso14443a_crc_append(abtSelectTag, 7);
|
||||
transmit_bytes(abtSelectTag, 9);
|
||||
transmit_bytes(abtSelectTag, 9, true);
|
||||
abtSak = abtRx[0];
|
||||
|
||||
// Test if we are dealing with a CL3
|
||||
@ -298,7 +298,7 @@ main(int argc, char *argv[])
|
||||
|
||||
// Prepare and send CL3 AC-Command
|
||||
abtSelectAll[0] = 0x97;
|
||||
transmit_bytes(abtSelectAll, 2);
|
||||
transmit_bytes(abtSelectAll, 2, true);
|
||||
|
||||
// Check answer
|
||||
if ((abtRx[0] ^ abtRx[1] ^ abtRx[2] ^ abtRx[3] ^ abtRx[4]) != 0) {
|
||||
@ -312,7 +312,7 @@ main(int argc, char *argv[])
|
||||
abtSelectTag[0] = 0x97;
|
||||
memcpy(abtSelectTag + 2, abtRx, 5);
|
||||
iso14443a_crc_append(abtSelectTag, 7);
|
||||
transmit_bytes(abtSelectTag, 9);
|
||||
transmit_bytes(abtSelectTag, 9, true);
|
||||
abtSak = abtRx[0];
|
||||
}
|
||||
}
|
||||
@ -323,7 +323,7 @@ main(int argc, char *argv[])
|
||||
}
|
||||
if ((abtRx[0] & SAK_FLAG_ATS_SUPPORTED) || force_rats) {
|
||||
iso14443a_crc_append(abtRats, 2);
|
||||
if (transmit_bytes(abtRats, 4)) {
|
||||
if (transmit_bytes(abtRats, 4, true)) {
|
||||
memcpy(abtAts, abtRx, szRx);
|
||||
szAts = szRx;
|
||||
}
|
||||
@ -331,7 +331,7 @@ main(int argc, char *argv[])
|
||||
|
||||
// Done, halt the tag now
|
||||
iso14443a_crc_append(abtHalt, 2);
|
||||
transmit_bytes(abtHalt, 4);
|
||||
transmit_bytes(abtHalt, 4, false);
|
||||
|
||||
printf("\nFound tag with\n UID: ");
|
||||
switch (szCL) {
|
||||
|
||||
@ -20,7 +20,9 @@ libnfc_la_SOURCES = \
|
||||
log-internal.h \
|
||||
mirror-subr.h \
|
||||
nfc-internal.h \
|
||||
target-subr.h
|
||||
target-subr.h \
|
||||
timing.h \
|
||||
timing.c
|
||||
|
||||
libnfc_la_LDFLAGS = -no-undefined -version-info 5:1:0 -export-symbols-regex '^nfc_|^iso14443a_|^iso14443b_|^str_nfc_|pn53x_transceive|pn532_SAMConfiguration|pn53x_read_register|pn53x_write_register'
|
||||
libnfc_la_CFLAGS = @DRIVERS_CFLAGS@
|
||||
|
||||
@ -143,10 +143,11 @@ uart_open(const char *pcPortName)
|
||||
uart_close_ext(sp, true);
|
||||
return INVALID_SERIAL_PORT;
|
||||
}
|
||||
|
||||
return sp;
|
||||
}
|
||||
|
||||
void
|
||||
int
|
||||
uart_flush_input(serial_port sp, bool wait)
|
||||
{
|
||||
// flush commands may seem to be without effect
|
||||
@ -158,34 +159,37 @@ uart_flush_input(serial_port sp, bool wait)
|
||||
}
|
||||
|
||||
// This line seems to produce absolutely no effect on my system (GNU/Linux 2.6.35)
|
||||
tcflush(UART_DATA(sp)->fd, TCIFLUSH);
|
||||
if (tcflush(UART_DATA(sp)->fd, TCIFLUSH)) {
|
||||
return NFC_EIO;
|
||||
}
|
||||
// So, I wrote this byte-eater
|
||||
// Retrieve the count of the incoming bytes
|
||||
int available_bytes_count = 0;
|
||||
int res;
|
||||
res = ioctl(UART_DATA(sp)->fd, FIONREAD, &available_bytes_count);
|
||||
if (res != 0) {
|
||||
return;
|
||||
return NFC_EIO;
|
||||
}
|
||||
if (available_bytes_count == 0) {
|
||||
return;
|
||||
return NFC_SUCCESS;
|
||||
}
|
||||
char *rx = malloc(available_bytes_count);
|
||||
if (!rx) {
|
||||
perror("malloc");
|
||||
return;
|
||||
return NFC_ESOFT;
|
||||
}
|
||||
// There is something available, read the data
|
||||
if (read(UART_DATA(sp)->fd, rx, available_bytes_count) < 0) {
|
||||
perror("uart read");
|
||||
free(rx);
|
||||
return;
|
||||
return NFC_EIO;
|
||||
}
|
||||
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "%d bytes have eaten.", available_bytes_count);
|
||||
free(rx);
|
||||
return NFC_SUCCESS;
|
||||
}
|
||||
|
||||
void
|
||||
int
|
||||
uart_set_speed(serial_port sp, const uint32_t uiPortSpeed)
|
||||
{
|
||||
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "Serial port speed requested to be set to %d baud.", uiPortSpeed);
|
||||
@ -226,15 +230,17 @@ uart_set_speed(serial_port sp, const uint32_t uiPortSpeed)
|
||||
default:
|
||||
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "Unable to set serial port speed to %d baud. Speed value must be one of those defined in termios(3).",
|
||||
uiPortSpeed);
|
||||
return;
|
||||
return NFC_ESOFT;
|
||||
};
|
||||
|
||||
// Set port speed (Input and Output)
|
||||
cfsetispeed(&(UART_DATA(sp)->termios_new), stPortSpeed);
|
||||
cfsetospeed(&(UART_DATA(sp)->termios_new), stPortSpeed);
|
||||
if (tcsetattr(UART_DATA(sp)->fd, TCSADRAIN, &(UART_DATA(sp)->termios_new)) == -1) {
|
||||
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "%s", "Unable to apply new speed settings.");
|
||||
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "Unable to apply new speed settings.");
|
||||
return NFC_EIO;
|
||||
}
|
||||
return NFC_SUCCESS;
|
||||
}
|
||||
|
||||
uint32_t
|
||||
@ -431,3 +437,16 @@ oom:
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
void
|
||||
uart_list_free(char ** acPorts)
|
||||
{
|
||||
char *acPort;
|
||||
size_t iDevice = 0;
|
||||
|
||||
while ((acPort = acPorts[iDevice++])) {
|
||||
free((void *)acPort);
|
||||
}
|
||||
|
||||
free(acPorts);
|
||||
}
|
||||
|
||||
@ -49,14 +49,15 @@ typedef void *serial_port;
|
||||
|
||||
serial_port uart_open(const char *pcPortName);
|
||||
void uart_close(const serial_port sp);
|
||||
void uart_flush_input(const serial_port sp, bool wait);
|
||||
int uart_flush_input(const serial_port sp, bool wait);
|
||||
|
||||
void uart_set_speed(serial_port sp, const uint32_t uiPortSpeed);
|
||||
int uart_set_speed(serial_port sp, const uint32_t uiPortSpeed);
|
||||
uint32_t uart_get_speed(const serial_port sp);
|
||||
|
||||
int uart_receive(serial_port sp, uint8_t *pbtRx, const size_t szRx, void *abort_p, int timeout);
|
||||
int uart_send(serial_port sp, const uint8_t *pbtTx, const size_t szTx, int timeout);
|
||||
|
||||
char **uart_list_ports(void);
|
||||
void uart_list_free(char **acPorts);
|
||||
|
||||
#endif // __NFC_BUS_UART_H__
|
||||
|
||||
@ -3,6 +3,6 @@
|
||||
AM_CPPFLAGS = $(all_includes) $(LIBNFC_CFLAGS)
|
||||
|
||||
noinst_LTLIBRARIES = libnfcchips.la
|
||||
libnfcchips_la_SOURCES = pn53x.c pn53x.h pn53x-internal.h
|
||||
libnfcchips_la_SOURCES = pn53x.c pn53x.h pn53x-internal.h rc522.c rc522.h rc522-internal.h
|
||||
libnfcchips_la_CFLAGS = -I$(top_srcdir)/libnfc
|
||||
|
||||
|
||||
@ -335,8 +335,6 @@ pn53x_transceive(struct nfc_device *pnd, const uint8_t *pbtTx, const size_t szTx
|
||||
if (res < 0) {
|
||||
pnd->last_error = res;
|
||||
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "Chip error: \"%s\" (%02x), returned error: \"%s\" (%d))", pn53x_strerror(pnd), CHIP_DATA(pnd)->last_status_byte, nfc_strerror(pnd), res);
|
||||
} else {
|
||||
pnd->last_error = 0;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
@ -1063,8 +1061,7 @@ pn53x_initiator_select_passive_target_ext(struct nfc_device *pnd,
|
||||
if (nm.nmt == NMT_ISO14443BI || nm.nmt == NMT_ISO14443B2SR || nm.nmt == NMT_ISO14443B2CT) {
|
||||
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;
|
||||
return NFC_ENOTIMPL;
|
||||
}
|
||||
// No native support in InListPassiveTarget so we do discovery by hand
|
||||
if ((res = nfc_device_set_property_bool(pnd, NP_FORCE_ISO14443_B, true)) < 0) {
|
||||
@ -1150,8 +1147,7 @@ pn53x_initiator_select_passive_target_ext(struct nfc_device *pnd,
|
||||
} else {
|
||||
const pn53x_modulation pm = pn53x_nm_to_pm(nm);
|
||||
if ((PM_UNDEFINED == pm) || (NBR_UNDEFINED == nm.nbr)) {
|
||||
pnd->last_error = NFC_EINVARG;
|
||||
return pnd->last_error;
|
||||
return NFC_EINVARG;
|
||||
}
|
||||
|
||||
if ((res = pn53x_InListPassiveTarget(pnd, pm, 1, pbtInitData, szInitData, abtTargetsData, &szTargetsData, timeout)) <= 0)
|
||||
@ -1174,8 +1170,7 @@ pn53x_initiator_select_passive_target_ext(struct nfc_device *pnd,
|
||||
}
|
||||
}
|
||||
if (pn53x_current_target_new(pnd, &nttmp) == NULL) {
|
||||
pnd->last_error = NFC_ESOFT;
|
||||
return pnd->last_error;
|
||||
return NFC_ESOFT;
|
||||
}
|
||||
// Is a tag info struct available
|
||||
if (pnt) {
|
||||
@ -1208,8 +1203,7 @@ pn53x_initiator_poll_target(struct nfc_device *pnd,
|
||||
for (size_t n = 0; n < szModulations; n++) {
|
||||
const pn53x_target_type ptt = pn53x_nm_to_ptt(pnmModulations[n]);
|
||||
if (PTT_UNDEFINED == ptt) {
|
||||
pnd->last_error = NFC_EINVARG;
|
||||
return pnd->last_error;
|
||||
return NFC_EINVARG;
|
||||
}
|
||||
apttTargetTypes[szTargetTypes] = ptt;
|
||||
if ((pnd->bAutoIso14443_4) && (ptt == PTT_MIFARE)) { // Hack to have ATS
|
||||
@ -1226,18 +1220,18 @@ pn53x_initiator_poll_target(struct nfc_device *pnd,
|
||||
return res;
|
||||
switch (res) {
|
||||
case 0:
|
||||
return pnd->last_error = NFC_SUCCESS;
|
||||
return NFC_SUCCESS;
|
||||
break;
|
||||
case 1:
|
||||
*pnt = ntTargets[0];
|
||||
if (pn53x_current_target_new(pnd, pnt) == NULL) {
|
||||
return pnd->last_error = NFC_ESOFT;
|
||||
return NFC_ESOFT;
|
||||
}
|
||||
return res;
|
||||
case 2:
|
||||
*pnt = ntTargets[1]; // We keep the selected one
|
||||
if (pn53x_current_target_new(pnd, pnt) == NULL) {
|
||||
return pnd->last_error = NFC_ESOFT;
|
||||
return NFC_ESOFT;
|
||||
}
|
||||
return res;
|
||||
default:
|
||||
@ -1258,8 +1252,8 @@ pn53x_initiator_poll_target(struct nfc_device *pnd,
|
||||
const int timeout_ms = uiPeriod * 150;
|
||||
|
||||
if ((res = pn53x_initiator_select_passive_target_ext(pnd, pnmModulations[n], pbtInitiatorData, szInitiatorData, pnt, timeout_ms)) < 0) {
|
||||
if (pnd->last_error != NFC_ETIMEOUT) {
|
||||
result = pnd->last_error;
|
||||
if (res != NFC_ETIMEOUT) {
|
||||
result = res;
|
||||
goto end;
|
||||
}
|
||||
} else {
|
||||
@ -1400,8 +1394,7 @@ pn53x_initiator_transceive_bytes(struct nfc_device *pnd, const uint8_t *pbtTx, c
|
||||
|
||||
// We can not just send bytes without parity if while the PN53X expects we handled them
|
||||
if (!pnd->bPar) {
|
||||
pnd->last_error = NFC_EINVARG;
|
||||
return pnd->last_error;
|
||||
return NFC_EINVARG;
|
||||
}
|
||||
|
||||
// Copy the data into the command frame
|
||||
@ -1418,16 +1411,14 @@ pn53x_initiator_transceive_bytes(struct nfc_device *pnd, const uint8_t *pbtTx, c
|
||||
|
||||
// To transfer command frames bytes we can not have any leading bits, reset this to zero
|
||||
if ((res = pn53x_set_tx_bits(pnd, 0)) < 0) {
|
||||
pnd->last_error = res;
|
||||
return pnd->last_error;
|
||||
return res;
|
||||
}
|
||||
|
||||
// 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)
|
||||
uint8_t abtRx[PN53x_EXTENDED_FRAME__DATA_MAX_LEN];
|
||||
if ((res = pn53x_transceive(pnd, abtCmd, szTx + szExtraTxLen, abtRx, sizeof(abtRx), timeout)) < 0) {
|
||||
pnd->last_error = res;
|
||||
return pnd->last_error;
|
||||
return res;
|
||||
}
|
||||
const size_t szRxLen = (size_t)res - 1;
|
||||
if (pbtRx != NULL) {
|
||||
@ -1538,18 +1529,15 @@ pn53x_initiator_transceive_bits_timed(struct nfc_device *pnd, const uint8_t *pbt
|
||||
|
||||
// Sorry, no arbitrary parity bits support for now
|
||||
if (!pnd->bPar) {
|
||||
pnd->last_error = NFC_ENOTIMPL;
|
||||
return pnd->last_error;
|
||||
return NFC_ENOTIMPL;
|
||||
}
|
||||
// Sorry, no easy framing support
|
||||
if (pnd->bEasyFraming) {
|
||||
pnd->last_error = NFC_ENOTIMPL;
|
||||
return pnd->last_error;
|
||||
return NFC_ENOTIMPL;
|
||||
}
|
||||
// TODO CRC support but it probably doesn't make sense for (szTxBits % 8 != 0) ...
|
||||
if (pnd->bCrc) {
|
||||
pnd->last_error = NFC_ENOTIMPL;
|
||||
return pnd->last_error;
|
||||
return NFC_ENOTIMPL;
|
||||
}
|
||||
|
||||
__pn53x_init_timer(pnd, *cycles);
|
||||
@ -1636,14 +1624,12 @@ pn53x_initiator_transceive_bytes_timed(struct nfc_device *pnd, const uint8_t *pb
|
||||
|
||||
// We can not just send bytes without parity while the PN53X expects we handled them
|
||||
if (!pnd->bPar) {
|
||||
pnd->last_error = NFC_EINVARG;
|
||||
return pnd->last_error;
|
||||
return NFC_EINVARG;
|
||||
}
|
||||
// Sorry, no easy framing support
|
||||
// TODO to be changed once we'll provide easy framing support from libnfc itself...
|
||||
if (pnd->bEasyFraming) {
|
||||
pnd->last_error = NFC_ENOTIMPL;
|
||||
return pnd->last_error;
|
||||
return NFC_ENOTIMPL;
|
||||
}
|
||||
|
||||
uint8_t txmode = 0;
|
||||
@ -2046,13 +2032,13 @@ pn53x_initiator_target_is_present(struct nfc_device *pnd, const nfc_target *pnt)
|
||||
// Check if there is a saved target
|
||||
if (CHIP_DATA(pnd)->current_target == NULL) {
|
||||
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "%s", "target_is_present(): no saved target");
|
||||
return pnd->last_error = NFC_EINVARG;
|
||||
return NFC_EINVARG;
|
||||
}
|
||||
|
||||
// Check if the argument target nt is equals to current saved target
|
||||
if ((pnt != NULL) && (!pn53x_current_target_is(pnd, pnt))) {
|
||||
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "%s", "target_is_present(): another target");
|
||||
return pnd->last_error = NFC_ETGRELEASED;
|
||||
return NFC_ETGRELEASED;
|
||||
}
|
||||
|
||||
// Ping target
|
||||
@ -2096,7 +2082,7 @@ pn53x_initiator_target_is_present(struct nfc_device *pnd, const nfc_target *pnt)
|
||||
}
|
||||
if (ret == NFC_ETGRELEASED)
|
||||
pn53x_current_target_free(pnd);
|
||||
return pnd->last_error = ret;
|
||||
return ret;
|
||||
}
|
||||
|
||||
#define SAK_ISO14443_4_COMPLIANT 0x20
|
||||
@ -2115,8 +2101,7 @@ pn53x_target_init(struct nfc_device *pnd, nfc_target *pnt, uint8_t *pbtRx, const
|
||||
case NMT_ISO14443A:
|
||||
ptm = PTM_PASSIVE_ONLY;
|
||||
if ((pnt->nti.nai.abtUid[0] != 0x08) || (pnt->nti.nai.szUidLen != 4)) {
|
||||
pnd->last_error = NFC_EINVARG;
|
||||
return pnd->last_error;
|
||||
return NFC_EINVARG;
|
||||
}
|
||||
pn53x_set_parameters(pnd, PARAM_AUTO_ATR_RES, false);
|
||||
if (CHIP_DATA(pnd)->type == PN532) { // We have a PN532
|
||||
@ -2144,8 +2129,7 @@ pn53x_target_init(struct nfc_device *pnd, nfc_target *pnt, uint8_t *pbtRx, const
|
||||
case NMT_ISO14443B2SR:
|
||||
case NMT_ISO14443B2CT:
|
||||
case NMT_JEWEL:
|
||||
pnd->last_error = NFC_EDEVNOTSUPP;
|
||||
return pnd->last_error;
|
||||
return NFC_EDEVNOTSUPP;
|
||||
}
|
||||
|
||||
// Let the PN53X be activated by the RF level detector from power down mode
|
||||
@ -2245,8 +2229,7 @@ pn53x_target_init(struct nfc_device *pnd, nfc_target *pnt, uint8_t *pbtRx, const
|
||||
case NMT_ISO14443B2SR:
|
||||
case NMT_ISO14443B2CT:
|
||||
case NMT_JEWEL:
|
||||
pnd->last_error = NFC_EDEVNOTSUPP;
|
||||
return pnd->last_error;
|
||||
return NFC_EDEVNOTSUPP;
|
||||
}
|
||||
|
||||
bool targetActivated = false;
|
||||
@ -2308,8 +2291,7 @@ pn53x_target_init(struct nfc_device *pnd, nfc_target *pnt, uint8_t *pbtRx, const
|
||||
pnt->nti.ndi.ndm = ndm; // Update DEP mode
|
||||
}
|
||||
if (pn53x_current_target_new(pnd, pnt) == NULL) {
|
||||
pnd->last_error = NFC_ESOFT;
|
||||
return pnd->last_error;
|
||||
return NFC_ESOFT;
|
||||
}
|
||||
|
||||
if (ptm & PTM_ISO14443_4_PICC_ONLY) {
|
||||
@ -2387,8 +2369,7 @@ pn53x_target_receive_bytes(struct nfc_device *pnd, uint8_t *pbtRx, const size_t
|
||||
break;
|
||||
} else {
|
||||
// TODO Support EasyFraming for other cases by software
|
||||
pnd->last_error = NFC_ENOTIMPL;
|
||||
return pnd->last_error;
|
||||
return NFC_ENOTIMPL;
|
||||
}
|
||||
}
|
||||
// NO BREAK
|
||||
@ -2410,7 +2391,7 @@ pn53x_target_receive_bytes(struct nfc_device *pnd, uint8_t *pbtRx, const size_t
|
||||
size_t szRx = sizeof(abtRx);
|
||||
int res = 0;
|
||||
if ((res = pn53x_transceive(pnd, abtCmd, sizeof(abtCmd), abtRx, szRx, timeout)) < 0)
|
||||
return pnd->last_error;
|
||||
return res;
|
||||
szRx = (size_t) res;
|
||||
// Save the received bytes count
|
||||
szRx -= 1;
|
||||
@ -2492,8 +2473,7 @@ pn53x_target_send_bytes(struct nfc_device *pnd, const uint8_t *pbtTx, const size
|
||||
break;
|
||||
} else {
|
||||
// TODO Support EasyFraming for other cases by software
|
||||
pnd->last_error = NFC_ENOTIMPL;
|
||||
return pnd->last_error;
|
||||
return NFC_ENOTIMPL;
|
||||
}
|
||||
}
|
||||
// NO BREAK
|
||||
@ -2642,8 +2622,7 @@ pn532_SAMConfiguration(struct nfc_device *pnd, const pn532_sam_mode sam_mode, in
|
||||
|
||||
if (CHIP_DATA(pnd)->type != PN532) {
|
||||
// This function is not supported by pn531 neither pn533
|
||||
pnd->last_error = NFC_EDEVNOTSUPP;
|
||||
return pnd->last_error;
|
||||
return NFC_EDEVNOTSUPP;
|
||||
}
|
||||
|
||||
switch (sam_mode) {
|
||||
@ -2657,8 +2636,7 @@ pn532_SAMConfiguration(struct nfc_device *pnd, const pn532_sam_mode sam_mode, in
|
||||
szCmd = 3;
|
||||
break;
|
||||
default:
|
||||
pnd->last_error = NFC_EINVARG;
|
||||
return pnd->last_error;
|
||||
return NFC_EINVARG;
|
||||
}
|
||||
CHIP_DATA(pnd)->sam_mode = sam_mode;
|
||||
return (pn53x_transceive(pnd, abtCmd, szCmd, NULL, 0, timeout));
|
||||
@ -2709,15 +2687,13 @@ pn53x_InListPassiveTarget(struct nfc_device *pnd,
|
||||
case PM_ISO14443B_106:
|
||||
if (!(pnd->btSupportByte & SUPPORT_ISO14443B)) {
|
||||
// Eg. Some PN532 doesn't support type B!
|
||||
pnd->last_error = NFC_EDEVNOTSUPP;
|
||||
return pnd->last_error;
|
||||
return NFC_EDEVNOTSUPP;
|
||||
}
|
||||
break;
|
||||
case PM_JEWEL_106:
|
||||
if (CHIP_DATA(pnd)->type == PN531) {
|
||||
// These modulations are not supported by pn531
|
||||
pnd->last_error = NFC_EDEVNOTSUPP;
|
||||
return pnd->last_error;
|
||||
return NFC_EDEVNOTSUPP;
|
||||
}
|
||||
break;
|
||||
case PM_ISO14443B_212:
|
||||
@ -2725,13 +2701,11 @@ pn53x_InListPassiveTarget(struct nfc_device *pnd,
|
||||
case PM_ISO14443B_847:
|
||||
if ((CHIP_DATA(pnd)->type != PN533) || (!(pnd->btSupportByte & SUPPORT_ISO14443B))) {
|
||||
// These modulations are not supported by pn531 neither pn532
|
||||
pnd->last_error = NFC_EDEVNOTSUPP;
|
||||
return pnd->last_error;
|
||||
return NFC_EDEVNOTSUPP;
|
||||
}
|
||||
break;
|
||||
case PM_UNDEFINED:
|
||||
pnd->last_error = NFC_EINVARG;
|
||||
return pnd->last_error;
|
||||
return NFC_EINVARG;
|
||||
}
|
||||
abtCmd[2] = pmInitModulation; // BrTy, the type of init modulation used for polling a passive tag
|
||||
|
||||
@ -2804,8 +2778,7 @@ pn53x_InAutoPoll(struct nfc_device *pnd,
|
||||
size_t szTargetFound = 0;
|
||||
if (CHIP_DATA(pnd)->type != PN532) {
|
||||
// This function is not supported by pn531 neither pn533
|
||||
pnd->last_error = NFC_EDEVNOTSUPP;
|
||||
return pnd->last_error;
|
||||
return NFC_EDEVNOTSUPP;
|
||||
}
|
||||
|
||||
// InAutoPoll frame looks like this { 0xd4, 0x60, 0x0f, 0x01, 0x00 } => { direction, command, pollnr, period, types... }
|
||||
@ -2903,8 +2876,7 @@ pn53x_InJumpForDEP(struct nfc_device *pnd,
|
||||
break;
|
||||
case NBR_847:
|
||||
case NBR_UNDEFINED:
|
||||
pnd->last_error = NFC_EINVARG;
|
||||
return pnd->last_error;
|
||||
return NFC_EINVARG;
|
||||
}
|
||||
|
||||
if (pbtNFCID3i) {
|
||||
@ -3029,25 +3001,25 @@ pn53x_TgInitAsTarget(struct nfc_device *pnd, pn53x_target_mode ptm,
|
||||
int
|
||||
pn53x_check_ack_frame(struct nfc_device *pnd, const uint8_t *pbtRxFrame, const size_t szRxFrameLen)
|
||||
{
|
||||
(void)pnd;
|
||||
if (szRxFrameLen >= sizeof(pn53x_ack_frame)) {
|
||||
if (0 == memcmp(pbtRxFrame, pn53x_ack_frame, sizeof(pn53x_ack_frame))) {
|
||||
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "%s", "PN53x ACKed");
|
||||
return NFC_SUCCESS;
|
||||
}
|
||||
}
|
||||
pnd->last_error = NFC_EIO;
|
||||
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "%s", "Unexpected PN53x reply!");
|
||||
return pnd->last_error;
|
||||
return NFC_EIO;
|
||||
}
|
||||
|
||||
int
|
||||
pn53x_check_error_frame(struct nfc_device *pnd, const uint8_t *pbtRxFrame, const size_t szRxFrameLen)
|
||||
{
|
||||
(void)pnd;
|
||||
if (szRxFrameLen >= sizeof(pn53x_error_frame)) {
|
||||
if (0 == memcmp(pbtRxFrame, pn53x_error_frame, sizeof(pn53x_error_frame))) {
|
||||
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "%s", "PN53x sent an error frame");
|
||||
pnd->last_error = NFC_EIO;
|
||||
return pnd->last_error;
|
||||
return NFC_EIO;
|
||||
}
|
||||
}
|
||||
return NFC_SUCCESS;
|
||||
|
||||
145
libnfc/chips/rc522-internal.h
Normal file
145
libnfc/chips/rc522-internal.h
Normal file
@ -0,0 +1,145 @@
|
||||
|
||||
|
||||
#ifndef __NFC_CHIPS_RC522_INTERNAL_H__
|
||||
#define __NFC_CHIPS_RC522_INTERNAL_H__
|
||||
|
||||
#define FIFO_SIZE 64
|
||||
// This is the default value for water level IRQs
|
||||
#define DEFAULT_WATER_LEVEL 8
|
||||
|
||||
typedef enum {
|
||||
RC522_UNKNOWN = 0x00,
|
||||
FM17522 = 0x88,
|
||||
MFRC522_V1 = 0x91,
|
||||
MFRC522_V2 = 0x92
|
||||
} rc522_type;
|
||||
|
||||
typedef enum {
|
||||
CMD_IDLE = 0x0,
|
||||
CMD_MEM = 0x1,
|
||||
CMD_GENRANDOMID = 0x2,
|
||||
CMD_CALCCRC = 0x3,
|
||||
CMD_TRANSMIT = 0x4,
|
||||
CMD_NOCMDCHANGE = 0x7,
|
||||
CMD_RECEIVE = 0x8,
|
||||
CMD_TRANSCEIVE = 0xC,
|
||||
CMD_MFAUTHENT = 0xE,
|
||||
CMD_SOFTRESET = 0xF
|
||||
} rc522_cmd;
|
||||
|
||||
#define REG_CommandReg 0x01
|
||||
#define REG_CommandReg_RcvOff (1 << 5)
|
||||
#define REG_CommandReg_PowerDown (1 << 4)
|
||||
#define REG_CommandReg_Command_MASK 0x0F
|
||||
|
||||
#define REG_ComlEnReg 0x02
|
||||
|
||||
#define REG_DivlEnReg 0x03
|
||||
|
||||
#define REG_ComIrqReg 0x04
|
||||
#define REG_ComIrqReg_Set1 (1 << 7)
|
||||
#define REG_ComIrqReg_TxIRq (1 << 6)
|
||||
#define REG_ComIrqReg_RxIRq (1 << 5)
|
||||
#define REG_ComIrqReg_IdleIRq (1 << 4)
|
||||
#define REG_ComIrqReg_HiAlertIRq (1 << 3)
|
||||
#define REG_ComIrqReg_LoAlertIRq (1 << 2)
|
||||
#define REG_ComIrqReg_ErrIRq (1 << 1)
|
||||
#define REG_ComIrqReg_TimerIRq (1 << 0)
|
||||
|
||||
#define REG_DivIrqReg 0x05
|
||||
#define REG_DivIrqReg_MfinActIRq (1 << 4)
|
||||
#define REG_DivIrqReg_CRCIRq (1 << 2)
|
||||
|
||||
#define REG_ErrorReg 0x06
|
||||
|
||||
#define REG_Status1Reg 0x07
|
||||
|
||||
#define REG_Status2Reg 0x08
|
||||
#define REG_Status2Reg_MFCrypto1On (1 << 3)
|
||||
|
||||
#define REG_FIFODataReg 0x09
|
||||
|
||||
#define REG_FIFOLevelReg 0x0A
|
||||
#define REG_FIFOLevelReg_FlushBuffer (1 << 7)
|
||||
#define REG_FIFOLevelReg_Level_PACK(x) ((x & 0x7F) << 0)
|
||||
#define REG_FIFOLevelReg_Level_UNPACK(x) ((x >> 0) & 0x7F)
|
||||
|
||||
#define REG_WaterLevelReg 0x0B
|
||||
|
||||
#define REG_ControlReg 0x0C
|
||||
|
||||
#define REG_BitFramingReg 0x0D
|
||||
#define REG_BitFramingReg_StartSend (1 << 7)
|
||||
#define REG_BitFramingReg_RxAlign_PACK(x) ((x & 7) << 4)
|
||||
#define REG_BitFramingReg_RxAlign_UNPACK(x) ((x >> 4) & 7)
|
||||
#define REG_BitFramingReg_TxLastBits_PACK(x) ((x & 7) << 0)
|
||||
#define REG_BitFramingReg_TxLastBits_UNPACK(x) ((x >> 0) & 7)
|
||||
|
||||
#define REG_CollReg 0x0E
|
||||
|
||||
#define REG_ModeReg 0x11
|
||||
|
||||
#define REG_TxModeReg 0x12
|
||||
#define REG_TxModeReg_TxCRCEn (1 << 7)
|
||||
#define REG_TxModeReg_TxSpeed_106k (0 << 4)
|
||||
#define REG_TxModeReg_TxSpeed_212k (1 << 4)
|
||||
#define REG_TxModeReg_TxSpeed_424k (2 << 4)
|
||||
#define REG_TxModeReg_TxSpeed_847k (3 << 4)
|
||||
#define REG_TxModeReg_TxSpeed_MASK (7 << 4)
|
||||
|
||||
#define REG_RxModeReg 0x13
|
||||
#define REG_RxModeReg_RxCRCEn (1 << 7)
|
||||
#define REG_RxModeReg_RxSpeed_106k (0 << 4)
|
||||
#define REG_RxModeReg_RxSpeed_212k (1 << 4)
|
||||
#define REG_RxModeReg_RxSpeed_424k (2 << 4)
|
||||
#define REG_RxModeReg_RxSpeed_847k (3 << 4)
|
||||
#define REG_RxModeReg_RxSpeed_MASK (7 << 4)
|
||||
|
||||
#define REG_TxControlReg 0x14
|
||||
#define REG_TxControlReg_Tx2RFEn (1 << 1)
|
||||
#define REG_TxControlReg_Tx1RFEn (1 << 0)
|
||||
|
||||
#define REG_TxASKReg 0x15
|
||||
|
||||
#define REG_TxSelReg 0x16
|
||||
|
||||
#define REG_RxSelReg 0x17
|
||||
|
||||
#define REG_RxThresholdReg 0x18
|
||||
|
||||
#define REG_DemodReg 0x19
|
||||
|
||||
#define REG_MfTxReg 0x1C
|
||||
|
||||
#define REG_MfRxReg 0x1D
|
||||
#define REG_MfRxReg_ParityDisable (1 << 4)
|
||||
|
||||
#define REG_SerialSpeedReg 0x1F
|
||||
#define REG_CRCResultReg 0x21
|
||||
#define REG_ModWidthReg 0x24
|
||||
#define REG_RFCfgReg 0x26
|
||||
#define REG_GsNReg 0x27
|
||||
#define REG_CWGsPReg 0x28
|
||||
#define REG_ModGsPReg 0x29
|
||||
#define REG_TModeReg 0x2A
|
||||
#define REG_TPrescalerReg 0x2B
|
||||
#define REG_TReloadReg 0x2C
|
||||
#define REG_TCounterValReg 0x2E
|
||||
#define REG_TestSel1Reg 0x31
|
||||
#define REG_TestSel2Reg 0x32
|
||||
#define REG_TestPinEnReg 0x33
|
||||
#define REG_TestPinValueReg 0x34
|
||||
#define REG_TestBusReg 0x35
|
||||
|
||||
#define REG_AutoTestReg 0x36
|
||||
#define REG_AutoTestReg_SelfTest_Disabled (0x0 << 0)
|
||||
#define REG_AutoTestReg_SelfTest_Enabled (0x9 << 0)
|
||||
#define REG_AutoTestReg_SelfTest_MASK (0xF << 0)
|
||||
|
||||
#define REG_VersionReg 0x37
|
||||
#define REG_AnalogTestReg 0x38
|
||||
#define REG_TestDAC1Reg 0x39
|
||||
#define REG_TestDAC2Reg 0x3A
|
||||
#define REG_TestADCReg 0x3B
|
||||
|
||||
#endif
|
||||
765
libnfc/chips/rc522.c
Normal file
765
libnfc/chips/rc522.c
Normal file
@ -0,0 +1,765 @@
|
||||
/*-
|
||||
* Free/Libre Near Field Communication (NFC) library
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by the
|
||||
* Free Software Foundation, either version 3 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "rc522.h"
|
||||
#include "rc522-internal.h"
|
||||
|
||||
#include "nfc/nfc.h"
|
||||
#include "nfc-internal.h"
|
||||
#include "timing.h"
|
||||
|
||||
// This divides by 8 with rounding towards infinity
|
||||
#define BITS2BYTES(x) ((x >> 3) + ((x & 7) ? 1 : 0))
|
||||
#define CHIP_DATA(x) ((struct rc522_chip_data *) (x)->chip_data)
|
||||
#define CHK(x) ret = (x); if (ret < 0) { return ret; }
|
||||
|
||||
#define LOG_CATEGORY "libnfc.chip.rc522"
|
||||
#define LOG_GROUP NFC_LOG_GROUP_CHIP
|
||||
|
||||
#define TIMEOUT_DEFAULT -1
|
||||
#define TIMEOUT_NEVER 0
|
||||
|
||||
const nfc_modulation_type rc522_initiator_modulation[] = { NMT_ISO14443A, 0 };
|
||||
const nfc_modulation_type rc522_target_modulation[] = { 0 };
|
||||
|
||||
const nfc_baud_rate rc522_iso14443a_supported_baud_rates[] = { NBR_847, NBR_424, NBR_212, NBR_106, 0 };
|
||||
|
||||
struct rc522_chip_data {
|
||||
const struct rc522_io * io;
|
||||
uint8_t version;
|
||||
int default_timeout;
|
||||
};
|
||||
|
||||
|
||||
int rc522_data_new(struct nfc_device * pnd, const struct rc522_io * io) {
|
||||
pnd->chip_data = malloc(sizeof(struct rc522_chip_data));
|
||||
if (!pnd->chip_data) {
|
||||
perror("malloc");
|
||||
return NFC_ESOFT;
|
||||
}
|
||||
|
||||
CHIP_DATA(pnd)->io = io;
|
||||
CHIP_DATA(pnd)->version = RC522_UNKNOWN;
|
||||
CHIP_DATA(pnd)->default_timeout = 500;
|
||||
return NFC_SUCCESS;
|
||||
}
|
||||
|
||||
void rc522_data_free(struct nfc_device * pnd) {
|
||||
free(pnd->chip_data);
|
||||
}
|
||||
|
||||
int rc522_read_bulk(struct nfc_device * pnd, uint8_t reg, uint8_t * val, size_t len) {
|
||||
int ret = CHIP_DATA(pnd)->io->read(pnd, reg, val, len);
|
||||
if (ret) {
|
||||
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "Unable to read register %02X (err: %d)", reg, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
#ifdef LOG
|
||||
char action[8];
|
||||
snprintf(action, sizeof(action), "RD %02X", reg);
|
||||
LOG_HEX(NFC_LOG_GROUP_CHIP, action, val, len);
|
||||
#endif
|
||||
|
||||
return NFC_SUCCESS;
|
||||
}
|
||||
|
||||
int rc522_write_bulk(struct nfc_device * pnd, uint8_t reg, const uint8_t * val, size_t len) {
|
||||
int ret = CHIP_DATA(pnd)->io->write(pnd, reg, val, len);
|
||||
if (ret) {
|
||||
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "Unable to write register %02X!", reg);
|
||||
return ret;
|
||||
}
|
||||
|
||||
#ifdef LOG
|
||||
char action[8];
|
||||
snprintf(action, sizeof(action), "WR %02X", reg);
|
||||
LOG_HEX(NFC_LOG_GROUP_CHIP, action, val, len);
|
||||
#endif
|
||||
|
||||
return NFC_SUCCESS;
|
||||
}
|
||||
|
||||
int rc522_read_reg(struct nfc_device * pnd, uint8_t reg) {
|
||||
uint8_t val;
|
||||
int ret;
|
||||
CHK(rc522_read_bulk(pnd, reg, &val, 1));
|
||||
return val;
|
||||
}
|
||||
|
||||
int rc522_write_reg(struct nfc_device * pnd, uint8_t reg, uint8_t val) {
|
||||
return rc522_write_bulk(pnd, reg, &val, 1);
|
||||
}
|
||||
|
||||
int rc522_write_reg_mask(struct nfc_device * pnd, uint8_t reg, uint8_t val, uint8_t mask) {
|
||||
if (mask != 0xFF) {
|
||||
int oldval = rc522_read_reg(pnd, reg);
|
||||
if (oldval < 0) {
|
||||
return oldval;
|
||||
}
|
||||
|
||||
val = (val & mask) | (oldval & ~mask);
|
||||
}
|
||||
|
||||
return rc522_write_reg(pnd, reg, val);
|
||||
}
|
||||
|
||||
int rc522_start_command(struct nfc_device * pnd, rc522_cmd cmd) {
|
||||
bool needsRX;
|
||||
|
||||
// Disabling RX saves energy, so based on the command we'll also update the RxOff flag
|
||||
switch (cmd) {
|
||||
case CMD_IDLE:
|
||||
case CMD_MEM:
|
||||
case CMD_GENRANDOMID:
|
||||
case CMD_CALCCRC:
|
||||
case CMD_TRANSMIT:
|
||||
case CMD_SOFTRESET:
|
||||
needsRX = false;
|
||||
break;
|
||||
|
||||
case CMD_RECEIVE:
|
||||
case CMD_TRANSCEIVE:
|
||||
case CMD_MFAUTHENT:
|
||||
needsRX = true;
|
||||
break;
|
||||
|
||||
case CMD_NOCMDCHANGE:
|
||||
return NFC_SUCCESS;
|
||||
|
||||
default:
|
||||
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "Attempted to execute non-existant command: %02X", cmd);
|
||||
return NFC_ESOFT;
|
||||
}
|
||||
|
||||
uint8_t regval = cmd;
|
||||
if (!needsRX) {
|
||||
regval |= REG_CommandReg_RcvOff;
|
||||
}
|
||||
|
||||
return rc522_write_reg(pnd, REG_CommandReg, regval);
|
||||
}
|
||||
|
||||
int rc522_wait_wakeup(struct nfc_device * pnd) {
|
||||
// NXP does not mention in the datasheet how much time does it take for RC522 to come back to life, so we'll wait up to 50ms
|
||||
timeout_t to;
|
||||
timeout_init(&to, 50);
|
||||
|
||||
while (timeout_check(&to)) {
|
||||
int ret = rc522_read_reg(pnd, REG_CommandReg);
|
||||
if (ret < 0 && ret != NFC_ETIMEOUT) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
// If the powerdown bit is zero the RC522 is ready to kick asses!
|
||||
if ((ret & REG_CommandReg_PowerDown) == 0) {
|
||||
return NFC_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "rc522_wait_wakeup timeout!");
|
||||
return NFC_ETIMEOUT;
|
||||
}
|
||||
|
||||
int rc522_send_baudrate(struct nfc_device * pnd, uint32_t baudrate) {
|
||||
uint8_t regval;
|
||||
|
||||
// MFRC522 datasheet 8.1.3.2
|
||||
switch (baudrate) {
|
||||
case 7200:
|
||||
regval = 0xFA;
|
||||
break;
|
||||
case 9600:
|
||||
regval = 0xEB;
|
||||
break;
|
||||
case 14400:
|
||||
regval = 0xDA;
|
||||
break;
|
||||
case 19200:
|
||||
regval = 0xCB;
|
||||
break;
|
||||
case 38400:
|
||||
regval = 0xAB;
|
||||
break;
|
||||
case 57600:
|
||||
regval = 0x9A;
|
||||
break;
|
||||
case 115200:
|
||||
regval = 0x7A;
|
||||
break;
|
||||
case 128000:
|
||||
regval = 0x74;
|
||||
break;
|
||||
case 230400:
|
||||
regval = 0x5A;
|
||||
break;
|
||||
case 460800:
|
||||
regval = 0x3A;
|
||||
break;
|
||||
case 921600:
|
||||
regval = 0x1C;
|
||||
break;
|
||||
case 1288000:
|
||||
regval = 0x15;
|
||||
break;
|
||||
default:
|
||||
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "rc522_write_baudrate unsupported baud rate: %d bps.", baudrate);
|
||||
return NFC_EDEVNOTSUPP;
|
||||
}
|
||||
|
||||
return rc522_write_reg(pnd, REG_SerialSpeedReg, regval);
|
||||
}
|
||||
|
||||
int rc522_soft_reset(struct nfc_device * pnd) {
|
||||
int ret;
|
||||
|
||||
// 1. Execute reset command
|
||||
CHK(rc522_start_command(pnd, CMD_SOFTRESET));
|
||||
|
||||
// 2. If using an UART, reset baud rate to RC522 default speed
|
||||
if (CHIP_DATA(pnd)->io->reset_baud_rate) {
|
||||
CHK(CHIP_DATA(pnd)->io->reset_baud_rate(pnd));
|
||||
}
|
||||
|
||||
// 3. Wait for the RC522 to come back to life, as we shouldn't modify any register till that happens
|
||||
CHK(rc522_wait_wakeup(pnd));
|
||||
|
||||
// 4. If using an UART, restore baud rate to user's choice
|
||||
if (CHIP_DATA(pnd)->io->upgrade_baud_rate) {
|
||||
CHK(CHIP_DATA(pnd)->io->upgrade_baud_rate(pnd));
|
||||
}
|
||||
|
||||
return NFC_SUCCESS;
|
||||
}
|
||||
|
||||
int rc522_set_rf_baud_rate(struct nfc_device * pnd, nfc_baud_rate speed) {
|
||||
uint8_t txVal, rxVal;
|
||||
int ret;
|
||||
|
||||
switch (speed) {
|
||||
case NBR_106:
|
||||
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "Updating RF baud rate to 106kbps.");
|
||||
txVal = REG_TxModeReg_TxSpeed_106k;
|
||||
rxVal = REG_RxModeReg_RxSpeed_106k;
|
||||
break;
|
||||
|
||||
case NBR_212:
|
||||
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "Updating RF baud rate to 212kbps.");
|
||||
txVal = REG_TxModeReg_TxSpeed_212k;
|
||||
rxVal = REG_RxModeReg_RxSpeed_212k;
|
||||
break;
|
||||
|
||||
case NBR_424:
|
||||
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "Updating RF baud rate to 424kbps.");
|
||||
txVal = REG_TxModeReg_TxSpeed_424k;
|
||||
rxVal = REG_RxModeReg_RxSpeed_424k;
|
||||
break;
|
||||
|
||||
case NBR_847:
|
||||
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "Updating RF baud rate to 847kbps.");
|
||||
txVal = REG_TxModeReg_TxSpeed_847k;
|
||||
rxVal = REG_RxModeReg_RxSpeed_847k;
|
||||
break;
|
||||
|
||||
default:
|
||||
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "Attempted to switch RF baud rate to 0x%08X.", speed);
|
||||
return NFC_EINVARG;
|
||||
}
|
||||
|
||||
CHK(rc522_write_reg_mask(pnd, REG_TxModeReg, txVal, REG_TxModeReg_TxSpeed_MASK));
|
||||
CHK(rc522_write_reg_mask(pnd, REG_RxModeReg, rxVal, REG_RxModeReg_RxSpeed_MASK));
|
||||
|
||||
return NFC_SUCCESS;
|
||||
}
|
||||
|
||||
int rc522_initiator_select_passive_target_ext(struct nfc_device * pnd, const nfc_modulation nm, const uint8_t * pbtInitData, const size_t szInitData, nfc_target * pnt, int timeout) {
|
||||
int ret;
|
||||
|
||||
if (nm.nmt != NMT_ISO14443A) {
|
||||
return NFC_EINVARG;
|
||||
}
|
||||
|
||||
CHK(rc522_set_rf_baud_rate(pnd, nm.nbr));
|
||||
|
||||
// TODO
|
||||
return NFC_ENOTIMPL;
|
||||
}
|
||||
|
||||
void rc522_timeout_init(struct nfc_device * pnd, timeout_t * to, int timeout) {
|
||||
if (timeout == TIMEOUT_NEVER) {
|
||||
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "rc522_timeout_init: creating timeout which doesn't expire.");
|
||||
timeout_never(to);
|
||||
} else {
|
||||
if (timeout == TIMEOUT_DEFAULT) {
|
||||
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "rc522_timeout_init: creating with default time (%d ms).", CHIP_DATA(pnd)->default_timeout);
|
||||
timeout = CHIP_DATA(pnd)->default_timeout;
|
||||
} else {
|
||||
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "rc522_timeout_init: creating with custom time of %d ms.", timeout);
|
||||
}
|
||||
|
||||
timeout_init(to, timeout);
|
||||
}
|
||||
}
|
||||
|
||||
int rc522_rf_tx(struct nfc_device * pnd, const uint8_t * txData, const size_t txBits, timeout_t * timeout, bool transceive) {
|
||||
size_t txBytes = BITS2BYTES(txBits);
|
||||
size_t transmitted = MIN(txBytes, FIFO_SIZE);
|
||||
int ret;
|
||||
|
||||
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "rc522_rf_tx: sending %d bits (%d bytes).", txBits, txBytes);
|
||||
|
||||
CHK(rc522_write_reg(pnd, REG_ComIrqReg, REG_ComIrqReg_TxIRq | REG_ComIrqReg_RxIRq | REG_ComIrqReg_LoAlertIRq | REG_ComIrqReg_ErrIRq));
|
||||
CHK(rc522_write_bulk(pnd, REG_FIFODataReg, txData, transmitted));
|
||||
|
||||
if (transceive) {
|
||||
// If transceiving we must first start the command and then configure framing and start transmission
|
||||
CHK(rc522_start_command(pnd, CMD_TRANSCEIVE));
|
||||
CHK(rc522_write_reg(pnd, REG_BitFramingReg, REG_BitFramingReg_StartSend | REG_BitFramingReg_RxAlign_PACK(0) | REG_BitFramingReg_TxLastBits_PACK(txBits)));
|
||||
} else {
|
||||
// If only transmitting we must configure framing and then start the transmission
|
||||
CHK(rc522_write_reg(pnd, REG_BitFramingReg, REG_BitFramingReg_RxAlign_PACK(0) | REG_BitFramingReg_TxLastBits_PACK(txBits)));
|
||||
CHK(rc522_start_command(pnd, CMD_TRANSMIT));
|
||||
}
|
||||
|
||||
while (1) {
|
||||
if (!timeout_check(timeout)) {
|
||||
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "rc522_rf_tx: transmission timeout.");
|
||||
return NFC_ETIMEOUT;
|
||||
}
|
||||
|
||||
int irqs = CHK(rc522_read_reg(pnd, REG_ComIrqReg));
|
||||
|
||||
if (irqs & REG_ComIrqReg_ErrIRq) {
|
||||
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "rc522_rf_tx: RC522 set ErrIRq flag.");
|
||||
// If the RC522 detects an error abort the transmission and notify the caller
|
||||
return NFC_ECHIP;
|
||||
}
|
||||
|
||||
if (irqs & REG_ComIrqReg_TxIRq) {
|
||||
// Check if the FIFO has underflowed (ie the transmission has ended before we've feeded all the bytes to the FIFO)
|
||||
if (transmitted < txBytes) {
|
||||
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "rc522_rf_tx: couldn't feed bytes fast enough. Only %d out of %d bytes have been sent. Aborting transmission.", transmitted, txBytes);
|
||||
return NFC_ESOFT;
|
||||
}
|
||||
// Otherwise we're done
|
||||
break;
|
||||
}
|
||||
|
||||
if ((irqs & REG_ComIrqReg_LoAlertIRq) && transmitted < txBytes) {
|
||||
// Okay, now attempt to write as many bytes as possible. This IRQ is generated based on the water level, so we know for sure we can feed at least FIFO_SIZE - DEFAULT_WATER_LEVEL bytes.
|
||||
size_t chunkSize = MIN(txBytes - transmitted, FIFO_SIZE - DEFAULT_WATER_LEVEL);
|
||||
CHK(rc522_write_bulk(pnd, REG_FIFODataReg, txData + transmitted, chunkSize));
|
||||
transmitted += chunkSize;
|
||||
|
||||
// TODO: Should we clear the flag before or after feeding the data?
|
||||
CHK(rc522_write_reg(pnd, REG_ComIrqReg, REG_ComIrqReg_LoAlertIRq));
|
||||
|
||||
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "rc522_rf_tx: fed another %d bytes to FIFO.", chunkSize);
|
||||
}
|
||||
}
|
||||
|
||||
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "rc522_rf_tx: transmission finished.");
|
||||
return NFC_SUCCESS;
|
||||
}
|
||||
|
||||
int rc522_rf_rx(struct nfc_device * pnd, uint8_t * rxData, const size_t rxMaxBytes, timeout_t * timeout, bool transceive) {
|
||||
int ret;
|
||||
size_t received = 0;
|
||||
|
||||
// Clear this as early as possible
|
||||
CHK(rc522_write_reg(pnd, REG_ComIrqReg, REG_ComIrqReg_HiAlertIRq));
|
||||
|
||||
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "rc522_rf_rx: receiving up to %d bytes.", rxMaxBytes);
|
||||
|
||||
if (!transceive) {
|
||||
CHK(rc522_write_reg(pnd, REG_ComIrqReg, REG_ComIrqReg_TxIRq | REG_ComIrqReg_RxIRq | REG_ComIrqReg_LoAlertIRq | REG_ComIrqReg_ErrIRq));
|
||||
CHK(rc522_start_command(pnd, CMD_RECEIVE));
|
||||
}
|
||||
|
||||
while (1) {
|
||||
if (!timeout_check(timeout)) {
|
||||
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "rc522_rf_rx: transmission timeout.");
|
||||
return NFC_ETIMEOUT;
|
||||
}
|
||||
|
||||
int irqs = CHK(rc522_read_reg(pnd, REG_ComIrqReg));
|
||||
|
||||
if (irqs & REG_ComIrqReg_ErrIRq) {
|
||||
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "rc522_rf_rx: RC522 set ErrIRq flag.");
|
||||
// If the RC522 detects an error abort the transmission and notify the caller
|
||||
return NFC_ECHIP;
|
||||
}
|
||||
|
||||
if (irqs & REG_ComIrqReg_RxIRq) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (irqs & REG_ComIrqReg_HiAlertIRq) {
|
||||
size_t chunkSize = FIFO_SIZE - DEFAULT_WATER_LEVEL;
|
||||
if (rxMaxBytes - received < chunkSize) {
|
||||
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "rc522_rf_rx: RX buffer overflow (buffer contains %d bytes and may hold up to %d bytes, but needs %d more).", received, rxMaxBytes, chunkSize);
|
||||
return NFC_EOVFLOW;
|
||||
}
|
||||
|
||||
CHK(rc522_read_bulk(pnd, REG_FIFODataReg, rxData + received, chunkSize));
|
||||
received += chunkSize;
|
||||
|
||||
// TODO: Should we clear the flag before or after feeding the data?
|
||||
CHK(rc522_write_reg(pnd, REG_ComIrqReg, REG_ComIrqReg_HiAlertIRq));
|
||||
|
||||
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "rc522_rf_rx: read another %d bytes from FIFO.", chunkSize);
|
||||
}
|
||||
}
|
||||
|
||||
CHK(rc522_read_reg(pnd, REG_FIFOLevelReg));
|
||||
size_t remaining = REG_FIFOLevelReg_Level_UNPACK(ret);
|
||||
|
||||
if (rxMaxBytes - received < remaining) {
|
||||
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "rc522_rf_rx: RX buffer overflow (buffer contains %d bytes and may hold up to %d bytes, but needs %d more).", received, rxMaxBytes, remaining);
|
||||
return NFC_EOVFLOW;
|
||||
}
|
||||
|
||||
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "rc522_rf_rx: reading last %d bytes from FIFO.", remaining);
|
||||
CHK(rc522_read_bulk(pnd, REG_FIFODataReg, rxData + received, remaining));
|
||||
received += remaining;
|
||||
|
||||
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "rc522_rf_rx: receive finished. Read %d bytes.", received);
|
||||
|
||||
return received;
|
||||
}
|
||||
|
||||
int rc522_transceive(struct nfc_device * pnd, const uint8_t * txData, const size_t txBits, uint8_t * rxData, const size_t rxMaxBytes, int timeout) {
|
||||
int ret;
|
||||
|
||||
bool doTX = txData != NULL && txBits > 0;
|
||||
bool doRX = rxData != NULL && rxMaxBytes > 0;
|
||||
bool isTransceive = doTX && doRX;
|
||||
|
||||
CHK(rc522_abort(pnd));
|
||||
|
||||
timeout_t to;
|
||||
rc522_timeout_init(pnd, &to, timeout);
|
||||
|
||||
if (doTX) {
|
||||
ret = rc522_rf_tx(pnd, txData, txBits, &to, isTransceive);
|
||||
if (ret < 0) {
|
||||
rc522_abort(pnd);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
if (doRX) {
|
||||
ret = rc522_rf_rx(pnd, rxData, rxMaxBytes, &to, isTransceive);
|
||||
if (ret < 0) {
|
||||
rc522_abort(pnd);
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int rc522_initiator_transceive_bits(struct nfc_device * pnd, const uint8_t * txData, const size_t txBits, const uint8_t * pbtTxPar, uint8_t * rxData, uint8_t * pbtRxPar) {
|
||||
int ret;
|
||||
// TODO: Do something with pbtTxPar and pbtRxPar
|
||||
CHK(rc522_transceive(pnd, txData, txBits, rxData, ~0, TIMEOUT_DEFAULT));
|
||||
return ret * 8;
|
||||
}
|
||||
|
||||
int rc522_initiator_transceive_bytes(struct nfc_device * pnd, const uint8_t * txData, const size_t txSize, uint8_t * rxData, const size_t rxMaxBytes, int timeout) {
|
||||
return rc522_transceive(pnd, txData, txSize * 8, rxData, rxMaxBytes, timeout);
|
||||
}
|
||||
|
||||
int rc522_get_supported_modulation(struct nfc_device * pnd, const nfc_mode mode, const nfc_modulation_type ** const supported_mt) {
|
||||
(void) pnd;
|
||||
|
||||
switch (mode) {
|
||||
case N_INITIATOR:
|
||||
*supported_mt = rc522_initiator_modulation;
|
||||
break;
|
||||
|
||||
case N_TARGET:
|
||||
*supported_mt = rc522_target_modulation;
|
||||
break;
|
||||
|
||||
default:
|
||||
return NFC_EINVARG;
|
||||
}
|
||||
|
||||
return NFC_SUCCESS;
|
||||
}
|
||||
|
||||
int rc522_get_supported_baud_rate(struct nfc_device * pnd, const nfc_mode mode, const nfc_modulation_type nmt, const nfc_baud_rate ** const supported_br) {
|
||||
(void) pnd;
|
||||
|
||||
switch (mode) {
|
||||
case N_INITIATOR:
|
||||
switch (nmt) {
|
||||
case NMT_ISO14443A:
|
||||
*supported_br = rc522_iso14443a_supported_baud_rates;
|
||||
break;
|
||||
|
||||
default:
|
||||
return NFC_EINVARG;
|
||||
}
|
||||
break;
|
||||
|
||||
case N_TARGET:
|
||||
default:
|
||||
return NFC_EINVARG;
|
||||
}
|
||||
|
||||
return NFC_SUCCESS;
|
||||
}
|
||||
|
||||
int rc522_set_property_bool(struct nfc_device * pnd, const nfc_property property, const bool enable) {
|
||||
int ret;
|
||||
|
||||
switch (property) {
|
||||
case NP_HANDLE_CRC:
|
||||
if (pnd->bCrc == enable) {
|
||||
return NFC_SUCCESS;
|
||||
}
|
||||
|
||||
CHK(rc522_write_reg_mask(pnd, REG_TxModeReg, enable ? ~0 : 0, REG_TxModeReg_TxCRCEn));
|
||||
CHK(rc522_write_reg_mask(pnd, REG_RxModeReg, enable ? ~0 : 0, REG_RxModeReg_RxCRCEn));
|
||||
|
||||
pnd->bCrc = enable;
|
||||
return NFC_SUCCESS;
|
||||
|
||||
case NP_HANDLE_PARITY:
|
||||
if (pnd->bPar == enable) {
|
||||
return NFC_SUCCESS;
|
||||
}
|
||||
|
||||
// Note it's parity DISABLE (ie active low)
|
||||
CHK(rc522_write_reg_mask(pnd, REG_MfRxReg, enable ? 0 : ~0, REG_MfRxReg_ParityDisable));
|
||||
|
||||
pnd->bPar = enable;
|
||||
return NFC_SUCCESS;
|
||||
|
||||
case NP_EASY_FRAMING:
|
||||
pnd->bEasyFraming = enable;
|
||||
return NFC_SUCCESS;
|
||||
|
||||
case NP_ACTIVATE_FIELD:
|
||||
return rc522_write_reg_mask(pnd, REG_TxControlReg, enable ? ~0 : 0, REG_TxControlReg_Tx2RFEn | REG_TxControlReg_Tx1RFEn);
|
||||
|
||||
case NP_ACTIVATE_CRYPTO1:
|
||||
return rc522_write_reg_mask(pnd, REG_Status2Reg, enable ? ~0 : 0, REG_Status2Reg_MFCrypto1On);
|
||||
|
||||
case NP_FORCE_ISO14443_A:
|
||||
// ISO14443-A is the only mode supported by MFRC522
|
||||
return NFC_SUCCESS;
|
||||
|
||||
case NP_FORCE_SPEED_106:
|
||||
if (!enable) {
|
||||
return NFC_SUCCESS;
|
||||
}
|
||||
|
||||
return rc522_set_rf_baud_rate(pnd, NBR_106);
|
||||
|
||||
case NP_ACCEPT_MULTIPLE_FRAMES:
|
||||
// TODO: Figure out what this does and implement it
|
||||
// HACK: Return NFC_SUCCESS so nfc-anticol runs
|
||||
return NFC_SUCCESS;
|
||||
|
||||
case NP_AUTO_ISO14443_4:
|
||||
// TODO: Figure out what this does and implement it
|
||||
// HACK: Return NFC_SUCCESS so nfc-anticol runs
|
||||
return NFC_SUCCESS;
|
||||
|
||||
case NP_ACCEPT_INVALID_FRAMES:
|
||||
// TODO: Figure out what this does and implement it
|
||||
// HACK: Return NFC_SUCCESS so nfc-anticol runs
|
||||
return NFC_SUCCESS;
|
||||
|
||||
case NP_INFINITE_SELECT:
|
||||
// TODO: The RC522 can't do scans on its own, what now?
|
||||
// HACK: Return NFC_SUCCESS so nfc-anticol runs
|
||||
return NFC_SUCCESS;
|
||||
|
||||
case NP_FORCE_ISO14443_B:
|
||||
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "Attempted to enable ISO14443B");
|
||||
if (enable) {
|
||||
return NFC_EDEVNOTSUPP;
|
||||
}
|
||||
return NFC_SUCCESS;
|
||||
|
||||
case NP_TIMEOUT_COMMAND:
|
||||
case NP_TIMEOUT_ATR:
|
||||
case NP_TIMEOUT_COM:
|
||||
break;
|
||||
}
|
||||
|
||||
return NFC_EINVARG;
|
||||
}
|
||||
|
||||
int rc522_set_property_int(struct nfc_device * pnd, const nfc_property property, const int value) {
|
||||
switch (property) {
|
||||
case NP_TIMEOUT_COMMAND:
|
||||
if (value >= 0) {
|
||||
CHIP_DATA(pnd)->default_timeout = value;
|
||||
return NFC_SUCCESS;
|
||||
}
|
||||
break;
|
||||
|
||||
case NP_TIMEOUT_ATR:
|
||||
// TODO: Figure out what this does and implement it
|
||||
return NFC_ENOTIMPL;
|
||||
|
||||
case NP_TIMEOUT_COM:
|
||||
// TODO: Figure out what this does and implement it
|
||||
return NFC_ENOTIMPL;
|
||||
|
||||
case NP_HANDLE_CRC:
|
||||
case NP_HANDLE_PARITY:
|
||||
case NP_EASY_FRAMING:
|
||||
case NP_ACTIVATE_FIELD:
|
||||
case NP_ACTIVATE_CRYPTO1:
|
||||
case NP_FORCE_ISO14443_A:
|
||||
case NP_FORCE_SPEED_106:
|
||||
case NP_ACCEPT_MULTIPLE_FRAMES:
|
||||
case NP_AUTO_ISO14443_4:
|
||||
case NP_ACCEPT_INVALID_FRAMES:
|
||||
case NP_INFINITE_SELECT:
|
||||
case NP_FORCE_ISO14443_B:
|
||||
break;
|
||||
}
|
||||
|
||||
return NFC_EINVARG;
|
||||
}
|
||||
|
||||
int rc522_initiator_init(struct nfc_device * pnd) {
|
||||
// TODO: Should we be doing something here?
|
||||
return NFC_SUCCESS;
|
||||
}
|
||||
|
||||
int rc522_abort(struct nfc_device * pnd) {
|
||||
int ret;
|
||||
|
||||
// Halt any running commands
|
||||
CHK(rc522_start_command(pnd, CMD_IDLE));
|
||||
// Clear FIFO
|
||||
CHK(rc522_write_reg(pnd, REG_FIFOLevelReg, REG_FIFOLevelReg_FlushBuffer));
|
||||
|
||||
return NFC_SUCCESS;
|
||||
}
|
||||
|
||||
int rc522_powerdown(struct nfc_device * pnd) {
|
||||
return rc522_write_reg(pnd, REG_CommandReg, REG_CommandReg_RcvOff | REG_CommandReg_PowerDown | CMD_NOCMDCHANGE);
|
||||
}
|
||||
|
||||
// NXP MFRC522 datasheet section 16.1.1
|
||||
const uint8_t MFRC522_V1_SELFTEST[FIFO_SIZE] = {
|
||||
0x00, 0xC6, 0x37, 0xD5, 0x32, 0xB7, 0x57, 0x5C, 0xC2, 0xD8, 0x7C, 0x4D, 0xD9, 0x70, 0xC7, 0x73,
|
||||
0x10, 0xE6, 0xD2, 0xAA, 0x5E, 0xA1, 0x3E, 0x5A, 0x14, 0xAF, 0x30, 0x61, 0xC9, 0x70, 0xDB, 0x2E,
|
||||
0x64, 0x22, 0x72, 0xB5, 0xBD, 0x65, 0xF4, 0xEC, 0x22, 0xBC, 0xD3, 0x72, 0x35, 0xCD, 0xAA, 0x41,
|
||||
0x1F, 0xA7, 0xF3, 0x53, 0x14, 0xDE, 0x7E, 0x02, 0xD9, 0x0F, 0xB5, 0x5E, 0x25, 0x1D, 0x29, 0x79
|
||||
};
|
||||
const uint8_t MFRC522_V2_SELFTEST[FIFO_SIZE] = {
|
||||
0x00, 0xEB, 0x66, 0xBA, 0x57, 0xBF, 0x23, 0x95, 0xD0, 0xE3, 0x0D, 0x3D, 0x27, 0x89, 0x5C, 0xDE,
|
||||
0x9D, 0x3B, 0xA7, 0x00, 0x21, 0x5B, 0x89, 0x82, 0x51, 0x3A, 0xEB, 0x02, 0x0C, 0xA5, 0x00, 0x49,
|
||||
0x7C, 0x84, 0x4D, 0xB3, 0xCC, 0xD2, 0x1B, 0x81, 0x5D, 0x48, 0x76, 0xD5, 0x71, 0x61, 0x21, 0xA9,
|
||||
0x86, 0x96, 0x83, 0x38, 0xCF, 0x9D, 0x5B, 0x6D, 0xDC, 0x15, 0xBA, 0x3E, 0x7D, 0x95, 0x3B, 0x2F
|
||||
};
|
||||
|
||||
int rc522_self_test(struct nfc_device * pnd) {
|
||||
const uint8_t * correct;
|
||||
switch (CHIP_DATA(pnd)->version) {
|
||||
case MFRC522_V1:
|
||||
correct = MFRC522_V1_SELFTEST;
|
||||
break;
|
||||
|
||||
case MFRC522_V2:
|
||||
correct = MFRC522_V2_SELFTEST;
|
||||
break;
|
||||
|
||||
default:
|
||||
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "Aborting self test for unknown version %02X.", CHIP_DATA(pnd)->version);
|
||||
return NFC_EDEVNOTSUPP;
|
||||
}
|
||||
|
||||
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "Executing self test");
|
||||
|
||||
uint8_t zeroes[25];
|
||||
memset(zeroes, 0x00, sizeof(zeroes));
|
||||
|
||||
int ret;
|
||||
// MFRC522 datasheet section 16.1.1
|
||||
// 1. Perform a soft reset
|
||||
CHK(rc522_soft_reset(pnd));
|
||||
// 2. Clear the internal buffer by writing 25 bytes of 0x00 and execute the Mem command
|
||||
CHK(rc522_write_bulk(pnd, REG_FIFODataReg, zeroes, sizeof(zeroes)));
|
||||
CHK(rc522_start_command(pnd, CMD_MEM));
|
||||
// 3. Enable the self test by writing 0x09 to the AutoTestReg register
|
||||
CHK(rc522_write_reg_mask(pnd, REG_AutoTestReg, REG_AutoTestReg_SelfTest_Enabled, REG_AutoTestReg_SelfTest_MASK));
|
||||
// 4. Write 0x00h to the FIFO buffer
|
||||
CHK(rc522_write_reg(pnd, REG_FIFODataReg, 0x00));
|
||||
// 5. Start the self test with the CalcCRC command
|
||||
CHK(rc522_start_command(pnd, CMD_CALCCRC));
|
||||
|
||||
// 6. Wait for the RC522 to calculate the selftest values
|
||||
// The official datasheet does not mentions how much time does it take, let's use 50ms
|
||||
timeout_t to;
|
||||
timeout_init(&to, 50);
|
||||
|
||||
while (1) {
|
||||
if (!timeout_check(&to)) {
|
||||
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "Self test timeout");
|
||||
return NFC_ETIMEOUT;
|
||||
}
|
||||
|
||||
CHK(rc522_read_reg(pnd, REG_DivIrqReg));
|
||||
|
||||
// If the RC522 has finished calculating the CRC proceed
|
||||
if (ret & REG_DivIrqReg_CRCIRq) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t response[FIFO_SIZE];
|
||||
// 7. Read selftest result
|
||||
CHK(rc522_read_bulk(pnd, REG_FIFODataReg, response, FIFO_SIZE));
|
||||
// 8. Disable selftest operation mode
|
||||
CHK(rc522_write_reg_mask(pnd, REG_AutoTestReg, REG_AutoTestReg_SelfTest_Disabled, REG_AutoTestReg_SelfTest_MASK));
|
||||
|
||||
if (memcmp(correct, response, FIFO_SIZE) != 0) {
|
||||
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "Self test values didn't match");
|
||||
return NFC_ECHIP;
|
||||
}
|
||||
|
||||
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "Self test executed successfully!");
|
||||
return NFC_SUCCESS;
|
||||
}
|
||||
|
||||
int rc522_init(struct nfc_device * pnd) {
|
||||
int ret;
|
||||
|
||||
int version = CHK(rc522_read_reg(pnd, REG_VersionReg));
|
||||
CHIP_DATA(pnd)->version = version;
|
||||
|
||||
ret = rc522_self_test(pnd);
|
||||
if (ret == NFC_EDEVNOTSUPP) {
|
||||
// TODO: Implement another test, maybe?
|
||||
ret = rc522_soft_reset(pnd);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
47
libnfc/chips/rc522.h
Normal file
47
libnfc/chips/rc522.h
Normal file
@ -0,0 +1,47 @@
|
||||
/*-
|
||||
* Free/Libre Near Field Communication (NFC) library
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by the
|
||||
* Free Software Foundation, either version 3 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __NFC_CHIPS_RC522_H__
|
||||
#define __NFC_CHIPS_RC522_H__
|
||||
|
||||
#include <stdint.h>
|
||||
#include <nfc/nfc-types.h>
|
||||
|
||||
struct rc522_io {
|
||||
int (*read)(struct nfc_device * pnd, uint8_t reg, uint8_t * data, size_t size);
|
||||
int (*write)(struct nfc_device * pnd, uint8_t reg, const uint8_t * data, size_t size);
|
||||
int (*reset_baud_rate)(struct nfc_device * pnd);
|
||||
int (*upgrade_baud_rate)(struct nfc_device * pnd);
|
||||
};
|
||||
|
||||
int rc522_data_new(struct nfc_device * pnd, const struct rc522_io * io);
|
||||
void rc522_data_free(struct nfc_device * pnd);
|
||||
int rc522_send_baudrate(struct nfc_device * pnd, uint32_t baudrate);
|
||||
int rc522_init(struct nfc_device * pnd);
|
||||
|
||||
int rc522_initiator_init(nfc_device * pnd);
|
||||
int rc522_initiator_transceive_bits(struct nfc_device * pnd, const uint8_t * txData, const size_t txBits, const uint8_t * pbtTxPar, uint8_t * rxData, uint8_t * pbtRxPar);
|
||||
int rc522_initiator_transceive_bytes(struct nfc_device * pnd, const uint8_t * txData, const size_t txSize, uint8_t * rxData, const size_t rxMaxBytes, int timeout);
|
||||
int rc522_get_supported_modulation(nfc_device * pnd, const nfc_mode mode, const nfc_modulation_type ** const supported_mt);
|
||||
int rc522_get_supported_baud_rate(nfc_device * pnd, const nfc_mode mode, const nfc_modulation_type nmt, const nfc_baud_rate ** const supported_br);
|
||||
int rc522_set_property_bool(struct nfc_device * pnd, const nfc_property property, const bool enable);
|
||||
int rc522_set_property_int(struct nfc_device * pnd, const nfc_property property, const int value);
|
||||
int rc522_abort(struct nfc_device * pnd);
|
||||
int rc522_powerdown(struct nfc_device * pnd);
|
||||
|
||||
#endif
|
||||
@ -39,6 +39,10 @@ if DRIVER_PN532_I2C_ENABLED
|
||||
libnfcdrivers_la_SOURCES += pn532_i2c.c pn532_i2c.h
|
||||
endif
|
||||
|
||||
if DRIVER_RC522_UART_ENABLED
|
||||
libnfcdrivers_la_SOURCES += rc522_uart.c rc522_uart.h
|
||||
endif
|
||||
|
||||
if PCSC_ENABLED
|
||||
libnfcdrivers_la_CFLAGS += @libpcsclite_CFLAGS@
|
||||
libnfcdrivers_la_LIBADD += @libpcsclite_LIBS@
|
||||
|
||||
@ -94,13 +94,9 @@ pn532_uart_scan(const nfc_context *context, nfc_connstring connstrings[], const
|
||||
snprintf(connstring, sizeof(nfc_connstring), "%s:%s:%"PRIu32, PN532_UART_DRIVER_NAME, acPort, PN532_UART_DEFAULT_SPEED);
|
||||
nfc_device *pnd = nfc_device_new(context, connstring);
|
||||
if (!pnd) {
|
||||
perror("malloc");
|
||||
perror("nfc_device_new");
|
||||
uart_close(sp);
|
||||
iDevice = 0;
|
||||
while ((acPort = acPorts[iDevice++])) {
|
||||
free((void *)acPort);
|
||||
}
|
||||
free(acPorts);
|
||||
uart_list_free(acPorts);
|
||||
return 0;
|
||||
}
|
||||
pnd->driver = &pn532_uart_driver;
|
||||
@ -109,25 +105,17 @@ pn532_uart_scan(const nfc_context *context, nfc_connstring connstrings[], const
|
||||
perror("malloc");
|
||||
uart_close(sp);
|
||||
nfc_device_free(pnd);
|
||||
iDevice = 0;
|
||||
while ((acPort = acPorts[iDevice++])) {
|
||||
free((void *)acPort);
|
||||
}
|
||||
free(acPorts);
|
||||
uart_list_free(acPorts);
|
||||
return 0;
|
||||
}
|
||||
DRIVER_DATA(pnd)->port = sp;
|
||||
|
||||
// Alloc and init chip's data
|
||||
if (pn53x_data_new(pnd, &pn532_uart_io) == NULL) {
|
||||
perror("malloc");
|
||||
perror("pn53x_data_new");
|
||||
uart_close(DRIVER_DATA(pnd)->port);
|
||||
nfc_device_free(pnd);
|
||||
iDevice = 0;
|
||||
while ((acPort = acPorts[iDevice++])) {
|
||||
free((void *)acPort);
|
||||
}
|
||||
free(acPorts);
|
||||
uart_list_free(acPorts);
|
||||
return 0;
|
||||
}
|
||||
// SAMConfiguration command if needed to wakeup the chip and pn53x_SAMConfiguration check if the chip is a PN532
|
||||
@ -141,11 +129,7 @@ pn532_uart_scan(const nfc_context *context, nfc_connstring connstrings[], const
|
||||
uart_close(DRIVER_DATA(pnd)->port);
|
||||
pn53x_data_free(pnd);
|
||||
nfc_device_free(pnd);
|
||||
iDevice = 0;
|
||||
while ((acPort = acPorts[iDevice++])) {
|
||||
free((void *)acPort);
|
||||
}
|
||||
free(acPorts);
|
||||
uart_list_free(acPorts);
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
@ -169,11 +153,7 @@ pn532_uart_scan(const nfc_context *context, nfc_connstring connstrings[], const
|
||||
break;
|
||||
}
|
||||
}
|
||||
iDevice = 0;
|
||||
while ((acPort = acPorts[iDevice++])) {
|
||||
free((void *)acPort);
|
||||
}
|
||||
free(acPorts);
|
||||
uart_list_free(acPorts);
|
||||
return device_found;
|
||||
}
|
||||
|
||||
@ -344,29 +324,26 @@ pn532_uart_send(nfc_device *pnd, const uint8_t *pbtData, const size_t szData, in
|
||||
size_t szFrame = 0;
|
||||
|
||||
if ((res = pn53x_build_frame(abtFrame, &szFrame, pbtData, szData)) < 0) {
|
||||
pnd->last_error = res;
|
||||
return pnd->last_error;
|
||||
return res;
|
||||
}
|
||||
|
||||
res = uart_send(DRIVER_DATA(pnd)->port, abtFrame, szFrame, timeout);
|
||||
if (res != 0) {
|
||||
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "%s", "Unable to transmit data. (TX)");
|
||||
pnd->last_error = res;
|
||||
return pnd->last_error;
|
||||
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "Unable to transmit data. (TX)");
|
||||
return res;
|
||||
}
|
||||
|
||||
uint8_t abtRxBuf[PN53x_ACK_FRAME__LEN];
|
||||
res = uart_receive(DRIVER_DATA(pnd)->port, abtRxBuf, sizeof(abtRxBuf), 0, timeout);
|
||||
if (res != 0) {
|
||||
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "%s", "Unable to read ACK");
|
||||
pnd->last_error = res;
|
||||
return pnd->last_error;
|
||||
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "Unable to read ACK");
|
||||
return res;
|
||||
}
|
||||
|
||||
if (pn53x_check_ack_frame(pnd, abtRxBuf, sizeof(abtRxBuf)) == 0) {
|
||||
// The PN53x is running the sent command
|
||||
} else {
|
||||
return pnd->last_error;
|
||||
return NFC_ECHIP;
|
||||
}
|
||||
return NFC_SUCCESS;
|
||||
}
|
||||
@ -384,21 +361,21 @@ pn532_uart_receive(nfc_device *pnd, uint8_t *pbtData, const size_t szDataLen, in
|
||||
abort_p = (void *) & (DRIVER_DATA(pnd)->abort_flag);
|
||||
#endif
|
||||
|
||||
pnd->last_error = uart_receive(DRIVER_DATA(pnd)->port, abtRxBuf, 5, abort_p, timeout);
|
||||
int res = uart_receive(DRIVER_DATA(pnd)->port, abtRxBuf, 5, abort_p, timeout);
|
||||
|
||||
if (abort_p && (NFC_EOPABORTED == pnd->last_error)) {
|
||||
if (abort_p && (NFC_EOPABORTED == res)) {
|
||||
pn532_uart_ack(pnd);
|
||||
return NFC_EOPABORTED;
|
||||
return res;
|
||||
}
|
||||
|
||||
if (pnd->last_error < 0) {
|
||||
if (res < 0) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
const uint8_t pn53x_preamble[3] = { 0x00, 0x00, 0xff };
|
||||
if (0 != (memcmp(abtRxBuf, pn53x_preamble, 3))) {
|
||||
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "%s", "Frame preamble+start code mismatch");
|
||||
pnd->last_error = NFC_EIO;
|
||||
res = NFC_EIO;
|
||||
goto error;
|
||||
}
|
||||
|
||||
@ -406,12 +383,12 @@ pn532_uart_receive(nfc_device *pnd, uint8_t *pbtData, const size_t szDataLen, in
|
||||
// Error frame
|
||||
uart_receive(DRIVER_DATA(pnd)->port, abtRxBuf, 3, 0, timeout);
|
||||
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "%s", "Application level error detected");
|
||||
pnd->last_error = NFC_EIO;
|
||||
res = NFC_EIO;
|
||||
goto error;
|
||||
} else if ((0xff == abtRxBuf[3]) && (0xff == abtRxBuf[4])) {
|
||||
// Extended frame
|
||||
pnd->last_error = uart_receive(DRIVER_DATA(pnd)->port, abtRxBuf, 3, 0, timeout);
|
||||
if (pnd->last_error != 0) {
|
||||
res = uart_receive(DRIVER_DATA(pnd)->port, abtRxBuf, 3, 0, timeout);
|
||||
if (res != 0) {
|
||||
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "%s", "Unable to receive data. (RX)");
|
||||
goto error;
|
||||
}
|
||||
@ -419,7 +396,7 @@ pn532_uart_receive(nfc_device *pnd, uint8_t *pbtData, const size_t szDataLen, in
|
||||
len = (abtRxBuf[0] << 8) + abtRxBuf[1] - 2;
|
||||
if (((abtRxBuf[0] + abtRxBuf[1] + abtRxBuf[2]) % 256) != 0) {
|
||||
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "%s", "Length checksum mismatch");
|
||||
pnd->last_error = NFC_EIO;
|
||||
res = NFC_EIO;
|
||||
goto error;
|
||||
}
|
||||
} else {
|
||||
@ -427,7 +404,7 @@ pn532_uart_receive(nfc_device *pnd, uint8_t *pbtData, const size_t szDataLen, in
|
||||
if (256 != (abtRxBuf[3] + abtRxBuf[4])) {
|
||||
// TODO: Retry
|
||||
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "%s", "Length checksum mismatch");
|
||||
pnd->last_error = NFC_EIO;
|
||||
res = NFC_EIO;
|
||||
goto error;
|
||||
}
|
||||
|
||||
@ -437,39 +414,39 @@ pn532_uart_receive(nfc_device *pnd, uint8_t *pbtData, const size_t szDataLen, in
|
||||
|
||||
if (len > szDataLen) {
|
||||
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "Unable to receive data: buffer too small. (szDataLen: %" PRIuPTR ", len: %" PRIuPTR ")", szDataLen, len);
|
||||
pnd->last_error = NFC_EIO;
|
||||
res = NFC_EIO;
|
||||
goto error;
|
||||
}
|
||||
|
||||
// TFI + PD0 (CC+1)
|
||||
pnd->last_error = uart_receive(DRIVER_DATA(pnd)->port, abtRxBuf, 2, 0, timeout);
|
||||
if (pnd->last_error != 0) {
|
||||
res = uart_receive(DRIVER_DATA(pnd)->port, abtRxBuf, 2, 0, timeout);
|
||||
if (res != 0) {
|
||||
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "%s", "Unable to receive data. (RX)");
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (abtRxBuf[0] != 0xD5) {
|
||||
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "%s", "TFI Mismatch");
|
||||
pnd->last_error = NFC_EIO;
|
||||
res = NFC_EIO;
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (abtRxBuf[1] != CHIP_DATA(pnd)->last_command + 1) {
|
||||
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "%s", "Command Code verification failed");
|
||||
pnd->last_error = NFC_EIO;
|
||||
res = NFC_EIO;
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (len) {
|
||||
pnd->last_error = uart_receive(DRIVER_DATA(pnd)->port, pbtData, len, 0, timeout);
|
||||
if (pnd->last_error != 0) {
|
||||
res = uart_receive(DRIVER_DATA(pnd)->port, pbtData, len, 0, timeout);
|
||||
if (res != 0) {
|
||||
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "%s", "Unable to receive data. (RX)");
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
||||
pnd->last_error = uart_receive(DRIVER_DATA(pnd)->port, abtRxBuf, 2, 0, timeout);
|
||||
if (pnd->last_error != 0) {
|
||||
res = uart_receive(DRIVER_DATA(pnd)->port, abtRxBuf, 2, 0, timeout);
|
||||
if (res != 0) {
|
||||
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "%s", "Unable to receive data. (RX)");
|
||||
goto error;
|
||||
}
|
||||
@ -482,20 +459,20 @@ pn532_uart_receive(nfc_device *pnd, uint8_t *pbtData, const size_t szDataLen, in
|
||||
|
||||
if (btDCS != abtRxBuf[0]) {
|
||||
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "%s", "Data checksum mismatch");
|
||||
pnd->last_error = NFC_EIO;
|
||||
res = NFC_EIO;
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (0x00 != abtRxBuf[1]) {
|
||||
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "%s", "Frame postamble mismatch");
|
||||
pnd->last_error = NFC_EIO;
|
||||
res = NFC_EIO;
|
||||
goto error;
|
||||
}
|
||||
// The PN53x command is done and we successfully received the reply
|
||||
return len;
|
||||
error:
|
||||
uart_flush_input(DRIVER_DATA(pnd)->port, true);
|
||||
return pnd->last_error;
|
||||
return res;
|
||||
}
|
||||
|
||||
int
|
||||
|
||||
373
libnfc/drivers/rc522_uart.c
Normal file
373
libnfc/drivers/rc522_uart.c
Normal file
@ -0,0 +1,373 @@
|
||||
/*-
|
||||
* Free/Libre Near Field Communication (NFC) library
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by the
|
||||
* Free Software Foundation, either version 3 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file rc522_uart.c
|
||||
* @brief Driver for MFRC522- and FM17222-based devices connected with an UART
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include "config.h"
|
||||
#endif
|
||||
|
||||
#include "rc522_uart.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <inttypes.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include <nfc/nfc.h>
|
||||
|
||||
#include "drivers.h"
|
||||
#include "nfc-internal.h"
|
||||
#include "chips/rc522.h"
|
||||
#include "uart.h"
|
||||
|
||||
#define LOG_CATEGORY "libnfc.driver.rc522_uart"
|
||||
#define LOG_GROUP NFC_LOG_GROUP_DRIVER
|
||||
|
||||
#define BOOT_BAUD_RATE 9600
|
||||
#define DEFAULT_BAUD_RATE 115200
|
||||
#define DRIVER_NAME "rc522_uart"
|
||||
#define IO_TIMEOUT 50
|
||||
|
||||
#define DRIVER_DATA(pnd) ((struct rc522_uart_data*)(pnd->driver_data))
|
||||
#define CHK(x) ret = (x); if (ret < 0) { return ret; }
|
||||
|
||||
// Internal data structs
|
||||
const struct rc522_io rc522_uart_io;
|
||||
struct rc522_uart_data {
|
||||
serial_port port;
|
||||
uint32_t baudrate;
|
||||
};
|
||||
|
||||
/*
|
||||
int rc522_uart_wakeup(struct nfc_device * pnd) {
|
||||
int ret;
|
||||
|
||||
// High Speed Unit (HSU) wake up consist to send 0x55 and wait a "long" delay for RC522 being wakeup.
|
||||
const uint8_t rc522_wakeup_preamble[] = { 0x55, 0x55, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
|
||||
ret = uart_send(DRIVER_DATA(pnd)->port, rc522_wakeup_preamble, sizeof(rc522_wakeup_preamble), IO_TIMEOUT);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
return rc522_wait_wakeup(pnd);
|
||||
}
|
||||
*/
|
||||
|
||||
void rc522_uart_close(nfc_device * pnd) {
|
||||
rc522_powerdown(pnd);
|
||||
// Release UART port
|
||||
uart_close(DRIVER_DATA(pnd)->port);
|
||||
rc522_data_free(pnd);
|
||||
nfc_device_free(pnd);
|
||||
}
|
||||
|
||||
bool rc522_uart_test_baudrate(struct nfc_device * pnd, uint32_t baudrate) {
|
||||
int ret;
|
||||
|
||||
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "Attempting to establish a connection at %d bps.", baudrate);
|
||||
|
||||
// Update UART baudrate
|
||||
if ((ret = uart_set_speed(DRIVER_DATA(pnd)->port, baudrate)) < 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Attempt to test and initialize the device
|
||||
if (rc522_init(pnd) != NFC_SUCCESS) {
|
||||
return false;
|
||||
}
|
||||
|
||||
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "Connection with a RC522 at %d bps established successfully.", baudrate);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int rc522_uart_create(const nfc_context * context, const nfc_connstring connstring, const char * portPath, uint32_t userBaudRate, struct nfc_device ** pndPtr) {
|
||||
int ret;
|
||||
serial_port sp;
|
||||
|
||||
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "Attempt to open: %s.", portPath);
|
||||
sp = uart_open(portPath);
|
||||
if (sp == INVALID_SERIAL_PORT) {
|
||||
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "Invalid serial port: %s", portPath);
|
||||
return NFC_EIO;
|
||||
}
|
||||
if (sp == CLAIMED_SERIAL_PORT) {
|
||||
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "Serial port already claimed: %s", portPath);
|
||||
return NFC_EIO;
|
||||
}
|
||||
|
||||
// We need to flush input to be sure first reply does not comes from older byte transceive
|
||||
if ((ret = uart_flush_input(sp, true)) < 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
nfc_device * pnd = nfc_device_new(context, connstring);
|
||||
if (!pnd) {
|
||||
perror("nfc_device_new");
|
||||
uart_close(sp);
|
||||
return NFC_ESOFT;
|
||||
}
|
||||
pnd->driver = &rc522_uart_driver;
|
||||
|
||||
pnd->driver_data = malloc(sizeof(struct rc522_uart_data));
|
||||
|
||||
if (!pnd->driver_data) {
|
||||
perror("malloc");
|
||||
uart_close(sp);
|
||||
nfc_device_free(pnd);
|
||||
return NFC_ESOFT;
|
||||
}
|
||||
DRIVER_DATA(pnd)->port = sp;
|
||||
DRIVER_DATA(pnd)->baudrate = userBaudRate;
|
||||
|
||||
// Alloc and init chip's data
|
||||
if (rc522_data_new(pnd, &rc522_uart_io)) {
|
||||
perror("rc522_data_new");
|
||||
uart_close(sp);
|
||||
nfc_device_free(pnd);
|
||||
return NFC_ESOFT;
|
||||
}
|
||||
|
||||
// Here we'll have to address several posibilities:
|
||||
// - The hard reset trick did the work, and the RC522 is up and listening at 9600
|
||||
// - The hard reset didn't work, but the RC522 hasn't been used yet and therefore listens at 9600
|
||||
// - The hard reset didn't work and the RC522 is not using the default, so we'll use the custom provided baud rate
|
||||
|
||||
// Let's try first with boot baud rate
|
||||
if (
|
||||
!rc522_uart_test_baudrate(pnd, BOOT_BAUD_RATE) &&
|
||||
!rc522_uart_test_baudrate(pnd, userBaudRate)
|
||||
) {
|
||||
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "Could not connect with RC522 at %d or %d bps.", BOOT_BAUD_RATE, userBaudRate);
|
||||
rc522_uart_close(pnd);
|
||||
return NFC_EIO;
|
||||
}
|
||||
|
||||
*pndPtr = pnd;
|
||||
return NFC_SUCCESS;
|
||||
}
|
||||
|
||||
size_t rc522_uart_scan(const nfc_context * context, nfc_connstring connstrings[], const size_t connstrings_len) {
|
||||
size_t device_found = 0;
|
||||
char ** acPorts = uart_list_ports();
|
||||
const char * acPort;
|
||||
size_t iDevice = 0;
|
||||
|
||||
while ((acPort = acPorts[iDevice++])) {
|
||||
nfc_connstring connstring;
|
||||
snprintf(connstring, sizeof(nfc_connstring), "%s:%s:%"PRIu32, DRIVER_NAME, acPort, DEFAULT_BAUD_RATE);
|
||||
|
||||
nfc_device * pnd;
|
||||
int ret = rc522_uart_create(context, connstring, acPort, DEFAULT_BAUD_RATE, &pnd);
|
||||
if (ret == NFC_ESOFT) {
|
||||
uart_list_free(acPorts);
|
||||
return 0;
|
||||
}
|
||||
if (ret != NFC_SUCCESS) {
|
||||
continue;
|
||||
}
|
||||
rc522_uart_close(pnd);
|
||||
|
||||
memcpy(connstrings[device_found], connstring, sizeof(nfc_connstring));
|
||||
device_found++;
|
||||
|
||||
// Test if we reach the maximum "wanted" devices
|
||||
if (device_found >= connstrings_len)
|
||||
break;
|
||||
}
|
||||
|
||||
uart_list_free(acPorts);
|
||||
return device_found;
|
||||
}
|
||||
|
||||
struct nfc_device * rc522_uart_open(const nfc_context * context, const nfc_connstring connstring) {
|
||||
char * port_str = NULL;
|
||||
char * baud_str = NULL;
|
||||
uint32_t baudrate;
|
||||
char * endptr;
|
||||
struct nfc_device * pnd = NULL;
|
||||
|
||||
int decodelvl = connstring_decode(connstring, DRIVER_NAME, NULL, &port_str, &baud_str);
|
||||
switch (decodelvl) {
|
||||
case 2: // Got port but no speed
|
||||
baudrate = DEFAULT_BAUD_RATE;
|
||||
break;
|
||||
|
||||
case 3: // Got port and baud rate
|
||||
// TODO: set baud rate AFTER initialization
|
||||
baudrate = (uint32_t) strtol(baud_str, &endptr, 10);
|
||||
if (*endptr != '\0') {
|
||||
free(port_str);
|
||||
free(baud_str);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
free(baud_str);
|
||||
break;
|
||||
|
||||
default: // Got unparseable gibberish
|
||||
free(port_str);
|
||||
free(baud_str);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
rc522_uart_create(context, connstring, port_str, baudrate, &pnd);
|
||||
free(port_str);
|
||||
return pnd;
|
||||
}
|
||||
|
||||
#define READ 1
|
||||
#define WRITE 0
|
||||
uint8_t rc522_uart_pack(int reg, int op) {
|
||||
assert(reg < 64);
|
||||
assert(op == READ || op == WRITE);
|
||||
|
||||
return op << 7 | reg;
|
||||
}
|
||||
|
||||
int rc522_uart_read(struct nfc_device * pnd, uint8_t reg, uint8_t * data, size_t size) {
|
||||
uint8_t cmd = rc522_uart_pack(reg, READ);
|
||||
int ret;
|
||||
|
||||
while (size > 0) {
|
||||
if ((ret = uart_send(DRIVER_DATA(pnd)->port, &cmd, 1, IO_TIMEOUT)) < 0) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
if ((ret = uart_receive(DRIVER_DATA(pnd)->port, data, 1, NULL, IO_TIMEOUT)) < 0) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
size--;
|
||||
data++;
|
||||
}
|
||||
|
||||
return NFC_SUCCESS;
|
||||
|
||||
error:
|
||||
uart_flush_input(DRIVER_DATA(pnd)->port, true);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int rc522_uart_write(struct nfc_device * pnd, uint8_t reg, const uint8_t * data, size_t size) {
|
||||
uint8_t cmd = rc522_uart_pack(reg, WRITE);
|
||||
int ret;
|
||||
|
||||
while (size > 0) {
|
||||
// First: send write request
|
||||
if ((ret = uart_send(DRIVER_DATA(pnd)->port, &cmd, 1, IO_TIMEOUT)) < 0) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
// Second: wait for a reply
|
||||
uint8_t reply;
|
||||
if ((ret = uart_receive(DRIVER_DATA(pnd)->port, &reply, 1, NULL, IO_TIMEOUT)) < 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
// Third: compare sent and received. They must match.
|
||||
if (cmd != reply) {
|
||||
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "rc522_uart_write ack does not match (sent %02X, received %02X)", cmd, reply);
|
||||
ret = NFC_ECHIP;
|
||||
goto error;
|
||||
}
|
||||
|
||||
// Fourth: send register data
|
||||
if ((ret = uart_send(DRIVER_DATA(pnd)->port, data, 1, IO_TIMEOUT)) < 0) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
size--;
|
||||
data++;
|
||||
}
|
||||
|
||||
return NFC_SUCCESS;
|
||||
|
||||
error:
|
||||
uart_flush_input(DRIVER_DATA(pnd)->port, true);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int rc522_uart_reset_baud_rate(struct nfc_device * pnd) {
|
||||
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "Restoring baud rate to default of %d bps.", BOOT_BAUD_RATE);
|
||||
return uart_set_speed(DRIVER_DATA(pnd)->port, BOOT_BAUD_RATE);
|
||||
}
|
||||
|
||||
int rc522_uart_upgrade_baud_rate(struct nfc_device * pnd) {
|
||||
int ret;
|
||||
uint32_t userBaudRate = DRIVER_DATA(pnd)->baudrate;
|
||||
if (userBaudRate == BOOT_BAUD_RATE) {
|
||||
return NFC_SUCCESS;
|
||||
}
|
||||
|
||||
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "Upgrading baud rate to user-specified %d bps.", userBaudRate);
|
||||
CHK(uart_set_speed(DRIVER_DATA(pnd)->port, userBaudRate));
|
||||
CHK(rc522_send_baudrate(pnd, userBaudRate));
|
||||
|
||||
return NFC_SUCCESS;
|
||||
}
|
||||
|
||||
const struct rc522_io rc522_uart_io = {
|
||||
.read = rc522_uart_read,
|
||||
.write = rc522_uart_write,
|
||||
.reset_baud_rate = rc522_uart_reset_baud_rate,
|
||||
.upgrade_baud_rate = rc522_uart_upgrade_baud_rate,
|
||||
};
|
||||
|
||||
const struct nfc_driver rc522_uart_driver = {
|
||||
.name = DRIVER_NAME,
|
||||
.scan_type = INTRUSIVE,
|
||||
.scan = rc522_uart_scan,
|
||||
.open = rc522_uart_open,
|
||||
.close = rc522_uart_close,
|
||||
// .strerror = rc522_strerror,
|
||||
|
||||
.initiator_init = rc522_initiator_init,
|
||||
// MFRC522 has no secure element
|
||||
.initiator_init_secure_element = NULL,
|
||||
// .initiator_select_passive_target = rc522_initiator_select_passive_target,
|
||||
// .initiator_poll_target = rc522_initiator_poll_target,
|
||||
.initiator_select_dep_target = NULL,
|
||||
// .initiator_deselect_target = rc522_initiator_deselect_target,
|
||||
.initiator_transceive_bytes = rc522_initiator_transceive_bytes,
|
||||
.initiator_transceive_bits = rc522_initiator_transceive_bits,
|
||||
// .initiator_transceive_bytes_timed = rc522_initiator_transceive_bytes_timed,
|
||||
// .initiator_transceive_bits_timed = rc522_initiator_transceive_bits_timed,
|
||||
// .initiator_target_is_present = rc522_initiator_target_is_present,
|
||||
|
||||
// MFRC522 is unable to work as target
|
||||
.target_init = NULL,
|
||||
.target_send_bytes = NULL,
|
||||
.target_receive_bytes = NULL,
|
||||
.target_send_bits = NULL,
|
||||
.target_receive_bits = NULL,
|
||||
|
||||
.device_set_property_bool = rc522_set_property_bool,
|
||||
.device_set_property_int = rc522_set_property_int,
|
||||
.get_supported_modulation = rc522_get_supported_modulation,
|
||||
.get_supported_baud_rate = rc522_get_supported_baud_rate,
|
||||
// .device_get_information_about = rc522_get_information_about,
|
||||
|
||||
.abort_command = rc522_abort,
|
||||
// .idle = rc522_idle,
|
||||
.powerdown = rc522_powerdown,
|
||||
};
|
||||
|
||||
30
libnfc/drivers/rc522_uart.h
Normal file
30
libnfc/drivers/rc522_uart.h
Normal file
@ -0,0 +1,30 @@
|
||||
/*-
|
||||
* Free/Libre Near Field Communication (NFC) library
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by the
|
||||
* Free Software Foundation, either version 3 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file rc522_uart.h
|
||||
* @brief Driver for MFRC522- and FM17222-based devices connected with an UART
|
||||
*/
|
||||
|
||||
#ifndef __NFC_DRIVER_RC522_UART_H__
|
||||
#define __NFC_DRIVER_RC555_UART_H__
|
||||
|
||||
#include <nfc/nfc-types.h>
|
||||
|
||||
extern const struct nfc_driver rc522_uart_driver;
|
||||
|
||||
#endif
|
||||
@ -27,6 +27,8 @@
|
||||
#ifndef __LOG_H__
|
||||
#define __LOG_H__
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include "config.h"
|
||||
#endif // HAVE_CONFIG_H
|
||||
|
||||
@ -44,13 +44,19 @@
|
||||
* @macro HAL
|
||||
* @brief Execute corresponding driver function if exists.
|
||||
*/
|
||||
#define HAL( FUNCTION, ... ) pnd->last_error = 0; \
|
||||
if (pnd->driver->FUNCTION) { \
|
||||
return pnd->driver->FUNCTION( __VA_ARGS__ ); \
|
||||
} else { \
|
||||
#define HAL( FUNCTION, ... ) do { \
|
||||
if (!pnd->driver->FUNCTION) { \
|
||||
pnd->last_error = NFC_EDEVNOTSUPP; \
|
||||
return false; \
|
||||
}
|
||||
return pnd->last_error; \
|
||||
} \
|
||||
int __ret = pnd->driver->FUNCTION( __VA_ARGS__ ); \
|
||||
if (__ret < 0) { \
|
||||
pnd->last_error = __ret; \
|
||||
} else { \
|
||||
pnd->last_error = NFC_SUCCESS; \
|
||||
} \
|
||||
return __ret; \
|
||||
} while (0);
|
||||
|
||||
#ifndef MIN
|
||||
#define MIN(a,b) (((a) < (b)) ? (a) : (b))
|
||||
|
||||
@ -119,6 +119,9 @@
|
||||
# include "drivers/pn532_i2c.h"
|
||||
#endif /* DRIVER_PN532_I2C_ENABLED */
|
||||
|
||||
#if defined (DRIVER_RC522_UART_ENABLED)
|
||||
# include "drivers/rc522_uart.h"
|
||||
#endif /* DRIVER_RC522_UART_ENABLED */
|
||||
|
||||
#define LOG_CATEGORY "libnfc.general"
|
||||
#define LOG_GROUP NFC_LOG_GROUP_GENERAL
|
||||
@ -157,6 +160,9 @@ nfc_drivers_init(void)
|
||||
#if defined (DRIVER_ARYGON_ENABLED)
|
||||
nfc_register_driver(&arygon_driver);
|
||||
#endif /* DRIVER_ARYGON_ENABLED */
|
||||
#if defined (DRIVER_RC522_UART_ENABLED)
|
||||
nfc_register_driver(&rc522_uart_driver);
|
||||
#endif /* DRIVER_RC522_UART_ENABLED */
|
||||
}
|
||||
|
||||
static int
|
||||
|
||||
86
libnfc/timing.c
Normal file
86
libnfc/timing.c
Normal file
@ -0,0 +1,86 @@
|
||||
/*-
|
||||
* Free/Libre Near Field Communication (NFC) library
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by the
|
||||
* Free Software Foundation, either version 3 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
*/
|
||||
|
||||
#include "timing.h"
|
||||
#include <assert.h>
|
||||
|
||||
#define MILLIS_PER_SEC 1000
|
||||
#define MICROS_PER_SEC 1000000
|
||||
#define NANOS_PER_SEC 1000000000
|
||||
|
||||
#define MAGIC_EXPIRED ((uint64_t) -1)
|
||||
#define MAGIC_NEVER ((uint64_t) -2)
|
||||
|
||||
// Use Windows' API directly if Win32 for highest possible resolution
|
||||
#if defined(CYGWIN) || defined(_WIN32)
|
||||
# include <windows.h>
|
||||
|
||||
static uint64_t timer_hz = 0;
|
||||
|
||||
ms_t time_millis() {
|
||||
if (!timer_hz) {
|
||||
// Windows API states that the frequency is fixed at boot and therefore can be cached safely
|
||||
assert(QueryPerformanceFrequency((LARGE_INTEGER *) &timer_hz));
|
||||
}
|
||||
|
||||
uint64_t ticks;
|
||||
assert(QueryPerformanceCounter((LARGE_INTEGER *) &ticks));
|
||||
return MILLIS_PER_SEC * ticks / timer_hz;
|
||||
}
|
||||
|
||||
// If not Windows use POSIX methods
|
||||
#else
|
||||
# include <time.h>
|
||||
|
||||
ms_t time_millis() {
|
||||
struct timespec ts;
|
||||
|
||||
// CLOCK_MONOTONIC_RAW isn't affected by NTP updates and therefore really monotonic, but it's Linux-specific
|
||||
# ifdef CLOCK_MONOTONIC_RAW
|
||||
clock_gettime(CLOCK_MONOTONIC_RAW, &ts);
|
||||
# else
|
||||
clock_gettime(CLOCK_MONOTONIC, &ts);
|
||||
# endif
|
||||
|
||||
return (ms_t) ts.tv_sec * MILLIS_PER_SEC + ts.tv_nsec / (NANOS_PER_SEC / MILLIS_PER_SEC);
|
||||
}
|
||||
#endif
|
||||
|
||||
void timeout_init(timeout_t * to, unsigned int millis) {
|
||||
*to = time_millis() + millis;
|
||||
}
|
||||
|
||||
void timeout_never(timeout_t * to) {
|
||||
*to = MAGIC_NEVER;
|
||||
}
|
||||
|
||||
bool timeout_check(timeout_t * to) {
|
||||
switch (*to) {
|
||||
case MAGIC_EXPIRED:
|
||||
return false;
|
||||
case MAGIC_NEVER:
|
||||
return true;
|
||||
}
|
||||
|
||||
ms_t now = time_millis();
|
||||
if (now >= *to) {
|
||||
// Mark as expired and fail in next check
|
||||
*to = MAGIC_EXPIRED;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
54
libnfc/timing.h
Normal file
54
libnfc/timing.h
Normal file
@ -0,0 +1,54 @@
|
||||
/*-
|
||||
* Free/Libre Near Field Communication (NFC) library
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by the
|
||||
* Free Software Foundation, either version 3 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
*/
|
||||
|
||||
#ifndef __NFC_TIMING_H__
|
||||
#define __NFC_TIMING_H__
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
typedef uint64_t ms_t;
|
||||
|
||||
/**
|
||||
* @brief Calculates a timestamp from a unspecified start with millisecond accuracy
|
||||
* @return Time in milliseconds
|
||||
*/
|
||||
ms_t time_millis();
|
||||
|
||||
typedef ms_t timeout_t;
|
||||
|
||||
/**
|
||||
* @brief Initializes a timeout
|
||||
* @param to Timeout handle
|
||||
* @param millis Minimum expiration time in milliseconds
|
||||
*/
|
||||
void timeout_init(timeout_t * to, unsigned int millis);
|
||||
|
||||
/**
|
||||
* @brief Initializes a timeout which never expires
|
||||
* @param to Timeout handle
|
||||
*/
|
||||
void timeout_never(timeout_t * to);
|
||||
|
||||
/**
|
||||
* @brief Checks if the timeout has NOT expired
|
||||
* @param to Timeout handle
|
||||
* @return True if the timeout has NOT expired
|
||||
*/
|
||||
bool timeout_check(timeout_t * to);
|
||||
|
||||
#endif
|
||||
@ -4,7 +4,7 @@ AC_DEFUN([LIBNFC_ARG_WITH_DRIVERS],
|
||||
[
|
||||
AC_MSG_CHECKING(which drivers to build)
|
||||
AC_ARG_WITH(drivers,
|
||||
AS_HELP_STRING([--with-drivers=DRIVERS], [Use a custom driver set, where DRIVERS is a coma-separated list of drivers to build support for. Available drivers are: 'acr122_pcsc', 'acr122_usb', 'acr122s', 'arygon', 'pn532_i2c', 'pn532_spi', 'pn532_uart' and 'pn53x_usb'. Default drivers set is 'acr122_usb,acr122s,arygon,pn532_i2c,pn532_spi,pn532_uart,pn53x_usb'. The special driver set 'all' compile all available drivers.]),
|
||||
AS_HELP_STRING([--with-drivers=DRIVERS], [Use a custom driver set, where DRIVERS is a coma-separated list of drivers to build support for. Available drivers are: 'acr122_pcsc', 'acr122_usb', 'acr122s', 'arygon', 'pn532_i2c', 'pn532_spi', 'pn532_uart', 'pn53x_usb' and 'rc522_uart'. Default drivers set is 'acr122_usb,acr122s,arygon,pn532_i2c,pn532_spi,pn532_uart,pn53x_usb,rc522_uart'. The special driver set 'all' compile all available drivers.]),
|
||||
[ case "${withval}" in
|
||||
yes | no)
|
||||
dnl ignore calls without any arguments
|
||||
@ -25,7 +25,7 @@ AC_DEFUN([LIBNFC_ARG_WITH_DRIVERS],
|
||||
|
||||
case "${DRIVER_BUILD_LIST}" in
|
||||
default)
|
||||
DRIVER_BUILD_LIST="acr122_usb acr122s arygon pn53x_usb pn532_uart"
|
||||
DRIVER_BUILD_LIST="acr122_usb acr122s arygon pn53x_usb pn532_uart rc522_uart"
|
||||
if test x"$spi_available" = x"yes"
|
||||
then
|
||||
DRIVER_BUILD_LIST="$DRIVER_BUILD_LIST pn532_spi"
|
||||
@ -36,7 +36,7 @@ AC_DEFUN([LIBNFC_ARG_WITH_DRIVERS],
|
||||
fi
|
||||
;;
|
||||
all)
|
||||
DRIVER_BUILD_LIST="acr122_pcsc acr122_usb acr122s arygon pn53x_usb pn532_uart"
|
||||
DRIVER_BUILD_LIST="acr122_pcsc acr122_usb acr122s arygon pn53x_usb pn532_uart rc522_uart"
|
||||
if test x"$spi_available" = x"yes"
|
||||
then
|
||||
DRIVER_BUILD_LIST="$DRIVER_BUILD_LIST pn532_spi"
|
||||
@ -58,6 +58,7 @@ AC_DEFUN([LIBNFC_ARG_WITH_DRIVERS],
|
||||
driver_pn532_uart_enabled="no"
|
||||
driver_pn532_spi_enabled="no"
|
||||
driver_pn532_i2c_enabled="no"
|
||||
driver_rc522_uart_enabled="no"
|
||||
|
||||
for driver in ${DRIVER_BUILD_LIST}
|
||||
do
|
||||
@ -102,6 +103,11 @@ AC_DEFUN([LIBNFC_ARG_WITH_DRIVERS],
|
||||
driver_pn532_i2c_enabled="yes"
|
||||
DRIVERS_CFLAGS="$DRIVERS_CFLAGS -DDRIVER_PN532_I2C_ENABLED"
|
||||
;;
|
||||
rc522_uart)
|
||||
uart_required="yes"
|
||||
driver_rc522_uart_enabled="yes"
|
||||
DRIVERS_CFLAGS="$DRIVERS_CFLAGS -DDRIVER_RC522_UART_ENABLED"
|
||||
;;
|
||||
*)
|
||||
AC_MSG_ERROR([Unknow driver: $driver])
|
||||
;;
|
||||
@ -116,6 +122,7 @@ AC_DEFUN([LIBNFC_ARG_WITH_DRIVERS],
|
||||
AM_CONDITIONAL(DRIVER_PN532_UART_ENABLED, [test x"$driver_pn532_uart_enabled" = xyes])
|
||||
AM_CONDITIONAL(DRIVER_PN532_SPI_ENABLED, [test x"$driver_pn532_spi_enabled" = xyes])
|
||||
AM_CONDITIONAL(DRIVER_PN532_I2C_ENABLED, [test x"$driver_pn532_i2c_enabled" = xyes])
|
||||
AM_CONDITIONAL(DRIVER_RC522_UART_ENABLED, [test x"$driver_rc522_uart_enabled" = xyes])
|
||||
])
|
||||
|
||||
AC_DEFUN([LIBNFC_DRIVERS_SUMMARY],[
|
||||
@ -129,4 +136,5 @@ echo " pn53x_usb........ $driver_pn53x_usb_enabled"
|
||||
echo " pn532_uart....... $driver_pn532_uart_enabled"
|
||||
echo " pn532_spi....... $driver_pn532_spi_enabled"
|
||||
echo " pn532_i2c........ $driver_pn532_i2c_enabled"
|
||||
echo " rc522_uart....... $driver_rc522_uart_enabled"
|
||||
])
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user