/      æ—¥æœ¬èªž

mwf_periph_ntag - NTAG

mwf_periph_ntag - NTAG

This describes the procedures for using the NTAG I2C controller (equivalent to NT3H2211) built into the JN5189.

In addition to using it as a simple EEPROM, it can communicate with NFC readers. Communication modes include the standard EEPROM mode, which behaves as an NFC Forum Type 2 Tag using EEPROM, and an extended SRAM mode that exchanges commands and responses using a pass-through proprietary protocol.

The controller is connected via I2C, but it does not use mwf::periph::i2c. It uses a dedicated API and the I2C2 port.

EEPROM Usage

The JN5189 does not have a standalone EEPROM. To use EEPROM, use the EEPROM of the NTAG I2C controller. This procedure allows reading and writing to a 1KB area (NT3H2211 I2C block addresses 64-127).

EEPROM Code Example

#include "mwf_periph_ntag.hpp"

void func() {
    // create the_ntag class object.
    if (!mwf::the_ntag) {
      mwf::ntag::global_init_ntag_manager();
    }

    // initialize
    mwf::the_ntag->init();

    // write 128bytes
    uint8_t xfer1[128];
    for (unsigned i = 0; i < 128; i++) xfer1[i] = i;
    mwf::the_ntag->write_user_area(0x00, xfer1);

    // read 128bytes
    uint8_t xfer2[128];
    mwf::the_ntag->read_user_area(0x00, xfer2);
}

General

global_init_ntag_manager(), global_deinit_ntag_manager()

static void global_init_ntag_manager();
static void global_deinit_ntag_manager();

Creates and destroys the the_ntag class object.

init(), deinit()

void init();
void deinit();

Performs initialization and termination procedures for device access. Initialization (init()) includes a waiting period of 300µs.

EEPROM Only

write_user_area()

bool write_user_area(uint16_t addr, const uint8_t *p, uint16_t len);
template <unsigned N> bool write_user_area(uint8_t addr, const uint8_t (&buf)[N]);

Writes a byte sequence to the EEPROM user area.

addr specifies the starting address from 0 to 1023. p or buf is the buffer for the data to be written. len or N is the number of data bytes.

read_user_area()

bool read_user_area(uint16_t addr, uint8_t *p, uint16_t len);
template <unsigned N> bool read_user_area(uint8_t addr, const uint8_t (&buf)[N]);

Reads a byte sequence from the EEPROM user area.

addr specifies the starting address from 0 to 1023. p or buf is the destination buffer for the data to be read. len or N is the number of data bytes.

NFC Usage

NFC Standard EEPROM Mode

In NFC standard EEPROM mode, NDEF messages can be written to or read from the EEPROM area by the device or a reader. While compatible with common NFC tags, transfer speed is similarly low, and bidirectional communication cannot be performed in a single session. Can be used with general-purpose apps such as NFC Tools ( Android / iOS ).

EEPROM Mode Operation

EEPROM Mode Operation

Below is an act sample that reads and writes NDEF URI records and Text records as a general NFC Forum Type 2 Tag.

#include <TWELITE>
#include "mwf_periph_ntag.hpp"

/*** the setup procedure (called on boot) */
void setup() {
    Serial << "--- NFC Tag Text Example ---" << crlf;
}

/*** the begin procedure (called after boot) */
void begin() {
    mwf::the_ntag->disable_pthru_mode(); // enabled by default
    mwf::the_ntag->write_uri("twelite.net");
    Serial << "Set an URL as default. Can be overwritten with text via UART or NFC." << crlf;
}

/*** the loop procedure (called every event) */
void loop() {
    // NFC output text buffer
    static char output_text[128];
    static char* output_text_ptr = &output_text[0];

    // Write serial input to NFC output
    if (Serial.available()) {
        char c;
        Serial >> c;
        Serial << c; // echo back
        *(output_text_ptr++) = c;
        if (c == '\n') {
            *output_text_ptr = '\0';
            mwf::the_ntag->write_text(output_text);
            Serial << format("Set:  %s", output_text) << crlf;
            output_text_ptr = &output_text[0];
        }
    }

    // Read NFC input if available
    if (mwf::the_ntag->available()) {
        char type;
        mwf::the_ntag->read_ndef_record_type(&type);
        if (type == 'T') { // Text record
            char input_text[128];
            char input_lang[3];
            mwf::the_ntag->read_text(input_text, input_lang);
            Serial << format("Read: %s", input_text) << crlf;
        }
    }
}
  • Since TWENET enables extended SRAM mode during initialization, disable it inside begin()
  • write_uri() can write an NDEF URI record
    • Touching a smartphone will open a browser
  • write_text() can write an NDEF Text record
  • When a new NDEF message is written by a reader, available() returns true
  • read_ndef_record_type() checks the type of the written NDEF record
    • Note: One NDEF record per NDEF message is assumed
  • read_text() reads the NDEF Text message

NFC Extended SRAM Mode

In NFC extended SRAM mode, the device responds to commands sent by a reader. Commands and responses consist of one or more frames. The SRAM has a 64-byte area used for per-frame transfers. Transfer speed is fast, and data can be returned in a single session.

SRAM Mode Operation

SRAM Mode Operation

The TWELITE application exchanges frames in the MWish (Mono Wireless Interactive Shell) format defined as follows.

MWish Frame

MWish Frame

Below is an act sample that responds to command input from the TWELITE app ( Android / iOS ).

Here, a command foo that returns text is implemented as follows.

Running in the TWELITE App

Running in the TWELITE App

  • foo -> bar
    • Returns bar in response to foo
  • foo 3 -> barbarbar
    • Repeats bar the number of times specified as an argument. Large transfers such as foo 1000 can be tested
  • foo -u -> BAR
    • The -u option (flag) returns uppercase BAR
  • foo -u 3 -> BARBARBAR
    • The -u option and argument can be applied simultaneously
#include <TWELITE>
#include "mwf_periph_ntag.hpp"

using namespace mwf::periph;

bool handle_commands(const ntag::MWishCommand* const c, ntag::MWishResponse* const r) {
    Serial << "Received user command " << c->command_str
           << format(" with flag(s) \"%s\" and data \"%s\"", c->flags, c->data) << crlf;

    // Command foo [-u] [times] implementation:
    // "foo" -> "bar"
    // "foo 3" -> "barbarbar"
    // "foo -u" -> "BAR"
    // "foo -u 3" -> "BARBARBAR"
    if (c->is_command("foo") and c->get_data_type() == ntag::PTHRU_DATA_TYPE::RAW_STRING) {
        int times = strtol(reinterpret_cast<char*>(c->data), nullptr, 10);
        if (times < 1 or times * 3 > ntag::MWishResponse::DATA_MAX_SIZE - 1) { times = 1; }
        for (int i = 0; i < times; i++) {
            if (c->contains_flag('u')) {
                r->printf("BAR");
            } else {
                r->printf("bar");
            }
        }
        return true;
    }
    return false; // No such command
}

/*** the setup procedure (called on boot) */
void setup() {
    Serial << "--- NFC App Command Example ---" << crlf;
}

/*** the begin procedure (called after boot) */
void begin() {
    mwf::the_ntag->enable_pthru_mode(); // enabled by default
    mwf::the_ntag->attach_pthru_command_handler(handle_commands);
    Serial << "Registered user command(s)." << crlf;
}

/*** the loop procedure (called every event) */
void loop() {
    // Update NFC pass-through process
    mwf::the_ntag->update_pthru();
}

NFC General

get_ntag_context()

Retrieves the NTAG-related context.

ntag_context

Stores NTAG-related state variables.

TypeNameDescription
uint8_tu8_i2c_addressI2C address
boolb_wake_enabledSleep wake enable flag
uint8_tu8_latest_checksumChecksum of the latest NDEF record
boolb_pthru_enabledSRAM mode enable flag
_FD_STATEfd_stateTag detection state
_PTHRU_STATEpthru_stateSRAM mode communication state
void (*)()fp_fd_in_additionalAdditional handler on reader approach
void (*)()fp_fd_out_additionalAdditional handler on reader departure

_FD_STATE

private Represents the field detection state.

  • NONE No reader
  • OUT Reader departed
  • IN Reader approached

_PTHRU_STATE

private Represents the SRAM mode state.

  • NOT_PRESENT No reader
  • RECEIVE_COMMAND Receiving the (first) frame of a command
  • RECEIVE_COMMAND_EX Receiving an extended frame of a command
  • SEND_RESPONSE Sending a response frame

enable_wakeup_source()

void enable_wakeup_source();

Enables waking from sleep via NFC.

disable_wakeup_source()

void disable_wakeup_source();

Disables waking from sleep via NFC.

check_if_wokeup_via_nfc()

static bool check_if_wokeup_via_nfc();

Returns true when woken from sleep via NFC.

attach_callback_fd_in()

void attach_callback_fd_in(void (*callback)());

Registers a callback function called when a reader is detected.

attach_callback_fd_out()

void attach_callback_fd_out(void (*callback)());

Registers a callback function called when a reader departs.

NFC Standard EEPROM Mode

write_ndef_record()

int write_ndef_record(const uint8_t* const ndef_record,
                      const int ndef_record_len, const bool lock_after = false);

Writes an arbitrary NDEF record.

write_uri()

int write_uri(const char* const uri, const URI_TYPE uri_type = URI_TYPE::HTTPS,
              const bool lock_after = false);

Writes a standard URI record.

URI_TYPE

  • NA None
  • HTTP_WWW http://www
  • HTTPS_WWW https://www
  • HTTP http://
  • HTTPS https://
  • TEL tel://
  • MAILTO mailto://

write_text()

int write_text(const char* const text, const char* const lang_code = "en",
               const bool lock_after = false);

Writes a standard Text record.

write_ascii()

int write_ascii(const char* const ascii, const int ascii_len,
                const bool lock_after = false);

Writes an ASCII string as a proprietary NDEF extension format with Type set to A.

write_binary()

int write_binary(const uint8_t* const binary, const int binary_len,
                 const bool lock_after = false);

Writes binary data as a proprietary NDEF extension format with Type set to B.

get_field_detection_status()

uint8_t get_field_detection_status();

Retrieves the field detection state _FD_STATE.

available()

bool available();

Called from the main loop. Returns true if a new NDEF record has been received when the NFC reader moves away.

read_is_ndef_record_new()

bool read_is_ndef_record_new();

Returns true if a new NDEF record has been received.

read_ndef_record()

int read_ndef_record(uint8_t* const ndef_record, int* const ndef_record_len);

Reads an arbitrary NDEF record.

read_ndef_record_type()

int read_ndef_record_type(char* const ndef_record_type);

Reads the type of an arbitrary NDEF record.

read_ndef_record_length()

int read_ndef_record_length(int* const ndef_record_len);

Reads the length of an arbitrary NDEF record.

read_is_ndef_record_short()

int read_is_ndef_record_short(bool* const is_record_short);

Returns true if the NDEF record is a short record.

read_uri()

int read_uri(char* const uri, URI_TYPE* const uri_type);

Reads a standard URI record.

read_text()

int read_text(char* const text, char* const lang_code);

Reads a standard Text record.

read_ascii()

int read_ascii(char* const ascii);

Reads an ASCII string from a proprietary NDEF extension format with Type set to A.

read_binary()

int read_binary(uint8_t* const binary);

Reads binary data from a proprietary NDEF extension format with Type set to B.

NFC Extended SRAM Mode

enable_pthru_mode()

void enable_pthru_mode();

Enables SRAM mode (default is EEPROM mode).

disable_pthru_mode()

void disable_pthru_mode();

Disables SRAM mode.

update_pthru()

void update_pthru();

Called from the main loop to perform SRAM mode state transitions.

MWishCommand

Mono Wireless interactive shell command

Handles command data sent from an NFC reader in extended SRAM mode. This is a singleton object.

Constants

TypeNameDescription
intDATA_MAX_SIZEMaximum data length: 8192 bytes

Member Variables

TypeNameDescription
const charmagic_numberMagic number "ZAMA"
uint8_tmajor_versionProtocol version
uint8_tminor_versionProtocol version
uint8_tpatch_versionProtocol version
uint16_ttransaction_idTransaction ID
inttotal_data_lengthTotal data length
chardata_typeData type
uint8_tlang_idLanguage ID
uint16_tpinPIN
char[8]command_strCommand string
char[8]flagsOption flags
uint8_t* constdataRead data area

getInstance()

static MWishCommand& getInstance();

Returns a reference to the singleton object.

get_data_type()

PTHRU_DATA_TYPE get_data_type() const;

Retrieves the data type.

PTHRU_DATA_TYPE
  • RAW_STRING String
  • RAW_BYTES Binary data
  • PROTOBUF Protocol Buffers

is_completed()

bool is_completed() const;

Returns true if all (split) frames have been stored.

is_japanese()

bool is_japanese() const;

Returns true if the language ID of the stored command is 2 (Japanese).

is_command()

bool is_command(const char* const str) const;

Returns true if the stored command string matches the argument.

contains_flag()

bool contains_flag(const char flag) const;

Returns true if the flag (option) specified in the argument is included in the command.

parse_new()

bool parse_new(const uint8_t* const frame);

Initializes the command and parses a new frame.

complete_with()

bool complete_with(const uint8_t* const another_frame);

Passes an additional frame to supplement the data.

MWishResponse

Mono Wireless interactive shell response

Handles response data sent to an NFC reader in extended SRAM mode. This is a singleton object.

Constants

TypeNameDescription
intDATA_MAX_SIZEMaximum data length: 8192 bytes

Member Variables

TypeNameDescription
const MWishCommand*commandCommand
inttotal_data_lengthTotal data length
chardata_typeData type
uint8_tlang_idLanguage ID
uint16_tpinPIN
intframes_serializedNumber of frames written
boolfinishedtrue if writing is complete
intrestart_afterWait time before resetting after response
uint8_t* constdataWrite data area

getInstance()

static MWishResponse& getInstance();

Returns a reference to the singleton object.

get_command()

const MWishCommand* const get_command() const;

Retrieves a pointer to the command to respond to.

get_data_type()

PTHRU_DATA_TYPE get_data_type() const;

Retrieves the data type.

PTHRU_DATA_TYPE
  • A String
  • B Binary data
  • P Protocol Buffers

set_data_type()

void set_data_type(const PTHRU_DATA_TYPE type);

Sets the data type.

get_data_len()

void set_data_len(const int len);

Sets the data length.

reset_data_len()

void reset_data_len();

Resets the data length.

get_data_ptr()

uint8_t* get_data_ptr() const;

Retrieves a pointer to the data sequence.

get_data_ptr_as()

template<typename Target> Target get_data_ptr_as() const;

Retrieves a pointer to the data sequence in the specified type.

get_pin()

uint16_t get_pin() const;

Retrieves the PIN.

set_pin()

void set_pin(const uint16_t code);

Sets the PIN.

is_serialization_finished()

 bool is_serialization_finished() const;

Returns true when data writing is complete.

restart_after_response()

void restart_after_response(const int warm_start_dur = -1);

Transitions directly to sleep immediately after the response, or puts the device to sleep for a specified duration immediately after the response.

is_restart_required()

bool is_restart_required() const;

Returns true if the device will sleep after the response.

is_cold_restart_required()

bool is_cold_restart_required() const;

Returns true if a reset is required immediately after the response.

get_warm_restart_duration()

int get_warm_restart_duration() const;

Returns the sleep duration after the response in milliseconds.

printf()

void printf(const char* format, ...);

Sets the data type to string and sets the specified string.

prepare_for()

void prepare_for(const MWishCommand& command);

Initializes the response data for the specified command.

serialize()

bool serialize(uint8_t* const destination);

Writes the response data to the specified area.

MWishCommandHandler

using MWishCommandHandler = bool (*)(const MWishCommand* const command_received,
                                     MWishResponse* const response_to_send);

Definition of the handler for registering command response processing.

attach_pthru_command_handler()

void attach_pthru_command_handler(MWishCommandHandler handler,
                                  bool is_system = false);

Registers a handler for processing responses to commands (use is_system = true for system-level handlers).

on_sleep()

Performs the termination procedure before sleep.

on_wakeup()

If the device was initialized before sleep, it re-initializes it. If re-initialization is not required, call deinit() before sleeping.