ISO/IEC 14443 PCD Abstract Class

Abstract ISO14443 Proximity Coupling Device (card reader) driver interface.

This header defines an abstract interface useful to access generic ISO14443-compliant PCDs (contactless card readers) in a standardized way.

Design

This header provides communication interface with the PCD (Proximity Coupling Device) as described in ISO/IEC 14443-3. This standard defines communication with 2 different card types: A and B. The naming convention is ‘A’-related functions end with A, B-related functions end with B, common functions end with AB.

Currently, API for part A is fully designed, API for part B will be added later.

Communication between the PCD and the PICC consists of sending and receiving frames. The frames are transmitted in pairs, PCD to PICC followed by PICC to PCD.

Part A of the standard defines transmission of 3 different types of frames:

  • Short frame: transmits 7 bits.
  • Standard frame: Used for data exchange and can transmit several bytes with parity.
  • Bit oriented anticollision frame: 7 byte long frame spit anywhere into two parts. First part is transmitted by the PCD, second part is added by the PICC. It is used during bit-oriented anticollision loop.

ISO/IEC 14443-3 specifies different communication methods (different modulation type / index, different encoding) for part A and B. This driver should support setting these modes, various other communication parameters within these modes as defined by the standard, and should also be able to advertise its capabilities. Communication speeds can’t be arbitrary and are defined by ISO/IEC 14443-4 as $ 1 etu = 128 / (D x fc) $, where etu is the elementary time unit (duration of one bit), fc is the carrier frequency (defined in ISO/IEC 14443-2 to be $ 13.56MHz \pm 7kHz $) and D is an integer divisor, which may be 1, 2, 4 or 8. This paradoxically means that increasing the divisor also increases the communication speed.

The readers also usually support a number of extended features, not covered by the ISO/IEC 14443 standard. For example, the MFRC522 is able to perform a Mifare authentication using its crypto unit, or a self-test. Upper layers which know how to use these extended features should have access to them, but they should not clutter the main API. That is why each extended feature will have a globally assigned number (in the global abstract header). Then other layers could use these numbers to invoke the extended feature, passing in a “parameter structure”. These structures are also defined globally in the abstract header (although in a different file) to allow their re-use.

Often PCDs have a maximum data size they can handle at once. ISO/IEC 14443 standard takes this into account and defines “protocol chaining”, a method to send large data units in multiple smaller frames. The upper library handles this, but for it to know whether to use chaining the PCD must be able to report maximum frame size it can handle.

Driver state diagram

This abstract class presumes a driver with state. The following diagram illustrates available states (see pcdstate_t) and transitions between them.

Some functions may be called only in specific states, this is indicated in documentation of each function. Calling a function in an invalid state will be caught by assertion (if assertions are enabled).

digraph card_state_transitions {
   PCD_UNINIT -> PCD_STOP [label="driver-specific\ninit\nmethod"]
   PCD_STOP -> PCD_RF_OFF [label="driver-specific\nactivation\nmethod"]
   PCD_RF_OFF -> PCD_READY [label="pcdActivateRFFieldAB()"]
   PCD_READY -> PCD_RF_OFF [label="pcdDeactivateRFFieldAB()"]
   PCD_READY -> PCD_ACTIVE [label="pcdTransceive*()"]
   PCD_ACTIVE -> PCD_READY [label="operation complete \n operation timeout \n operation error"]
}

Thread safety

Implementation of this API does not have to guarantee that it is thread-safe. If you need API access from multiple threads use pcdAcquireBus and pcdReleaseBus APIs in order to get exclusive access.

Macro functions (Pcd)

Convenience macros for easy calling of ‘member functions’

pcdGetStateAB(ip)

See
BasePcdVMT.getStateAB

pcdActivateRFAB(ip)

See
BasePcdVMT.activateRFAB

pcdDeactivateRFAB(ip)

See
BasePcdVMT.deactivateRFAB

pcdGetSupportedParamsAB(ip)

See
BasePcdVMT.getSupportedParamsAB

pcdSetParamsAB(ip, rx_spd, tx_spd, mode, txcrc, rxcrc)

See
BasePcdVMT.setParamsAB

pcdTransceiveShortFrameA(ip, data, resp_len_p, timeout_us)

See
BasePcdVMT.transceiveShortFrameA

pcdTransceiveStandardFrameA(ip, data, size, resp_len_p, timeout_us)

See
BasePcdVMT.transceiveStandardFrameA

pcdTransceiveAnticollFrameA(ip, data, size, n_last_bits, align_rx, resp_len_p, timeout_us)

See
BasePcdVMT.transceiveAnticollFrameA

pcdGetRespLengthA(ip)

See
BasePcdVMT.getResponseLengthA

pcdGetRespAB(ip, buf_size, buffer, size_copied, n_last_bits_p)

See
BasePcdVMT.getResponseAB

pcdAcquireBus(ip)

See
BasePcdVMT.acquireBus

pcdReleaseBus(ip)

See
BasePcdVMT.releaseBus

pcdSupportsExtFeature(ip, feature)

See
BasePcdVMT.supportsExtFeature

pcdCallExtFeature(ip, feature, params, result)

See
BasePcdVMT.callExtFeature

Enums

enum pcdstate_t

States of the driver state machine.

Values:

PCD_UNINT

Not initialized

PCD_STOP

Initialized, not active.

PCD_RF_OFF

RF Field is off

PCD_READY

Ready to transmit

PCD_ACTIVE

Transceiving

enum pcdresult_t

Operation result codes.

Values:

PCD_OK

Command completed successfully

PCD_BAD_STATE

Command not possible in this state

PCD_UNSUPPORTED

This PCD does not support this command

PCD_OK_COLLISION

Command OK, but received collision

PCD_OK_TIMEOUT

Command OK, but card did not respond

PCD_ERROR

An unspecified error has occured

PCD_TX_ERROR

Transmission error

PCD_RX_ERROR

Receiver error (such as bad parity)

PCD_RX_OVERFLOW

A receive buffer has overflown

PCD_TX_OVERFLOW

This message won’t fit to tx buffer

enum pcdspeed_rx_t

Receive speed keys for speed bitmask.

Values:

PCD_RX_SPEED_106 = 1
PCD_RX_SPEED_212 = 2
PCD_RX_SPEED_424 = 4
PCD_RX_SPEED_848 = 8
enum pcdspeed_tx_t

Transmit speed keys for speed bitmask.

Values:

PCD_TX_SPEED_106 = 16
PCD_TX_SPEED_212 = 32
PCD_TX_SPEED_424 = 64
PCD_TX_SPEED_848 = 128
enum pcdmode_t

Standard communication modes.

Values:

PCD_ISO14443_A = 1
PCD_ISO14443_B = 2
enum pcdfeature_t

List of possible extended features.

For each extended feature 2 structures are defined in file hal_abstract_iso14443_pcd_ext.h. The first is a param strucure, the second is a response structure.

Values:

PCD_EXT_SELFTEST

Perform a self-test

PCD_EXT_CALCULATE_CRC_A

Calculate type-A CRC

PCD_EXT_CALCULATE_CRC_B

Calculate type-B CRC

PCD_EXT_MIFARE_AUTH

Perform a Mifare auth and turn on crypto

struct PcdSParams
#include <hal_abstract_iso14443_pcd.h>

Structure of communuication parameters supported by the PCD.

Public Members

uint8_t supported_speedsA

Bit mask of supported tx/rx speeds

uint8_t supported_speedsB

Bit mask of supported tx/rx speeds

bool supported_asym_speeds

Support of asymetric speed setting

uint8_t supported_modes

Bit mask of supported modes (A or B)

uint8_t supported_crc_on

Support for automatic CRC generation

uint8_t supported_crc_off

Whether CRC gen can be off at the given speed

uint16_t max_tx_size

Maximum Transmit buffer size

uint16_t max_rx_size

Maximum Receive buffer size

struct BasePcdVMT
#include <hal_abstract_iso14443_pcd.h>

Abstract ISO14443 PCD Virtual Method Table.

Note
use macros defined in this file to call these functions for convenience. Name of the macro is the same as a name of this function with pcd prefix.

Public Members

pcdstate_t (*getStateAB)(void *inst)

Returns the device state.

Note
This function can be called in all states.
Return
State of the device
Parameters
  • inst: Pointer to a Pcd structure

pcdresult_t (*activateRFAB)(void *inst)

Activates RF Field of the PCD.

Note
This function can be called in the following states:
Parameters
  • inst: Pointer to a Pcd structure
Return Value
  • PCD_OK: RF Field successfully activated. Pcd transitions to PCD_READY state.
  • PCD_BAD_STATE: RF Field cannot be activated now or is already active. State won’t change.
  • PCD_ERROR: An error has occured. State won’t change.

pcdresult_t (*deactivateRFAB)(void *inst)

Deactivates the RF Field of the PCD.

Note
This function can be called in the following states:
Parameters
  • inst: Pointer to a Pcd structure
Return Value
  • PCD_OK: Field successfully deactivated. Pcd transitions to PCD_RF_OFF state.
  • PCD_BAD_STATE: RF Field cannot be deactivated now or is already inactive. State won’t change.
  • PCD_ERROR: An error has occured. State won’t change.

const PcdSParams *(*getSupportedParamsAB)(void *inst)

Returns structure with supported features of this PCD.

Note
This function can be called in all states
Return
Pointer to a PcdSParams structure. Content of this structure should not be modified.
Parameters
  • inst: Pointer to a Pcd structure

pcdresult_t (*setParamsAB)(void *inst, pcdspeed_rx_t rx_spd, pcdspeed_tx_t tx_spd, pcdmode_t mode, bool generate_CRC, bool verify_CRC)

Sets communication parameters.

If the parameter combination is unsupported PCD_UNSUPPORTED will be returned. It is advised to first check the value returned by getSupportedParamsAB.

Note
This function can be called in the following states:
Parameters
  • inst: pointer to a Pcd strucutre
  • rx_spd: desired reception speed
  • tx_spd: desired transmission speed
  • mode: desired communication mode
  • generate_CRC: Whether the CRC should be generated and transmitted automatically during transmission
  • verify_CRC: Whether the CRC should be verified automatically during reception
Return Value
  • PCD_OK: Parameters applied successfully. State won’t change.
  • PCD_BAD_STATE: Parameters can’t be changed now. State won’t change.
  • PCD_UNSUPPORTED: Some requested parameters are not supported byt this PCD. State won’t change.
  • PCD_ERROR: An error has occured. State won’t change.

pcdresult_t (*transceiveShortFrameA)(void *inst, uint8_t data, uint16_t *resp_length, uint32_t timeout_us)

Transmits a ‘Short Frame’ and blocks until the response is received or a timeout occurs.

Short frame transmits 7 data bits without parity. Therefore only 7 Least Significant Bits of parameter data are sent. This function discards remaining data in the response buffer, if any.

Note
This function can be called in the following states:
Note
This function call either returns immediatelly with error or will change the state PCD_ACTIVE when the operation is in progress. Unless noted otherwise, the state returns to PCD_READY after this function returns.
Parameters
  • inst: pointer to a Pcd structure
  • data: 7 bits of data to be sent (MSB is ignored)
  • resp_len_p: Length of the received response (see transceiveStandardFrameA).
  • timeout_us: Max number of microseconds to wait for a response.
Return Value
  • PCD_OK: Transmission successful and response received.
  • PCD_OK_COLLISION: Transmission successful and multiple responses received.
  • PCD_OK_TIMEOUT: Transmission successful but no response was received.
  • PCD_BAD_STATE: Can’t transmit right now. The state won’t change.
  • PCD_ERROR: A driver od hardware error has occured.
  • PCD_TX_ERROR: A transmission error has occured.
  • PCD_RX_ERROR: A reception error has occured.
  • PCD_RX_OVERFLOW: Too much data received.

pcdresult_t (*transceiveStandardFrameA)(void *inst, uint8_t *buffer, uint16_t length, uint16_t *resp_length, uint32_t timeout_us)

Transmits a ‘Standard Frame’ and blocks until the response is ready.

Standard frame transmits n (where n >= 1) bytes. The len parameter cannot be greater than maximum buffer size supported by the reader. After the response is received resp_len_p will be set to the received response length. You can then use this parameter to allocate a new buffer and obtain the response using the getResponseAB function. This function discards remaining data in the response buffer, if any.

Note
This function can be called in the following states:
Note
This function call either returns immediatelly with error or will change the state PCD_ACTIVE when the operation is in progress. Unless noted otherwise, the state returns to PCD_READY after this function returns.
Parameters
  • inst: pointer to a Pcd structure
  • buffer: Bytes to send in a standard frame
  • len: Size of the buffer
  • resp_len_p: Size of received response
  • timeout_us: Max number of microseconds to wait for a response.
Return Value
  • PCD_OK: Transmission successful and response received.
  • PCD_OK_COLLISION: Transmission successful and multiple responses received.
  • PCD_OK_TIMEOUT: Transmission successful but no response was received.
  • PCD_BAD_STATE: Can’t transmit right now. The state won’t change.
  • PCD_ERROR: A driver od hardware error has occured.
  • PCD_TX_ERROR: A transmission error has occured.
  • PCD_RX_ERROR: A reception error has occured.
  • PCD_RX_OVERFLOW: Too much data received.
  • PCD_TX_OVERFLOW: Can’t transmit this much data. The state won’t change.

pcdresult_t (*transceiveAnticollFrameA)(void *inst, uint8_t *buffer, uint16_t length, uint8_t n_last_bits, uint8_t align_rx, uint16_t *resp_length, uint32_t timeout_us)

Transmits the first part of an ‘Anticollision Frame’ and blocks until the response is ready.

Anticollision frame is a standard 7-byte frame split anywhere after 16th bit and before 55th bit. First part is transmitted by the PCD and the second part is transmitted by the PICC as a part of an anticollision sequence. For resp_len_p meaning see pcdTransceiveStdFrameA. This function discards remaining data in the response buffer, if any.

Note
This function can be called in the following states:
Note
This function call either returns immediatelly with error or will change the state PCD_ACTIVE when the operation is in progress. Unless noted otherwise, the state returns to PCD_READY after this function returns.
Parameters
  • inst: pointer to a Pcd structure
  • buffer: Bytes to send in an anticoll frame
  • len: Size of the buffer
  • n_last_bits: Number of valid bits in the last byte to be transmitted. 0 means the whole byte is valid.
  • align_rx: Desired position of the first received bit in the first byte of the response.
  • resp_len_p: Size of the received response
  • timeout_us: Max number of microseconds to wait for a response.
Return Value
  • PCD_OK: Transmission successful and response received.
  • PCD_OK_COLLISION: Transmission successful and multiple responses received.
  • PCD_OK_TIMEOUT: Transmission successful but no response was received.
  • PCD_BAD_STATE: Can’t transmit right now. The state won’t change.
  • PCD_ERROR: A driver od hardware error has occured.
  • PCD_TX_ERROR: A transmission error has occured.
  • PCD_RX_ERROR: A reception error has occured.
  • PCD_RX_OVERFLOW: Too much data received.
  • PCD_TX_OVERFLOW: Can’t transmit this much data. The state won’t change.

uint16_t (*getResponseLengthA)(void *inst)

Gets (remaining) size of response stored in the buffer, if any.

Note
This function can be called in the following states:
Return
Number of bytes in the response buffer. 0 if the response buffer is empty.
Parameters
  • inst: pointer to a Pcd structure

pcdresult_t (*getResponseAB)(void *inst, uint16_t buffer_size, uint8_t *buffer, uint16_t *size_copied, uint8_t *n_last_bits)

Read response from the internal response buffer.

Read response from the internal buffer. If size of the buffer passed to this function is smaller than the response size only part of the response will be copied and this function must be called several times. Bytes received first are copied first. n_last_bits_p is valid only when copying last part of the response.

Note
This function can be called in the following states:
Parameters
  • inst: pointer to a Pcd structure
  • buf_size: Max size to read
  • buffer: The buffer
  • size_copied: Number of bytes written to the buffer
  • n_last_bits_p: Number of valid bits in last byte copied to the buffer.
Return Value
  • PCD_OK: Bytes were copied
  • PCD_ERROR: No more bytes to copy
  • PCD_BAD_STATE: This function can’t be called in this state.

void (*acquireBus)(void *inst)

Acquires exclusive access to the PCD.

Parameters
  • inst: pointer to a Pcd structure

void (*releaseBus)(void *inst)

Acquires exclusive access to the PCD.

Parameters
  • inst: pointer to a Pcd structure

bool (*supportsExtFeature)(void *inst, pcdfeature_t feature)

Checks whether this PCD supports the given extended feature.

Parameters
  • inst: pointer to a Pcd structure

pcdresult_t (*callExtFeature)(void *inst, pcdfeature_t feature, void *params, void *result)

Invokes an extended feature.

Parameters
  • inst: pointer to a Pcd structure
  • feature: identifier of the feature
  • params: parameters passed to the feature function. Can be NULL if function doesn’t expect any.
  • result: result of the feature function.
Return Value
  • PCD_OK: Feature function executed successfully
  • PCD_BAD_STATE: Feature function can’t be executed now
  • PCD_UNSUPPORTED: This feature is not supported

struct Pcd
#include <hal_abstract_iso14443_pcd.h>

Base ISO/IEC 14443 PCD.

This class represents a generic ISO/IEC 14443 Proximity Coupling device.

Public Members

const struct BasePcdVMT *vmt

Virtual Methods Table

void *data

Private data of a driver

ISO/IEC 14443 PCD Structures for Extended Features

Structures for extended / optional features of an abstract ISO/IEC 14443 PCD.

Real-world ISO/IEC 14443 PCDs (card readers) support a number of extended features which are not covered by the abstract PCD driver. These features can be still used using the pcdCallExtraFeatures API. Structures used as parameters and results of various commands are defined here.

struct PcdExtSelftest_params
#include <hal_abstract_iso14443_pcd_ext.h>

Parameters for PCD_EXT_SELFTEST command.

PCD_EXT_SELFTEST takes no parameters, this structure is empty and params argument can be NULL.

struct PcdExtSelftest_result
#include <hal_abstract_iso14443_pcd_ext.h>

Result of the PCD_EXT_SELFTEST command.

Public Members

bool passed

Did the self-test passed?

struct PcdExtCalcCRC_params
#include <hal_abstract_iso14443_pcd_ext.h>

Parameters for PCD_EXT_CALCULATE_CRC_A and PCD_EXT_CALCULATE_CRC_B commands.

Public Members

uint16_t length

Size of the data to calculate CRC of

uint8_t *buffer

Pointer to data buffer

struct PcdExtCalcCRC_result
#include <hal_abstract_iso14443_pcd_ext.h>

Result of PCD_EXT_CALCULATE_CRC_A and PCD_EXT_CALCULATE_CRC_B commands.

Public Members

uint16_t crc

Resulting CRC

struct PcdExtMifareAuth_params
#include <hal_abstract_iso14443_pcd_ext.h>

Parameters for the PCD_EXT_MIFARE_AUTH command.

Public Members

uint8_t authCommandCode
uint8_t blockAddr
uint8_t sectorKey[6]
uint8_t cardSerialNumber[4]
struct PcdExtMifareAuth_result
#include <hal_abstract_iso14443_pcd_ext.h>

Result of the PCD_EXT_MIFARE_AUTH command.

Public Members

bool authSuccess