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
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()returnstrue 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
The TWELITE application exchanges frames in the MWish (Mono Wireless Interactive Shell) format defined as follows.

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
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 1000can be tested
- Repeats bar the number of times specified as an argument. Large transfers such as
foo -u->BAR- The
-uoption (flag) returns uppercase BAR
- The
foo -u 3->BARBARBAR- The
-uoption and argument can be applied simultaneously
- The
#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();
}
- Although extended SRAM mode is enabled during TWENET initialization, it is explicitly enabled inside
begin() attach_pthru_command_handler()registers a callback function to handle command handlers- Here,
handle_commands()at the top is registered - Fill in
rofntag::MWishResponseforcgiven byntag::MWishCommand c->is_command()matches the command string (up to 7 characters)c->data()retrieves the string given as an argument. Here it is converted to a number withstrtol()c->contains_flag()checks for the presence of an option flag (up to 7). Here the-uoption is detectedr->printf()stores a string. HerebarorBARis stored
- Here,
update_pthru()is called insideloop()
NFC General
get_ntag_context()
Retrieves the NTAG-related context.
ntag_context
Stores NTAG-related state variables.
| Type | Name | Description |
|---|---|---|
uint8_t | u8_i2c_address | I2C address |
bool | b_wake_enabled | Sleep wake enable flag |
uint8_t | u8_latest_checksum | Checksum of the latest NDEF record |
bool | b_pthru_enabled | SRAM mode enable flag |
_FD_STATE | fd_state | Tag detection state |
_PTHRU_STATE | pthru_state | SRAM mode communication state |
void (*)() | fp_fd_in_additional | Additional handler on reader approach |
void (*)() | fp_fd_out_additional | Additional handler on reader departure |
_FD_STATE
private Represents the field detection state.
NONENo readerOUTReader departedINReader approached
_PTHRU_STATE
private Represents the SRAM mode state.
NOT_PRESENTNo readerRECEIVE_COMMANDReceiving the (first) frame of a commandRECEIVE_COMMAND_EXReceiving an extended frame of a commandSEND_RESPONSESending 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
To use standard EEPROM mode, call mwf::the_ntag->disable_pthru_mode() after TWENET initialization. TWENET enables extended SRAM mode during initialization. For acts, you can use begin() {}.
void begin() {
mwf::the_ntag->disable_pthru_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
NANoneHTTP_WWWhttp://wwwHTTPS_WWWhttps://wwwHTTPhttp://HTTPShttps://TELtel://MAILTOmailto://
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
| Type | Name | Description |
|---|---|---|
int | DATA_MAX_SIZE | Maximum data length: 8192 bytes |
Member Variables
| Type | Name | Description |
|---|---|---|
const char | magic_number | Magic number "ZAMA" |
uint8_t | major_version | Protocol version |
uint8_t | minor_version | Protocol version |
uint8_t | patch_version | Protocol version |
uint16_t | transaction_id | Transaction ID |
int | total_data_length | Total data length |
char | data_type | Data type |
uint8_t | lang_id | Language ID |
uint16_t | pin | PIN |
char[8] | command_str | Command string |
char[8] | flags | Option flags |
uint8_t* const | data | Read 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_STRINGStringRAW_BYTESBinary dataPROTOBUFProtocol 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
| Type | Name | Description |
|---|---|---|
int | DATA_MAX_SIZE | Maximum data length: 8192 bytes |
Member Variables
| Type | Name | Description |
|---|---|---|
const MWishCommand* | command | Command |
int | total_data_length | Total data length |
char | data_type | Data type |
uint8_t | lang_id | Language ID |
uint16_t | pin | PIN |
int | frames_serialized | Number of frames written |
bool | finished | true if writing is complete |
int | restart_after | Wait time before resetting after response |
uint8_t* const | data | Write 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
AStringBBinary dataPProtocol 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).
sys_ev_handler Related
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.