chip/pn53x: handle PN532 "power down" and "low VBat" power mode instead of a simple "sleep" mode. (Fixes Issue 167)
This commit is contained in:
parent
09b18bf6b8
commit
1198a71d64
6 changed files with 73 additions and 31 deletions
|
@ -136,6 +136,12 @@ pn53x_transceive (nfc_device_t * pnd, const byte_t * pbtTx, const size_t szTx, b
|
|||
// Call the send/receice callback functions of the current driver
|
||||
if (!CHIP_DATA(pnd)->io->send (pnd, pbtTx, szTx))
|
||||
return false;
|
||||
|
||||
// Handle power mode for PN532
|
||||
if ((CHIP_DATA(pnd)->type == PN532) && (TgInitAsTarget == pbtTx[0])) { // PN532 automatically goes into PowerDown mode when TgInitAsTarget command will be sent
|
||||
CHIP_DATA(pnd)->power_mode = POWERDOWN;
|
||||
}
|
||||
|
||||
int res = CHIP_DATA(pnd)->io->receive (pnd, pbtRx, *pszRx);
|
||||
if (res < 0) {
|
||||
return false;
|
||||
|
@ -144,6 +150,10 @@ pn53x_transceive (nfc_device_t * pnd, const byte_t * pbtTx, const size_t szTx, b
|
|||
if (pnd->iLastError)
|
||||
return false;
|
||||
|
||||
if ((CHIP_DATA(pnd)->type == PN532) && (TgInitAsTarget == pbtTx[0])) { // PN532 automatically wakeup on external RF field
|
||||
CHIP_DATA(pnd)->power_mode = NORMAL; // When TgInitAsTarget reply that means an external RF have waken up the chip
|
||||
}
|
||||
|
||||
*pszRx = (size_t) res;
|
||||
|
||||
switch (pbtTx[0]) {
|
||||
|
@ -678,6 +688,15 @@ pn53x_InDeselect (nfc_device_t * pnd, const uint8_t ui8Target)
|
|||
return (pn53x_transceive (pnd, abtCmd, sizeof (abtCmd), NULL, NULL));
|
||||
}
|
||||
|
||||
/*
|
||||
typedef enum {
|
||||
NORMAL = 0x01,
|
||||
VIRTUAL_CARD = 0x02,
|
||||
WIRED_MODE = 0x03,
|
||||
DUAL_CARD = 0x04
|
||||
} pn532_sam_mode;
|
||||
*/
|
||||
|
||||
bool
|
||||
pn53x_SAMConfiguration (nfc_device_t * pnd, const uint8_t ui8Mode)
|
||||
{
|
||||
|
|
|
@ -137,10 +137,10 @@ typedef enum {
|
|||
} pn53x_type;
|
||||
|
||||
typedef enum {
|
||||
SLEEP = 0x00, // Need to be wake up to process commands
|
||||
NORMAL = 0x01, // Ready to process command
|
||||
EXECUTE = 0x02, // Need to cancel the running command to process new one
|
||||
} pn53x_state;
|
||||
NORMAL, // In that case, there is no power saved but the PN53x reacts as fast as possible on the host controller interface.
|
||||
POWERDOWN, // Only on PN532, need to be wake up to process commands with a long preamble
|
||||
LOWVBAT // Only on PN532, need to be wake up to process commands with a long preamble and SAMConfiguration command
|
||||
} pn53x_power_mode;
|
||||
|
||||
struct pn53x_io {
|
||||
bool (*send)(nfc_device_t * pnd, const byte_t * pbtData, const size_t szData);
|
||||
|
@ -149,7 +149,7 @@ struct pn53x_io {
|
|||
|
||||
struct pn53x_data {
|
||||
pn53x_type type;
|
||||
pn53x_state state;
|
||||
pn53x_power_mode power_mode;
|
||||
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;
|
||||
|
|
|
@ -220,7 +220,7 @@ acr122_connect (const nfc_device_desc_t * pndd)
|
|||
// Done, we found the reader we are looking for
|
||||
snprintf (pnd->acName, sizeof (pnd->acName), "%s / %s", pndd->acDevice, pcFirmware);
|
||||
|
||||
CHIP_DATA (pnd)->state = NORMAL;
|
||||
CHIP_DATA (pnd)->power_mode = NORMAL;
|
||||
CHIP_DATA (pnd)->io = &acr122_io;
|
||||
// 50: empirical tuning on Touchatag
|
||||
// 46: empirical tuning on ACR122U
|
||||
|
|
|
@ -112,7 +112,7 @@ arygon_probe (nfc_device_desc_t pnddDevices[], size_t szDevices, size_t * pszDev
|
|||
pnd->driver_data = malloc(sizeof(struct arygon_data));
|
||||
DRIVER_DATA (pnd)->port = sp;
|
||||
pnd->chip_data = malloc(sizeof(struct pn53x_data));
|
||||
CHIP_DATA (pnd)->state = NORMAL;
|
||||
CHIP_DATA (pnd)->power_mode = NORMAL;
|
||||
CHIP_DATA (pnd)->io = &arygon_tama_io;
|
||||
|
||||
bool res = arygon_reset_tama (pnd);
|
||||
|
@ -172,7 +172,7 @@ arygon_connect (const nfc_device_desc_t * pndd)
|
|||
pnd->chip_data = malloc(sizeof(struct pn53x_data));
|
||||
|
||||
// The PN53x chip connected to ARYGON MCU doesn't seems to be in SLEEP mode
|
||||
CHIP_DATA (pnd)->state = NORMAL;
|
||||
CHIP_DATA (pnd)->power_mode = NORMAL;
|
||||
CHIP_DATA (pnd)->io = &arygon_tama_io;
|
||||
// empirical tuning
|
||||
CHIP_DATA (pnd)->timer_correction = 46;
|
||||
|
@ -239,7 +239,7 @@ arygon_tama_send (nfc_device_t * pnd, const byte_t * pbtData, const size_t szDat
|
|||
}
|
||||
|
||||
if (pn53x_check_ack_frame (pnd, abtRxBuf, sizeof(abtRxBuf))) {
|
||||
CHIP_DATA (pnd)->state = EXECUTE;
|
||||
// The PN53x is running the sent command
|
||||
} else if (0 == memcmp(arygon_error_unknown_mode, abtRxBuf, sizeof(abtRxBuf))) {
|
||||
ERR( "Bad frame format." );
|
||||
// We have already read 6 bytes and arygon_error_unknown_mode is 10 bytes long
|
||||
|
@ -255,8 +255,6 @@ arygon_tama_send (nfc_device_t * pnd, const byte_t * pbtData, const size_t szDat
|
|||
int
|
||||
arygon_abort (nfc_device_t *pnd)
|
||||
{
|
||||
CHIP_DATA (pnd)->state = NORMAL;
|
||||
|
||||
// Send a valid TAMA packet to wakup the PN53x (we will not have an answer, according to Arygon manual)
|
||||
byte_t dummy[] = { 0x32, 0x00, 0x00, 0xff, 0x09, 0xf7, 0xd4, 0x00, 0x00, 0x6c, 0x69, 0x62, 0x6e, 0x66, 0x63, 0xbe, 0x00 };
|
||||
|
||||
|
@ -384,7 +382,7 @@ arygon_tama_receive (nfc_device_t * pnd, byte_t * pbtData, const size_t szDataLe
|
|||
pnd->iLastError = DEIO;
|
||||
return -1;
|
||||
}
|
||||
CHIP_DATA (pnd)->state = NORMAL;
|
||||
// The PN53x command is done and we successfully received the reply
|
||||
return len;
|
||||
}
|
||||
|
||||
|
|
|
@ -49,7 +49,7 @@
|
|||
static const byte_t ack_frame[] = { 0x00, 0x00, 0xff, 0x00, 0xff, 0x00 };
|
||||
|
||||
int pn532_uart_ack (nfc_device_t * pnd);
|
||||
// void pn532_uart_wakeup (const nfc_device_spec_t nds);
|
||||
int pn532_uart_wakeup (nfc_device_t * pnd);
|
||||
|
||||
const struct pn53x_io pn532_uart_io;
|
||||
|
||||
|
@ -94,7 +94,7 @@ pn532_uart_probe (nfc_device_desc_t pnddDevices[], size_t szDevices, size_t * ps
|
|||
DRIVER_DATA (pnd)->port = sp;
|
||||
pnd->chip_data = malloc(sizeof(struct pn53x_data));
|
||||
CHIP_DATA (pnd)->type = PN532;
|
||||
CHIP_DATA (pnd)->state = SLEEP;
|
||||
CHIP_DATA (pnd)->power_mode = LOWVBAT;
|
||||
CHIP_DATA (pnd)->io = &pn532_uart_io;
|
||||
|
||||
// Check communication using "Diagnose" command, with "Communication test" (0x00)
|
||||
|
@ -158,7 +158,7 @@ pn532_uart_connect (const nfc_device_desc_t * pndd)
|
|||
DRIVER_DATA(pnd)->port = sp;
|
||||
pnd->chip_data = malloc(sizeof(struct pn53x_data));
|
||||
CHIP_DATA(pnd)->type = PN532;
|
||||
CHIP_DATA(pnd)->state = SLEEP;
|
||||
CHIP_DATA(pnd)->power_mode = LOWVBAT;
|
||||
CHIP_DATA(pnd)->io = &pn532_uart_io;
|
||||
// empirical tuning
|
||||
CHIP_DATA(pnd)->timer_correction = 48;
|
||||
|
@ -182,21 +182,42 @@ pn532_uart_disconnect (nfc_device_t * pnd)
|
|||
nfc_device_free (pnd);
|
||||
}
|
||||
|
||||
int
|
||||
pn532_uart_wakeup (nfc_device_t * pnd)
|
||||
{
|
||||
/* High Speed Unit (HSU) wake up consist to send 0x55 and wait a "long" delay for PN532 being wakeup. */
|
||||
const byte_t pn532_wakeup_preamble[] = { 0x55, 0x55, 0x00, 0x00, 0x00 };
|
||||
int res = uart_send (DRIVER_DATA(pnd)->port, pn532_wakeup_preamble, sizeof (pn532_wakeup_preamble));
|
||||
CHIP_DATA(pnd)->power_mode = NORMAL; // PN532 should now be awake
|
||||
return res;
|
||||
}
|
||||
|
||||
#define PN532_BUFFER_LEN (PN53x_EXTENDED_FRAME__DATA_MAX_LEN + PN53x_EXTENDED_FRAME__OVERHEAD)
|
||||
bool
|
||||
pn532_uart_send (nfc_device_t * pnd, const byte_t * pbtData, const size_t szData)
|
||||
{
|
||||
if (CHIP_DATA(pnd)->state == SLEEP) {
|
||||
/** PN532C106 wakeup. */
|
||||
/** High Speed Unit (HSU) wake up consist to send 0x55 and wait a "long" delay for PN532 being wakeup. */
|
||||
const byte_t pn532_wakeup_preamble[] = { 0x55, 0x55, 0x00, 0x00, 0x00 };
|
||||
uart_send (DRIVER_DATA(pnd)->port, pn532_wakeup_preamble, sizeof (pn532_wakeup_preamble));
|
||||
CHIP_DATA(pnd)->state = NORMAL; // PN532 should now be awake
|
||||
// According to PN532 application note, C106 appendix: to go out Low Vbat mode and enter in normal mode we need to send a SAMConfiguration command
|
||||
if (!pn53x_SAMConfiguration (pnd, 0x01)) {
|
||||
return false;
|
||||
switch (CHIP_DATA(pnd)->power_mode) {
|
||||
case LOWVBAT: {
|
||||
/** PN532C106 wakeup. */
|
||||
if (-1 == pn532_uart_wakeup(pnd)) {
|
||||
return false;
|
||||
}
|
||||
// According to PN532 application note, C106 appendix: to go out Low Vbat mode and enter in normal mode we need to send a SAMConfiguration command
|
||||
if (!pn53x_SAMConfiguration (pnd, 0x01)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case POWERDOWN: {
|
||||
if (-1 == pn532_uart_wakeup(pnd)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case NORMAL:
|
||||
// Nothing to do :)
|
||||
break;
|
||||
};
|
||||
|
||||
byte_t abtFrame[PN532_BUFFER_LEN] = { 0x00, 0x00, 0xff }; // Every packet must start with "00 00 ff"
|
||||
CHIP_DATA (pnd)->ui8LastCommand = pbtData[0];
|
||||
|
@ -223,7 +244,7 @@ pn532_uart_send (nfc_device_t * pnd, const byte_t * pbtData, const size_t szData
|
|||
}
|
||||
|
||||
if (pn53x_check_ack_frame (pnd, abtRxBuf, sizeof(abtRxBuf))) {
|
||||
CHIP_DATA(pnd)->state = EXECUTE;
|
||||
// The PN53x is running the sent command
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
@ -353,14 +374,18 @@ pn532_uart_receive (nfc_device_t * pnd, byte_t * pbtData, const size_t szDataLen
|
|||
pnd->iLastError = DEIO;
|
||||
return -1;
|
||||
}
|
||||
CHIP_DATA(pnd)->state = NORMAL;
|
||||
// The PN53x command is done and we successfully received the reply
|
||||
return len;
|
||||
}
|
||||
|
||||
int
|
||||
pn532_uart_ack (nfc_device_t * pnd)
|
||||
{
|
||||
CHIP_DATA(pnd)->state = NORMAL;
|
||||
if (POWERDOWN == CHIP_DATA(pnd)->power_mode) {
|
||||
if (-1 == pn532_uart_wakeup(pnd)) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
return (0 == uart_send (DRIVER_DATA(pnd)->port, ack_frame, sizeof (ack_frame))) ? 0 : -1;
|
||||
}
|
||||
|
||||
|
|
|
@ -285,7 +285,7 @@ pn53x_usb_connect (const nfc_device_desc_t *pndd)
|
|||
*DRIVER_DATA (pnd) = data;
|
||||
pnd->chip_data = malloc(sizeof(struct pn53x_data));
|
||||
|
||||
CHIP_DATA (pnd)->state = NORMAL;
|
||||
CHIP_DATA (pnd)->power_mode = NORMAL;
|
||||
CHIP_DATA (pnd)->io = &pn53x_usb_io;
|
||||
|
||||
switch (DRIVER_DATA (pnd)->model) {
|
||||
|
@ -388,7 +388,7 @@ pn53x_usb_send (nfc_device_t * pnd, const byte_t * pbtData, const size_t szData)
|
|||
}
|
||||
|
||||
if (pn53x_check_ack_frame (pnd, abtRxBuf, res)) {
|
||||
CHIP_DATA(pnd)->state = EXECUTE;
|
||||
// The PN53x is running the sent command
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
@ -529,7 +529,7 @@ read:
|
|||
pnd->iLastError = DEIO;
|
||||
return -1;
|
||||
}
|
||||
CHIP_DATA (pnd)->state = NORMAL;
|
||||
// The PN53x command is done and we successfully received the reply
|
||||
return len;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue