Читаем и пишем NFC Tag на MeeGo Harmattan / Хабр

Читаем и пишем NFC Tag на MeeGo Harmattan / Хабр NFC

Ndef compatible tag types

The NFC Forum has mandated the support of five different tag types to be
operable with NFC devices. The same is required on operating systems, such
as Android.

In addition to that, the MIFARE Standard specifies a way
for NDEF to work on top of the older MIFARE Standard, which may
be optionally supported by implementers.

A note about the NDEF mapping can be found here:

MIFARE Classic as NFC Type MIFARE Classic Tag.

  1. NFC Forum Type 1: This tag is based on the ISO/IEC 14443-3A
    (NFC-A). The tags are rewritable and can be
    configured to become read-only. Memory size can be between `96` bytes and
    `2` Kbytes. Communication speed is `106` kbit/s. In contrast to all other
    types, these tags have no anti-collision protection for dealing with multiple
    tags within the NFC field.
  2. NFC Forum Type 2: This tag is based on the
    ISO/IEC 14443-3A (NFC-A). The tags are rewritable and can be configured
    to become read-only. Memory size can be between `48` bytes and `2` Kbytes.
    Communication speed is `106` kbit/s.
  3. NFC Forum Type 3: This tag is based on the Japanese Industrial
    Standard (JIS) X 6319-4 (ISO/IEC 18092), commonly known as FeliCa. The tags are
    preconfigured to be either rewritable or read-only. Memory is `2` kbytes.
    Communication speed is `212` kbit/s or `424` kbit/s.
  4. NFC Forum Type 4: This tag is based on the ISO/IEC 14443-4 A/B
    (NFC A, NFC B) and thus supports either NFC-A or NFC-B
    for communication. On top of that the tag may optionally support ISO-DEP
    (Data Exchange Protocol defined in ISO/IEC 14443 (ISO/IEC 14443-4:2008
    Part 4: Transmission protocol). The tags are preconfigured
    to be either rewritable or read-only. Variable memory, up to `32` kbytes.
    Supports three different communication speeds `106` or `212` or
    `424` kbit/s.
  5. NFC Forum Type 5: This tag is based on ISO/IEC 15693 (NFC-V) and
    allows reading and writing an NDEF message on an ISO/IEC 15693 RF tag
    that is accessible by long range RFID readers as well. The NFC communication
    is limited to short distance and may use the Active Communication Mode of
    ISO/IEC 18092 where the sending peer generates the field which balances
    power consumption and improves link stability. Variable memory, up to `64` kbytes.
    Communication speed is `26.48` kbit/s.
  6. MIFARE Standard: This tag, often sold under the brand names MIFARE
    Classic or MIFARE Mini, is based on the ISO/IEC 14443-3A (also known as NFC-A,
    as defined in ISO/IEC 14443-3:2021, Part 3: Initialization and anticollision).
    The tags are rewritable and can be configured to become read-only. Memory size
    can be between `320` and `4` kbytes. Communication speed is `106` kbit/s.

    MIFARE Standard is not an NFC Forum type and can only be read by devices
    using NXP hardware. Support for reading and writing to tags based on the
    MIFARE Standard is thus non-nominative, but the type is included
    due to the popularity and use in legacy systems.

In addition to data types standardized for NDEF records by the NFC
Forum, many commercial products such as bus cards, door openers may be based
on the MIFARE Standard which requires specific NFC chips (same vendor of
card and reader) in order to function.

Read and write a mime type record #

The mediaType property of a MIME type record represents the MIME type of the NDEF record payload so that data can be properly decoded. For instance, use JSON.parse to decode JSON text and an Image element to decode image data.

functionreadMimeRecord(record){
console.assert(record.recordType ==="mime");
if(record.mediaType ==="application/json"){
const textDecoder =newTextDecoder();
console.log(`JSON: ${JSON.parse(decoder.decode(record.data))}`);
}
elseif(record.mediaType.startsWith('image/')){
const blob =newBlob([record.data],{ type: record.mediaType });
const img =newImage();
img.src =URL.createObjectURL(blob);
document.body.appendChild(img);
}
else{
// TODO: Handle other MIME types.
}
}

To write a MIME type record, pass an NDEF message dictionary to the NDEFReader write() method. The MIME type record contained in the NDEF message is defined as an object with a recordType key set to «mime», a mediaType key set to the actual MIME type of the content, and a data key set to an object that can be either an ArrayBuffer or provides a view on to an ArrayBuffer (e.g. Uint8Array, DataView).

const encoder =newTextEncoder();
const data ={
firstname:"François",
lastname:"Beaufort"
};
const jsonRecord ={
recordType:"mime",
mediaType:"application/json",
data: encoder.encode(JSON.stringify(data))
};

const imageRecord ={
recordType:"mime",
mediaType:"image/png",
data:await(awaitfetch("icon1.png")).arrayBuffer()
};

const ndef =newNDEFReader();
await ndef.write({ records:[jsonRecord, imageRecord]});

Read and write a smart poster record #

A smart poster record (used in magazine advertisements, fliers, billboards, etc.), describes some web content as an NDEF record that contains an NDEF message as its payload. Call record.toRecords() to transform data to a list of records contained in the smart poster record.

Проблемы NFC:  NFC | Sony Xperia X

It should have a URL record, a text record for the title, a MIME type record for the image, and some custom local type records such as «:t», «:act», and «:s» respectively for the type, action, and size of the smart poster record.

Local type records are unique only within the local context of the containing NDEF record. Use them when the meaning of the types doesn’t matter outside of the local context of the containing record and when storage usage is a hard constraint. Local type record names always start with :

functionreadSmartPosterRecord(smartPosterRecord){
console.assert(record.recordType ==="smart-poster");
let action, text, url;

for(const record of smartPosterRecord.toRecords()){
if(record.recordType =="text"){
const decoder =newTextDecoder(record.encoding);
text = decoder.decode(record.data);
}elseif(record.recordType =="url"){
const decoder =newTextDecoder();
url = decoder.decode(record.data);
}elseif(record.recordType ==":act"){
action = record.data.getUint8(0);
}else{
// TODO: Handle other type of records such as `:t`, `:s`.
}
}

switch(action){
case0:
// Do the action
break;
case1:
// Save for later
break;
case2:
// Open for editing
break;
}
}

To write a smart poster record, pass an NDEF message to the NDEFReader write() method. The smart poster record contained in the NDEF message is defined as an object with a recordType key set to «smart-poster» and a data key set to an object that represents (once again) an NDEF message contained in the smart poster record.

Read and write a text record #

The text record data can be decoded with a TextDecoder instantiated with the record encoding property. Note that the language of the text record is available through its lang property.

functionreadTextRecord(record){
console.assert(record.recordType ==="text");
const textDecoder =newTextDecoder(record.encoding);
console.log(`Text: ${textDecoder.decode(record.data)} (${record.lang})`);
}

To write a simple text record, pass a string to the NDEFReader write() method.

const ndef =newNDEFReader();
await ndef.write("Hello World");

The makereadonly() method

The

NDEFReader.makeReadOnly

method, when invoked, MUST run the

make an NFC tag permanently read-only

algorithm:

  1. Let |p:Promise| be a new {{Promise}} object.
  2. If not currently executing in the currently active top-level
    browsing context
    , then reject |p| with and
    {{«InvalidStateError»}} {{DOMException}} and return |p|.
  3. Let |options:NDEFMakeReadOnlyOptions| be the second argument.
  4. Let |signal:AbortSignal| be the |options|’ dictionary member
    of the same name if present, or `null` otherwise.
  5. If |signal| is [= AbortSignal/aborted =], then reject |p|
    with |signal|’s [=AbortSignal/abort reason=] and return |p|.
  6. If |signal| is not `null`, then

    add the following abort steps
    to |signal|:
    1. Run the abort a pending make read-only operation on the
      environment settings object.
  7. [=promise/React=] to |p|:
    1. If |p| was settled (fulfilled or rejected), then clear the
      pending write tuple if it exists.
  8. Return |p| and run the following steps in parallel:
    1. If the obtain permission steps return `false`, then
      reject |p| with a {{«NotAllowedError»}} {{DOMException}} and
      abort these steps.
    2. If there is no underlying NFC Adapter, or if a connection
      cannot be established, then reject |p| with a
      {{«NotSupportedError»}} {{DOMException}}
      and abort these steps.
    3. If the UA is not allowed to access the underlying NFC Adapter
      (e.g. a user preference), then reject |p| with a
      {{«NotReadableError»}} {{DOMException}}
      and abort these steps.
    4. An implementation MAY reject |p| with
      a {{«NotSupportedError»}} {{DOMException}}
      and abort these steps.

      The UA might abort at this point. The reasons for termination
      are implementation details. For example, the implementation
      might be unable to support the requested operation.

    5. Attempt to abort a pending make read-only operation.

      A make read-only operation replaces all previously configured
      make read-only operations.

    6. Set pending makeReadOnly tuple to (`this`, |p|).
    7. Run the start the NFC make read-only steps whenever an
      NFC tag |device| comes within communication range.

      If NFC is suspended, continue waiting until promise is
      aborted by the user or an NFC tag comes within
      communication range.

Проблемы NFC:  Выбор чехла для защиты банковских карт от бесконтактной кражи денег / Подборки товаров с Aliexpress и не только / iXBT Live

The nfc standard

NFC is standardized in the NFC Forum and described in [[NFC-STANDARDS]].

Ndef compatible tag types

The NFC Forum has mandated the support of five different tag types to be
operable with NFC devices. The same is required on operating systems, such
as Android.

In addition to that, the MIFARE Standard specifies a way
for NDEF to work on top of the older MIFARE Standard, which may
be optionally supported by implementers.

A note about the NDEF mapping can be found here:

MIFARE Classic as NFC Type MIFARE Classic Tag
.

  1. NFC Forum Type 1: This tag is based on the ISO/IEC 14443-3A
    (NFC-A). The tags are rewritable and can be
    configured to become read-only. Memory size can be between `96` bytes and
    `2` Kbytes. Communication speed is `106` kbit/s. In contrast to all other
    types, these tags have no anti-collision protection for dealing with multiple
    tags within the NFC field.
  2. NFC Forum Type 2: This tag is based on the
    ISO/IEC 14443-3A (NFC-A). The tags are rewritable and can be configured
    to become read-only. Memory size can be between `48` bytes and `2` Kbytes.
    Communication speed is `106` kbit/s.
  3. NFC Forum Type 3: This tag is based on the Japanese Industrial
    Standard (JIS) X 6319-4 (ISO/IEC 18092), commonly known as FeliCa. The tags are
    preconfigured to be either rewritable or read-only. Memory is `2` kbytes.
    Communication speed is `212` kbit/s or `424` kbit/s.
  4. NFC Forum Type 4: This tag is based on the ISO/IEC 14443-4 A/B
    (NFC A, NFC B) and thus supports either NFC-A or NFC-B
    for communication. On top of that the tag may optionally support ISO-DEP
    (Data Exchange Protocol defined in ISO/IEC 14443 (ISO/IEC 14443-4:2008
    Part 4: Transmission protocol). The tags are preconfigured
    to be either rewritable or read-only. Variable memory, up to `32` kbytes.
    Supports three different communication speeds `106` or `212` or
    `424` kbit/s.
  5. NFC Forum Type 5: This tag is based on ISO/IEC 15693 (NFC-V) and
    allows reading and writing an NDEF message on an ISO/IEC 15693 RF tag
    that is accessible by long range RFID readers as well. The NFC communication
    is limited to short distance and may use the Active Communication Mode of
    ISO/IEC 18092 where the sending peer generates the field which balances
    power consumption and improves link stability. Variable memory, up to `64` kbytes.
    Communication speed is `26.48` kbit/s.
  6. MIFARE Standard: This tag, often sold under the brand names MIFARE
    Classic or MIFARE Mini, is based on the ISO/IEC 14443-3A (also known as NFC-A,
    as defined in ISO/IEC 14443-3:2021, Part 3: Initialization and anticollision).
    The tags are rewritable and can be configured to become read-only. Memory size
    can be between `320` and `4` kbytes. Communication speed is `106` kbit/s.

    MIFARE Standard is not an NFC Forum type and can only be read by devices
    using NXP hardware. Support for reading and writing to tags based on the
    MIFARE Standard is thus non-nominative, but the type is included
    due to the popularity and use in legacy systems.

In addition to data types standardized for NDEF records by the NFC
Forum, many commercial products such as bus cards, door openers may be based
on the MIFARE Standard which requires specific NFC chips (same vendor of
card and reader) in order to function.

The write() method

The

NDEFReader.write

method, when invoked, MUST run the

write a message

algorithm:

  1. Let |p:Promise| be a new {{Promise}} object.
  2. If not currently executing in the currently active top-level
    browsing context
    , then reject |p| with and
    {{«InvalidStateError»}} {{DOMException}} and return |p|.
  3. Let |message:NDEFMessageSource| be the first argument.
  4. Let |options:NDEFWriteOptions| be the second argument.
  5. Let |signal:AbortSignal| be the |options|’ dictionary member
    of the same name if present, or `null` otherwise.
  6. If |signal| is [= AbortSignal/aborted =], then reject |p|
    with |signal|’s [=AbortSignal/abort reason=] and return |p|.
  7. If |signal| is not `null`, then

    add the following abort steps
    to |signal|:
    1. Run the abort a pending write operation on the
      environment settings object.
  8. [=promise/React=] to |p|:
    1. If |p| was settled (fulfilled or rejected), then clear the
      pending write tuple if it exists.
  9. Return |p| and run the following steps in parallel:
    1. If the obtain permission steps return `false`, then
      reject |p| with a {{«NotAllowedError»}} {{DOMException}} and
      abort these steps.
    2. If there is no underlying NFC Adapter, or if a connection
      cannot be established, then reject |p| with a
      {{«NotSupportedError»}} {{DOMException}}
      and abort these steps.
    3. If the UA is not allowed to access the underlying NFC Adapter
      (e.g. a user preference), then reject |p| with a
      {{«NotReadableError»}} {{DOMException}}
      and abort these steps.
    4. If pushing data is not supported by the underlying
      NFC Adapter, then reject |p| with a {{«NotSupportedError»}}
      {{DOMException}} and abort these steps.
    5. An implementation MAY reject |p| with
      a {{«NotSupportedError»}} {{DOMException}}
      and abort these steps.

      The UA might abort message write at this point. The reasons
      for termination are implementation details. For example, the
      implementation might be unable to support the requested
      operation.

    6. Let |output| be the notation for the NDEF message
      to be created by UA, as the result of invoking
      create NDEF message with |message|, `»»`, and `0`.
      If this throws an exception, reject |p| with that
      exception and abort these steps.
    7. Attempt to abort a pending write operation.

      A write replaces all previously configured write operations.

    8. Set `this`.[[WriteOptions]] to |options|.
    9. Set `this`.[[WriteMessage]] to |output|.
    10. Set pending write tuple to (`this`, |p|).
    11. Run the start the NFC write steps whenever an
      NFC tag |device| comes within communication range.

      If NFC is suspended, continue waiting until promise is
      aborted by the user or an NFC tag comes within
      communication range.

Проблемы NFC:  Poco X3 Pro vs Poco X3 NFC - различия. Что лучше выбрать?

To

start the NFC write

, run these steps:

  1. Let |p:Promise| be the pending write tuple‘s promise.
  2. Let |writer| be the pending write tuple‘s writer.
  3. Let |options:NDEFWriteOptions| be |writer|.[[WriteOptions]].
  4. If the NFC tag in proximity range does not expose
    NDEF technology for formatting or writing, then
    reject |p| with a {{«NotSupportedError»}} {{DOMException}} and
    return |p|.
  5. Verify that NFC is not suspended.
  6. In case of success, run the following steps:
    1. If |device| is an NFC tag and if |options|’s overwrite is
      `false`, read the tag to check whether there are NDEF
      records on the tag. If yes, then reject |p| with a
      {{«NotAllowedError»}} {{DOMException}} and return |p|.
    2. Let |output:NDEFMessage| be |writer|.[[WriteMessage]].
    3. Initiate data transfer to |device| using
      |output| as buffer, using the NFC adapter
      in communication range with |device|.

      If the NFC tag in proximity range is unformatted and
      NDEF-formatable, format it and write |output| as
      buffer.

      Multiple adapters should be used sequentially by users.
      There is very little likelihood that a simultaneous tap
      will happen on two or multiple different and connected
      NFC adapters.
      If it happens, the user will likely need to repeat the
      taps until success, preferably one device at a time.
      The error here gives an indication that the operation
      needs to be repeated. Otherwise the user may think the
      operation succeeded on all connected NFC adapters.

    4. If the transfer fails, reject |p| with
      {{«NetworkError»}} {{DOMException}}
      and abort these steps.
    5. When the transfer has completed, resolve |p|.

Чтение

Теперь рассмотрим методы чтения тега:

void NfcManager::readTarget(QNearFieldTarget *target)
{
    connect(target, SIGNAL(error(QNearFieldTarget::Error,QNearFieldTarget::RequestId)), this, SLOT(errorHandler(QNearFieldTarget::Error,QNearFieldTarget::RequestId)));
    connect(target, SIGNAL(ndefMessageRead(QNdefMessage)), this, SLOT(readRecords(QNdefMessage)));
    target->readNdefMessages();

}


Чтение происходит в асинхронном режиме, поэтому в данном методе мы просто подключаем сигнал обработки ошибок и сигнал завершения чтения, который вызовется только в случае, если чтение произошло без ошибок.

После этого мы просто вызываем метод для чтения:

void NfcManager::readRecords(const QNdefMessage &message)
{
    if (message.isEmpty())
        return;

    QNdefRecord record = message.at(0); // Read only first
    readRecord(record);
}

Если чтение прошло успешно, то мы попадем в данный слот, где получим первую запись из списка присутсвующих на теге записей.


Да-да, по спецификации на теге может быть несколько записей, но как говорит документация, для

SymbianHarmattan

доступно чтение и запись только одной записи.

void NfcManager::readRecord(const QtMobility::QNdefRecord &record)
{
    DataContainer *result = 0;

    if (record.isRecordType<QNdefNfcUriRecord>()) {
        QNdefNfcUriRecord uriRecord(record);
        result = new UriDataContainer(uriRecord.payload(), uriRecord.uri().toString());
    }
    else if (record.isRecordType<QNdefNfcTextRecord>()) {
        QNdefNfcTextRecord textRecord(record);
        result = new TextDataContainer(textRecord.payload(), textRecord.text());
    }
    else if (record.isRecordType<NdefNfcSmartPosterRecord>()) {
        NdefNfcSmartPosterRecord smartPosterRecord(record);
        result = new SmartPosterDataContainer(smartPosterRecord.payload(), smartPosterRecord.uri().toString(), smartPosterRecord.title());
    }
    else {
        result = new DataContainer(record.payload());
    }

    emit tagReadFinished(result);
}

И вот, после нескольких переходов по вспомогательным методам мы добрались до самого главного метода, который превращает информацию закодированную в теги в привычные нам буквы.

На данный момент

Qt Mobility

из коробки поддерживает только два вида записей это ссылки (

Uri

) и текст (

Text

), к третьему типу —

Smart Poster

мы еще вернемся ниже.


Как можно заметить данные из записи сразу помещаются в некий новый объект, это простые объекты, которые я специально создал для облегчения передачи данных в

QML

В конце вызывается сигнал, содержащий объект с данными. В дальнейшем мы будем ловить этот сигнал в QML.

Оцените статью
NFC в смартфонах
Добавить комментарий