WIP support for MFRC522
This commit is contained in:
parent
7f23f1f84d
commit
6b4ba0dbf3
@ -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}/drivers)
|
||||
|
||||
@ -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
|
||||
|
||||
|
||||
95
libnfc/chips/rc522-internal.h
Normal file
95
libnfc/chips/rc522-internal.h
Normal file
@ -0,0 +1,95 @@
|
||||
|
||||
|
||||
#ifndef __NFC_CHIPS_RC522_INTERNAL_H__
|
||||
#define __NFC_CHIPS_RC522_INTERNAL_H__
|
||||
|
||||
#define RC522_REG_CommandReg 0x01
|
||||
|
||||
#define RC522_REG_ComlEnReg 0x02
|
||||
|
||||
#define RC522_REG_DivlEnReg 0x03
|
||||
|
||||
#define RC522_REG_ComIrqReg 0x04
|
||||
|
||||
#define RC522_REG_DivIrqReg 0x05
|
||||
|
||||
#define RC522_REG_ErrorReg 0x06
|
||||
|
||||
#define RC522_REG_Status1Reg 0x07
|
||||
|
||||
#define RC522_REG_Status2Reg 0x08
|
||||
#define RC522_REG_Status2Reg_MFCrypto1On (1 << 3)
|
||||
|
||||
#define RC522_REG_FIFODataReg 0x09
|
||||
|
||||
#define RC522_REG_FIFOLevelReg 0x0A
|
||||
|
||||
#define RC522_REG_WaterLevelReg 0x0B
|
||||
|
||||
#define RC522_REG_ControlReg 0x0C
|
||||
|
||||
#define RC522_REG_BitFramingReg 0x0D
|
||||
|
||||
#define RC522_REG_CollReg 0x0E
|
||||
|
||||
#define RC522_REG_ModeReg 0x11
|
||||
|
||||
#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 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 RC522_REG_TxControlReg 0x14
|
||||
#define RC522_REG_TxControlReg_Tx2RFEn (1 << 1)
|
||||
#define RC522_REG_TxControlReg_Tx1RFEn (1 << 0)
|
||||
|
||||
#define RC522_REG_TxASKReg 0x15
|
||||
|
||||
#define RC522_REG_TxSelReg 0x16
|
||||
|
||||
#define RC522_REG_RxSelReg 0x17
|
||||
|
||||
#define RC522_REG_RxThresholdReg 0x18
|
||||
|
||||
#define RC522_REG_DemodReg 0x19
|
||||
|
||||
#define RC522_REG_MfTxReg 0x1C
|
||||
|
||||
#define RC522_REG_MfRxReg 0x1D
|
||||
#define RC522_REG_MfRxReg_ParityDisable (1 << 4)
|
||||
|
||||
#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
|
||||
|
||||
#endif
|
||||
212
libnfc/chips/rc522.c
Normal file
212
libnfc/chips/rc522.c
Normal file
@ -0,0 +1,212 @@
|
||||
/*-
|
||||
* 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"
|
||||
|
||||
#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 };
|
||||
|
||||
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;
|
||||
};
|
||||
|
||||
#define CHIP_DATA(x) ((struct rc522_chip_data *) (x)->chip_data)
|
||||
|
||||
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;
|
||||
return NFC_SUCCESS;
|
||||
}
|
||||
|
||||
int rc522_read_reg(struct nfc_device * pnd, uint8_t reg) {
|
||||
uint8_t val;
|
||||
|
||||
int ret = CHIP_DATA(pnd)->io->read(pnd, reg, &val, 1, RC522_TIMEOUT);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
int rc522_write_reg(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 CHIP_DATA(pnd)->io->write(pnd, reg, &val, 1, RC522_TIMEOUT);
|
||||
}
|
||||
|
||||
int rc522_set_speed(struct nfc_device * pnd, nfc_baud_rate speed) {
|
||||
uint8_t txVal, rxVal;
|
||||
|
||||
switch (speed) {
|
||||
case NBR_106:
|
||||
txVal = RC522_REG_TxModeReg_TxSpeed_106k;
|
||||
rxVal = RC522_REG_RxModeReg_RxSpeed_106k;
|
||||
break;
|
||||
|
||||
case NBR_212:
|
||||
txVal = RC522_REG_TxModeReg_TxSpeed_212k;
|
||||
rxVal = RC522_REG_RxModeReg_RxSpeed_212k;
|
||||
break;
|
||||
|
||||
case NBR_424:
|
||||
txVal = RC522_REG_TxModeReg_TxSpeed_424k;
|
||||
rxVal = RC522_REG_RxModeReg_RxSpeed_424k;
|
||||
break;
|
||||
|
||||
case NBR_847:
|
||||
txVal = RC522_REG_TxModeReg_TxSpeed_847k;
|
||||
rxVal = RC522_REG_RxModeReg_RxSpeed_847k;
|
||||
break;
|
||||
|
||||
default:
|
||||
return NFC_EINVARG;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
int rc522_get_supported_modulation(struct nfc_device * pnd, const nfc_mode mode, const nfc_modulation_type ** const supported_mt) {
|
||||
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) {
|
||||
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;
|
||||
}
|
||||
|
||||
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);
|
||||
if (ret) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
pnd->bCrc = enable;
|
||||
return NFC_SUCCESS;
|
||||
|
||||
case NP_HANDLE_PARITY:
|
||||
if (pnd->bPar == enable) {
|
||||
return NFC_SUCCESS;
|
||||
}
|
||||
|
||||
ret = rc522_write_reg(pnd, RC522_REG_MfRxReg, enable ? 0 : ~0, RC522_REG_MfRxReg_ParityDisable);
|
||||
if (ret) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
pnd->bPar = enable;
|
||||
return NFC_SUCCESS;
|
||||
|
||||
case NP_EASY_FRAMING:
|
||||
pnd->bEasyFraming = enable;
|
||||
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);
|
||||
|
||||
case NP_ACTIVATE_CRYPTO1:
|
||||
return rc522_write_reg(pnd, RC522_REG_Status2Reg, enable ? ~0 : 0, RC522_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_speed(pnd, NBR_106);
|
||||
|
||||
case NP_AUTO_ISO14443_4:
|
||||
case NP_ACCEPT_INVALID_FRAMES:
|
||||
case NP_INFINITE_SELECT:
|
||||
case NP_FORCE_ISO14443_B:
|
||||
case NP_TIMEOUT_COMMAND:
|
||||
case NP_TIMEOUT_ATR:
|
||||
case NP_TIMEOUT_COM:
|
||||
return NFC_EINVARG;
|
||||
}
|
||||
|
||||
return NFC_EINVARG;
|
||||
}
|
||||
35
libnfc/chips/rc522.h
Normal file
35
libnfc/chips/rc522.h
Normal file
@ -0,0 +1,35 @@
|
||||
/*-
|
||||
* 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, unsigned int timeout);
|
||||
int (*write)(struct nfc_device * pnd, uint8_t reg, const uint8_t * data, size_t size, unsigned int timeout);
|
||||
};
|
||||
|
||||
int rc522_data_new(struct nfc_device * pnd, const struct rc522_io * io);
|
||||
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);
|
||||
|
||||
#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@
|
||||
|
||||
334
libnfc/drivers/rc522_uart.c
Normal file
334
libnfc/drivers/rc522_uart.c
Normal file
@ -0,0 +1,334 @@
|
||||
/*-
|
||||
* 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 <nfc/nfc.h>
|
||||
|
||||
#include "drivers.h"
|
||||
#include "nfc-internal.h"
|
||||
#include "chips/rc522.h"
|
||||
#include "uart.h"
|
||||
|
||||
#define RC522_UART_DEFAULT_SPEED 9600
|
||||
#define RC522_UART_DRIVER_NAME "rc522_uart"
|
||||
|
||||
#define LOG_CATEGORY "libnfc.driver.rc522_uart"
|
||||
#define LOG_GROUP NFC_LOG_GROUP_DRIVER
|
||||
|
||||
// Internal data structs
|
||||
const struct rc522_io rc522_uart_io;
|
||||
struct rc522_uart_data {
|
||||
serial_port port;
|
||||
};
|
||||
|
||||
#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);
|
||||
|
||||
// Release UART port
|
||||
uart_close(DRIVER_DATA(pnd)->port);
|
||||
free(DRIVER_DATA(pnd));
|
||||
|
||||
rc522_data_free(pnd);
|
||||
nfc_device_free(pnd);
|
||||
}
|
||||
|
||||
struct nfc_device * rc522_uart_open(const nfc_context * context, const nfc_connstring connstring) {
|
||||
char * port_str;
|
||||
char * baud_str;
|
||||
uint32_t baudrate;
|
||||
|
||||
int decodelvl = connstring_decode(connstring, RC522_UART_DRIVER_NAME, NULL, &port_str, &baud_str);
|
||||
switch (decodelvl) {
|
||||
case 2: // Got port but no speed
|
||||
baudrate = RC522_UART_DEFAULT_SPEED;
|
||||
break;
|
||||
|
||||
case 3: // Got port and baud rate
|
||||
char * endptr;
|
||||
baudrate = (uint32_t) strtol(speed_s, &endptr, 10);
|
||||
if (*endptr != '\0') {
|
||||
free(port_str);
|
||||
free(bps_str);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
free(bps_str);
|
||||
break;
|
||||
|
||||
default: // Got unparseable gibberish
|
||||
free(port_str);
|
||||
free(bps_str);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
serial_port sp;
|
||||
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);
|
||||
|
||||
if (sp == INVALID_SERIAL_PORT) {
|
||||
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "Invalid serial port: %s", port_str);
|
||||
free(port_str);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (sp == CLAIMED_SERIAL_PORT) {
|
||||
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "Serial port already claimed: %s", port_str);
|
||||
free(port_str);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// We need to flush input to be sure first reply does not comes from older byte transceive
|
||||
uart_flush_input(sp, true);
|
||||
uart_set_speed(sp, baudrate);
|
||||
|
||||
// We have a connection
|
||||
pnd = nfc_device_new(context, connstring);
|
||||
if (!pnd) {
|
||||
perror("nfc_device_new");
|
||||
free(port_str);
|
||||
uart_close(sp);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
snprintf(pnd->name, sizeof(pnd->name), "%s:%s", RC522_UART_DRIVER_NAME, port_str);
|
||||
free(port_str);
|
||||
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 NULL;
|
||||
}
|
||||
DRIVER_DATA(pnd)->port = sp;
|
||||
|
||||
// Alloc and init chip's data
|
||||
if (rc522_data_new(pnd, &rc522_uart_io) == NULL) {
|
||||
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");
|
||||
rc522_uart_close(pnd);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
rc522_init(pnd);
|
||||
return pnd;
|
||||
}
|
||||
|
||||
int rc522_uart_wakeup(struct nfc_device *pnd) {
|
||||
/* 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;
|
||||
}
|
||||
|
||||
#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, unsigned int timeout) {
|
||||
uint8_t cmd = rc522_uart_pack(reg, READ);
|
||||
|
||||
while (size > 0) {
|
||||
pnd->last_error = uart_send(pnd->driver_data, &cmd, sizeof(cmd), timeout);
|
||||
if (pnd->last_error < 0) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
pnd->last_error = uart_receive(pnd->driver_data, data, 1, timeout);
|
||||
if (pnd->last_error < 0) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
size--;
|
||||
data++;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
error:
|
||||
uart_flush_input(DRIVER_DATA(pnd)->port, true);
|
||||
return pnd->last_error;
|
||||
}
|
||||
|
||||
int rc522_uart_write(struct nfc_device * pnd, uint8_t reg, uint8_t * data, size_t size, unsigned int timeout) {
|
||||
uint8_t cmd[2];
|
||||
cmd[0] = rc522_uart_pack(reg, WRITE);
|
||||
|
||||
while (size > 0) {
|
||||
cmd[1] = *data;
|
||||
pnd->last_error = uart_send(pnd->driver_data, &cmd, sizeof(cmd), timeout);
|
||||
if (pnd->last_error < 0) {
|
||||
return pnd->last_error;
|
||||
}
|
||||
|
||||
size--;
|
||||
data++;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
const struct rc522_io rc522_uart_io = {
|
||||
.read = rc522_uart_read,
|
||||
.write = rc522_uart_write,
|
||||
};
|
||||
|
||||
const struct nfc_driver rc522_uart_driver = {
|
||||
.name = RC522_UART_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_uart_abort_command,
|
||||
.idle = rc522_idle,
|
||||
.powerdown = rc522_softdown,
|
||||
};
|
||||
|
||||
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
|
||||
@ -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