Basic support for RC522 detection
This commit is contained in:
parent
6204340059
commit
053dc8d5f8
@ -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@
|
||||
|
||||
@ -3,108 +3,124 @@
|
||||
#ifndef __NFC_CHIPS_RC522_INTERNAL_H__
|
||||
#define __NFC_CHIPS_RC522_INTERNAL_H__
|
||||
|
||||
#define RC522_FIFO_SIZE 64
|
||||
#define FIFO_SIZE 64
|
||||
|
||||
#define RC522_REG_CommandReg 0x01
|
||||
#define RC522_REG_CommandReg_RcvOff (1 << 5)
|
||||
#define RC522_REG_CommandReg_PowerDown (1 << 4)
|
||||
typedef enum {
|
||||
RC522_UNKNOWN = 0x00,
|
||||
FM17522 = 0x88,
|
||||
MFRC522_V1 = 0x91,
|
||||
MFRC522_V2 = 0x92
|
||||
} rc522_type;
|
||||
|
||||
#define RC522_REG_ComlEnReg 0x02
|
||||
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 RC522_REG_DivlEnReg 0x03
|
||||
#define REG_CommandReg 0x01
|
||||
#define REG_CommandReg_RcvOff (1 << 5)
|
||||
#define REG_CommandReg_PowerDown (1 << 4)
|
||||
|
||||
#define RC522_REG_ComIrqReg 0x04
|
||||
#define REG_ComlEnReg 0x02
|
||||
|
||||
#define RC522_REG_DivIrqReg 0x05
|
||||
#define REG_DivlEnReg 0x03
|
||||
|
||||
#define RC522_REG_ErrorReg 0x06
|
||||
#define REG_ComIrqReg 0x04
|
||||
|
||||
#define RC522_REG_Status1Reg 0x07
|
||||
#define REG_DivIrqReg 0x05
|
||||
#define REG_DivIrqReg_MfinActIRq (1 << 4)
|
||||
#define REG_DivIrqReg_CRCIRq (1 << 2)
|
||||
|
||||
#define RC522_REG_Status2Reg 0x08
|
||||
#define RC522_REG_Status2Reg_MFCrypto1On (1 << 3)
|
||||
#define REG_ErrorReg 0x06
|
||||
|
||||
#define RC522_REG_FIFODataReg 0x09
|
||||
#define REG_Status1Reg 0x07
|
||||
|
||||
#define RC522_REG_FIFOLevelReg 0x0A
|
||||
#define REG_Status2Reg 0x08
|
||||
#define REG_Status2Reg_MFCrypto1On (1 << 3)
|
||||
|
||||
#define RC522_REG_WaterLevelReg 0x0B
|
||||
#define REG_FIFODataReg 0x09
|
||||
|
||||
#define RC522_REG_ControlReg 0x0C
|
||||
#define REG_FIFOLevelReg 0x0A
|
||||
|
||||
#define RC522_REG_BitFramingReg 0x0D
|
||||
#define REG_WaterLevelReg 0x0B
|
||||
|
||||
#define RC522_REG_CollReg 0x0E
|
||||
#define REG_ControlReg 0x0C
|
||||
|
||||
#define RC522_REG_ModeReg 0x11
|
||||
#define REG_BitFramingReg 0x0D
|
||||
|
||||
#define RC522_REG_TxModeReg 0x12
|
||||
#define RC522_REG_TxModeReg_TxCRCEn (1 << 7)
|
||||
#define RC522_REG_TxModeReg_TxSpeed_106k (0 << 4)
|
||||
#define RC522_REG_TxModeReg_TxSpeed_212k (1 << 4)
|
||||
#define RC522_REG_TxModeReg_TxSpeed_424k (2 << 4)
|
||||
#define RC522_REG_TxModeReg_TxSpeed_847k (3 << 4)
|
||||
#define RC522_REG_TxModeReg_TxSpeed_MASK (7 << 4)
|
||||
#define REG_CollReg 0x0E
|
||||
|
||||
#define RC522_REG_RxModeReg 0x13
|
||||
#define RC522_REG_RxModeReg_RxCRCEn (1 << 7)
|
||||
#define RC522_REG_RxModeReg_RxSpeed_106k (0 << 4)
|
||||
#define RC522_REG_RxModeReg_RxSpeed_212k (1 << 4)
|
||||
#define RC522_REG_RxModeReg_RxSpeed_424k (2 << 4)
|
||||
#define RC522_REG_RxModeReg_RxSpeed_847k (3 << 4)
|
||||
#define RC522_REG_RxModeReg_RxSpeed_MASK (7 << 4)
|
||||
#define REG_ModeReg 0x11
|
||||
|
||||
#define RC522_REG_TxControlReg 0x14
|
||||
#define RC522_REG_TxControlReg_Tx2RFEn (1 << 1)
|
||||
#define RC522_REG_TxControlReg_Tx1RFEn (1 << 0)
|
||||
#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 RC522_REG_TxASKReg 0x15
|
||||
#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 RC522_REG_TxSelReg 0x16
|
||||
#define REG_TxControlReg 0x14
|
||||
#define REG_TxControlReg_Tx2RFEn (1 << 1)
|
||||
#define REG_TxControlReg_Tx1RFEn (1 << 0)
|
||||
|
||||
#define RC522_REG_RxSelReg 0x17
|
||||
#define REG_TxASKReg 0x15
|
||||
|
||||
#define RC522_REG_RxThresholdReg 0x18
|
||||
#define REG_TxSelReg 0x16
|
||||
|
||||
#define RC522_REG_DemodReg 0x19
|
||||
#define REG_RxSelReg 0x17
|
||||
|
||||
#define RC522_REG_MfTxReg 0x1C
|
||||
#define REG_RxThresholdReg 0x18
|
||||
|
||||
#define RC522_REG_MfRxReg 0x1D
|
||||
#define RC522_REG_MfRxReg_ParityDisable (1 << 4)
|
||||
#define REG_DemodReg 0x19
|
||||
|
||||
#define RC522_REG_SerialSpeedReg 0x1F
|
||||
#define RC522_REG_CRCResultReg 0x21
|
||||
#define RC522_REG_ModWidthReg 0x24
|
||||
#define RC522_REG_RFCfgReg 0x26
|
||||
#define RC522_REG_GsNReg 0x27
|
||||
#define RC522_REG_CWGsPReg 0x28
|
||||
#define RC522_REG_ModGsPReg 0x29
|
||||
#define RC522_REG_TModeReg 0x2A
|
||||
#define RC522_REG_TPrescalerReg 0x2B
|
||||
#define RC522_REG_TReloadReg 0x2C
|
||||
#define RC522_REG_TCounterValReg 0x2E
|
||||
#define RC522_REG_TestSel1Reg 0x31
|
||||
#define RC522_REG_TestSel2Reg 0x32
|
||||
#define RC522_REG_TestPinEnReg 0x33
|
||||
#define RC522_REG_TestPinValueReg 0x34
|
||||
#define RC522_REG_TestBusReg 0x35
|
||||
#define RC522_REG_AutoTestReg 0x36
|
||||
#define RC522_REG_VersionReg 0x37
|
||||
#define RC522_REG_AnalogTestReg 0x38
|
||||
#define RC522_REG_TestDAC1Reg 0x39
|
||||
#define RC522_REG_TestDAC2Reg 0x3A
|
||||
#define RC522_REG_TestADCReg 0x3B
|
||||
#define REG_MfTxReg 0x1C
|
||||
|
||||
#define RC522_CMD_Idle 0x0
|
||||
#define RC522_CMD_Mem 0x1
|
||||
#define RC522_CMD_GenerateRandomId 0x2
|
||||
#define RC522_CMD_CalcCRC 0x3
|
||||
#define RC522_CMD_Transmit 0x4
|
||||
#define RC522_CMD_NoCmdChange 0x7
|
||||
#define RC522_CMD_Receive 0x8
|
||||
#define RC522_CMD_Transceive 0xC
|
||||
#define RC522_CMD_MFAuthent 0xE
|
||||
#define RC522_CMD_SoftReset 0xF
|
||||
#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
|
||||
|
||||
@ -23,12 +23,11 @@
|
||||
|
||||
#include "nfc/nfc.h"
|
||||
#include "nfc-internal.h"
|
||||
#include "timing.h"
|
||||
|
||||
#define LOG_CATEGORY "libnfc.chip.rc522"
|
||||
#define LOG_GROUP NFC_LOG_GROUP_CHIP
|
||||
|
||||
#define RC522_TIMEOUT 5
|
||||
|
||||
const nfc_modulation_type rc522_initiator_modulation[] = { NMT_ISO14443A, 0 };
|
||||
const nfc_modulation_type rc522_target_modulation[] = { 0 };
|
||||
|
||||
@ -36,6 +35,7 @@ const nfc_baud_rate rc522_iso14443a_supported_baud_rates[] = { NBR_847, NBR_424,
|
||||
|
||||
struct rc522_chip_data {
|
||||
const struct rc522_io * io;
|
||||
rc522_type version;
|
||||
};
|
||||
|
||||
#define CHIP_DATA(x) ((struct rc522_chip_data *) (x)->chip_data)
|
||||
@ -48,14 +48,51 @@ int rc522_data_new(struct nfc_device * pnd, const struct rc522_io * io) {
|
||||
}
|
||||
|
||||
CHIP_DATA(pnd)->io = io;
|
||||
CHIP_DATA(pnd)->version = RC522_UNKNOWN;
|
||||
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!", reg);
|
||||
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;
|
||||
|
||||
int ret = CHIP_DATA(pnd)->io->read(pnd, reg, &val, 1);
|
||||
if (ret < 0) {
|
||||
if ((ret = rc522_read_bulk(pnd, reg, &val, 1)) < 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -72,32 +109,99 @@ int rc522_write_reg(struct nfc_device * pnd, uint8_t reg, uint8_t val, uint8_t m
|
||||
val = (val & mask) | (oldval & ~mask);
|
||||
}
|
||||
|
||||
return CHIP_DATA(pnd)->io->write(pnd, reg, &val, 1);
|
||||
return rc522_write_bulk(pnd, reg, &val, 1);
|
||||
}
|
||||
|
||||
int rc522_start_command(struct nfc_device * pnd, rc522_cmd cmd) {
|
||||
bool needsRX = false;
|
||||
|
||||
// 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:
|
||||
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);
|
||||
pnd->last_error = NFC_ESOFT;
|
||||
return pnd->last_error;
|
||||
}
|
||||
|
||||
uint8_t regval = cmd;
|
||||
if (!needsRX) {
|
||||
regval |= REG_CommandReg_RcvOff;
|
||||
}
|
||||
|
||||
return rc522_write_reg(pnd, REG_CommandReg, regval, 0xFF);
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
// rc522_read_reg updates last_error. Backup it to ignore timeouts
|
||||
int last_error = pnd->last_error;
|
||||
|
||||
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) {
|
||||
pnd->last_error = last_error;
|
||||
return NFC_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "rc522_wait_wakeup timeout!");
|
||||
pnd->last_error = NFC_ETIMEOUT;
|
||||
return pnd->last_error;
|
||||
}
|
||||
|
||||
int rc522_soft_reset(struct nfc_device * pnd) {
|
||||
return
|
||||
rc522_start_command(pnd, CMD_SOFTRESET) ||
|
||||
rc522_wait_wakeup(pnd);
|
||||
}
|
||||
|
||||
int rc522_set_baud_rate(struct nfc_device * pnd, nfc_baud_rate speed) {
|
||||
uint8_t txVal, rxVal;
|
||||
int ret;
|
||||
|
||||
switch (speed) {
|
||||
case NBR_106:
|
||||
txVal = RC522_REG_TxModeReg_TxSpeed_106k;
|
||||
rxVal = RC522_REG_RxModeReg_RxSpeed_106k;
|
||||
txVal = REG_TxModeReg_TxSpeed_106k;
|
||||
rxVal = REG_RxModeReg_RxSpeed_106k;
|
||||
break;
|
||||
|
||||
case NBR_212:
|
||||
txVal = RC522_REG_TxModeReg_TxSpeed_212k;
|
||||
rxVal = RC522_REG_RxModeReg_RxSpeed_212k;
|
||||
txVal = REG_TxModeReg_TxSpeed_212k;
|
||||
rxVal = REG_RxModeReg_RxSpeed_212k;
|
||||
break;
|
||||
|
||||
case NBR_424:
|
||||
txVal = RC522_REG_TxModeReg_TxSpeed_424k;
|
||||
rxVal = RC522_REG_RxModeReg_RxSpeed_424k;
|
||||
txVal = REG_TxModeReg_TxSpeed_424k;
|
||||
rxVal = REG_RxModeReg_RxSpeed_424k;
|
||||
break;
|
||||
|
||||
case NBR_847:
|
||||
txVal = RC522_REG_TxModeReg_TxSpeed_847k;
|
||||
rxVal = RC522_REG_RxModeReg_RxSpeed_847k;
|
||||
txVal = REG_TxModeReg_TxSpeed_847k;
|
||||
rxVal = REG_RxModeReg_RxSpeed_847k;
|
||||
break;
|
||||
|
||||
default:
|
||||
@ -105,8 +209,8 @@ int rc522_set_baud_rate(struct nfc_device * pnd, nfc_baud_rate speed) {
|
||||
}
|
||||
|
||||
return
|
||||
rc522_write_reg(pnd, RC522_REG_TxModeReg, txVal, RC522_REG_TxModeReg_TxSpeed_MASK) ||
|
||||
rc522_write_reg(pnd, RC522_REG_RxModeReg, rxVal, RC522_REG_RxModeReg_RxSpeed_MASK);
|
||||
rc522_write_reg(pnd, REG_TxModeReg, txVal, REG_TxModeReg_TxSpeed_MASK) ||
|
||||
rc522_write_reg(pnd, REG_RxModeReg, rxVal, REG_RxModeReg_RxSpeed_MASK);
|
||||
}
|
||||
|
||||
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)
|
||||
@ -173,8 +277,9 @@ int rc522_set_property_bool(struct nfc_device * pnd, const nfc_property property
|
||||
return NFC_SUCCESS;
|
||||
}
|
||||
|
||||
ret = rc522_write_reg(pnd, RC522_REG_TxModeReg, enable ? ~0 : 0, RC522_REG_TxModeReg_TxCRCEn) ||
|
||||
rc522_write_reg(pnd, RC522_REG_RxModeReg, enable ? ~0 : 0, RC522_REG_RxModeReg_RxCRCEn);
|
||||
ret =
|
||||
rc522_write_reg(pnd, REG_TxModeReg, enable ? ~0 : 0, REG_TxModeReg_TxCRCEn) ||
|
||||
rc522_write_reg(pnd, REG_RxModeReg, enable ? ~0 : 0, REG_RxModeReg_RxCRCEn);
|
||||
if (ret) {
|
||||
return ret;
|
||||
}
|
||||
@ -187,7 +292,7 @@ int rc522_set_property_bool(struct nfc_device * pnd, const nfc_property property
|
||||
return NFC_SUCCESS;
|
||||
}
|
||||
|
||||
ret = rc522_write_reg(pnd, RC522_REG_MfRxReg, enable ? 0 : ~0, RC522_REG_MfRxReg_ParityDisable);
|
||||
ret = rc522_write_reg(pnd, REG_MfRxReg, enable ? 0 : ~0, REG_MfRxReg_ParityDisable);
|
||||
if (ret) {
|
||||
return ret;
|
||||
}
|
||||
@ -200,10 +305,10 @@ int rc522_set_property_bool(struct nfc_device * pnd, const nfc_property property
|
||||
return NFC_SUCCESS;
|
||||
|
||||
case NP_ACTIVATE_FIELD:
|
||||
return rc522_write_reg(pnd, RC522_REG_TxControlReg, enable ? ~0 : 0, RC522_REG_TxControlReg_Tx2RFEn | RC522_REG_TxControlReg_Tx1RFEn);
|
||||
return rc522_write_reg(pnd, REG_TxControlReg, enable ? ~0 : 0, REG_TxControlReg_Tx2RFEn | REG_TxControlReg_Tx1RFEn);
|
||||
|
||||
case NP_ACTIVATE_CRYPTO1:
|
||||
return rc522_write_reg(pnd, RC522_REG_Status2Reg, enable ? ~0 : 0, RC522_REG_Status2Reg_MFCrypto1On);
|
||||
return rc522_write_reg(pnd, REG_Status2Reg, enable ? ~0 : 0, REG_Status2Reg_MFCrypto1On);
|
||||
|
||||
case NP_FORCE_ISO14443_A:
|
||||
// ISO14443-A is the only mode supported by MFRC522
|
||||
@ -214,8 +319,13 @@ int rc522_set_property_bool(struct nfc_device * pnd, const nfc_property property
|
||||
return NFC_SUCCESS;
|
||||
}
|
||||
|
||||
return rc522_set_baud_rate(pnd, NBR_106);
|
||||
|
||||
int ret = rc522_set_baud_rate(pnd, NBR_106);
|
||||
if (ret) {
|
||||
pnd->last_error = ret;
|
||||
}
|
||||
return ret;
|
||||
|
||||
case NP_ACCEPT_MULTIPLE_FRAMES:
|
||||
case NP_AUTO_ISO14443_4:
|
||||
case NP_ACCEPT_INVALID_FRAMES:
|
||||
case NP_INFINITE_SELECT:
|
||||
@ -223,9 +333,11 @@ int rc522_set_property_bool(struct nfc_device * pnd, const nfc_property property
|
||||
case NP_TIMEOUT_COMMAND:
|
||||
case NP_TIMEOUT_ATR:
|
||||
case NP_TIMEOUT_COM:
|
||||
pnd->last_error = NFC_EINVARG;
|
||||
return NFC_EINVARG;
|
||||
}
|
||||
|
||||
pnd->last_error = NFC_EINVARG;
|
||||
return NFC_EINVARG;
|
||||
}
|
||||
|
||||
@ -234,8 +346,116 @@ int rc522_set_property_int(struct nfc_device * pnd, const nfc_property property,
|
||||
return NFC_ENOTIMPL;
|
||||
}
|
||||
|
||||
int rc522_idle(struct nfc_device * pnd) {
|
||||
// Set idle and disable RX demodulator to save energy
|
||||
return rc522_write_reg(pnd, RC522_REG_CommandReg, RC522_CMD_Idle | RC522_REG_CommandReg_PowerDown, 0xFF);
|
||||
int rc522_abort(struct nfc_device * pnd) {
|
||||
return rc522_start_command(pnd, CMD_IDLE);
|
||||
}
|
||||
|
||||
int rc522_powerdown(struct nfc_device * pnd) {
|
||||
return rc522_write_reg(pnd, REG_CommandReg, REG_CommandReg_RcvOff | REG_CommandReg_PowerDown | CMD_IDLE, 0xFF);
|
||||
}
|
||||
|
||||
// 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
|
||||
};
|
||||
|
||||
// Extracted from a FM17522 with version 0x88. Fudan Semiconductor datasheet does not include it, though.
|
||||
const uint8_t FM17522_SELFTEST[FIFO_SIZE] = {
|
||||
0x00, 0xD6, 0x78, 0x8C, 0xE2, 0xAA, 0x0C, 0x18, 0x2A, 0xB8, 0x7A, 0x7F, 0xD3, 0x6A, 0xCF, 0x0B,
|
||||
0xB1, 0x37, 0x63, 0x4B, 0x69, 0xAE, 0x91, 0xC7, 0xC3, 0x97, 0xAE, 0x77, 0xF4, 0x37, 0xD7, 0x9B,
|
||||
0x7C, 0xF5, 0x3C, 0x11, 0x8F, 0x15, 0xC3, 0xD7, 0xC1, 0x5B, 0x00, 0x2A, 0xD0, 0x75, 0xDE, 0x9E,
|
||||
0x51, 0x64, 0xAB, 0x3E, 0xE9, 0x15, 0xB5, 0xAB, 0x56, 0x9A, 0x98, 0x82, 0x26, 0xEA, 0x2A, 0x62
|
||||
};
|
||||
|
||||
int rc522_self_test(struct nfc_device * pnd) {
|
||||
int version = rc522_read_reg(pnd, REG_VersionReg);
|
||||
if (version < 0) {
|
||||
return version;
|
||||
}
|
||||
|
||||
const uint8_t * correct;
|
||||
switch (version) {
|
||||
case MFRC522_V1:
|
||||
correct = MFRC522_V1_SELFTEST;
|
||||
break;
|
||||
|
||||
case MFRC522_V2:
|
||||
correct = MFRC522_V2_SELFTEST;
|
||||
break;
|
||||
|
||||
case FM17522:
|
||||
correct = FM17522_SELFTEST;
|
||||
break;
|
||||
|
||||
default:
|
||||
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "Unknown chip version: 0x%02X", version);
|
||||
return NFC_ECHIP;
|
||||
}
|
||||
|
||||
int ret;
|
||||
uint8_t zeroes[25];
|
||||
memset(zeroes, 0x00, sizeof(zeroes));
|
||||
// MFRC522 datasheet section 16.1.1
|
||||
ret =
|
||||
// 1. Perform a soft reset
|
||||
rc522_soft_reset(pnd) ||
|
||||
// 2. Clear the internal buffer by writing 25 bytes of 0x00 and execute the Mem command
|
||||
rc522_write_bulk(pnd, REG_FIFODataReg, zeroes, sizeof(zeroes)) ||
|
||||
rc522_start_command(pnd, CMD_MEM) ||
|
||||
// 3. Enable the self test by writing 0x09 to the AutoTestReg register
|
||||
rc522_write_reg(pnd, REG_AutoTestReg, REG_AutoTestReg_SelfTest_Enabled, REG_AutoTestReg_SelfTest_MASK) ||
|
||||
// 4. Write 0x00h to the FIFO buffer
|
||||
rc522_write_reg(pnd, REG_FIFODataReg, 0x00, 0xFF) ||
|
||||
// 5. Start the self test with the CalcCRC command
|
||||
rc522_start_command(pnd, CMD_CALCCRC);
|
||||
if (ret) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
// 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 5ms
|
||||
timeout_t to;
|
||||
timeout_init(&to, 5);
|
||||
|
||||
while (1) {
|
||||
if (!timeout_check(&to)) {
|
||||
return NFC_ETIMEOUT;
|
||||
}
|
||||
|
||||
if ((ret = rc522_read_reg(pnd, REG_DivIrqReg)) < 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
// If the RC522 has finished calculating the CRC proceed
|
||||
if (ret & REG_DivIrqReg_CRCIRq) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t response[FIFO_SIZE];
|
||||
ret =
|
||||
// 7. Read selftest result
|
||||
rc522_read_bulk(pnd, REG_FIFODataReg, response, FIFO_SIZE) ||
|
||||
// 8. Disable selftest operation mode
|
||||
rc522_write_reg(pnd, REG_AutoTestReg, REG_AutoTestReg_SelfTest_Disabled, REG_AutoTestReg_SelfTest_MASK);
|
||||
if (ret) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (memcmp(correct, response, FIFO_SIZE) != 0) {
|
||||
return NFC_ECHIP;
|
||||
}
|
||||
|
||||
CHIP_DATA(pnd)->version = version;
|
||||
return NFC_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
@ -28,10 +28,15 @@ struct rc522_io {
|
||||
};
|
||||
|
||||
int rc522_data_new(struct nfc_device * pnd, const struct rc522_io * io);
|
||||
void rc522_data_free(struct nfc_device * pnd);
|
||||
int rc522_self_test(struct nfc_device * pnd);
|
||||
int rc522_wait_wakeup(struct nfc_device * pnd);
|
||||
|
||||
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_idle(struct nfc_device * pnd);
|
||||
int rc522_abort(struct nfc_device * pnd);
|
||||
int rc522_powerdown(struct nfc_device * pnd);
|
||||
|
||||
#endif
|
||||
|
||||
@ -28,6 +28,8 @@
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <inttypes.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include <nfc/nfc.h>
|
||||
|
||||
@ -51,98 +53,90 @@ struct rc522_uart_data {
|
||||
|
||||
#define DRIVER_DATA(pnd) ((struct rc522_uart_data*)(pnd->driver_data))
|
||||
|
||||
static size_t
|
||||
rc522_uart_scan(const nfc_context *context, nfc_connstring connstrings[], const size_t connstrings_len)
|
||||
{
|
||||
size_t device_found = 0;
|
||||
serial_port sp;
|
||||
char **acPorts = uart_list_ports();
|
||||
const char *acPort;
|
||||
int iDevice = 0;
|
||||
|
||||
while ((acPort = acPorts[iDevice++])) {
|
||||
sp = uart_open(acPort);
|
||||
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "Trying to find RC522 device on serial port: %s at %d baud.", acPort, RC522_UART_DEFAULT_SPEED);
|
||||
|
||||
if ((sp != INVALID_SERIAL_PORT) && (sp != CLAIMED_SERIAL_PORT)) {
|
||||
// We need to flush input to be sure first reply does not comes from older byte transceive
|
||||
uart_flush_input(sp, true);
|
||||
// Serial port claimed but we need to check if a RC522_UART is opened.
|
||||
uart_set_speed(sp, RC522_UART_DEFAULT_SPEED);
|
||||
|
||||
nfc_connstring connstring;
|
||||
snprintf(connstring, sizeof(nfc_connstring), "%s:%s:%"PRIu32, RC522_UART_DRIVER_NAME, acPort, RC522_UART_DEFAULT_SPEED);
|
||||
nfc_device *pnd = nfc_device_new(context, connstring);
|
||||
if (!pnd) {
|
||||
perror("malloc");
|
||||
uart_close(sp);
|
||||
iDevice = 0;
|
||||
while ((acPort = acPorts[iDevice++])) {
|
||||
free((void *)acPort);
|
||||
}
|
||||
free(acPorts);
|
||||
return 0;
|
||||
}
|
||||
pnd->driver = &rc522_uart_driver;
|
||||
pnd->driver_data = sp;
|
||||
|
||||
// Alloc and init chip's data
|
||||
if (rc522_data_new(pnd, &rc522_uart_io) == NULL) {
|
||||
perror("rc522_data_new");
|
||||
uart_close(DRIVER_DATA(pnd)->port);
|
||||
nfc_device_free(pnd);
|
||||
iDevice = 0;
|
||||
while ((acPort = acPorts[iDevice++])) {
|
||||
free((void *)acPort);
|
||||
}
|
||||
free(acPorts);
|
||||
return 0;
|
||||
}
|
||||
// SAMConfiguration command if needed to wakeup the chip and rc522_SAMConfiguration check if the chip is a RC522
|
||||
CHIP_DATA(pnd)->type = RC522;
|
||||
// This device starts in LowVBat power mode
|
||||
CHIP_DATA(pnd)->power_mode = LOWVBAT;
|
||||
|
||||
// Check communication using "Diagnose" command, with "Communication test" (0x00)
|
||||
int res = rc522_check_communication(pnd);
|
||||
uart_close(DRIVER_DATA(pnd)->port);
|
||||
rc522_data_free(pnd);
|
||||
nfc_device_free(pnd);
|
||||
if (res < 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
memcpy(connstrings[device_found], connstring, sizeof(nfc_connstring));
|
||||
device_found++;
|
||||
|
||||
// Test if we reach the maximum "wanted" devices
|
||||
if (device_found >= connstrings_len)
|
||||
break;
|
||||
}
|
||||
}
|
||||
iDevice = 0;
|
||||
while ((acPort = acPorts[iDevice++])) {
|
||||
free((void *)acPort);
|
||||
}
|
||||
free(acPorts);
|
||||
return device_found;
|
||||
}
|
||||
|
||||
void rc522_uart_close(nfc_device * pnd) {
|
||||
rc522_idle(pnd);
|
||||
// rc522_idle(pnd);
|
||||
|
||||
// Release UART port
|
||||
uart_close(DRIVER_DATA(pnd)->port);
|
||||
free(DRIVER_DATA(pnd));
|
||||
|
||||
rc522_data_free(pnd);
|
||||
nfc_device_free(pnd);
|
||||
}
|
||||
|
||||
size_t rc522_uart_scan(const nfc_context * context, nfc_connstring connstrings[], const size_t connstrings_len) {
|
||||
size_t device_found = 0;
|
||||
serial_port sp;
|
||||
char ** acPorts = uart_list_ports();
|
||||
const char * acPort;
|
||||
size_t iDevice = 0;
|
||||
|
||||
while ((acPort = acPorts[iDevice++])) {
|
||||
sp = uart_open(acPort);
|
||||
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "Trying to find RC522 device on serial port: %s at %d baud.", acPort, RC522_UART_DEFAULT_SPEED);
|
||||
|
||||
if (sp == INVALID_SERIAL_PORT || sp == CLAIMED_SERIAL_PORT) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// We need to flush input to be sure first reply does not comes from older byte transceive
|
||||
uart_flush_input(sp, true);
|
||||
// Serial port claimed but we need to check if a RC522_UART is opened.
|
||||
uart_set_speed(sp, RC522_UART_DEFAULT_SPEED);
|
||||
|
||||
nfc_connstring connstring;
|
||||
snprintf(connstring, sizeof(nfc_connstring), "%s:%s:%"PRIu32, RC522_UART_DRIVER_NAME, acPort, RC522_UART_DEFAULT_SPEED);
|
||||
nfc_device * pnd = nfc_device_new(context, connstring);
|
||||
if (!pnd) {
|
||||
perror("nfc_device_new");
|
||||
uart_close(sp);
|
||||
nfc_device_free(pnd);
|
||||
uart_list_free(acPorts);
|
||||
return 0;
|
||||
}
|
||||
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);
|
||||
uart_list_free(acPorts);
|
||||
return 0;
|
||||
}
|
||||
DRIVER_DATA(pnd)->port = sp;
|
||||
|
||||
// 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);
|
||||
uart_list_free(acPorts);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Check communication using self test
|
||||
int res = rc522_self_test(pnd);
|
||||
rc522_uart_close(pnd);
|
||||
if (res < 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
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;
|
||||
char * baud_str;
|
||||
uint32_t baudrate;
|
||||
char * endptr;
|
||||
|
||||
int decodelvl = connstring_decode(connstring, RC522_UART_DRIVER_NAME, NULL, &port_str, &baud_str);
|
||||
switch (decodelvl) {
|
||||
@ -151,20 +145,20 @@ struct nfc_device * rc522_uart_open(const nfc_context * context, const nfc_conns
|
||||
break;
|
||||
|
||||
case 3: // Got port and baud rate
|
||||
char * endptr;
|
||||
baudrate = (uint32_t) strtol(speed_s, &endptr, 10);
|
||||
// TODO: set baud rate AFTER initialization
|
||||
baudrate = (uint32_t) strtol(baud_str, &endptr, 10);
|
||||
if (*endptr != '\0') {
|
||||
free(port_str);
|
||||
free(bps_str);
|
||||
free(baud_str);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
free(bps_str);
|
||||
free(baud_str);
|
||||
break;
|
||||
|
||||
default: // Got unparseable gibberish
|
||||
free(port_str);
|
||||
free(bps_str);
|
||||
free(baud_str);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@ -172,7 +166,7 @@ struct nfc_device * rc522_uart_open(const nfc_context * context, const nfc_conns
|
||||
struct nfc_device * pnd = NULL;
|
||||
|
||||
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "Attempt to open: %s at %d baud.", port_str, baudrate);
|
||||
sp = uart_open(ndd.port);
|
||||
sp = uart_open(port_str);
|
||||
|
||||
if (sp == INVALID_SERIAL_PORT) {
|
||||
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "Invalid serial port: %s", port_str);
|
||||
@ -212,51 +206,53 @@ struct nfc_device * rc522_uart_open(const nfc_context * context, const nfc_conns
|
||||
DRIVER_DATA(pnd)->port = sp;
|
||||
|
||||
// Alloc and init chip's data
|
||||
if (rc522_data_new(pnd, &rc522_uart_io) == NULL) {
|
||||
if (!rc522_data_new(pnd, &rc522_uart_io)) {
|
||||
perror("rc522_data_new");
|
||||
uart_close(sp);
|
||||
nfc_device_free(pnd);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (rc522_check_communication(pnd) < 0) {
|
||||
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "rc522_check_communication error");
|
||||
if (rc522_self_test(pnd)) {
|
||||
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "rc522_self_test error");
|
||||
rc522_uart_close(pnd);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
rc522_init(pnd);
|
||||
return pnd;
|
||||
}
|
||||
|
||||
int rc522_uart_wakeup(struct nfc_device *pnd) {
|
||||
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 };
|
||||
int res = uart_send(DRIVER_DATA(pnd)->port, rc522_wakeup_preamble, sizeof(rc522_wakeup_preamble), 0);
|
||||
CHIP_DATA(pnd)->power_mode = NORMAL; // RC522 should now be awake
|
||||
return res;
|
||||
if ((ret = uart_send(DRIVER_DATA(pnd)->port, rc522_wakeup_preamble, sizeof(rc522_wakeup_preamble), 0)) < 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
return rc522_wait_wakeup(pnd);
|
||||
}
|
||||
|
||||
#define READ 1
|
||||
#define WRITE 0
|
||||
uint8_t rc522_uart_pack(int reg, int op) {
|
||||
assert(reg < 64);
|
||||
assert(op == READ | op == WRITE);
|
||||
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) {
|
||||
pnd->last_error = uart_send(pnd->driver_data, &cmd, 1, RC522_UART_IO_TIMEOUT);
|
||||
if (pnd->last_error < 0) {
|
||||
if ((ret = uart_send(pnd->driver_data, &cmd, 1, RC522_UART_IO_TIMEOUT)) < 0) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
pnd->last_error = uart_receive(pnd->driver_data, data, 1, RC522_UART_IO_TIMEOUT);
|
||||
if (pnd->last_error < 0) {
|
||||
if ((ret = uart_receive(pnd->driver_data, data, 1, NULL, RC522_UART_IO_TIMEOUT)) < 0) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
@ -271,7 +267,7 @@ error:
|
||||
return pnd->last_error;
|
||||
}
|
||||
|
||||
int rc522_uart_write(struct nfc_device * pnd, uint8_t reg, uint8_t * data, size_t size) {
|
||||
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);
|
||||
|
||||
while (size > 0) {
|
||||
@ -283,7 +279,7 @@ int rc522_uart_write(struct nfc_device * pnd, uint8_t reg, uint8_t * data, size_
|
||||
|
||||
// Second: wait for a reply
|
||||
uint8_t reply;
|
||||
pnd->last_error = uart_receive(pnd->driver_data, &reply, 1, RC522_UART_IO_TIMEOUT);
|
||||
pnd->last_error = uart_receive(pnd->driver_data, &reply, 1, NULL, RC522_UART_IO_TIMEOUT);
|
||||
if (pnd->last_error < 0) {
|
||||
return pnd->last_error;
|
||||
}
|
||||
@ -322,20 +318,20 @@ const struct nfc_driver rc522_uart_driver = {
|
||||
.scan = rc522_uart_scan,
|
||||
.open = rc522_uart_open,
|
||||
.close = rc522_uart_close,
|
||||
.strerror = rc522_strerror,
|
||||
// .strerror = rc522_strerror,
|
||||
|
||||
.initiator_init = rc522_initiator_init,
|
||||
// .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_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,
|
||||
// .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,
|
||||
@ -348,10 +344,10 @@ const struct nfc_driver rc522_uart_driver = {
|
||||
.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,
|
||||
// .device_get_information_about = rc522_get_information_about,
|
||||
|
||||
.abort_command = rc522_idle,
|
||||
.idle = rc522_idle,
|
||||
.powerdown = rc522_softdown,
|
||||
.abort_command = rc522_abort,
|
||||
// .idle = rc522_idle,
|
||||
.powerdown = rc522_powerdown,
|
||||
};
|
||||
|
||||
|
||||
@ -118,6 +118,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
|
||||
@ -156,6 +159,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
|
||||
|
||||
75
libnfc/timing.c
Normal file
75
libnfc/timing.c
Normal file
@ -0,0 +1,75 @@
|
||||
/*-
|
||||
* 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
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
bool timeout_check(timeout_t * to) {
|
||||
if (*to == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
ms_t now = time_millis();
|
||||
if (now >= *to) {
|
||||
*to = 0;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
48
libnfc/timing.h
Normal file
48
libnfc/timing.h
Normal file
@ -0,0 +1,48 @@
|
||||
/*-
|
||||
* 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 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
|
||||
Loading…
x
Reference in New Issue
Block a user