/      English

mwf_periph_ntag - NTAG

mwf_periph_ntag - NTAG

JN5189に内蔵されている NTAG I2C コントローラ (NT3H2211相当) を使用するための手続きをまとめています。

単なる EEPROM として使うほか、NFC リーダとの通信を行うことができます。通信方式には、EEPROM を使った NFC Forum Type 2 Tag として振る舞う標準 EEPROM モードと、Pass-throughな独自のプロトコルによってコマンド-レスポンスのやりとりを行う拡張 SRAM モードがあります。

コントローラはI2C接続されていますが、mwf::periph::i2cは用いません。専用の API と I2C2 ポートを使用します。

EEPROM の使用

JN5189 に単体の EEPROM は搭載されておらず、EEPROM を使用する場合は NTAG I2C コントローラの EEPROM を使用します。 この手続きにより読み書きできるのは 1KB の領域(NT3H2211 の I2C block address 64-127)です。

EEPROM を扱うコード例

#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);
}

全般

global_init_ntag_manager(), global_deinit_ntag_manager()

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

the_ntagクラスオブジェクトの生成と破棄を行います。

init(), deinit()

void init();
void deinit();

デバイスアクセスのための初期化と利用終了手続きを行います。初期化init()には300usecの待ち処理が含まれます。

EEPROM のみ

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]);

EEPROMのユーザエリアにバイト列を書き込みます。

addrは開始アドレスで0..1023を指定します。pまたはbufは書込みデータのバッファです。lenまたはNはデータバイト数です。

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]);

EEPROMのユーザエリアからバイト列を読み出します。

addrは開始アドレスで0..1023を指定します。pまたはbufは読み出し先のデータのバッファです。lenまたはNはデータバイト数です。

NFC の使用

NFC 標準 EEPROM モード

NFC 標準 EEPROM モードでは、本体あるいはリーダから EEPROM の領域に NDEF メッセージを書き込んだり、NDEF メッセージを読み出したりすることができます。一般的な NFC タグと互換性があるものの、同様に転送速度は低速であり、一度のセッションで双方向通信はできません。NFC Tools(Android / iOS)などの汎用アプリを使用できます。

EEPROM モードの動作

EEPROM モードの動作

汎用的な NFC Forum Type 2 Tag として振る舞い、NDEF URI レコードの書き込みや Text レコードの読み書きを行う act サンプルを以下に示します。

#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;
        }
    }
}
  • TWENET の初期化時に 拡張 SRAM モードを有効化するため、begin() 内で無効化します
  • write_uri() で NDEF URI レコードを書き込むことができます
    • スマホをタッチすればブラウザを開くことができます
  • write_text() で NDEF Text レコードを書き込むことができます
  • 新たな NDEF メッセージがリーダによって書き込まれると、available()true を返します。
  • read_ndef_record_type() で書き込まれた NDEF レコードの種別を確認します
    • 注)一つの NDEF メッセージにつき、一つの NDEF レコードを想定しています
  • read_text() で NDEF Text メッセージを読み取ります

NFC 拡張 SRAM モード

NFC 拡張 SRAM モードでは、リーダが送るコマンドに対して、端末が応答します。コマンドとレスポンスは一つまたは複数のフレームで構成されます。SRAM は 64バイトの領域を持ち、これをフレームごとの転送に使用します。転送速度は速く、データを一度のセッションで打ち返すことができます。

SRAM モードの動作

SRAM モードの動作

TWELITE アプリは、以下のように定めた MWish (Mono Wireless Interactive Shell) 形式のフレームをやり取りします。

MWish フレーム

MWish フレーム

TWELITE アプリ(Android / iOS)のコマンド入力に応答する act サンプルを以下に示します。

ここでは、次のようにテキストを返すコマンド foo を実装しています。

TWELITE アプリで動作する様子

TWELITE アプリで動作する様子

  • foo -> bar
    • foo に対して bar を返します
  • foo 3 -> barbarbar
    • 引数に指定した数だけ bar を繰り返します。foo 1000 といった大容量の転送をテストできます
  • foo -u -> BAR
    • -u オプション(フラグ)により、大文字の BAR を返します
  • foo -u 3 -> BARBARBAR
    • -u オプションと引数は同時に適用できます
#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();
}
  • TWENET の初期化時に 拡張 SRAM モードは有効化されますが、begin() 内で明示的に有効化しています
  • attach_pthru_command_handler() で コマンドハンドラを処理するコールバック関数を登録できます
    • ここでは、冒頭の handle_commands() を登録しています
    • ntag::MWishCommand で与えられる c に対して ntag::MWishResponser を埋めてゆきます
    • c->is_command() でコマンド文字列(最大7文字)を照合しています
    • c->data() で引数として与えられた文字列を取得できます。ここでは strtol() で数値に変換しています
    • c->contains_flag() でオプションフラグ(最大7つ)の有無を照合できます。ここでは -u オプションを検知しています
    • r->printf() で文字列を格納できます。ここでは bar または BAR を格納しています
  • loop() 内で update_pthru() を呼び出します

NFC 全般

get_ntag_context()

NTAG 関連のコンテキストを取得します。

ntag_context

NTAG 関連の状態変数を格納しています。

名称説明
uint8_tu8_i2c_addressI2Cアドレス
boolb_wake_enabledスリープ起床の有効フラグ
uint8_tu8_latest_checksum最新のNDEFレコードのチェックサム
boolb_pthru_enabledSRAMモードの有効フラグ
_FD_STATEfd_stateタグの検出状態
_PTHRU_STATEpthru_stateSRAMモードの通信状態
void (*)()fp_fd_in_additional近接時の追加ハンドラ
void (*)()fp_fd_out_additional離脱時の追加ハンドラ

_FD_STATE

private フィールド検出の状態を表します。

  • NONE リーダなし
  • OUT リーダ離脱
  • IN リーダ近接

_PTHRU_STATE

private SRAM モードの状態を表します。

  • NOT_PRESENT リーダなし
  • RECEIVE_COMMAND コマンドの(初回)フレームを受信中
  • RECEIVE_COMMAND_EX コマンドの拡張フレームを受信中
  • SEND_RESPONSE レスポンスのフレームを送信中

enable_wakeup_source()

void enable_wakeup_source();

NFC によるスリープからの起床を有効化します。

disable_wakeup_source()

void disable_wakeup_source();

NFC によるスリープからの起床を無効化します。

check_if_wokeup_via_nfc()

static bool check_if_wokeup_via_nfc();

NFC によってスリープから起床した際は true を返します。

attach_callback_fd_in()

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

リーダに検出された際のコールバック関数を登録します。

attach_callback_fd_out()

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

リーダが離脱した際のコールバック関数を登録します。

NFC 標準 EEPROM モード

write_ndef_record()

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

任意の NDEF レコードを書き込みます。

write_uri()

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

標準の URI レコードを書き込みます。

URI_TYPE

  • NA なし
  • 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);

標準のテキストレコードを書き込みます。

write_ascii()

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

Type に A を指定した独自の NDEF 拡張形式として、アスキー文字列を書き込みます。

write_binary()

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

Type に B を指定した独自の NDEF 拡張形式として、バイナリデータを書き込みます。

get_field_detection_status()

uint8_t get_field_detection_status();

フィールド検出の状態 _FD_STATE を取得します。

available()

bool available();

メインループから呼び出します。NFC リーダが遠ざかった際に、新たな NDEF レコードを受信していたら true を返します。

read_is_ndef_record_new()

bool read_is_ndef_record_new();

新たな NDEF レコードを受信していたら true を返します。

read_ndef_record()

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

任意の NDEF レコードを読み出します。

read_ndef_record_type()

int read_ndef_record_type(char* const ndef_record_type);

任意の NDEF レコードの type を読み出します。

read_ndef_record_length()

int read_ndef_record_length(int* const ndef_record_len);

任意の NDEF レコードの長さを読み出します。

read_is_ndef_record_short()

int read_is_ndef_record_short(bool* const is_record_short);

NDEF レコードが short レコードである場合は true を返します。

read_uri()

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

標準の URI レコードを読み出します。

read_text()

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

標準のテキストレコードを読み出します。

read_ascii()

int read_ascii(char* const ascii);

Type に A を指定した独自の NDEF 拡張形式として、アスキー文字列を読み出します。

read_binary()

int read_binary(uint8_t* const binary);

Type に B を指定した独自の NDEF 拡張形式として、バイナリデータを読み出します。

NFC 拡張 SRAM モード

enable_pthru_mode()

void enable_pthru_mode();

SRAM モードを有効化します(既定は EEPROM モード)。

disable_pthru_mode()

void disable_pthru_mode();

SRAM モードを無効化します。

update_pthru()

void update_pthru();

メインループから呼び出し、SRAM モードの状態遷移を行います。

MWishCommand

Mono Wireless interactive shell command

拡張 SRAM モードで NFC リーダから送信されるコマンドデータを扱います。シングルトンのオブジェクトです。

定数

名称説明
intDATA_MAX_SIZE最大データ長 8192 バイト

メンバ変数

名称説明
const charmagic_numberマジックナンバー"ZAMA"
uint8_tmajor_versionプロトコルバージョン
uint8_tminor_versionプロトコルバージョン
uint8_tpatch_versionプロトコルバージョン
uint16_ttransaction_idトランザクションID
inttotal_data_length全データ長
chardata_typeデータ種別
uint8_tlang_id言語ID
uint16_tpinPIN
char[8]command_strコマンド文字列
char[8]flagsオプションフラグ
uint8_t* constdata読み出しデータ領域

getInstance()

static MWishCommand& getInstance();

シングルトンのオブジェクトへの参照を返します。

get_data_type()

PTHRU_DATA_TYPE get_data_type() const;

データ種別を取得します。

PTHRU_DATA_TYPE
  • RAW_STRING 文字列
  • RAW_BYTES バイナリデータ
  • PROTOBUF Protocol Buffers

is_completed()

bool is_completed() const;

すべての(分割)フレームの格納が完了していれば true を返します。

is_japanese()

bool is_japanese() const;

格納したコマンドの言語IDが 2 であり、日本語であれば true を返します。

is_command()

bool is_command(const char* const str) const;

格納したコマンド文字列が引数と一致している場合は true を返します。

contains_flag()

bool contains_flag(const char flag) const;

引数に指定したフラグ(オプション)がコマンドに含まれている場合は true を返します。

parse_new()

bool parse_new(const uint8_t* const frame);

コマンドを初期化し、新たなフレームを解釈させます。

complete_with()

bool complete_with(const uint8_t* const another_frame);

追加のフレームを渡し、データを補完します。

MWishResponse

Mono Wireless interactive shell response

拡張 SRAM モードで NFC リーダへ送信する応答データを扱います。シングルトンのオブジェクトです。

定数

名称説明
intDATA_MAX_SIZE最大データ長 8192 バイト

メンバ変数

名称説明
const MWishCommand*commandコマンド
inttotal_data_length全データ長
chardata_typeデータ種別
uint8_tlang_id言語ID
uint16_tpinPIN
intframes_serialized書き出したフレーム数
boolfinished書き出し完了ならtrue
intrestart_after応答後にリセットする際の待機時間
uint8_t* constdata書き出しデータ領域

getInstance()

static MWishResponse& getInstance();

シングルトンのオブジェクトへの参照を返します。

get_command()

const MWishCommand* const get_command() const;

応答を返す対象のコマンドへのポインタを取得します。

get_data_type()

PTHRU_DATA_TYPE get_data_type() const;

データ種別を取得します。

PTHRU_DATA_TYPE
  • A 文字列
  • B バイナリデータ
  • P Protocol Buffers

set_data_type()

void set_data_type(const PTHRU_DATA_TYPE type);

データ種別を設定します。

get_data_len()

void set_data_len(const int len);

データ長を設定します。

reset_data_len()

void reset_data_len();

データ長を初期化します。

get_data_ptr()

uint8_t* get_data_ptr() const;

データ列へのポインタを取得します。

get_data_ptr_as()

template<typename Target> Target get_data_ptr_as() const;

データ列へのポインタを指定した形式で取得します。

get_pin()

uint16_t get_pin() const;

PINを取得します。

set_pin()

void set_pin(const uint16_t code);

PINを設定します。

is_serialization_finished()

 bool is_serialization_finished() const;

データの書き出しが終わった際は true を返します。

restart_after_response()

void restart_after_response(const int warm_start_dur = -1);

応答の直後に直接スリープ状態へ移行する、または応答の直後に決められた時間の間スリープさせます。

is_restart_required()

bool is_restart_required() const;

応答後にスリープする場合は true を返します。

is_cold_restart_required()

bool is_cold_restart_required() const;

応答直後にリセットする場合は true を返します。

get_warm_restart_duration()

int get_warm_restart_duration() const;

応答後にスリープする時間をミリ秒単位で返します。

printf()

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

データ種別を文字列に設定し、指定された文字列を設定します。

prepare_for()

void prepare_for(const MWishCommand& command);

指定されたコマンドのために応答データを初期化します。

serialize()

bool serialize(uint8_t* const destination);

指定された領域に応答データを書き出します。

MWishCommandHandler

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

コマンドに対する応答の処理を登録するためのハンドラの定義です。

attach_pthru_command_handler()

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

コマンドに対する応答の処理を登録するためのハンドラを登録します(is_system = true でシステム向け)。

sys_ev_handler 関連

on_sleep()

スリープ前に利用終了の手続きを行います。

on_wakeup()

スリープ時に初期化済みの場合は、再度初期化します。再初期化が不要な場合は deinit() してからスリープしてください。