diff --git a/connectivity/drivers/nfc/CMakeLists.txt b/connectivity/drivers/nfc/CMakeLists.txt
index 214a1e0ba8..aa4d75cfdd 100644
--- a/connectivity/drivers/nfc/CMakeLists.txt
+++ b/connectivity/drivers/nfc/CMakeLists.txt
@@ -4,3 +4,7 @@
if("PN512" IN_LIST MBED_TARGET_LABELS)
add_subdirectory(PN512)
endif()
+
+if("M24SR" IN_LIST MBED_TARGET_LABELS)
+ add_subdirectory(TARGET_M24SR)
+endif()
diff --git a/connectivity/drivers/nfc/TARGET_M24SR/CMakeLists.txt b/connectivity/drivers/nfc/TARGET_M24SR/CMakeLists.txt
new file mode 100644
index 0000000000..dc2a4d7c28
--- /dev/null
+++ b/connectivity/drivers/nfc/TARGET_M24SR/CMakeLists.txt
@@ -0,0 +1,13 @@
+# Copyright (c) 2020 ARM Limited. All rights reserved.
+# SPDX-License-Identifier: Apache-2.0
+
+target_include_directories(mbed-nfc
+ INTERFACE
+ include
+ include/nfc
+)
+
+target_sources(mbed-nfc
+ INTERFACE
+ source/m24sr_driver.cpp
+)
diff --git a/connectivity/drivers/nfc/TARGET_M24SR/include/nfc/m24sr_driver.h b/connectivity/drivers/nfc/TARGET_M24SR/include/nfc/m24sr_driver.h
new file mode 100644
index 0000000000..3f7b623344
--- /dev/null
+++ b/connectivity/drivers/nfc/TARGET_M24SR/include/nfc/m24sr_driver.h
@@ -0,0 +1,1573 @@
+/* mbed Microcontroller Library
+ * SPDX-License-Identifier: BSD-3-Clause
+ ******************************************************************************
+ * @file m24sr_driver.h
+ * @author ST Central Labs
+ * @brief This file provides a set of functions to interface with the M24SR
+ * device.
+ ******************************************************************************
+ * @attention
+ *
+ *
© COPYRIGHT(c) 2018 STMicroelectronics
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. Neither the name of STMicroelectronics nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ ******************************************************************************
+ */
+
+/*
+ Based on: X-CUBE-MEMS1/trunk/Drivers/BSP/Components/m24sr/m24sr.h
+ Revision: M24SR Driver V1.0.0
+ */
+
+#ifndef M24SR_H
+#define M24SR_H
+
+#include
+#include
+#include "I2C.h"
+#include "NFCEEPROMDriver.h"
+#include "EventQueue.h"
+
+#if defined TARGET_DISCO_L475VG_IOT01A
+
+#define M24SR_I2C_SDA_PIN PB_11
+#define M24SR_I2C_SCL_PIN PB_10
+#define M24SR_GPO_PIN PE_4
+#define M24SR_RF_DISABLE_PIN PE_2
+
+#elif MBED_CONF_X_NUCLEO_NFC01A1
+
+#define M24SR_I2C_SDA_PIN D14
+#define M24SR_I2C_SCL_PIN D15
+#define M24SR_GPO_PIN D12
+#define M24SR_RF_DISABLE_PIN D11
+
+#else
+
+#define M24SR_I2C_SDA_PIN NC
+#define M24SR_I2C_SCL_PIN NC
+#define M24SR_GPO_PIN NC
+#define M24SR_RF_DISABLE_PIN NC
+
+#endif
+
+namespace mbed {
+namespace nfc {
+namespace vendor {
+namespace ST {
+
+#define OPEN_SESSION_RETRIES 5
+#define CC_FILE_LENGTH 15
+#define NDEF_FILE_HEADER_SIZE 2
+#define MAX_NDEF_SIZE 0x1FFF
+
+/**
+ * User parameter used to invoke a command,
+ * it is used to provide the data back with the response
+ */
+struct CommandData_t {
+ uint8_t *data; /**< data */
+ uint16_t length; /**< number of bytes in the data array */
+ uint16_t offset; /**< offset parameter used in the read/write command */
+};
+
+/**
+ * @brief APDU Command structure
+ */
+class C_APDU {
+public:
+ struct C_APDUHeader_t {
+ uint8_t CLA; /**< Command class */
+ uint8_t INS; /**< Operation code */
+ uint8_t P1; /**< Selection Mode */
+ uint8_t P2; /**< Selection Option */
+ };
+
+ struct C_APDUBody_t {
+ uint8_t LC; /**< Data field length */
+ const uint8_t *data; /**< Command parameters */
+ uint8_t LE; /**< Expected length of data to be returned */
+ };
+
+ C_APDU(uint8_t cla, uint8_t ins, uint16_t p1p2, uint8_t length, const uint8_t *data, uint8_t expected)
+ {
+ header.CLA = cla;
+ header.INS = ins;
+ header.P1 = (uint8_t)((p1p2 & 0xFF00) >> 8);
+ header.P2 = (uint8_t)(p1p2 & 0x00FF);
+ body.LC = length;
+ body.data = data;
+ body.LE = expected;
+ }
+
+ C_APDUHeader_t header;
+ C_APDUBody_t body;
+};
+
+/**
+ * @brief SC response structure
+ */
+struct R_APDU {
+ uint8_t *data; /**< Data returned from the card */ // pointer on the transceiver buffer = ReaderRecBuf[CR95HF_DATA_OFFSET ];
+ uint8_t SW1; /**< Command Processing status */
+ uint8_t SW2; /**< Command Processing qualification */
+};
+
+enum M24srError_t : uint16_t {
+ M24SR_SUCCESS = 0,
+ M24SR_ERROR = 0x6F00,
+ M24SR_FILE_OVERFLOW_LE = 0x6280,
+ M24SR_EOF = 0x6282,
+ M24SR_PASSWORD_REQUIRED = 0x6300,
+ M24SR_PASSWORD_INCORRECT = 0x63C0,
+ M24SR_PASSWORD_INCORRECT1RETRY = 0x63C1,
+ M24SR_PASSWORD_INCORRECT2RETRY = 0x63C2,
+ M24SR_WRONG_LENGHT = 0x6700,
+ M24SR_UNSUCESSFUL_UPDATING = 0x6581,
+ M24SR_INCOPATIBLE_COMMAND = 0x6981,
+ M24SR_SECURITY_UNSATISFIED = 0x6982,
+ M24SR_REFERENCE_DATA_NOT_USABLE = 0x6984,
+
+ M24SR_INCORRECT_PARAMETER = 0x6a80,
+ M24SR_FILE_NOT_FOUND = 0x6a82,
+ M24SR_FILE_OVERFLOW_LC = 0x6A84,
+
+ M24SR_INCORRECT_P1_OR_P2 = 0x6A86,
+ M24SR_RF_SESSION_KILLED = 0x6500,
+ M24SR_INS_NOT_SUPPORTED = 0x6D00,
+ M24SR_CLASS_NOT_SUPPORTED = 0x6E00,
+
+ M24SR_IO_ERROR_I2CTIMEOUT = 0x0011,
+ M24SR_IO_ERROR_CRC = 0x0012,
+ M24SR_IO_ERROR_NACK = 0x0013,
+ M24SR_IO_ERROR_PARAMETER = 0x0014,
+ M24SR_IO_ERROR_NBATEMPT = 0x0015,
+ M24SR_IO_NOACKNOWLEDGE = 0x0016,
+ M24SR_IO_PIN_NOT_CONNECTED = 0x0017
+};
+
+/**
+ * @brief GPO state
+ */
+enum NfcGpoState_t {
+ HIGH_IMPEDANCE = 0,
+ SESSION_OPENED = 1,
+ WIP = 2,
+ I2C_ANSWER_READY = 3,
+ INTERRUPT = 4,
+ STATE_CONTROL = 5
+};
+
+/**
+ * Possible password to set.
+ */
+enum PasswordType_t {
+ READ_PASSWORD = 0x01, /**< Password to use before reading the tag */
+ WRITE_PASSWORD = 0x02, /**< Password to use before writing the tag */
+ I2C_PASSWORD = 0x03, /**< Root password, used only through nfc */
+};
+
+/**
+ * Command that the component can accept
+ */
+enum Command_t {
+ NONE,
+ DESELECT,
+ SELECT_APPLICATION,
+ SELECT_CC_FILE,
+ SELECT_NDEF_FILE,
+ SELECT_SYSTEM_FILE,
+ READ,
+ UPDATE,
+ VERIFY,
+ MANAGE_I2C_GPO,
+ MANAGE_RF_GPO,
+ CHANGE_REFERENCE_DATA,
+ ENABLE_VERIFICATION_REQUIREMENT,
+ DISABLE_VERIFICATION_REQUIREMENT,
+ ENABLE_PERMANET_STATE,
+ DISABLE_PERMANET_STATE,
+};
+
+/**
+ * Communication mode used by this device
+ */
+enum Communication_t {
+ SYNC, /**< SYNC wait the command response before returning */
+ ASYNC /**< ASYNC use a callback to notify the end of a command */
+};
+
+/**
+ * Class representing a M24SR component.
+ * This component has two operation modes, sync or async.
+ * In sync mode each function call returns only after the command has completed.
+ * In async mode each function call returns immediately and the answer will be notified
+ * through a callback.
+ * The default behaviour is sync mode.
+ * To enable the async mode ManageI2CGPO(I2C_ANSWER_READY) function must be called.
+ * When the component notifies an interrupt user must call {@link ManageEvent} function.
+ * Note that passing a parameter other than I2C_ANSWER_READY to ManageI2CGPO initialize the component in sync mode.
+ */
+class M24srDriver : public NFCEEPROMDriver {
+public:
+ /**
+ * Object that contains all the callbacks fired by this class, each command has its own callback.
+ * The callback default implementation is an empty function.
+ */
+ class Callbacks {
+ public:
+ /** called when get_session completes */
+ virtual void on_session_open(M24srDriver *nfc, M24srError_t status)
+ {
+ (void) nfc;
+ (void) status;
+ }
+
+ /** called when deselect completes */
+ virtual void on_deselect(M24srDriver *nfc, M24srError_t status)
+ {
+ (void) nfc;
+ (void) status;
+ }
+
+ /** called when select_application completes */
+ virtual void on_selected_application(M24srDriver *nfc, M24srError_t status)
+ {
+ (void) nfc;
+ (void) status;
+ }
+
+ /** called when select_cc_file completes */
+ virtual void on_selected_cc_file(M24srDriver *nfc, M24srError_t status)
+ {
+ (void) nfc;
+ (void) status;
+ }
+
+ /** called when select_ndef_file completes */
+ virtual void on_selected_ndef_file(M24srDriver *nfc, M24srError_t status)
+ {
+ (void) nfc;
+ (void) status;
+ }
+
+ /** called when select_system_file completes */
+ virtual void on_selected_system_file(M24srDriver *nfc, M24srError_t status)
+ {
+ (void) nfc;
+ (void) status;
+ }
+
+ /** called when read_binary completes */
+ virtual void on_read_byte(M24srDriver *nfc, M24srError_t status, uint16_t offset, uint8_t *bytes_read,
+ uint16_t read_count)
+ {
+ (void) nfc;
+ (void) status;
+ (void) offset;
+ (void) bytes_read;
+ (void) read_count;
+ }
+
+ /** called when update_binary completes */
+ virtual void on_updated_binary(M24srDriver *nfc, M24srError_t status, uint16_t offset, uint8_t *bytes_written,
+ uint16_t write_count)
+ {
+ (void) nfc;
+ (void) status;
+ (void) bytes_written;
+ (void) write_count;
+ (void) offset;
+ }
+
+ /** called when verify completes */
+ virtual void on_verified(M24srDriver *nfc, M24srError_t status, PasswordType_t password_type, const uint8_t *pwd)
+ {
+ (void) nfc;
+ (void) status;
+ (void) password_type;
+ (void) pwd;
+ }
+
+ /** called when manage_i2c_gpo completes */
+ virtual void on_manage_i2c_gpo(M24srDriver *nfc, M24srError_t status, NfcGpoState_t new_status)
+ {
+ (void) nfc;
+ (void) status;
+ (void) new_status;
+ }
+
+ /** called when manage_rf_gpo completes */
+ virtual void on_manage_rf_gpo(M24srDriver *nfc, M24srError_t status, NfcGpoState_t new_status)
+ {
+ (void) nfc;
+ (void) status;
+ (void) new_status;
+ }
+
+ /** called when change_reference_data completes */
+ virtual void on_change_reference_data(M24srDriver *nfc, M24srError_t status, PasswordType_t type,
+ const uint8_t *data)
+ {
+ (void) nfc;
+ (void) status;
+ (void) type;
+ (void) data;
+ }
+
+ /** called when enable_verification_requirement completes */
+ virtual void on_enable_verification_requirement(M24srDriver *nfc, M24srError_t status, PasswordType_t type)
+ {
+ (void) nfc;
+ (void) status;
+ (void) type;
+ }
+
+ /** called when disable_verification_requirement completes */
+ virtual void on_disable_verification_requirement(M24srDriver *nfc, M24srError_t status, PasswordType_t type)
+ {
+ (void) nfc;
+ (void) status;
+ (void) type;
+ }
+
+ /** called when enable_permanent_state completes */
+ virtual void on_enable_permanent_state(M24srDriver *nfc, M24srError_t status, PasswordType_t type)
+ {
+ (void) nfc;
+ (void) status;
+ (void) type;
+ }
+
+ /** called when disable_permanent_state completes */
+ virtual void on_disable_permanent_state(M24srDriver *nfc, M24srError_t status, PasswordType_t type)
+ {
+ (void) nfc;
+ (void) status;
+ (void) type;
+ }
+
+ /** called when read_id completes */
+ virtual void on_read_id(M24srDriver *nfc, M24srError_t status, uint8_t *id)
+ {
+ (void) nfc;
+ (void) status;
+ (void) id;
+ }
+
+ /** called when enable_read_password completes */
+ virtual void on_enable_read_password(M24srDriver *nfc, M24srError_t status, const uint8_t *new_password)
+ {
+ (void) nfc;
+ (void) status;
+ (void) new_password;
+ }
+
+ /** called when oenable_write_password completes */
+ virtual void on_enable_write_password(M24srDriver *nfc, M24srError_t status, const uint8_t *new_password)
+ {
+ (void) nfc;
+ (void) status;
+ (void) new_password;
+ }
+
+ /** called when disable_read_password completes */
+ virtual void on_disable_read_password(M24srDriver *nfc, M24srError_t status)
+ {
+ (void) nfc;
+ (void) status;
+ }
+
+ /** called when disable_write_password completes */
+ virtual void on_disable_write_password(M24srDriver *nfc, M24srError_t status)
+ {
+ (void) nfc;
+ (void) status;
+ }
+
+ /** called when disable_all_password completes */
+ virtual void on_disable_all_password(M24srDriver *nfc, M24srError_t status)
+ {
+ (void) nfc;
+ (void) status;
+ }
+
+ /** called when enable_read_only completes */
+ virtual void on_enable_read_only(M24srDriver *nfc, M24srError_t status)
+ {
+ (void) nfc;
+ (void) status;
+ }
+
+ /** called when enable_write_only completes */
+ virtual void on_enable_write_only(M24srDriver *nfc, M24srError_t status)
+ {
+ (void) nfc;
+ (void) status;
+ }
+
+ /** called when disable_read_only completes */
+ virtual void on_disable_read_only(M24srDriver *nfc, M24srError_t status)
+ {
+ (void) nfc;
+ (void) status;
+ }
+
+ /** called when disable_write_only completes */
+ virtual void on_disable_write_only(M24srDriver *nfc, M24srError_t status)
+ {
+ (void) nfc;
+ (void) status;
+ }
+
+ virtual ~Callbacks() { }
+ };
+
+public:
+ /** Create the driver, default pin names will be used appropriate for the board.
+ * @param i2c_data_pin I2C data pin name.
+ * @param i2c_clock_pin I2C clock pin name.
+ * @param gpo_pin I2C GPO pin name.
+ * @param rf_disable_pin pin name for breaking the RF connection.
+ */
+ M24srDriver(PinName i2c_data_pin = M24SR_I2C_SDA_PIN, PinName i2c_clock_pin = M24SR_I2C_SCL_PIN,
+ PinName gpo_pin = M24SR_GPO_PIN, PinName rf_disable_pin = M24SR_RF_DISABLE_PIN);
+
+ virtual ~M24srDriver() { }
+
+ /** @see NFCEEPROMDriver::reset
+ */
+ virtual void reset()
+ {
+ set_callback(&_default_cb);
+ init();
+ manage_i2c_gpo(I2C_ANSWER_READY);
+ }
+
+ /** @see NFCEEPROMDriver::get_max_size
+ */
+ virtual size_t read_max_size()
+ {
+ return MAX_NDEF_SIZE;
+ }
+
+ /** @see NFCEEPROMDriver::start_session
+ */
+ virtual void start_session(bool force = true)
+ {
+ if (_is_session_open) {
+ delegate()->on_session_started(true);
+ return;
+ }
+
+ set_callback(&_open_session_cb);
+
+ get_session(force);
+ }
+
+ /** @see NFCEEPROMDriver::end_session
+ */
+ virtual void end_session()
+ {
+ set_callback(&_close_session_cb);
+ deselect();
+ }
+
+ /** @see NFCEEPROMDriver::read_bytes
+ */
+ virtual void read_bytes(uint32_t address, uint8_t *bytes, size_t count)
+ {
+ if (!_is_session_open) {
+ delegate()->on_bytes_read(0);
+ return;
+ }
+
+ if (address > _ndef_size) {
+ delegate()->on_bytes_read(0);
+ return;
+ }
+
+ set_callback(&_read_byte_cb);
+
+ if (count > _max_read_bytes) {
+ count = _max_read_bytes;
+ }
+
+ if (address + count > _ndef_size) {
+ count = _ndef_size - address;
+ }
+
+ if (count == 0) {
+ delegate()->on_bytes_read(0);
+ return;
+ }
+
+ /* offset by ndef file size*/
+ address += NDEF_FILE_HEADER_SIZE;
+
+ read_binary((uint16_t) address, (uint8_t) count, bytes);
+ }
+
+ /** @see NFCEEPROMDriver::write_bytes
+ */
+ virtual void write_bytes(uint32_t address, const uint8_t *bytes, size_t count)
+ {
+ if (!_is_session_open) {
+ delegate()->on_bytes_written(0);
+ return;
+ }
+
+ if (address > _ndef_size) {
+ delegate()->on_bytes_written(0);
+ return;
+ }
+
+ if (bytes) {
+ set_callback(&_write_byte_cb);
+ } else {
+ set_callback(&_erase_bytes_cb);
+ }
+
+ if (count > _max_write_bytes) {
+ count = _max_write_bytes;
+ }
+
+ if (address + count > _ndef_size) {
+ count = _ndef_size - address;
+ }
+
+ if (count == 0) {
+ delegate()->on_bytes_written(0);
+ return;
+ }
+
+ /* offset by ndef file size*/
+ address += NDEF_FILE_HEADER_SIZE;
+
+ update_binary((uint16_t) address, (uint8_t) count, bytes);
+ }
+
+ /** @see NFCEEPROMDriver::set_size
+ */
+ virtual void write_size(size_t count)
+ {
+ if (!_is_session_open) {
+ delegate()->on_size_read(false, 0);
+ return;
+ }
+
+ if (count > MAX_NDEF_SIZE - NDEF_FILE_HEADER_SIZE) {
+ delegate()->on_size_read(false, 0);
+ return;
+ }
+
+ set_callback(&_set_size_cb);
+
+ _ndef_size = (uint16_t)count;
+
+ /* NDEF file size is BE */
+ uint8_t *bytes = (uint8_t *)&_ndef_size;
+ _ndef_size_buffer[0] = bytes[1];
+ _ndef_size_buffer[1] = bytes[0];
+
+ update_binary(0, NDEF_FILE_HEADER_SIZE, (const uint8_t *)&_ndef_size_buffer);
+ }
+
+ /** @see NFCEEPROMDriver::get_size
+ */
+ virtual void read_size()
+ {
+ if (!_is_session_open) {
+ delegate()->on_size_read(false, 0);
+ return;
+ }
+
+ set_callback(&_get_size_cb);
+
+ read_binary(0, NDEF_FILE_HEADER_SIZE, (uint8_t *)&_ndef_size_buffer);
+ }
+
+ /** @see NFCEEPROMDriver::erase_bytes
+ */
+ virtual void erase_bytes(uint32_t address, size_t size)
+ {
+ write_bytes(address, NULL, size);
+ }
+
+private:
+ /**
+ * Change the function to call when a command ends.
+ * @param commandCallback Object containing the callback, if NULL it will use empty callback
+ */
+ void set_callback(Callbacks *callback)
+ {
+ if (callback) {
+ _command_cb = callback;
+ } else {
+ _command_cb = &_default_cb;
+ }
+ }
+
+ /**
+ * get the callback object to use
+ * @return callback object to use
+ */
+ Callbacks *get_callback()
+ {
+ /* this allows for two levels of operation, the previous command will continue
+ * when this set of callbacks has finished */
+ if (_subcommand_cb) {
+ return _subcommand_cb;
+ }
+ return _command_cb;
+ }
+
+ void nfc_interrupt_callback()
+ {
+ if (_communication_type == ASYNC) {
+ event_queue()->call(this, &M24srDriver::manage_event);
+ }
+ }
+
+ /**
+ * Enable the request of a password before reading the tag.
+ * @param current_write_password Current password
+ * @param new_password Password to request before reading the tag.
+ * @return return M24SR_SUCCESS if no errors
+ * @note The password must have a length of 16 chars.
+ */
+ M24srError_t enable_read_password(const uint8_t *current_write_password, const uint8_t *new_password)
+ {
+ _subcommand_cb = &_change_password_request_status_cb;
+ _change_password_request_status_cb.set_task(READ_PASSWORD, new_password);
+
+ return verify(WRITE_PASSWORD, current_write_password);
+ }
+
+ /**
+ * Disable the request of a password before reading the tag.
+ * @param current_write_password Current password
+ * @return return M24SR_SUCCESS if no errors
+ * @note The password must have a length of 16 chars.
+ */
+ M24srError_t disable_read_password(const uint8_t *current_write_password)
+ {
+ _subcommand_cb = &_change_password_request_status_cb;
+ _change_password_request_status_cb.set_task(READ_PASSWORD, NULL);
+
+ return verify(WRITE_PASSWORD, current_write_password);
+ }
+
+ /**
+ * Enable the request of a password before writing to the tag.
+ * @param current_write_password Current password
+ * @param new_password Password to request before reading the tag.
+ * @return return M24SR_SUCCESS if no errors
+ * @note The password must have a length of 16 chars.
+ */
+ M24srError_t enable_write_password(const uint8_t *current_write_password, uint8_t *new_password)
+ {
+ _subcommand_cb = &_change_password_request_status_cb;
+ _change_password_request_status_cb.set_task(WRITE_PASSWORD, new_password);
+
+ return verify(WRITE_PASSWORD, current_write_password);
+ }
+
+ /**
+ * Disable the request of a password before writing the tag.
+ * @param current_write_password Current password.
+ * @return return M24SR_SUCCESS if no errors
+ * @note The password must have a length of 16 chars.
+ */
+ M24srError_t disable_write_password(const uint8_t *current_write_password)
+ {
+ _subcommand_cb = &_change_password_request_status_cb;
+ _change_password_request_status_cb.set_task(WRITE_PASSWORD, NULL);
+
+ return verify(WRITE_PASSWORD, current_write_password);
+ }
+
+ /**
+ * @brief This function disables both read and write passwords.
+ * @param super_user_password I2C super user password.
+ * @return return M24SR_SUCCESS if no errors
+ * @note The password must have a length of 16 chars.
+ */
+ M24srError_t disable_all_password(const uint8_t *super_user_password)
+ {
+ _subcommand_cb = &_remove_password_cb;
+ return verify(I2C_PASSWORD, super_user_password);
+ }
+
+ /**
+ * @brief This function enables read only mode.
+ * @param current_write_password Write password is needed to enable read only mode.
+ * @return return M24SR_SUCCESS if no errors
+ * @note The password must have a length of 16 chars.
+ */
+ M24srError_t enable_read_only(const uint8_t *current_write_password)
+ {
+ _subcommand_cb = &_change_access_state_cb;
+ _change_access_state_cb.change_access_state(ChangeAccessStateCallback::WRITE, false);
+
+ return verify(WRITE_PASSWORD, current_write_password);
+ }
+
+ /**
+ * @brief This function disables read only mode.
+ * @param current_write_password Write password is needed to disable read only mode.
+ * @return return M24SR_SUCCESS if no errors
+ * @note The password must have a length of 16 chars.
+ */
+ M24srError_t disable_read_only(const uint8_t *current_write_password)
+ {
+ _subcommand_cb = &_change_access_state_cb;
+ _change_access_state_cb.change_access_state(ChangeAccessStateCallback::WRITE, true);
+
+ return verify(I2C_PASSWORD, current_write_password);
+ }
+
+ /**
+ * @brief This function enables write only mode.
+ * @param current_write_password Write password is needed to enable write only mode.
+ * @return return M24SR_SUCCESS if no errors
+ * @note The password must have a length of 16 chars.
+ */
+ M24srError_t enable_write_only(const uint8_t *current_write_password)
+ {
+ _subcommand_cb = &_change_access_state_cb;
+ _change_access_state_cb.change_access_state(ChangeAccessStateCallback::READ, false);
+
+ return verify(WRITE_PASSWORD, current_write_password);
+ }
+
+ /**
+ * @brief This function disables write only mode.
+ * @param current_write_password Write password is needed to disable write only mode.
+ * @return return M24SR_SUCCESS if no errors
+ * @note The password must have a length of 16 chars.
+ */
+ M24srError_t disable_write_only(const uint8_t *current_write_password)
+ {
+ _subcommand_cb = &_change_access_state_cb;
+ _change_access_state_cb.change_access_state(ChangeAccessStateCallback::READ, true);
+
+ return verify(I2C_PASSWORD, current_write_password);
+ }
+
+private:
+ M24srError_t init();
+ M24srError_t read_id(uint8_t *nfc_id);
+ M24srError_t get_session(bool force = false);
+
+ M24srError_t deselect();
+ M24srError_t receive_deselect();
+
+ M24srError_t select_application();
+ M24srError_t receive_select_application();
+
+ M24srError_t select_cc_file();
+ M24srError_t receive_select_cc_file();
+
+ M24srError_t select_ndef_file(uint16_t ndef_file_id);
+ M24srError_t receive_select_ndef_file();
+
+ M24srError_t select_system_file();
+ M24srError_t receive_select_system_file();
+
+ M24srError_t read_binary(uint16_t offset, uint8_t length, uint8_t *buffer);
+ M24srError_t st_read_binary(uint16_t offset, uint8_t length, uint8_t *buffer);
+ M24srError_t receive_read_binary();
+
+ M24srError_t update_binary(uint16_t offset, uint8_t length, const uint8_t *data);
+ M24srError_t receive_update_binary();
+
+ M24srError_t verify(PasswordType_t password_type, const uint8_t *password);
+ M24srError_t receive_verify();
+
+ M24srError_t change_reference_data(PasswordType_t password_type, const uint8_t *password);
+ M24srError_t receive_change_reference_data();
+
+ M24srError_t enable_verification_requirement(PasswordType_t password_type);
+ M24srError_t receive_enable_verification_requirement();
+
+ M24srError_t disable_verification_requirement(PasswordType_t password_type);
+ M24srError_t receive_disable_verification_requirement();
+
+ M24srError_t enable_permanent_state(PasswordType_t password_type);
+ M24srError_t receive_enable_permanent_state();
+
+ M24srError_t disable_permanent_state(PasswordType_t password_type);
+ M24srError_t receive_disable_permanent_state();
+
+ M24srError_t send_interrupt();
+ M24srError_t state_control(bool gpo_reset);
+
+ M24srError_t manage_i2c_gpo(NfcGpoState_t gpo_i2c_config);
+ M24srError_t manage_rf_gpo(NfcGpoState_t gpo_rf_config);
+
+ M24srError_t rf_config(bool enable);
+ M24srError_t send_fwt_extension(uint8_t fwt_byte);
+
+ M24srError_t send_receive_i2c(uint16_t length, uint8_t *command);
+
+ /**
+ * Function to call when the component fire an interrupt.
+ * @return last operation status
+ */
+ M24srError_t manage_event();
+
+ /**
+ * Send a command to the component.
+ * @param length Length of the command.
+ * @param command Buffer containing the command.
+ * @return M24SR_SUCCESS if no errors
+ */
+ M24srError_t io_send_i2c_command(uint8_t length, const uint8_t *command);
+
+ /**
+ * Read a command response.
+ * @param length Number of bytes to read.
+ * @param command Buffer to store the response into.
+ * @return M24SR_SUCCESS if no errors
+ */
+ M24srError_t io_receive_i2c_response(uint8_t length, uint8_t *command);
+
+ /**
+ * Do an active polling on the I2C bus until the answer is ready.
+ * @return M24SR_SUCCESS if no errors
+ */
+ M24srError_t io_poll_i2c();
+
+ bool manage_sync_communication(M24srError_t *status);
+
+private:
+ /**
+ * @brief This class permits to enable/disable the password request to read/write into the tag
+ */
+ class ChangePasswordRequestStatusCallback : public Callbacks {
+ public:
+ /**
+ * Build the chain of callbacks.
+ */
+ ChangePasswordRequestStatusCallback()
+ : _new_password(NULL),
+ _type(I2C_PASSWORD),
+ _enable(false) { }
+
+ /* This class is equivalent to calling the methods:
+ *
+ * To enable the request:
+ * - Verify
+ * - change_reference_data
+ * - enable_permanent_state
+ *
+ * To disable the request:
+ * - verify
+ * - disable_verification_requirement
+ */
+
+ /**
+ * Set the password to enable/disable.
+ * @param type Type of password to enable/disable.
+ * @param new_password Array of 16bytes with the new password, if null the request will be disabled.
+ */
+ void set_task(PasswordType_t type, const uint8_t *new_password)
+ {
+ _new_password = new_password;
+ _type = type;
+ _enable = (new_password != NULL);
+ }
+
+ virtual void on_verified(M24srDriver *nfc, M24srError_t status, PasswordType_t, const uint8_t *)
+ {
+ if (status != M24SR_SUCCESS) {
+ return on_finish_command(nfc, status);
+ }
+ if (_enable) {
+ nfc->change_reference_data(_type, _new_password);
+ } else {
+ nfc->disable_verification_requirement(_type);
+ }
+ }
+
+ virtual void on_disable_verification_requirement(M24srDriver *nfc, M24srError_t status, PasswordType_t)
+ {
+ on_finish_command(nfc, status);
+ }
+
+ virtual void on_change_reference_data(M24srDriver *nfc, M24srError_t status, PasswordType_t type, const uint8_t *)
+ {
+ if (status == M24SR_SUCCESS) {
+ nfc->enable_permanent_state(type);
+ } else {
+ on_finish_command(nfc, status);
+ }
+ }
+
+ virtual void on_enable_permanent_state(M24srDriver *nfc, M24srError_t status, PasswordType_t)
+ {
+ on_finish_command(nfc, status);
+ }
+
+ private:
+ /**
+ * Remove the private callbacks and call the user callback.
+ * @param nfc Object triggering the command.
+ * @param status Command status.
+ */
+ void on_finish_command(M24srDriver *nfc, M24srError_t status)
+ {
+ nfc->_subcommand_cb = NULL;
+
+ if (_enable) {
+ if (_type == READ_PASSWORD) {
+ nfc->get_callback()->on_enable_read_password(nfc, status, _new_password);
+ } else {
+ nfc->get_callback()->on_enable_write_password(nfc, status, _new_password);
+ }
+ } else {
+ if (_type == READ_PASSWORD) {
+ nfc->get_callback()->on_disable_read_password(nfc, status);
+ } else {
+ nfc->get_callback()->on_disable_write_password(nfc, status);
+ }
+ }
+ }
+
+ private:
+ const uint8_t *_new_password;
+ PasswordType_t _type;
+ bool _enable;
+ };
+
+ /**
+ * @brief This class permits to disable all the password requests to read/write into the tag.
+ */
+ class RemoveAllPasswordCallback : public Callbacks {
+ public:
+ /**
+ * Build the chain of callbacks.
+ */
+ RemoveAllPasswordCallback()
+ : _password(NULL) { }
+
+ /* This class is equivalent to calling the methods:
+ * - verify(i2c)
+ * - disable_permanent_state(Read)
+ * - disable_permanent_state(write)
+ * - disable_verification_requirement(Read)
+ * - disable_verification_requirement(write)
+ * - change_reference_data(Read)
+ * - change_reference_data(write)
+ */
+
+ virtual void on_verified(M24srDriver *nfc, M24srError_t status, PasswordType_t, const uint8_t *data)
+ {
+ if (status != M24SR_SUCCESS) {
+ return on_finish_command(nfc, status);
+ }
+ _password = data;
+ nfc->disable_permanent_state(READ_PASSWORD);
+ }
+
+ virtual void on_disable_permanent_state(M24srDriver *nfc, M24srError_t status, PasswordType_t type)
+ {
+ if (status != M24SR_SUCCESS) {
+ return on_finish_command(nfc, status);
+ }
+ if (type == READ_PASSWORD) {
+ nfc->disable_permanent_state(WRITE_PASSWORD);
+ } else {
+ nfc->disable_verification_requirement(READ_PASSWORD);
+ }
+ }
+
+ virtual void on_disable_verification_requirement(M24srDriver *nfc, M24srError_t status, PasswordType_t type)
+ {
+ if (status != M24SR_SUCCESS) {
+ return on_finish_command(nfc, status);
+ }
+ if (type == READ_PASSWORD) {
+ nfc->disable_verification_requirement(WRITE_PASSWORD);
+ } else {
+ nfc->change_reference_data(READ_PASSWORD, _password);
+ }
+ }
+
+ virtual void on_change_reference_data(M24srDriver *nfc, M24srError_t status, PasswordType_t type,
+ const uint8_t *data)
+ {
+ if (status != M24SR_SUCCESS) {
+ return on_finish_command(nfc, status);
+ }
+ if (type == READ_PASSWORD) {
+ nfc->change_reference_data(WRITE_PASSWORD, data);
+ } else {
+ on_finish_command(nfc, status);
+ }
+ }
+
+ private:
+ /**
+ * Remove the private callback and call the onDisableAllPassword callback.
+ * @param nfc Object triggering the command.
+ * @param status Command status.
+ */
+ void on_finish_command(M24srDriver *nfc, M24srError_t status)
+ {
+ nfc->_subcommand_cb = NULL;
+ _password = NULL;
+ nfc->get_callback()->on_disable_all_password(nfc, status);
+ }
+
+ private:
+ /**
+ * Store the default password used for open a super user session
+ * it will be set as default read/write password
+ */
+ const uint8_t *_password;
+ };
+
+ /**
+ * @brief This class permits to set the tag as read/write only.
+ */
+ class ChangeAccessStateCallback : public Callbacks {
+ public:
+ enum AccessType_t {
+ WRITE,
+ READ
+ };
+
+ /**
+ * Build the chain of callbacks.
+ */
+ ChangeAccessStateCallback()
+ : _type(WRITE),
+ _enable(false) { }
+
+ /* This class is equivalent to calling the methods:
+ * - verify(i2c)
+ * - enable_permanent_state(Read/write)
+ * or:
+ * - verify(i2c)
+ * - disable_permanent_state
+ * - disable_verification_requirement(Read/write)
+ */
+
+ /**
+ * Set the access to enable/disable an access type.
+ * @param type Access type.
+ * @param enable True to enable the state, False to disable it.
+ */
+ void change_access_state(AccessType_t type, bool enable)
+ {
+ _type = type;
+ _enable = enable;
+ }
+
+ virtual void on_verified(M24srDriver *nfc, M24srError_t status, PasswordType_t, const uint8_t *)
+ {
+ if (status != M24SR_SUCCESS) {
+ return on_finish_command(nfc, status);
+ }
+
+ if (_enable) {
+ nfc->disable_permanent_state(_type == WRITE ? WRITE_PASSWORD : READ_PASSWORD);
+ } else {
+ nfc->enable_permanent_state(_type == WRITE ? WRITE_PASSWORD : READ_PASSWORD);
+ }
+
+ }
+
+ virtual void on_disable_permanent_state(M24srDriver *nfc, M24srError_t status, PasswordType_t type)
+ {
+ if (status != M24SR_SUCCESS) {
+ return on_finish_command(nfc, status);
+ }
+
+ nfc->disable_verification_requirement(type);
+ }
+
+ virtual void on_disable_verification_requirement(M24srDriver *nfc, M24srError_t status, PasswordType_t)
+ {
+ on_finish_command(nfc, status);
+ }
+
+ virtual void on_enable_permanent_state(M24srDriver *nfc, M24srError_t status, PasswordType_t)
+ {
+ on_finish_command(nfc, status);
+ }
+
+ private:
+ /**
+ * Remove the private callback and call the user callback.
+ * @param nfc Object triggering the command.
+ * @param status Command status.
+ */
+ void on_finish_command(M24srDriver *nfc, M24srError_t status)
+ {
+ nfc->_subcommand_cb = NULL;
+ if (_enable) {
+ if (_type == READ) {
+ //enable read = disable write only
+ nfc->get_callback()->on_disable_write_only(nfc, status);
+ } else {
+ //enable write = disable read only
+ nfc->get_callback()->on_disable_read_only(nfc, status);
+ }
+ } else {
+ if (_type == WRITE) {
+ //disable write = enable read only
+ nfc->get_callback()->on_enable_read_only(nfc, status);
+ } else {
+ nfc->get_callback()->on_enable_write_only(nfc, status);
+ }
+ }
+ }
+
+ private:
+ AccessType_t _type;
+ bool _enable;
+ };
+
+ /**
+ * @brief Object with the callback used to send a ManageGPO command.
+ */
+ class ManageGPOCallback : public Callbacks {
+
+ public:
+ /**
+ * Build the chain of callbacks.
+ * @param parent Parent component to run the command on.
+ */
+ ManageGPOCallback()
+ : _new_gpo_config(HIGH_IMPEDANCE),
+ _read_gpo_config(0),
+ _change_i2c_gpo(true) { }
+
+ /* This class is equivalent to calling the methods:
+ * - selected_application
+ * - select_system_file
+ * - read_binary
+ * - verify
+ * - update_binary
+ */
+
+ /**
+ * Command parameters.
+ * @param i2cGpo true to change the i2c gpo, false for the rf gpo.
+ * @param new_config new gpo function.
+ */
+ void set_new_gpo_config(bool i2cGpo, NfcGpoState_t new_config)
+ {
+ _new_gpo_config = new_config;
+ _change_i2c_gpo = i2cGpo;
+ }
+
+ virtual void on_selected_application(M24srDriver *nfc, M24srError_t status)
+ {
+ if (status == M24SR_SUCCESS) {
+ nfc->select_system_file();
+ } else {
+ on_finish_command(nfc, status);
+ }
+ }
+
+ virtual void on_selected_system_file(M24srDriver *nfc, M24srError_t status)
+ {
+ if (status == M24SR_SUCCESS) {
+ nfc->read_binary(0x0004, 0x01, &_read_gpo_config);
+ } else {
+ on_finish_command(nfc, status);
+ }
+ }
+
+ virtual void on_read_byte(M24srDriver *nfc, M24srError_t status, uint16_t, uint8_t *, uint16_t)
+ {
+ if (status == M24SR_SUCCESS) {
+ nfc->verify(I2C_PASSWORD, default_password);
+ } else {
+ on_finish_command(nfc, status);
+ }
+ }
+
+ virtual void on_verified(M24srDriver *nfc, M24srError_t status, PasswordType_t, const uint8_t *)
+ {
+ if (status != M24SR_SUCCESS) {
+ return on_finish_command(nfc, status);
+ }
+
+ if (_change_i2c_gpo) {
+ _read_gpo_config = (_read_gpo_config & 0xF0) | (uint8_t) _new_gpo_config;
+ } else {
+ _read_gpo_config = (_read_gpo_config & 0x0F) | (((uint8_t) _new_gpo_config) << 4);
+ }
+
+ nfc->update_binary(0x0004, 0x01, &_read_gpo_config);
+ }
+
+ virtual void on_updated_binary(M24srDriver *nfc, M24srError_t status, uint16_t, uint8_t *, uint16_t)
+ {
+
+ if (status == M24SR_SUCCESS) {
+ if (_new_gpo_config == I2C_ANSWER_READY) {
+ nfc->_communication_type = ASYNC;
+ } else {
+ nfc->_communication_type = SYNC;
+ }
+ }
+ on_finish_command(nfc, status);
+ }
+
+ private:
+ /**
+ * Remove the private callback and call the user callback.
+ * @param nfc Object where the command was send to.
+ * @param status Command status.
+ */
+ void on_finish_command(M24srDriver *nfc, M24srError_t status)
+ {
+ nfc->_subcommand_cb = NULL;
+ if (_change_i2c_gpo) {
+ nfc->_command_cb->on_manage_i2c_gpo(nfc, status, _new_gpo_config);
+ } else {
+ nfc->_command_cb->on_manage_rf_gpo(nfc, status, _new_gpo_config);
+ }
+ }
+
+ private:
+ /** new gpo function that this class has to write */
+ NfcGpoState_t _new_gpo_config;
+
+ /** variable where storeing the read gpo configuration */
+ uint8_t _read_gpo_config;
+
+ /** true to change the i2c gpo, false to change the rf gpo */
+ bool _change_i2c_gpo;
+ };
+
+ /**
+ * @brief Object with the callback used to read the component ID
+ */
+ class ReadIDCallback : public Callbacks {
+ public:
+ /**
+ * Build the chain of callbacks.
+ * @param parent object where to send the command to.
+ */
+ ReadIDCallback() : _id(NULL) { }
+
+ /* This class is equivalent to calling the methods:
+ * - select_application
+ * - select_system_file
+ * - read_binary
+ */
+
+ /**
+ * Set the variable containing the result
+ * @param idPtr
+ */
+ void set_task(uint8_t *id)
+ {
+ _id = id;
+ }
+
+ virtual void on_selected_application(M24srDriver *nfc, M24srError_t status)
+ {
+ if (status == M24SR_SUCCESS) {
+ nfc->select_system_file();
+ } else {
+ on_finish_command(nfc, status);
+ }
+
+ }
+
+ virtual void on_selected_system_file(M24srDriver *nfc, M24srError_t status)
+ {
+ if (status == M24SR_SUCCESS) {
+ nfc->read_binary(0x0011, 0x01, _id);
+ } else {
+ on_finish_command(nfc, status);
+ }
+ }
+
+ virtual void on_read_byte(M24srDriver *nfc, M24srError_t status, uint16_t, uint8_t *, uint16_t)
+ {
+ on_finish_command(nfc, status);
+ }
+
+ private:
+ /**
+ * Remove the private callback and call the user onReadId function.
+ * @param nfc Object where the command was send.
+ * @param status Command status.
+ */
+ void on_finish_command(M24srDriver *nfc, M24srError_t status)
+ {
+ nfc->_subcommand_cb = NULL;
+ nfc->get_callback()->on_read_id(nfc, status, _id);
+ }
+
+ private:
+ /** pointer to read id */
+ uint8_t *_id;
+ };
+
+ /**
+ * Class containing the callback needed to open a session and read the max
+ * read/write size
+ */
+ class OpenSessionCallBack : public Callbacks {
+ public:
+ OpenSessionCallBack()
+ : _retries(OPEN_SESSION_RETRIES) { }
+
+ void on_session_open(M24srDriver *nfc, M24srError_t status)
+ {
+ if (status == M24SR_SUCCESS) {
+ nfc->select_application();
+ } else {
+ nfc->delegate()->on_session_started(false);
+ }
+ }
+
+ void on_selected_application(M24srDriver *nfc, M24srError_t status)
+ {
+ if (status == M24SR_SUCCESS) {
+ nfc->select_cc_file();
+ } else {
+ if (_retries == 0) {
+ nfc->delegate()->on_session_started(false);
+ } else {
+ _retries--;
+ nfc->select_application();
+ }
+ }
+ }
+
+ void on_selected_cc_file(M24srDriver *nfc, M24srError_t status)
+ {
+ if (status == M24SR_SUCCESS) {
+ nfc->read_binary(0x0000, CC_FILE_LENGTH, CCFile);
+ } else {
+ nfc->delegate()->on_session_started(false);
+ }
+ }
+
+ void on_read_byte(M24srDriver *nfc, M24srError_t status, uint16_t, uint8_t *bytes_read,
+ uint16_t read_count)
+ {
+ if (status != M24SR_SUCCESS || read_count != CC_FILE_LENGTH) {
+ nfc->delegate()->on_session_started(false);
+ }
+ uint16_t ndef_file_id = (uint16_t)((bytes_read[0x09] << 8) | bytes_read[0x0A]);
+ nfc->_max_read_bytes = (uint16_t)((bytes_read[0x03] << 8) | bytes_read[0x04]);
+ nfc->_max_write_bytes = (uint16_t)((bytes_read[0x05] << 8) | bytes_read[0x06]);
+ nfc->select_ndef_file(ndef_file_id);
+ }
+
+ void on_selected_ndef_file(M24srDriver *nfc, M24srError_t status)
+ {
+ nfc->_is_session_open = (status == M24SR_SUCCESS);
+ nfc->delegate()->on_session_started(nfc->_is_session_open);
+ }
+
+ private:
+ /** number of trials done for open the session */
+ uint32_t _retries;
+
+ /** buffer where read the CC file */
+ uint8_t CCFile[15];
+ };
+
+ /**
+ * Class containing the callback needed to close a session
+ */
+ class CloseSessionCallBack : public Callbacks {
+ public:
+ CloseSessionCallBack() { }
+
+ virtual void on_deselect(M24srDriver *nfc, M24srError_t status)
+ {
+ if (status == M24SR_SUCCESS) {
+ nfc->_is_session_open = false;
+ nfc->delegate()->on_session_ended(true);
+ } else {
+ nfc->delegate()->on_session_ended(false);
+ }
+ }
+ };
+
+ /**
+ * Class containing the callback needed to write a buffer
+ */
+ class WriteByteCallback : public Callbacks {
+ public:
+ WriteByteCallback() { }
+
+ virtual void on_updated_binary(M24srDriver *nfc, M24srError_t status, uint16_t offset, uint8_t *bytes_written,
+ uint16_t write_count)
+ {
+ if (status != M24SR_SUCCESS) {
+ nfc->delegate()->on_bytes_written(0);
+ return;
+ }
+
+ nfc->delegate()->on_bytes_written(write_count);
+ }
+ };
+
+ /**
+ * Class containing the callback needed to read a buffer
+ */
+ class ReadByteCallback : public Callbacks {
+ public:
+ ReadByteCallback() { }
+
+ virtual void on_read_byte(M24srDriver *nfc, M24srError_t status, uint16_t offset, uint8_t *bytes_read,
+ uint16_t read_count)
+ {
+ if (status != M24SR_SUCCESS) {
+ nfc->delegate()->on_bytes_read(0);
+ return;
+ }
+
+ nfc->delegate()->on_bytes_read(read_count);
+ }
+ };
+
+ class SetSizeCallback : public Callbacks {
+ public:
+ SetSizeCallback() { }
+
+ virtual void on_updated_binary(M24srDriver *nfc, M24srError_t status, uint16_t offset, uint8_t *bytes_written,
+ uint16_t write_count)
+ {
+ if (status != M24SR_SUCCESS) {
+ nfc->delegate()->on_size_written(false);
+ return;
+ }
+
+ nfc->delegate()->on_size_written(true);
+ }
+ };
+
+ class GetSizeCallback : public Callbacks {
+ public:
+ GetSizeCallback() { }
+
+ virtual void on_read_byte(M24srDriver *nfc, M24srError_t status, uint16_t offset, uint8_t *bytes_read,
+ uint16_t read_count)
+ {
+ if (status != M24SR_SUCCESS) {
+ nfc->delegate()->on_size_read(false, 0);
+ return;
+ }
+
+ /* NDEF file size is BE */
+ nfc->_ndef_size = (((uint16_t) nfc->_ndef_size_buffer[0]) << 8 | nfc->_ndef_size_buffer[1]);
+
+ nfc->delegate()->on_size_read(true, nfc->_ndef_size);
+ }
+ };
+
+ class EraseBytesCallback : public Callbacks {
+ public:
+ EraseBytesCallback() { }
+
+ virtual void on_updated_binary(M24srDriver *nfc, M24srError_t status, uint16_t offset, uint8_t *bytes_written,
+ uint16_t write_count)
+ {
+ if (status != M24SR_SUCCESS) {
+ nfc->delegate()->on_bytes_erased(0);
+ return;
+ }
+
+ nfc->delegate()->on_bytes_erased(write_count);
+ }
+ };
+
+private:
+ /** Default password used to change the write/read permission */
+ static const uint8_t default_password[16];
+
+ I2C _i2c_channel;
+
+ /** Interrupt object fired when the gpo status changes */
+ InterruptIn _gpo_event_interrupt;
+ DigitalIn _gpo_pin;
+ DigitalOut _rf_disable_pin;
+
+ /** object containing the callbacks to use*/
+ Callbacks *_command_cb;
+
+ /**
+ * Object with private callbacks used to hide high level commands each
+ * calling multiple low level commands. This callbacks object has
+ * higher priority comparing to the user callbacks.
+ */
+ Callbacks *_subcommand_cb;
+
+ Callbacks _default_cb;
+ ManageGPOCallback _manage_gpo_cb;
+ ReadIDCallback _read_id_cb;
+ ChangePasswordRequestStatusCallback _change_password_request_status_cb;
+ RemoveAllPasswordCallback _remove_password_cb;
+ ChangeAccessStateCallback _change_access_state_cb;
+ OpenSessionCallBack _open_session_cb;
+ CloseSessionCallBack _close_session_cb;
+ WriteByteCallback _write_byte_cb;
+ ReadByteCallback _read_byte_cb;
+ SetSizeCallback _set_size_cb;
+ GetSizeCallback _get_size_cb;
+ EraseBytesCallback _erase_bytes_cb;
+
+
+ uint8_t _buffer[0xFF];
+
+ /** Type of communication being used (SYNC, ASYNC) */
+ Communication_t _communication_type;
+
+ Command_t _last_command;
+ CommandData_t _last_command_data;
+
+ /** Buffer used to build the command to send to the chip. */
+ uint16_t _ndef_size;
+ uint8_t _ndef_size_buffer[NDEF_FILE_HEADER_SIZE];
+ uint8_t _max_read_bytes;
+ uint8_t _max_write_bytes;
+ uint8_t _did_byte;
+
+ bool _is_session_open;
+};
+
+} //ST
+} //vendor
+} //nfc
+} //mbed
+
+#endif // M24SR_H
+
+/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
diff --git a/connectivity/drivers/nfc/TARGET_M24SR/mbed_lib.json b/connectivity/drivers/nfc/TARGET_M24SR/mbed_lib.json
new file mode 100644
index 0000000000..e30eb925bb
--- /dev/null
+++ b/connectivity/drivers/nfc/TARGET_M24SR/mbed_lib.json
@@ -0,0 +1,15 @@
+{
+ "name": "M24SR-nfc",
+ "config": {
+ "X_NUCLEO_NFC01A1": {
+ "macro_name": "MBED_CONF_X_NUCLEO_NFC01A1",
+ "value": false,
+ "help": "Device is using an X-NUCLEO-NFC01A1 shield attached through an arduino header"
+ },
+ "nfceeprom": {
+ "macro_name": "MBED_CONF_NFCEEPROM",
+ "value": true,
+ "help": "Device supports NFC EEPROM"
+ }
+ }
+}
diff --git a/connectivity/drivers/nfc/TARGET_M24SR/source/m24sr_driver.cpp b/connectivity/drivers/nfc/TARGET_M24SR/source/m24sr_driver.cpp
new file mode 100644
index 0000000000..f0b06fa377
--- /dev/null
+++ b/connectivity/drivers/nfc/TARGET_M24SR/source/m24sr_driver.cpp
@@ -0,0 +1,1465 @@
+/* mbed Microcontroller Library
+ * SPDX-License-Identifier: BSD-3-Clause
+ ******************************************************************************
+ * @file m24sr_driver.cpp
+ * @author ST Central Labs
+ * @brief This file provides a set of functions to interface with the M24SR
+ * device.
+ ******************************************************************************
+ * @attention
+ *
+ * © COPYRIGHT(c) 2018 STMicroelectronics
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. Neither the name of STMicroelectronics nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ ******************************************************************************
+ */
+
+#include
+#include "Callback.h"
+
+namespace mbed {
+namespace nfc {
+namespace vendor {
+namespace ST {
+
+#define MAX_OPERATION_SIZE 246
+#define MAX_PAYLOAD 241
+
+/** value returned by the NFC chip when a command is successfully completed */
+static constexpr const uint16_t NFC_COMMAND_SUCCESS = 0x9000;
+/** I2C nfc address */
+#define M24SR_ADDR 0xAC
+
+#define SYSTEM_FILE_ID_BYTES {0xE1,0x01}
+#define CC_FILE_ID_BYTES {0xE1,0x03}
+
+#define UB_STATUS_OFFSET 4
+#define LB_STATUS_OFFSET 3
+
+/* APDU command: class list */
+#define C_APDU_CLA_DEFAULT 0x00
+#define C_APDU_CLA_ST 0xA2
+
+/* data area management commands */
+#define C_APDU_SELECT_FILE 0xA4
+#define C_APDU_GET_RESPONCE 0xC0
+#define C_APDU_STATUS 0xF2
+#define C_APDU_UPDATE_BINARY 0xD6
+#define C_APDU_READ_BINARY 0xB0
+#define C_APDU_WRITE_BINARY 0xD0
+#define C_APDU_UPDATE_RECORD 0xDC
+#define C_APDU_READ_RECORD 0xB2
+
+/* safety management commands */
+#define C_APDU_VERIFY 0x20
+#define C_APDU_CHANGE 0x24
+#define C_APDU_DISABLE 0x26
+#define C_APDU_ENABLE 0x28
+
+/* GPO management commands */
+#define C_APDU_INTERRUPT 0xD6
+
+/* length */
+#define STATUS_LENGTH 2
+#define CRC_LENGTH 2
+#define STATUS_RESPONSE_LENGTH 5
+#define DESELECT_RESPONSE_LENGTH 3
+#define WATING_TIME_EXT_RESPONSE_LENGTH 4
+#define PASSWORD_LENGTH 16
+
+#define DESELECT_REQUEST_COMMAND {0xC2,0xE0,0xB4}
+#define SELECT_APPLICATION_COMMAND {0xD2,0x76,0x00,0x00,0x85,0x01,0x01}
+
+/* command structure mask */
+#define CMD_MASK_SELECT_APPLICATION 0x01FF
+#define CMD_MASK_SELECT_CC_FILE 0x017F
+#define CMD_MASK_SELECT_NDEF_FILE 0x017F
+#define CMD_MASK_READ_BINARY 0x019F
+#define CMD_MASK_UPDATE_BINARY 0x017F
+#define CMD_MASK_VERIFY_BINARY_WO_PWD 0x013F
+#define CMD_MASK_VERIFY_BINARY_WITH_PWD 0x017F
+#define CMD_MASK_CHANGE_REF_DATA 0x017F
+#define CMD_MASK_ENABLE_VERIFREQ 0x011F
+#define CMD_MASK_DISABLE_VERIFREQ 0x011F
+#define CMD_MASK_SEND_INTERRUPT 0x013F
+#define CMD_MASK_GPO_STATE 0x017F
+
+/* command structure values for the mask */
+#define PCB_NEEDED 0x0001 /* PCB byte present or not */
+#define CLA_NEEDED 0x0002 /* CLA byte present or not */
+#define INS_NEEDED 0x0004 /* Operation code present or not*/
+#define P1_NEEDED 0x0008 /* Selection Mode present or not*/
+#define P2_NEEDED 0x0010 /* Selection Option present or not*/
+#define LC_NEEDED 0x0020 /* Data field length byte present or not */
+#define DATA_NEEDED 0x0040 /* Data present or not */
+#define LE_NEEDED 0x0080 /* Expected length present or not */
+#define CRC_NEEDED 0x0100 /* 2 CRC bytes present or not */
+#define DID_NEEDED 0x08 /* DID byte present or not */
+
+/* offset */
+#define OFFSET_PCB 0
+#define OFFSET_CLASS 1
+#define OFFSET_INS 2
+#define OFFSET_P1 3
+
+/* mask */
+#define MASK_BLOCK 0xC0
+#define MASK_I_BLOCK 0x00
+#define MASK_R_BLOCK 0x80
+#define MASK_S_BLOCK 0xC0
+
+#define GETMSB(val) ((uint8_t) ((val & 0xFF00)>>8))
+#define GETLSB(val) ((uint8_t) (val & 0x00FF))
+
+/** default password, also used to enable super user mode through the I2C channel */
+const uint8_t M24srDriver::default_password[16] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
+/**
+ * @brief This function updates the CRC
+ */
+static uint16_t update_crc(uint8_t ch, uint16_t *lpw_crc)
+{
+ ch = (ch ^ (uint8_t)((*lpw_crc) & 0x00FF));
+ ch = (ch ^ (ch << 4));
+ *lpw_crc = (*lpw_crc >> 8) ^ ((uint16_t) ch << 8) ^ ((uint16_t) ch << 3) ^ ((uint16_t) ch >> 4);
+
+ return (*lpw_crc);
+}
+
+/**
+ * @brief This function returns the CRC 16
+ * @param data pointer on the data used to compute the CRC16
+ * @param length number of bytes of the data
+ * @retval CRC16
+ */
+static uint16_t compute_crc(uint8_t *data, uint8_t length)
+{
+ uint8_t block;
+ uint16_t crc16 = 0x6363; /* ITU-V.41 */
+
+ do {
+ block = *data++;
+ update_crc(block, &crc16);
+ } while (--length);
+
+ return crc16;
+}
+
+/**
+ * @brief This function computes the CRC16 residue as defined by CRC ISO/IEC 13239
+ * @param data input data
+ * @param length Number of bits of DataIn
+ * @retval Status (SW1&SW2) CRC16 residue is correct
+ * @retval M24SR_ERROR_CRC CRC16 residue is false
+ */
+static M24srError_t is_correct_crc_residue(uint8_t *data, uint8_t length)
+{
+ uint16_t res_crc = 0x0000;
+ uint16_t status;
+
+ /* check the CRC16 Residue */
+ if (length != 0) {
+ res_crc = compute_crc(data, length);
+ }
+
+ if (res_crc == 0x0000) {
+ /* Good CRC, but error status from M24SR */
+ status = ((data[length - UB_STATUS_OFFSET] << 8) & 0xFF00)
+ | (data[length - LB_STATUS_OFFSET] & 0x00FF);
+ } else {
+ res_crc = 0x0000;
+ res_crc = compute_crc(data, 5);
+ if (res_crc != 0x0000) {
+ /* Bad CRC */
+ return M24SR_IO_ERROR_CRC;
+ } else {
+ /* Good CRC, but error status from M24SR */
+ status = ((data[1] << 8) & 0xFF00) | (data[2] & 0x00FF);
+ }
+ }
+
+ if (status == NFC_COMMAND_SUCCESS) {
+ return M24SR_SUCCESS;
+ }
+
+ return (M24srError_t)status;
+}
+
+/**
+ * @brief This functions creates an I block command according to the structures command_mask and Command.
+ * @param command_mask structure which contains the field of the different parameters
+ * @param command structure of the command
+ * @param length number of bytes of the command
+ * @param command_buffer pointer to the command created
+ */
+static void build_I_block_command(uint16_t command_mask, C_APDU *command, uint8_t did, uint16_t *length,
+ uint8_t *command_buffer)
+{
+ uint16_t crc16;
+ static uint8_t block_number = 0x01;
+
+ (*length) = 0;
+
+ /* add the PCD byte */
+ if ((command_mask & PCB_NEEDED) != 0) {
+ /* toggle the block number */
+ block_number = !block_number;
+ /* Add the I block byte */
+ command_buffer[(*length)++] = 0x02 | block_number;
+ }
+
+ /* add the DID byte */
+ if ((block_number & DID_NEEDED) != 0) {
+ /* Add the I block byte */
+ command_buffer[(*length)++] = did;
+ }
+
+ /* add the Class byte */
+ if ((command_mask & CLA_NEEDED) != 0) {
+ command_buffer[(*length)++] = command->header.CLA;
+ }
+
+ /* add the instruction byte byte */
+ if ((command_mask & INS_NEEDED) != 0) {
+ command_buffer[(*length)++] = command->header.INS;
+ }
+
+ /* add the Selection Mode byte */
+ if ((command_mask & P1_NEEDED) != 0) {
+ command_buffer[(*length)++] = command->header.P1;
+ }
+
+ /* add the Selection Mode byte */
+ if ((command_mask & P2_NEEDED) != 0) {
+ command_buffer[(*length)++] = command->header.P2;
+ }
+
+ /* add Data field lengthbyte */
+ if ((command_mask & LC_NEEDED) != 0) {
+ command_buffer[(*length)++] = command->body.LC;
+ }
+
+ /* add Data field */
+ if ((command_mask & DATA_NEEDED) != 0) {
+ if (command->body.data) {
+ memcpy(&(command_buffer[(*length)]), command->body.data, command->body.LC);
+ } else {
+ memset(&(command_buffer[(*length)]), 0, command->body.LC);
+ }
+ (*length) += command->body.LC;
+ }
+
+ /* add Le field */
+ if ((command_mask & LE_NEEDED) != 0) {
+ command_buffer[(*length)++] = command->body.LE;
+ }
+
+ /* add CRC field */
+ if ((command_mask & CRC_NEEDED) != 0) {
+ crc16 = compute_crc(command_buffer, (uint8_t)(*length));
+ /* append the CRC16 */
+ command_buffer[(*length)++] = GETLSB(crc16);
+ command_buffer[(*length)++] = GETMSB(crc16);
+ }
+}
+
+/**
+ * @brief This function returns M24SR_STATUS_SUCCESS if the buffer is an s-block
+ * @param buffer pointer to the data
+ * @retval M24SR_SUCCESS the data is a S-Block
+ * @retval NFC_ERROR the data is not a S-Block
+ */
+static M24srError_t is_S_block(uint8_t *buffer)
+{
+ if ((buffer[OFFSET_PCB] & MASK_BLOCK) == MASK_S_BLOCK) {
+ return M24SR_SUCCESS;
+ } else {
+ return M24SR_ERROR;
+ }
+}
+
+M24srDriver::M24srDriver(PinName i2c_data_pin, PinName i2c_clock_pin,
+ PinName gpo_pin, PinName rf_disable_pin)
+ : _i2c_channel(i2c_data_pin, i2c_clock_pin),
+ _gpo_event_interrupt(gpo_pin),
+ _gpo_pin(gpo_pin),
+ _rf_disable_pin(rf_disable_pin),
+ _command_cb(&_default_cb),
+ _subcommand_cb(NULL),
+ _communication_type(SYNC),
+ _last_command(NONE),
+ _ndef_size(MAX_NDEF_SIZE),
+ _max_read_bytes(MAX_PAYLOAD),
+ _max_write_bytes(MAX_PAYLOAD),
+ _is_session_open(false)
+{
+ /* driver requires valid pin names */
+ MBED_ASSERT(i2c_data_pin != NC);
+ MBED_ASSERT(i2c_clock_pin != NC);
+ MBED_ASSERT(gpo_pin != NC);
+ MBED_ASSERT(rf_disable_pin != NC);
+
+ memset(_buffer, 0, 0xFF);
+ _did_byte = 0;
+
+ if (_rf_disable_pin.is_connected() != 0) {
+ _rf_disable_pin = 0;
+ }
+
+ if (_gpo_pin.is_connected() != 0) {
+ _gpo_event_interrupt.fall(mbed::callback(this, &M24srDriver::nfc_interrupt_callback));
+ _gpo_event_interrupt.mode(PullUp);
+ _gpo_event_interrupt.disable_irq();
+ }
+}
+
+/**
+ * @brief This function initialize the M24SR device
+ * @return M24SR_SUCCESS if no errors
+ */
+M24srError_t M24srDriver::init()
+{
+ /* force sync comms to avoid triggering the application with an event */
+ _communication_type = SYNC;
+
+ /* force to open a i2c session */
+ M24srError_t status = get_session(true);
+
+ if (status != M24SR_SUCCESS) {
+ return status;
+ }
+
+ /* leave the gpo always up */
+ if (_gpo_pin.is_connected() != 0) {
+ status = manage_i2c_gpo(HIGH_IMPEDANCE);
+ if (status != M24SR_SUCCESS) {
+ return status;
+ }
+ }
+
+ if (_rf_disable_pin.is_connected() != 0) {
+ status = manage_rf_gpo(HIGH_IMPEDANCE);
+ if (status != M24SR_SUCCESS) {
+ return status;
+ }
+ }
+
+ /* close the session */
+ status = deselect();
+
+ if (status != M24SR_SUCCESS) {
+ return status;
+ }
+
+ if (_gpo_pin.is_connected() != 0) {
+ _gpo_event_interrupt.enable_irq();
+ }
+
+ return M24SR_SUCCESS;
+}
+
+/**
+ * Handle communication if SYNC mode is selected
+ * @param status the return error
+ * @return true if communication has been handled successfully (or was not needed)
+ */
+bool M24srDriver::manage_sync_communication(M24srError_t *status)
+{
+ if (_communication_type == SYNC) {
+ *status = io_poll_i2c();
+ if (*status == M24SR_SUCCESS) {
+ *status = manage_event();
+ } else {
+ _last_command = NONE;
+ return false;
+ }
+ }
+
+ return true;
+}
+
+/**
+ * @brief This function sends the FWT extension command (S-Block format)
+ * @param fwt_byte FWT value
+ * @return M24SR_SUCCESS if no errors
+ */
+M24srError_t M24srDriver::send_fwt_extension(uint8_t fwt_byte)
+{
+ uint8_t buffer[STATUS_RESPONSE_LENGTH];
+ M24srError_t status;
+ uint8_t length = 0;
+ uint16_t crc16;
+
+ /* create the response */
+ buffer[length++] = 0xF2;
+ buffer[length++] = fwt_byte;
+ /* compute the CRC */
+ crc16 = compute_crc(buffer, 0x02);
+ /* append the CRC16 */
+ buffer[length++] = GETLSB(crc16);
+ buffer[length++] = GETMSB(crc16);
+
+ /* send the request */
+ status = io_send_i2c_command(length, buffer);
+ if (status != M24SR_SUCCESS) {
+ return status;
+ }
+
+ _last_command = UPDATE;
+
+ if (!manage_sync_communication(&status)) {
+ get_callback()->on_updated_binary(this, status, _last_command_data.offset, _last_command_data.data,
+ _last_command_data.length);
+ }
+
+ return status;
+}
+
+/**
+ * @brief This function sends the Deselect command (S-Block format)
+ * @return M24SR_SUCCESS if no errors
+ */
+M24srError_t M24srDriver::deselect()
+{
+ uint8_t buffer[] = DESELECT_REQUEST_COMMAND;
+ M24srError_t status;
+
+ /* send the request */
+ status = io_send_i2c_command(sizeof(buffer), buffer);
+
+ if (status != M24SR_SUCCESS) {
+ get_callback()->on_deselect(this, status);
+ }
+
+ _last_command = DESELECT;
+
+ if (!manage_sync_communication(&status)) {
+ get_callback()->on_selected_application(this, status);
+ }
+
+ return status;
+}
+
+M24srError_t M24srDriver::receive_deselect()
+{
+ uint8_t buffer[4];
+ M24srError_t status;
+
+ status = io_receive_i2c_response(sizeof(buffer), buffer);
+ get_callback()->on_deselect(this, status);
+
+ return status;
+}
+
+/**
+ * @brief This function sends the GetSession command to the M24SR device
+ * @retval M24SR_SUCCESS the function is successful.
+ * @retval Status (SW1&SW2) if operation does not complete.
+ */
+M24srError_t M24srDriver::get_session(bool force)
+{
+ /* special M24SR command */
+ const uint8_t M24SR_OPENSESSION_COMMAND = 0x26;
+ const uint8_t M24SR_KILLSESSION_COMMAND = 0x52;
+
+ M24srError_t status;
+
+ if (force) {
+ status = io_send_i2c_command(1, &M24SR_OPENSESSION_COMMAND);
+ } else {
+ status = io_send_i2c_command(1, &M24SR_KILLSESSION_COMMAND);
+ }
+
+ if (status != M24SR_SUCCESS) {
+ get_callback()->on_session_open(this, status);
+ return status;
+ }
+
+ /* Insure no access will be done just after open session */
+ /* The only way here is to poll I2C to know when M24SR is ready */
+ /* GPO can not be use with KillSession command */
+ status = io_poll_i2c();
+
+ get_callback()->on_session_open(this, status);
+ return status;
+}
+
+/**
+ * @brief This function sends the SelectApplication command
+ * @return M24SR_SUCCESS if no errors
+ */
+M24srError_t M24srDriver::select_application()
+{
+ M24srError_t status;
+ uint8_t data_out[] = SELECT_APPLICATION_COMMAND;
+ uint16_t P1_P2 = 0x0400;
+ uint16_t length;
+
+ C_APDU command(C_APDU_CLA_DEFAULT, C_APDU_SELECT_FILE, P1_P2, sizeof(data_out), data_out, 0);
+
+ /* build the I2C command */
+ build_I_block_command(CMD_MASK_SELECT_APPLICATION, &command, _did_byte, &length, _buffer);
+
+ /* send the request */
+ status = io_send_i2c_command(length, _buffer);
+ if (status != M24SR_SUCCESS) {
+ get_callback()->on_selected_application(this, status);
+ return status;
+ }
+
+ _last_command = SELECT_APPLICATION;
+
+ if (!manage_sync_communication(&status)) {
+ get_callback()->on_selected_application(this, status);
+ }
+
+ return status;
+}
+
+M24srError_t M24srDriver::receive_select_application()
+{
+ uint8_t data_in[STATUS_RESPONSE_LENGTH];
+ M24srError_t status;
+
+ _last_command = NONE;
+
+ status = io_receive_i2c_response(sizeof(data_in), data_in);
+ if (status != M24SR_SUCCESS) {
+ get_callback()->on_selected_application(this, status);
+ return status;
+ }
+
+ status = is_correct_crc_residue(data_in, sizeof(data_in));
+ get_callback()->on_selected_application(this, status);
+
+ return status;
+}
+
+M24srError_t M24srDriver::read_id(uint8_t *nfc_id)
+{
+ if (!nfc_id) {
+ return M24SR_ERROR;
+ }
+
+ _subcommand_cb = &_read_id_cb;
+ _read_id_cb.set_task(nfc_id);
+
+ return select_application();
+}
+
+/**
+ * @brief This function sends the SelectCCFile command
+ * @retval M24SR_SUCCESS the function is successful.
+ * @retval M24SR_ERROR_I2CTIMEOUT I2C timeout occurred.
+ * @retval Status (SW1&SW2) if operation does not complete for another reason.
+ */
+M24srError_t M24srDriver::select_cc_file()
+{
+ M24srError_t status;
+ uint8_t data_out[] = CC_FILE_ID_BYTES;
+ uint16_t P1_P2 = 0x000C;
+ uint16_t length;
+
+ C_APDU command(C_APDU_CLA_DEFAULT, C_APDU_SELECT_FILE, P1_P2, sizeof(data_out), data_out, 0);
+
+ /* build the I2C command */
+ build_I_block_command(CMD_MASK_SELECT_CC_FILE, &command, _did_byte, &length, _buffer);
+
+ /* send the request */
+ status = io_send_i2c_command(length, _buffer);
+ if (status != M24SR_SUCCESS) {
+ get_callback()->on_selected_cc_file(this, status);
+ return status;
+ }
+
+ _last_command = SELECT_CC_FILE;
+
+ if (!manage_sync_communication(&status)) {
+ get_callback()->on_selected_cc_file(this, status);
+ }
+
+ return status;
+}
+
+M24srError_t M24srDriver::receive_select_cc_file()
+{
+ uint8_t data_in[STATUS_RESPONSE_LENGTH];
+ M24srError_t status;
+
+ _last_command = NONE;
+
+ status = io_receive_i2c_response(sizeof(data_in), data_in);
+
+ if (status != M24SR_SUCCESS) {
+ get_callback()->on_selected_cc_file(this, status);
+ return status;
+ }
+
+ status = is_correct_crc_residue(data_in, sizeof(data_in));
+ get_callback()->on_selected_cc_file(this, status);
+
+ return status;
+}
+
+/**
+ * @brief This function sends the SelectSystemFile command
+ * @retval Status (SW1&SW2) Status of the operation to complete.
+ * @retval M24SR_ERROR_I2CTIMEOUT I2C timeout occurred.
+ */
+M24srError_t M24srDriver::select_system_file()
+{
+ uint8_t data_out[] = SYSTEM_FILE_ID_BYTES;
+ M24srError_t status;
+ uint16_t P1_P2 = 0x000C;
+ uint16_t length;
+
+ C_APDU command(C_APDU_CLA_DEFAULT, C_APDU_SELECT_FILE, P1_P2, sizeof(data_out), data_out, 0);
+
+ /* build the command */
+ build_I_block_command(CMD_MASK_SELECT_CC_FILE, &command, _did_byte, &length, _buffer);
+
+ /* send the request */
+ status = io_send_i2c_command(length, _buffer);
+ if (status != M24SR_SUCCESS) {
+ get_callback()->on_selected_system_file(this, status);
+ return status;
+ }
+
+ _last_command = SELECT_SYSTEM_FILE;
+
+ if (!manage_sync_communication(&status)) {
+ get_callback()->on_selected_system_file(this, status);
+ }
+
+ return status;
+}
+
+M24srError_t M24srDriver::receive_select_system_file()
+{
+ uint8_t data_in[STATUS_RESPONSE_LENGTH];
+ M24srError_t status;
+
+ _last_command = NONE;
+
+ status = io_receive_i2c_response(sizeof(data_in), data_in);
+
+ if (status != M24SR_SUCCESS) {
+ get_callback()->on_selected_system_file(this, status);
+ return status;
+ }
+
+ status = is_correct_crc_residue(data_in, sizeof(data_in));
+ get_callback()->on_selected_system_file(this, status);
+
+ return status;
+}
+
+/**
+ * @brief This function sends the SelectNDEFfile command
+ * @retval Status (SW1&SW2) Status of the operation to complete.
+ * @retval M24SR_ERROR_I2CTIMEOUT I2C timeout occurred.
+ */
+M24srError_t M24srDriver::select_ndef_file(uint16_t ndef_file_id)
+{
+ M24srError_t status;
+ uint8_t data_out[] = { GETMSB(ndef_file_id), GETLSB(ndef_file_id) };
+ uint16_t P1_P2 = 0x000C;
+ uint16_t length;
+
+ C_APDU command(C_APDU_CLA_DEFAULT, C_APDU_SELECT_FILE, P1_P2, sizeof(data_out), data_out, 0);
+
+ /* build the I2C command */
+ build_I_block_command(CMD_MASK_SELECT_NDEF_FILE, &command, _did_byte, &length, _buffer);
+
+ /* send the request */
+ status = io_send_i2c_command(length, _buffer);
+ if (status != M24SR_SUCCESS) {
+ return status;
+ }
+
+ _last_command = SELECT_NDEF_FILE;
+
+ if (!manage_sync_communication(&status)) {
+ get_callback()->on_selected_ndef_file(this, status);
+ }
+
+ return status;
+}
+
+M24srError_t M24srDriver::receive_select_ndef_file()
+{
+ uint8_t data_in[STATUS_RESPONSE_LENGTH];
+ M24srError_t status;
+
+ _last_command = NONE;
+
+ status = io_receive_i2c_response(sizeof(data_in), data_in);
+
+ if (status != M24SR_SUCCESS) {
+ get_callback()->on_selected_ndef_file(this, status);
+ return status;
+ }
+
+ status = is_correct_crc_residue(data_in, sizeof(data_in));
+ get_callback()->on_selected_ndef_file(this, status);
+
+ return status;
+}
+
+/**
+ * @brief This function sends a read binary command
+ * @param offset first byte to read
+ * @param length number of bytes to read
+ * @param buffer pointer to the buffer read from the M24SR device
+ * @retval Status (SW1&SW2) Status of the operation to complete.
+ * @retval M24SR_ERROR_I2CTIMEOUT I2C timeout occurred.
+ */
+M24srError_t M24srDriver::read_binary(uint16_t offset, uint8_t length, uint8_t *buffer)
+{
+ uint16_t command_length;
+ M24srError_t status;
+
+ if (length > MAX_OPERATION_SIZE) {
+ length = MAX_OPERATION_SIZE;
+ }
+
+ C_APDU command(C_APDU_CLA_DEFAULT, C_APDU_READ_BINARY, offset, 0, NULL, length);
+
+ build_I_block_command(CMD_MASK_READ_BINARY, &command, _did_byte, &command_length, _buffer);
+
+ status = io_send_i2c_command(command_length, _buffer);
+ if (status != M24SR_SUCCESS) {
+ get_callback()->on_read_byte(this, status, offset, buffer, length);
+ return status;
+ }
+
+ _last_command = READ;
+ _last_command_data.data = buffer;
+ _last_command_data.length = length;
+ _last_command_data.offset = offset;
+
+ if (!manage_sync_communication(&status)) {
+ get_callback()->on_read_byte(this, status, offset, buffer, length);
+ }
+
+ return status;
+}
+
+M24srError_t M24srDriver::receive_read_binary()
+{
+ M24srError_t status;
+ const uint16_t length = _last_command_data.length;
+ const uint16_t offset = _last_command_data.offset;
+ uint8_t *data = _last_command_data.data;
+
+ _last_command = NONE;
+
+ status = io_receive_i2c_response(length + STATUS_RESPONSE_LENGTH, _buffer);
+ if (status != M24SR_SUCCESS) {
+ get_callback()->on_read_byte(this, status, offset, data, length);
+ return status;
+ }
+
+ status = is_correct_crc_residue(_buffer, length + STATUS_RESPONSE_LENGTH);
+ if (status != M24SR_SUCCESS) {
+ get_callback()->on_read_byte(this, status, offset, data, length);
+ } else {
+ /* retrieve the data without SW1 & SW2 as provided as return value of the function */
+ memcpy(_last_command_data.data, &_buffer[1], length);
+ get_callback()->on_read_byte(this, status, offset, data, length);
+ }
+
+ return status;
+}
+
+/**
+ * @brief This function sends a ST read binary command (no error if access is not inside NDEF file)
+ * @param offset first byte to read
+ * @param length number of bytes to read
+ * @param buffer pointer to the buffer read from the M24SR device
+ * @retval Status (SW1&SW2) Status of the operation to complete.
+ * @retval M24SR_ERROR_I2CTIMEOUT I2C timeout occurred.
+ */
+M24srError_t M24srDriver::st_read_binary(uint16_t offset, uint8_t length, uint8_t *buffer)
+{
+ uint16_t command_length;
+ M24srError_t status;
+
+ if (length > MAX_OPERATION_SIZE) {
+ length = MAX_OPERATION_SIZE;
+ }
+
+ C_APDU command(C_APDU_CLA_ST, C_APDU_READ_BINARY, offset, 0, NULL, length);
+
+ build_I_block_command(CMD_MASK_READ_BINARY, &command, _did_byte, &command_length, _buffer);
+
+ status = io_send_i2c_command(command_length, _buffer);
+ if (status != M24SR_SUCCESS) {
+ get_callback()->on_read_byte(this, status, offset, buffer, length);
+ return status;
+ }
+
+ _last_command = READ;
+ _last_command_data.data = buffer;
+ _last_command_data.length = length;
+
+ if (!manage_sync_communication(&status)) {
+ get_callback()->on_read_byte(this, status, offset, buffer, length);
+ }
+
+ return status;
+}
+
+/**
+ * @brief This function sends a Update binary command
+ * @param offset first byte to read
+ * @param length number of bytes to write
+ * @param buffer pointer to the buffer read from the M24SR device
+ * @retval Status (SW1&SW2) Status of the operation to complete.
+ * @retval M24SR_ERROR_I2CTIMEOUT I2C timeout occurred.
+ */
+M24srError_t M24srDriver::update_binary(uint16_t offset, uint8_t length, const uint8_t *data)
+{
+ M24srError_t status;
+ uint16_t command_length;
+
+ if (length > MAX_OPERATION_SIZE) {
+ length = MAX_OPERATION_SIZE;
+ }
+
+ C_APDU command(C_APDU_CLA_DEFAULT, C_APDU_UPDATE_BINARY, offset, length, data, 0);
+
+ build_I_block_command(CMD_MASK_UPDATE_BINARY, &command, _did_byte, &command_length, _buffer);
+
+ status = io_send_i2c_command(command_length, _buffer);
+ if (status != M24SR_SUCCESS) {
+ get_callback()->on_updated_binary(this, status, offset, (uint8_t *) data, length);
+ return status;
+ }
+
+ _last_command = UPDATE;
+ _last_command_data.data = (uint8_t *) data;
+ _last_command_data.length = length;
+ _last_command_data.offset = offset;
+
+ if (!manage_sync_communication(&status)) {
+ get_callback()->on_updated_binary(this, status, offset, (uint8_t *) data, length);
+ }
+
+ return status;
+}
+
+M24srError_t M24srDriver::receive_update_binary()
+{
+ uint8_t response[STATUS_RESPONSE_LENGTH];
+ M24srError_t status;
+ const uint16_t length = _last_command_data.length;
+ uint8_t *data = _last_command_data.data;
+ const uint16_t offset = _last_command_data.offset;
+
+ _last_command = NONE;
+
+ status = io_receive_i2c_response(sizeof(response), response);
+ if (status != M24SR_SUCCESS) {
+ get_callback()->on_updated_binary(this, status, offset, data, length);
+ return status;
+ }
+
+ if (is_S_block(response) == M24SR_SUCCESS) {
+ /* check the CRC */
+ status = is_correct_crc_residue(response, WATING_TIME_EXT_RESPONSE_LENGTH);
+ if (status != M24SR_IO_ERROR_CRC) {
+ /* send the FrameExension response*/
+ status = send_fwt_extension(response[OFFSET_PCB + 1]);
+ if (status != M24SR_SUCCESS) {
+ /* abort update */
+ get_callback()->on_updated_binary(this, status, offset, data, length);
+ }
+ }
+ } else {
+ status = is_correct_crc_residue(response, STATUS_RESPONSE_LENGTH);
+ get_callback()->on_updated_binary(this, status, offset, data, length);
+ }
+
+ return status;
+}
+
+/**
+ * @brief This function sends the Verify command
+ * @param password_type PasswordId ( 0x0001 : Read NDEF pwd or 0x0002 : Write NDEF pwd or 0x0003 : I2C pwd)
+ * @param password pointer to the password
+ * @retval Status (SW1&SW2) Status of the operation to complete.
+ * @retval M24SR_ERROR_I2CTIMEOUT I2C timeout occurred.
+ */
+M24srError_t M24srDriver::verify(PasswordType_t password_type, const uint8_t *password)
+{
+ M24srError_t status;
+ uint16_t length;
+
+ /* check the parameters */
+ if (password_type > I2C_PASSWORD) {
+ get_callback()->on_verified(this, M24SR_IO_ERROR_PARAMETER, password_type, password);
+ return M24SR_IO_ERROR_PARAMETER;
+ }
+
+ C_APDU command(C_APDU_CLA_DEFAULT, C_APDU_VERIFY, password_type, password ? PASSWORD_LENGTH : 0, NULL, 0);
+
+ uint16_t command_mask = CMD_MASK_VERIFY_BINARY_WO_PWD;
+
+ if (password) {
+ /* copy the password */
+ command.body.data = password;
+ /* build the I2C command */
+ command_mask = CMD_MASK_VERIFY_BINARY_WITH_PWD;
+ }
+
+ /* build the I2C command */
+ build_I_block_command(command_mask, &command, _did_byte, &length, _buffer);
+
+ /* send the request */
+ status = io_send_i2c_command(length, _buffer);
+ if (status != M24SR_SUCCESS) {
+ get_callback()->on_verified(this, status, password_type, password);
+ return status;
+ }
+
+ _last_command = VERIFY;
+ _last_command_data.data = (uint8_t *) password;
+ /* use the offset to store the password type */
+ _last_command_data.offset = password_type;
+
+ if (!manage_sync_communication(&status)) {
+ get_callback()->on_verified(this, status, password_type, password);
+ }
+
+ return status;
+}
+
+M24srError_t M24srDriver::receive_verify()
+{
+ M24srError_t status;
+ uint8_t respBuffer[STATUS_RESPONSE_LENGTH];
+ _last_command = NONE;
+
+ const uint8_t *data = _last_command_data.data;
+ const PasswordType_t type = PasswordType_t(_last_command_data.offset);
+
+ status = io_receive_i2c_response(sizeof(respBuffer), respBuffer);
+
+ if (status != M24SR_SUCCESS) {
+ get_callback()->on_verified(this, status, type, data);
+ return status;
+ }
+
+ status = is_correct_crc_residue(respBuffer, STATUS_RESPONSE_LENGTH);
+ get_callback()->on_verified(this, status, type, data);
+ return status;
+}
+
+/**
+ * @brief This function sends the ChangeReferenceData command
+ * @param password_type PasswordId (0x0001 : Read NDEF pwd or 0x0002 : Write NDEF pwd or 0x0003 : I2C pwd)
+ * @param password pointer to the passwaord
+ * @retval Status (SW1&SW2) Satus of the operation to complete.
+ * @retval M24SR_ERROR_I2CTIMEOUT I2C timeout occurred.
+ */
+M24srError_t M24srDriver::change_reference_data(PasswordType_t password_type, const uint8_t *password)
+{
+ M24srError_t status;
+ uint16_t length;
+
+ /* check the parameters */
+ if (password_type > I2C_PASSWORD) {
+ get_callback()->on_change_reference_data(this, M24SR_IO_ERROR_PARAMETER, password_type, password);
+ return M24SR_IO_ERROR_PARAMETER;
+ }
+
+ C_APDU command(C_APDU_CLA_DEFAULT, C_APDU_CHANGE, password_type, PASSWORD_LENGTH, password, 0);
+
+ /* build the command */
+ build_I_block_command(CMD_MASK_CHANGE_REF_DATA, &command, _did_byte, &length, _buffer);
+
+ /* send the request */
+ status = io_send_i2c_command(length, _buffer);
+ if (status != M24SR_SUCCESS) {
+ get_callback()->on_change_reference_data(this, status, password_type, password);
+ return status;
+ }
+
+ _last_command = CHANGE_REFERENCE_DATA;
+ _last_command_data.data = (uint8_t *) password;
+ /* use the offset to store the password type */
+ _last_command_data.offset = password_type;
+
+ if (!manage_sync_communication(&status)) {
+ get_callback()->on_change_reference_data(this, status, password_type, password);
+ }
+
+ return status;
+}
+
+M24srError_t M24srDriver::receive_change_reference_data()
+{
+ M24srError_t status;
+ uint8_t rensponse[STATUS_RESPONSE_LENGTH];
+
+ PasswordType_t type = PasswordType_t(_last_command_data.offset);
+ uint8_t *data = _last_command_data.data;
+
+ status = io_receive_i2c_response(STATUS_RESPONSE_LENGTH, rensponse);
+ if (status != M24SR_SUCCESS) {
+ get_callback()->on_change_reference_data(this, status, type, data);
+ return status;
+ }
+
+ status = is_correct_crc_residue(rensponse, STATUS_RESPONSE_LENGTH);
+ get_callback()->on_change_reference_data(this, status, type, data);
+ return status;
+}
+
+/**
+ * @brief This function sends the EnableVerificationRequirement command
+ * @param password_type enable the read or write protection ( 0x0001 : Read or 0x0002 : Write )
+ * @retval Status (SW1&SW2) Status of the operation to complete.
+ * @retval M24SR_ERROR_I2CTIMEOUT I2C timeout occurred.
+ */
+M24srError_t M24srDriver::enable_verification_requirement(PasswordType_t password_type)
+{
+ M24srError_t status;
+ uint16_t length;
+
+ /* check the parameters */
+ if ((password_type != READ_PASSWORD) && (password_type != WRITE_PASSWORD)) {
+ get_callback()->on_enable_verification_requirement(this, M24SR_IO_ERROR_PARAMETER, password_type);
+ return M24SR_IO_ERROR_PARAMETER;
+ }
+
+ C_APDU command(C_APDU_CLA_DEFAULT, C_APDU_ENABLE, password_type, 0, NULL, 0);
+
+ /* build the I2C command */
+ build_I_block_command(CMD_MASK_ENABLE_VERIFREQ, &command, _did_byte, &length, _buffer);
+
+ /* send the request */
+ status = io_send_i2c_command(length, _buffer);
+ if (status != M24SR_SUCCESS) {
+ get_callback()->on_enable_verification_requirement(this, status, password_type);
+ return status;
+ }
+
+ _last_command = ENABLE_VERIFICATION_REQUIREMENT;
+ /* use the offset to store the password type */
+ _last_command_data.offset = password_type;
+
+ if (!manage_sync_communication(&status)) {
+ get_callback()->on_enable_verification_requirement(this, status, password_type);
+ }
+
+ return status;
+}
+
+M24srError_t M24srDriver::receive_enable_verification_requirement()
+{
+ M24srError_t status;
+ uint8_t rensponse[STATUS_RESPONSE_LENGTH];
+
+ PasswordType_t type = PasswordType_t(_last_command_data.offset);
+
+ status = io_receive_i2c_response(STATUS_RESPONSE_LENGTH, rensponse);
+ if (status != M24SR_SUCCESS) {
+ get_callback()->on_enable_verification_requirement(this, status, type);
+ return status;
+ }
+
+ status = is_correct_crc_residue(rensponse, STATUS_RESPONSE_LENGTH);
+ get_callback()->on_enable_verification_requirement(this, status, type);
+ return status;
+}
+
+/**
+ * @brief This function sends the DisableVerificationRequirement command
+ * @param password_type enable the read or write protection ( 0x0001 : Read or 0x0002 : Write )
+ * @retval Status (SW1&SW2) Status of the operation to complete.
+ * @retval M24SR_ERROR_I2CTIMEOUT I2C timeout occurred.
+ */
+M24srError_t M24srDriver::disable_verification_requirement(PasswordType_t password_type)
+{
+ M24srError_t status;
+ uint16_t length;
+
+ /* check the parameters */
+ if ((password_type != READ_PASSWORD) && (password_type != WRITE_PASSWORD)) {
+ get_callback()->on_disable_verification_requirement(this, M24SR_IO_ERROR_PARAMETER, password_type);
+ return M24SR_IO_ERROR_PARAMETER;
+ }
+
+ C_APDU command(C_APDU_CLA_DEFAULT, C_APDU_DISABLE, password_type, 0, NULL, 0);
+
+ /* build the command */
+ build_I_block_command(CMD_MASK_DISABLE_VERIFREQ, &command, _did_byte, &length, _buffer);
+
+ /* send the request */
+ status = io_send_i2c_command(length, _buffer);
+ if (status != M24SR_SUCCESS) {
+ get_callback()->on_disable_verification_requirement(this, status, password_type);
+ return status;
+ }
+
+ _last_command = DISABLE_VERIFICATION_REQUIREMENT;
+ /* use the offset to store the password type */
+ _last_command_data.offset = password_type;
+
+ if (!manage_sync_communication(&status)) {
+ get_callback()->on_disable_verification_requirement(this, status, password_type);
+ }
+
+ return status;
+}
+
+M24srError_t M24srDriver::receive_disable_verification_requirement()
+{
+ M24srError_t status;
+ uint8_t rensponse[STATUS_RESPONSE_LENGTH];
+
+ PasswordType_t type = PasswordType_t(_last_command_data.offset);
+
+ status = io_receive_i2c_response(STATUS_RESPONSE_LENGTH, rensponse);
+ if (status != M24SR_SUCCESS) {
+ get_callback()->on_disable_verification_requirement(this, status, type);
+ return status;
+ }
+
+ status = is_correct_crc_residue(rensponse, STATUS_RESPONSE_LENGTH);
+ get_callback()->on_disable_verification_requirement(this, status, type);
+ return status;
+}
+
+/**
+ * @brief This function sends the EnablePermananentState command
+ * @param password_type enable the read or write protection ( 0x0001 : Read or 0x0002 : Write )
+ * @retval Status (SW1&SW2) Status of the operation to complete.
+ * @retval M24SR_ERROR_I2CTIMEOUT I2C timeout occurred.
+ */
+M24srError_t M24srDriver::enable_permanent_state(PasswordType_t password_type)
+{
+ M24srError_t status;
+ uint16_t length;
+
+ /* check the parameters */
+ if ((password_type != READ_PASSWORD) && (password_type != WRITE_PASSWORD)) {
+ get_callback()->on_enable_permanent_state(this, M24SR_IO_ERROR_PARAMETER, password_type);
+ return M24SR_IO_ERROR_PARAMETER;
+ }
+
+ C_APDU command(C_APDU_CLA_ST, C_APDU_ENABLE, password_type, 0, NULL, 0);
+
+ /* build the I2C command */
+ build_I_block_command(CMD_MASK_ENABLE_VERIFREQ, &command, _did_byte, &length, _buffer);
+
+ /* send the request */
+ status = io_send_i2c_command(length, _buffer);
+ if (status != M24SR_SUCCESS) {
+ get_callback()->on_enable_permanent_state(this, status, password_type);
+ return status;
+ }
+
+ _last_command = ENABLE_PERMANET_STATE;
+ /* use the offset to store the password type */
+ _last_command_data.offset = password_type;
+
+ if (!manage_sync_communication(&status)) {
+ get_callback()->on_enable_permanent_state(this, status, password_type);
+ }
+
+ return status;
+}
+
+M24srError_t M24srDriver::receive_enable_permanent_state()
+{
+ M24srError_t status;
+ uint8_t rensponse[STATUS_RESPONSE_LENGTH];
+
+ PasswordType_t type = PasswordType_t(_last_command_data.offset);
+
+ status = io_receive_i2c_response(STATUS_RESPONSE_LENGTH, rensponse);
+ if (status != M24SR_SUCCESS) {
+ get_callback()->on_enable_permanent_state(this, status, type);
+ return status;
+ }
+
+ status = is_correct_crc_residue(rensponse, STATUS_RESPONSE_LENGTH);
+ get_callback()->on_enable_permanent_state(this, status, type);
+ return status;
+}
+
+/**
+ * @brief This function sends the DisablePermanentState command
+ * @param password_type enable the read or write protection ( 0x0001 : Read or 0x0002 : Write )
+ * @retval Status (SW1&SW2) Status of the operation to complete.
+ * @retval M24SR_ERROR_I2CTIMEOUT I2C timeout occurred.
+ */
+M24srError_t M24srDriver::disable_permanent_state(PasswordType_t password_type)
+{
+ M24srError_t status;
+ uint16_t length;
+
+ /* check the parameters */
+ if ((password_type != READ_PASSWORD) && (password_type != WRITE_PASSWORD)) {
+ get_callback()->on_disable_permanent_state(this, M24SR_IO_ERROR_PARAMETER, password_type);
+ return M24SR_IO_ERROR_PARAMETER;
+ }
+
+ C_APDU command(C_APDU_CLA_ST, C_APDU_DISABLE, password_type, 0, NULL, 0);
+
+ /* build the I2C command */
+ build_I_block_command(CMD_MASK_DISABLE_VERIFREQ, &command, _did_byte, &length, _buffer);
+
+ /* send the request */
+ status = io_send_i2c_command(length, _buffer);
+ if (status != M24SR_SUCCESS) {
+ get_callback()->on_enable_permanent_state(this, status, password_type);
+ return status;
+ }
+
+ _last_command = DISABLE_PERMANET_STATE;
+ /* use the offset to store the password type */
+ _last_command_data.offset = password_type;
+
+ if (!manage_sync_communication(&status)) {
+ get_callback()->on_disable_permanent_state(this, status, password_type);
+ }
+
+ return status;
+}
+
+M24srError_t M24srDriver::receive_disable_permanent_state()
+{
+ M24srError_t status;
+ uint8_t rensponse[STATUS_RESPONSE_LENGTH];
+
+ PasswordType_t type = PasswordType_t(_last_command_data.offset);
+
+ status = io_receive_i2c_response(STATUS_RESPONSE_LENGTH, rensponse);
+ if (status != M24SR_SUCCESS) {
+ get_callback()->on_disable_permanent_state(this, status, type);
+ return status;
+ }
+
+ status = is_correct_crc_residue(rensponse, STATUS_RESPONSE_LENGTH);
+ get_callback()->on_disable_permanent_state(this, status, type);
+ return status;
+}
+
+/**
+ * @brief This function generates an interrupt on GPO pin
+ * @retval Status (SW1&SW2) Status of the operation to complete.
+ * @retval M24SR_ERROR_I2CTIMEOUT I2C timeout occurred.
+ */
+M24srError_t M24srDriver::send_interrupt()
+{
+ uint16_t length;
+ uint16_t P1_P2 = 0x001E;
+
+ M24srError_t status = manage_i2c_gpo(INTERRUPT);
+ if (status != M24SR_SUCCESS) {
+ return status;
+ }
+
+ C_APDU command(C_APDU_CLA_ST, C_APDU_INTERRUPT, P1_P2, 0, NULL, 0);
+
+ /* build the I2C command */
+ build_I_block_command(CMD_MASK_SEND_INTERRUPT, &command, _did_byte, &length, _buffer);
+
+ return send_receive_i2c(length, _buffer);
+}
+
+M24srError_t M24srDriver::send_receive_i2c(uint16_t length, uint8_t *buffer)
+{
+ M24srError_t status;
+
+ /* send the request */
+ status = io_send_i2c_command(length, buffer);
+ if (status != M24SR_SUCCESS) {
+ return status;
+ }
+
+ status = io_poll_i2c();
+ if (status != M24SR_SUCCESS) {
+ return status;
+ }
+
+ /* read the response */
+ status = io_receive_i2c_response(STATUS_RESPONSE_LENGTH, buffer);
+ if (status != M24SR_SUCCESS) {
+ return status;
+ }
+
+ return is_correct_crc_residue(buffer, STATUS_RESPONSE_LENGTH);
+}
+
+/**
+ * @brief This function forces GPO pin to low state or high Z
+ * @param uSetOrReset select if GPO must be low (reset) or HiZ
+ * @retval Status (SW1&SW2) Status of the operation to complete.
+ * @retval M24SR_ERROR_I2CTIMEOUT I2C timeout occurred.
+ */
+M24srError_t M24srDriver::state_control(bool gpo_reset)
+{
+ uint16_t length;
+ uint16_t P1_P2 = 0x001F;
+
+ M24srError_t status = manage_i2c_gpo(STATE_CONTROL);
+ if (status == M24SR_SUCCESS) {
+ return status;
+ }
+
+ uint8_t reset = (uint8_t)gpo_reset;
+
+ C_APDU command(C_APDU_CLA_ST, C_APDU_INTERRUPT, P1_P2, 1, &reset, 0);
+
+ /* build the I2C command */
+ build_I_block_command(CMD_MASK_GPO_STATE, &command, _did_byte, &length, _buffer);
+
+ return send_receive_i2c(length, _buffer);
+}
+
+M24srError_t M24srDriver::manage_i2c_gpo(NfcGpoState_t gpo_i2c_config)
+{
+ if (_gpo_pin.is_connected() == 0) {
+ return M24SR_IO_PIN_NOT_CONNECTED;
+ }
+
+ if (gpo_i2c_config > STATE_CONTROL) {
+ return M24SR_IO_ERROR_PARAMETER;
+ }
+
+ _subcommand_cb = &_manage_gpo_cb;
+ _manage_gpo_cb.set_new_gpo_config(true, gpo_i2c_config);
+
+ return select_application();
+}
+
+M24srError_t M24srDriver::manage_rf_gpo(NfcGpoState_t gpo_rf_config)
+{
+ if (_rf_disable_pin.is_connected() == 0) {
+ return M24SR_IO_PIN_NOT_CONNECTED;
+ }
+
+ if (gpo_rf_config > STATE_CONTROL) {
+ return M24SR_IO_ERROR_PARAMETER;
+ }
+
+ _subcommand_cb = &_manage_gpo_cb;
+ _manage_gpo_cb.set_new_gpo_config(false, gpo_rf_config);
+
+ return select_application();
+}
+
+M24srError_t M24srDriver::rf_config(bool enable)
+{
+ if (_rf_disable_pin.is_connected() == 0) {
+ return M24SR_IO_PIN_NOT_CONNECTED;
+ }
+ /* invert since it's a disable pin */
+ _rf_disable_pin = !enable;
+
+ return M24SR_SUCCESS;
+}
+
+M24srError_t M24srDriver::io_send_i2c_command(uint8_t length, const uint8_t *buffer)
+{
+ int ret = _i2c_channel.write(M24SR_ADDR, (const char *) buffer, length);
+ if (ret == 0) {
+ return M24SR_SUCCESS;
+ }
+ return M24SR_IO_ERROR_I2CTIMEOUT;
+}
+
+M24srError_t M24srDriver::io_receive_i2c_response(uint8_t length, uint8_t *buffer)
+{
+ int ret = _i2c_channel.read(M24SR_ADDR, (char *) buffer, length);
+ if (ret == 0) {
+ return M24SR_SUCCESS;
+ }
+
+ return M24SR_IO_ERROR_I2CTIMEOUT;
+}
+
+M24srError_t M24srDriver::io_poll_i2c()
+{
+ int status = 1;
+ while (status != 0) {
+ /* send the device address and wait to receive an ack bit */
+ status = _i2c_channel.write(M24SR_ADDR, NULL, 0);
+ }
+ return M24SR_SUCCESS;
+}
+
+M24srError_t M24srDriver::manage_event()
+{
+ switch (_last_command) {
+ case DESELECT:
+ return receive_deselect();
+ case SELECT_APPLICATION:
+ return receive_select_application();
+ case SELECT_CC_FILE:
+ return receive_select_cc_file();
+ case SELECT_NDEF_FILE:
+ return receive_select_ndef_file();
+ case SELECT_SYSTEM_FILE:
+ return receive_select_system_file();
+ case READ:
+ return receive_read_binary();
+ case UPDATE:
+ return receive_update_binary();
+ case VERIFY:
+ return receive_verify();
+ case CHANGE_REFERENCE_DATA:
+ return receive_change_reference_data();
+ case ENABLE_VERIFICATION_REQUIREMENT:
+ return receive_enable_verification_requirement();
+ case DISABLE_VERIFICATION_REQUIREMENT:
+ return receive_disable_verification_requirement();
+ case ENABLE_PERMANET_STATE:
+ return receive_enable_permanent_state();
+ case DISABLE_PERMANET_STATE:
+ return receive_disable_permanent_state();
+ default:
+ return M24SR_SUCCESS;
+ }
+}
+
+} //ST
+} //vendor
+} //nfc
+} //mbed
+
+mbed::nfc::NFCEEPROMDriver *greentea_nfc_EEPROM_driver_get_instance()
+{
+ static mbed::nfc::vendor::ST::M24srDriver instance;
+ return &instance;
+}
+
+/******************* (C) COPYRIGHT 2013 STMicroelectronics *****END OF FILE****/