From be0f0b082841873ba1a41838c7c4149ca0c92dd3 Mon Sep 17 00:00:00 2001 From: Romuald Conty Date: Mon, 9 May 2011 10:09:40 +0000 Subject: [PATCH] New function nfc_idle() to set the NFC device in idle mode. nfc_disconnect() now switch NFC device into idle before disconnecting; pn53x_data now have a operating_mode enum to know the current running mode (initiator, target or idle); new pn53x_PowerDown wrapper for PowerDown (PN532) command; Note: ARYGON idle mode now to be implemented and ACR122 does not support this mode. --- include/nfc/nfc.h | 1 + libnfc/chips/pn53x.c | 53 +++++++++++++++++++++++++++++++++++++ libnfc/chips/pn53x.h | 16 ++++++++++- libnfc/drivers/acr122.c | 1 + libnfc/drivers/arygon.c | 2 ++ libnfc/drivers/pn532_uart.c | 1 + libnfc/drivers/pn53x_usb.c | 6 +++-- libnfc/nfc-internal.h | 1 + libnfc/nfc.c | 22 ++++++++++++--- 9 files changed, 96 insertions(+), 7 deletions(-) diff --git a/include/nfc/nfc.h b/include/nfc/nfc.h index 2e37667..95ae096 100644 --- a/include/nfc/nfc.h +++ b/include/nfc/nfc.h @@ -66,6 +66,7 @@ extern "C" { NFC_EXPORT bool nfc_abort_command (nfc_device_t * pnd); NFC_EXPORT void nfc_list_devices (nfc_device_desc_t pnddDevices[], size_t szDevices, size_t * pszDeviceFound); NFC_EXPORT bool nfc_configure (nfc_device_t * pnd, const nfc_device_option_t ndo, const bool bEnable); + NFC_EXPORT bool nfc_idle (nfc_device_t * pnd); /* NFC initiator: act as "reader" */ NFC_EXPORT bool nfc_initiator_init (nfc_device_t * pnd); diff --git a/libnfc/chips/pn53x.c b/libnfc/chips/pn53x.c index 9c3b232..2b04e8b 100644 --- a/libnfc/chips/pn53x.c +++ b/libnfc/chips/pn53x.c @@ -67,6 +67,9 @@ pn53x_init(nfc_device_t * pnd) return false; } + // PN53x starts in initiator mode + CHIP_DATA (pnd)->operating_mode = INITIATOR; + // Set current target to NULL CHIP_DATA (pnd)->current_target = NULL; @@ -660,6 +663,43 @@ pn53x_configure (nfc_device_t * pnd, const nfc_device_option_t ndo, const bool b return true; } +bool +pn53x_idle (nfc_device_t *pnd) +{ + switch (CHIP_DATA (pnd)->operating_mode) { + case TARGET: + return pn53x_InRelease (pnd, 0); + break; + case INITIATOR: + // Deselect all active communications + if (!pn53x_InDeselect (pnd, 0)) { + return false; + } + // Disable RF field to avoid heating + if (!nfc_configure (pnd, NDO_ACTIVATE_FIELD, false)) { + return false; + } + if (CHIP_DATA (pnd)->type == PN532) { + // Use InPowerDown to go in "Low VBat" + if (!pn53x_PowerDown (pnd)) { + return false; + } + CHIP_DATA (pnd)->power_mode = LOWVBAT; + } else { + // Use InRelease to go in "Standby mode" + if (!pn53x_InRelease (pnd, 0)) { + return false; + } + } + break; + default: + // Nothing to do + break; + }; + CHIP_DATA (pnd)->operating_mode = IDLE; + return true; +} + bool pn53x_check_communication (nfc_device_t *pnd) { @@ -682,6 +722,8 @@ pn53x_initiator_init (nfc_device_t * pnd) // Configure the PN53X to be an Initiator or Reader/Writer if (!pn53x_write_register (pnd, REG_CIU_CONTROL, SYMBOL_INITIATOR, 0x10)) return false; + + CHIP_DATA (pnd)->operating_mode = INITIATOR; return true; } @@ -1137,7 +1179,11 @@ bool pn53x_target_init (nfc_device_t * pnd, nfc_target_t * pnt, byte_t * pbtRx, size_t * pszRx) { pn53x_reset_settings(pnd); + + CHIP_DATA (pnd)->operating_mode = TARGET; + pn53x_target_mode_t ptm = PTM_NORMAL; + switch (pnt->nm.nmt) { case NMT_ISO14443A: ptm = PTM_PASSIVE_ONLY; @@ -1600,6 +1646,13 @@ pn53x_SAMConfiguration (nfc_device_t * pnd, const uint8_t ui8Mode) pnd->iLastError = DENOTSUP; return false; } + return (pn53x_transceive (pnd, abtCmd, szCmd, NULL, NULL)); +} + +bool +pn53x_PowerDown (nfc_device_t * pnd) +{ + byte_t abtCmd[] = { PowerDown, 0xf0 }; return (pn53x_transceive (pnd, abtCmd, sizeof (abtCmd), NULL, NULL)); } diff --git a/libnfc/chips/pn53x.h b/libnfc/chips/pn53x.h index ad5cf4a..11458f5 100644 --- a/libnfc/chips/pn53x.h +++ b/libnfc/chips/pn53x.h @@ -29,6 +29,7 @@ # include +// TODO Remove double register address defines // Registers and symbols masks used to covers parts within a register # define REG_CIU_TX_MODE 0x6302 # define SYMBOL_TX_CRC_ENABLE 0x80 @@ -144,15 +145,27 @@ typedef enum { LOWVBAT // Only on PN532, need to be wake up to process commands with a long preamble and SAMConfiguration command } pn53x_power_mode; +typedef enum { + IDLE, + INITIATOR, + TARGET, +} pn53x_operating_mode; + struct pn53x_io { bool (*send)(nfc_device_t * pnd, const byte_t * pbtData, const size_t szData); int (*receive)(nfc_device_t * pnd, byte_t * pbtData, const size_t szDataLen); }; struct pn53x_data { +/** Chip type (PN531, PN532 or PN533)*/ pn53x_type type; +/** Current power mode */ pn53x_power_mode power_mode; +/** Current operating mode */ + pn53x_operating_mode operating_mode; +/** Current emulated target */ nfc_target_t* current_target; +/** PN53x I/O functions stored in struct */ const struct pn53x_io * io; /** Register cache for REG_CIU_BIT_FRAMING, SYMBOL_TX_LAST_BITS: The last TX bits setting, we need to reset this if it does not apply anymore */ uint8_t ui8TxBits; @@ -166,7 +179,6 @@ struct pn53x_data { #define CHIP_DATA(pnd) ((struct pn53x_data*)(pnd->chip_data)) -/* PN53x specific types */ /** * @enum pn53x_modulation_t * @brief NFC modulation @@ -265,6 +277,7 @@ bool pn53x_write_register (nfc_device_t * pnd, uint16_t ui16Reg, uint8_t ui8S bool pn53x_get_firmware_version (nfc_device_t * pnd, char abtFirmwareText[18]); bool pn53x_configure (nfc_device_t * pnd, const nfc_device_option_t ndo, const bool bEnable); bool pn53x_check_communication (nfc_device_t *pnd); +bool pn53x_idle (nfc_device_t * pnd); // NFC device as Initiator functions bool pn53x_initiator_init (nfc_device_t * pnd); @@ -305,6 +318,7 @@ const char *pn53x_strerror (const nfc_device_t * pnd); // C wrappers for PN53x commands bool pn53x_SetParameters (nfc_device_t * pnd, const uint8_t ui8Value); bool pn53x_SAMConfiguration (nfc_device_t * pnd, const uint8_t ui8Mode); +bool pn53x_PowerDown (nfc_device_t * pnd); bool pn53x_InListPassiveTarget (nfc_device_t * pnd, const pn53x_modulation_t pmInitModulation, const byte_t szMaxTargets, const byte_t * pbtInitiatorData, const size_t szInitiatorDataLen, byte_t * pbtTargetsData, size_t * pszTargetsData); diff --git a/libnfc/drivers/acr122.c b/libnfc/drivers/acr122.c index 93bc025..7151c84 100644 --- a/libnfc/drivers/acr122.c +++ b/libnfc/drivers/acr122.c @@ -427,5 +427,6 @@ const struct nfc_driver_t acr122_driver = { .configure = pn53x_configure, .abort_command = NULL, + .idle = NULL, }; diff --git a/libnfc/drivers/arygon.c b/libnfc/drivers/arygon.c index a39d3bd..f58c423 100644 --- a/libnfc/drivers/arygon.c +++ b/libnfc/drivers/arygon.c @@ -494,5 +494,7 @@ const struct nfc_driver_t arygon_driver = { .configure = pn53x_configure, .abort_command = arygon_abort_command, + // FIXME Implement me + .idle = NULL, }; diff --git a/libnfc/drivers/pn532_uart.c b/libnfc/drivers/pn532_uart.c index 29f6786..b8db826 100644 --- a/libnfc/drivers/pn532_uart.c +++ b/libnfc/drivers/pn532_uart.c @@ -444,5 +444,6 @@ const struct nfc_driver_t pn532_uart_driver = { .configure = pn53x_configure, .abort_command = pn532_uart_abort_command, + .idle = pn53x_idle, }; diff --git a/libnfc/drivers/pn53x_usb.c b/libnfc/drivers/pn53x_usb.c index 564f831..6716947 100644 --- a/libnfc/drivers/pn53x_usb.c +++ b/libnfc/drivers/pn53x_usb.c @@ -341,16 +341,17 @@ error: void pn53x_usb_disconnect (nfc_device_t * pnd) { - int res; - pn53x_usb_ack (pnd); + pn53x_idle (pnd); + if (DRIVER_DATA (pnd)->model == ASK_LOGO) { /* Set P30, P31, P32, P33, P35 to logic 1 and P34 to 0 logic */ /* ie. Switch all LEDs off and turn off progressive field */ pn53x_write_register (pnd, SFR_P3, 0xFF, _BV (P30) | _BV (P31) | _BV (P32) | _BV (P33) | _BV (P35)); } + int res; if ((res = usb_release_interface (DRIVER_DATA (pnd)->pudh, 0)) < 0) { ERR ("usb_release_interface failed (%i)", res); } @@ -654,4 +655,5 @@ const struct nfc_driver_t pn53x_usb_driver = { .configure = pn53x_usb_configure, .abort_command = pn53x_usb_abort_command, + .idle = pn53x_idle, }; diff --git a/libnfc/nfc-internal.h b/libnfc/nfc-internal.h index ee427bc..e41bab8 100644 --- a/libnfc/nfc-internal.h +++ b/libnfc/nfc-internal.h @@ -126,6 +126,7 @@ struct nfc_driver_t { bool (*configure) (nfc_device_t * pnd, const nfc_device_option_t ndo, const bool bEnable); bool (*abort_command) (nfc_device_t * pnd); + bool (*idle) (nfc_device_t * pnd); }; nfc_device_t *nfc_device_new (void); diff --git a/libnfc/nfc.c b/libnfc/nfc.c index 45281f6..3494243 100644 --- a/libnfc/nfc.c +++ b/libnfc/nfc.c @@ -138,10 +138,8 @@ void nfc_disconnect (nfc_device_t * pnd) { if (pnd) { - // Release and deselect all active communications - nfc_initiator_deselect_target (pnd); - // Disable RF field to avoid heating - nfc_configure (pnd, NDO_ACTIVATE_FIELD, false); + // Go in idle mode + nfc_idle (pnd); // Disconnect, clean up and release the device pnd->driver->disconnect (pnd); } @@ -645,6 +643,22 @@ nfc_target_init (nfc_device_t * pnd, nfc_target_t * pnt, byte_t * pbtRx, size_t HAL (target_init, pnd, pnt, pbtRx, pszRx); } +/** + * @brief Turn NFC device in idle mode + * @return Returns \c true if action was successfully performed; otherwise returns \c false. + * + * @param pnd \a nfc_device_t struct pointer that represent currently used device + * + * This function switch the device in idle mode. + * In initiator mode, the RF field is turned off and the device is set to low power mode (if avaible); + * In target mode, the emulation is stoped (no target available from external initiator) and the device is set to low power mode (if avaible). + */ +bool +nfc_idle (nfc_device_t * pnd) +{ + HAL (idle, pnd); +} + /** * @brief Abort current running command * @return Returns \c true if action was successfully performed; otherwise returns \c false.