ST25DV

The St25dv provides a utility class for NFC communications using the ST25DV Dynamic NFC / RFID tag. The tag includes 4Kb, 16Kb, or 64Kb EEPROM along with support for fast transfer mode - which enables bi-directional communications with other NFC/RFID enabled devices such as phones. This chip stores in its EEPROM NFC T5T tag records - which include a CC header (that this class maintains) followed by serialized NDEF records.

API Reference

Header File

Functions

Warning

doxygenfunction: Unable to resolve function “operator==” with arguments None in doxygen xml output for project “esp-docs” from directory: /home/runner/work/espp/espp/doc/_build/en/esp32/xml_in/. Potential matches:

- bool operator==(const AdcConfig &lhs, const AdcConfig &rhs)
- bool operator==(const Config &rhs) const = default
- bool operator==(const DetentConfig &lhs, const DetentConfig &rhs)
- bool operator==(const Hsv &rhs) const = default
- bool operator==(const PinConfig &rhs) const = default
- bool operator==(const PointerData &rhs) const = default
- bool operator==(const Rgb &rhs) const = default
- bool operator==(const TouchpadData &rhs) const = default
- bool operator==(const TouchpadData &rhs) const = default
- bool operator==(const Vector2d &other) const
- bool operator==(const espp::Bm8563::Date &lhs, const espp::Bm8563::Date &rhs)
- bool operator==(const espp::Bm8563::DateTime &lhs, const espp::Bm8563::DateTime &rhs)
- bool operator==(const espp::Bm8563::Time &lhs, const espp::Bm8563::Time &rhs)
- bool operator==(const espp::QwiicNes::ButtonState &lhs, const espp::QwiicNes::ButtonState &rhs)
- bool operator==(const espp::St25dv::IT_STS &lhs, const espp::St25dv::IT_STS &rhs)

Unions

espp::St25dv::IT_STS.__unnamed15__

Public Members

struct espp::St25dv::IT_STS::[anonymous]::[anonymous] [anonymous]
uint8_t raw

Classes

class St25dv : public espp::BasePeripheral<uint16_t>

Class for wireless communications using a ST25DV Dynamic NFC/RFID tag. The datasheet for the ST25DV can be found here: https://www.st.com/resource/en/datasheet/st25dv04k.pdf.

St25dv Example

    // make the I2C that we'll use to communicate
    espp::I2c i2c({
        .port = I2C_NUM_0,
        .sda_io_num = (gpio_num_t)CONFIG_EXAMPLE_I2C_SDA_GPIO,
        .scl_io_num = (gpio_num_t)CONFIG_EXAMPLE_I2C_SCL_GPIO,
        .clk_speed = 1000 * 1000,
    });

    // now make the st25dv which decodes the data
    espp::St25dv st25dv({.write = std::bind(&espp::I2c::write, &i2c, std::placeholders::_1,
                                            std::placeholders::_2, std::placeholders::_3),
                         .read = std::bind(&espp::I2c::read, &i2c, std::placeholders::_1,
                                           std::placeholders::_2, std::placeholders::_3),
                         .log_level = espp::Logger::Verbosity::INFO});

    std::array<uint8_t, 50> programmed_data;
    std::error_code ec;
    st25dv.read(programmed_data.data(), programmed_data.size(), ec);
    if (ec) {
      fmt::print("Failed to read st25dv: {}\n", ec.message());
      return;
    }
    fmt::print("Read: {}\n", programmed_data);

    std::vector<espp::Ndef> records;

    // create some sample records
    int payload_id = '0';

    records.emplace_back(espp::Ndef::make_handover_select(payload_id));
    records.emplace_back(espp::Ndef::make_text("hello!"));
    records.emplace_back(espp::Ndef::make_uri("github.com/esp-cpp/espp", espp::Ndef::Uic::HTTPS));
    records.emplace_back(espp::Ndef::make_android_launcher("com.google.android.apps.photos"));
    records.emplace_back(espp::Ndef::make_wifi_config({
        .ssid = CONFIG_ESP_WIFI_SSID,
        .key = CONFIG_ESP_WIFI_PASSWORD,
    }));

    // create BLE OOB pairing record
    uint64_t radio_mac_addr = 0x060504030201; // 48b, example address 06:05:04:03:02:01
#if CONFIG_BT_BLE_ENABLED
    // get the mac address of the radio
    init_low_level(HID_DEV_MODE);
    const uint8_t *point = esp_bt_dev_get_address();
    if (point == nullptr) {
      fmt::print("Failed to get radio mac address!\n");
      return;
    } else {
      // convert the 6 byte mac address to a 48 bit integer
      for (int i = 0; i < 6; i++) {
        radio_mac_addr |= (uint64_t)point[5 - i] << (i * 8);
      }
    }
    fmt::print("radio mac addr: {:#x}\n", radio_mac_addr);
#endif
    auto ble_role = espp::Ndef::BleRole::PERIPHERAL_ONLY;
    auto ble_appearance = espp::Ndef::BtAppearance::GAMEPAD;
    std::string_view ble_radio_name = "BLE Radio";
    records.emplace_back(
        espp::Ndef::make_le_oob_pairing(radio_mac_addr, ble_role, ble_radio_name, ble_appearance));
    records.back().set_id(payload_id);

    // set one of the records we made to be the active tag
    st25dv.set_records(records, ec);

    // and finally, make the task to periodically poll the st25dv and print the
    // state. The task will trigger sample quit when the phone reads the tag.
    auto task_fn = [&quit_test, &st25dv](std::mutex &m, std::condition_variable &cv) {
      {
        std::unique_lock<std::mutex> lock(m);
        cv.wait_for(lock, 30ms);
      }
      std::error_code ec;
      auto it_sts = st25dv.get_interrupt_status(ec);
      if (ec) {
        fmt::print("Failed to get interrupt status: {}\n", ec.message());
        // wait a bit before trying again
        std::unique_lock<std::mutex> lock(m);
        cv.wait_for(lock, 300ms);
        return false;
      }
      static auto last_it_sts = it_sts;
      if (it_sts != last_it_sts) {
        fmt::print("[{:.3f}] IT STS: {}\n", elapsed(), it_sts);
      }
      last_it_sts = it_sts;
      // we don't want to stop the task, so return false
      return false;
    };
    auto task = espp::Task({.callback = task_fn,
                            .task_config =
                                {
                                    .name = "St25dv Task",
                                    .stack_size_bytes = 5 * 1024,
                                },
                            .log_level = espp::Logger::Verbosity::WARN});
    task.start();

Note

See https://stackoverflow.com/questions/61622309/base-address-requirement-for-ndef-messages-on-type-5-tags for some discussion about the Capability Container (CC) header that must be the first data in the EEPROM.

Public Types

typedef std::function<bool(uint8_t)> probe_fn

Function to probe the peripheral

Param address

The address to probe

Return

True if the peripheral is found at the given address

Public Functions

inline explicit St25dv(const Config &config)

Construct the St25dv with the provided configuration.

inline void initialize(std::error_code &ec)

Initialize the St25dv.

Parameters

&ec – Error code to be filled with any errors that occur during initialization.

inline IT_STS get_interrupt_status(std::error_code &ec)

Get the interrupt status register (dynamic IT_STS).

Note

Reading the interrupt status register clears it.

Note

The available states / flags in the register are available in St25dv::IT_STS.

Parameters

&ec – Error code to be filled with any errors that occur during reading.

Returns

The interrupt status register.

inline void set_record(Ndef &record, std::error_code &ec)

Writes the provided record (along with CC header) to the EEPROM.

Note

Right now this only supports 4 B CC headers (for memory less than 16 Kbit).

Parameters
  • record – The new NDEF record to serialize to the NFC EEPROM.

  • &ec – Error code to be filled with any errors that occur during writing.

inline void set_record(const std::vector<uint8_t> &record_data, std::error_code &ec)

Writes the provided record (along with CC header) to the EEPROM.

Parameters
  • &record_data – The serialized NDEF record to write to the NFC EEPROM.

  • &ec – Error code to be filled with any errors that occur during writing.

inline void set_records(std::vector<Ndef> &records, std::error_code &ec)

Writes the provided records (along with CC header) to the EEPROM.

Parameters
  • &records – Vector of NDEF records to serialize to the NFC EEPROM.

  • &ec – Error code to be filled with any errors that occur during writing.

inline void write(std::string_view payload, std::error_code &ec)

Write a raw sequence of bytes to the EEPROM.

Parameters
  • payload – Sequence of bytes to write.

  • &ec – Error code to be filled with any errors that occur during writing.

inline void read(uint8_t *data, uint8_t length, std::error_code &ec)

Read a sequence of bytes from the EEPROM starting at offset 0.

Note

This may contain raw NDEF bytes as well as the CC header.

Parameters
  • *data – Pointer to memory to be filled with bytes read.

  • length – Number of bytes to read.

  • &ec – Error code to be filled with any errors that occur during reading.

inline void read(uint8_t *data, uint8_t length, uint16_t offset, std::error_code &ec)

Read a sequence of bytes from the EEPROM starting at the provided offset.

Note

This may contain raw NDEF bytes as well as the CC header.

Parameters
  • *data – Pointer to memory to be filled with bytes read.

  • length – Number of bytes to read.

  • offset – Offset to start reading from.

  • &ec – Error code to be filled with any errors that occur during reading.

inline void start_fast_transfer_mode(std::error_code &ec)

Enable fast transfer mode (using up to 255 bytes at a time) between RF and I2C. After calling this, you can call transfer(), receive(), and get_ftm_length() for fast bi-directional communications between RF and I2C.

Note

You must call stop_fast_transfer_mode() before calling any other functions on this class.

Parameters

&ec – Error code to be filled with any errors that occur during writing.

inline void stop_fast_transfer_mode(std::error_code &ec)

Disable fast transfer mode (using up to 255 bytes at a time) between RF and I2C. After calling this, you cannot call transfer() or receive() without again calling start_fast_transfer_mode() first.

Parameters

&ec – Error code to be filled with any errors that occur during writing.

inline uint8_t get_ftm_length(std::error_code &ec)

Returns the available message length in the FTM message box.

Will return non-zero if the RF received data into the FTM.

Parameters

&ec – Error code to be filled with any errors that occur during reading.

Returns

Number of bytes (up to 255) available in the FTM message box.

inline void transfer(const uint8_t *data, uint8_t length, std::error_code &ec)

Write data to the FTM message box to send.

Note

Must call start_fast_transfer_mode() prior to use.

Parameters
  • data – Data to be written.

  • length – Number of bytes to write.

  • &ec – Error code to be filled with any errors that occur during

inline void receive(uint8_t *data, uint8_t length, std::error_code &ec)

Read data from the FTM message box.

Note

Must call start_fast_transfer_mode() prior to use.

Note

The length available to be read can be found by calling get_ftm_length().

Parameters
  • data – Pointer to memory to be filled with data.

  • length – Number of bytes to read.

  • &ec – Error code to be filled with any errors that occur during

inline bool probe (std::error_code &ec) requires(true)

Probe the peripheral

Note

This function is thread safe

Note

If the probe function is not set, this function will return false and set the error code to operation_not_supported

Note

This function is only available if UseAddress is true

Parameters

ec – The error code to set if there is an error

Returns

True if the peripheral is found

inline void set_address (uint8_t address) requires(true)

Set the address of the peripheral

Note

This function is thread safe

Note

This function is only available if UseAddress is true

Parameters

address – The address of the peripheral

inline void set_probe (const probe_fn &probe) requires(true)

Set the probe function

Note

This function is thread safe

Note

This should rarely be used, as the probe function is usually set in the constructor. If you need to change the probe function, consider using the set_config function instead.

Note

This function is only available if UseAddress is true

Parameters

probe – The probe function

inline void set_write(const write_fn &write)

Set the write function

Note

This function is thread safe

Note

This should rarely be used, as the write function is usually set in the constructor. If you need to change the write function, consider using the set_config function instead.

Parameters

write – The write function

inline void set_read(const read_fn &read)

Set the read function

Note

This function is thread safe

Note

This should rarely be used, as the read function is usually set in the constructor. If you need to change the read function, consider using the set_config function instead.

Parameters

read – The read function

inline void set_read_register(const read_register_fn &read_register)

Set the read register function

Note

This function is thread safe

Note

This should rarely be used, as the read register function is usually set in the constructor. If you need to change the read register function, consider using the set_config function instead.

Parameters

read_register – The read register function

inline void set_write_then_read(const write_then_read_fn &write_then_read)

Set the write then read function

Note

This function is thread safe

Note

This should rarely be used, as the write then read function is usually set in the constructor. If you need to change the write then

Parameters

write_then_read – The write then read function

inline void set_separate_write_then_read_delay(const std::chrono::milliseconds &delay)

Set the delay between the write and read operations in write_then_read

Note

This function is thread safe

Note

This should rarely be used, as the delay is usually set in the constructor. If you need to change the delay, consider using the set_config function instead.

Note

This delay is only used if the write_then_read function is not set to a custom function and the write and read functions are separate functions.

Parameters

delay – The delay between the write and read operations in write_then_read

inline void set_config(const Config &config)

Set the configuration for the peripheral

Note

This function is thread safe

Note

The configuration should normally be set in the constructor, but this function can be used to change the configuration after the peripheral has been created - for instance if the peripheral could be found on different communications buses.

Parameters

config – The configuration for the peripheral

inline void set_config(Config &&config)

Set the configuration for the peripheral

Note

This function is thread safe

Note

The configuration should normally be set in the constructor, but this function can be used to change the configuration after the peripheral has been created - for instance if the peripheral could be found on different communications buses.

Parameters

config – The configuration for the peripheral

inline const std::string &get_name() const

Get the name of the component

Note

This is the tag of the logger

Returns

A const reference to the name of the component

inline void set_log_tag(const std::string_view &tag)

Set the tag for the logger

Parameters

tag – The tag to use for the logger

inline espp::Logger::Verbosity get_log_level() const

Get the log level for the logger

Returns

The verbosity level of the logger

inline void set_log_level(espp::Logger::Verbosity level)

Set the log level for the logger

Parameters

level – The verbosity level to use for the logger

inline void set_log_verbosity(espp::Logger::Verbosity level)

Set the log verbosity for the logger

See also

set_log_level

Note

This is a convenience method that calls set_log_level

Parameters

level – The verbosity level to use for the logger

inline espp::Logger::Verbosity get_log_verbosity() const

Get the log verbosity for the logger

See also

get_log_level

Note

This is a convenience method that calls get_log_level

Returns

The verbosity level of the logger

inline void set_log_rate_limit(std::chrono::duration<float> rate_limit)

Set the rate limit for the logger

Note

Only calls to the logger that have _rate_limit suffix will be rate limited

Parameters

rate_limit – The rate limit to use for the logger

Public Static Attributes

static constexpr uint8_t DATA_ADDRESS = (0xA6 >> 1)

I2C Address for writing / reading data.

static constexpr uint8_t SYST_ADDRESS = (0xAE >> 1)

I2C Address for writing / reading system config.

struct Config

Configuration information for the St25dv.

Public Members

BasePeripheral::write_fn write

Function to write to the device.

BasePeripheral::read_fn read

Function to read from the device.

bool auto_init = {true}

Automatically initialize the device.

Logger::Verbosity log_level = {Logger::Verbosity::WARN}

Log verbosity for the component.

struct IT_STS

Encapsulates the different flags / bit fields that the IT_STS dynamic register holds for the different states it represents. Reading this register clears it to 0x00.

Note

RF events are reported in the IT_STS register even if GPO output is disabled.

IT_STS.__unnamed15__
IT_STS.__unnamed15__.__unnamed17__

Public Members

uint8_t RF_USER

Manage GPO (set / reset GPO)

uint8_t RF_ACTIVITY

Indicates RF Access.

uint8_t RF_INTTERUPT

GPO Interrupt request.

uint8_t FIELD_FALLING

RF field is falling.

uint8_t FIELD_RISING

RF field is rising.

uint8_t RF_PUT_MSG

Message put by RF into FTM mailbox.

uint8_t RF_GET_MSG

reached.

Message read by RF from FTM mailbox, and end of message has been

uint8_t RF_WRITE

Write in eeprom.

class GPO
class EH_CTRL
class MB_CTRL