Demonstration of possible usage of the the NFCController class.

NFC SmartPoster example

Demonstration of possible usage of the the NFCController class.

The application creates a smart poster record and sends it when a connected peer requests it. The smart poster record generated contains:

  • A URI: https://www.mbed.com
  • A title: "mbed website"
  • An action: EXECUTE which asks the peer to open the URI.

Running the application

Verification of the sample application can be seen on any a smartphone with an NFC reader. After running you will be able to read the tag with an NFC tag reader application.

Information about activity is also printed over the serial connection - please have a client open. You may use:

Tera Term - https://ttssh2.osdn.jp/index.html.en

This example is known to work on boards connected to a PN512 shield.

Files at this revision

API Documentation at this revision

Comitter:
mbed_official
Date:
Mon Sep 24 17:09:42 2018 +0100
Child:
1:6c82b777db0b
Commit message:
Add mbed deploy into the SmartPoster instructions.
.
Commit copied from https://github.com/ARMmbed/mbed-os-example-nfc

Changed in this revision

.mbed Show annotated file Show diff for this revision Revisions of this file
README.md Show annotated file Show diff for this revision Revisions of this file
SmartPoster.cpp Show annotated file Show diff for this revision Revisions of this file
SmartPoster.h Show annotated file Show diff for this revision Revisions of this file
main.cpp Show annotated file Show diff for this revision Revisions of this file
mbed-os.lib Show annotated file Show diff for this revision Revisions of this file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/.mbed	Mon Sep 24 17:09:42 2018 +0100
@@ -0,0 +1,1 @@
+ROOT=.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/README.md	Mon Sep 24 17:09:42 2018 +0100
@@ -0,0 +1,49 @@
+# NFC SmartPoster example
+
+Demonstration of possible usage of the the `NFCController` class.
+
+The application creates a smart poster record and sends it when a connected peer requests it.
+The smart poster record generated contains:
+- A URI: https://www.mbed.com
+- A title: "mbed website"
+- An action: `EXECUTE` which asks the peer to open the URI.
+
+# Running the application
+
+## Requirements
+
+Verification of the sample application can be seen on any a smartphone with an NFC reader. After running you will be able to read the tag with an NFC tag reader application.
+
+Information about activity is also printed over the serial connection - please have a client open. You may use:
+
+- [Tera Term](https://ttssh2.osdn.jp/index.html.en)
+
+This example is known to work on boards connected to a PN512 shield.
+
+## Building instructions
+
+Clone the repository containing the collection of examples:
+
+```
+git clone https://github.com/ARMmbed/mbed-os-example-nfc.git
+```
+
+Using a command-line tool, navigate to the exmaple:
+
+```
+cd mbed-os-example-nfc
+cd NFC_SmartPoster
+```
+
+Update the source tree:
+
+```
+mbed deploy
+```
+
+Run the build:
+
+```
+mbed compile -t <ARM | GCC_ARM> -m <YOUR_TARGET>
+```
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/SmartPoster.cpp	Mon Sep 24 17:09:42 2018 +0100
@@ -0,0 +1,282 @@
+/* mbed Microcontroller Library
+ * Copyright (c) 2018-2018 ARM Limited
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "SmartPoster.h"
+
+#include "nfc/ndef/common/Text.h"
+#include "nfc/ndef/common/URI.h"
+#include "nfc/ndef/common/Mime.h"
+#include "nfc/ndef/MessageBuilder.h"
+#include "nfc/ndef/common/util.h"
+
+using mbed::Span;
+
+using mbed::nfc::ndef::MessageBuilder;
+using mbed::nfc::ndef::RecordType;
+using mbed::nfc::ndef::Record;
+using mbed::nfc::ndef::RecordID;
+using mbed::nfc::ndef::RecordPayload;
+using mbed::nfc::ndef::common::span_from_cstr;
+using mbed::nfc::ndef::common::Mime;
+using mbed::nfc::ndef::common::Text;
+using mbed::nfc::ndef::common::URI;
+
+namespace {
+static RecordType smart_poster_record_type()
+{
+    return RecordType(
+        RecordType::well_known_type,
+        span_from_cstr("Sp")
+    );
+}
+
+static RecordType action_record_type() {
+    return RecordType(
+        RecordType::well_known_type,
+        span_from_cstr("act")
+    );
+}
+
+static RecordType size_record_type() {
+    return RecordType(
+        RecordType::well_known_type,
+        span_from_cstr("s")
+    );
+}
+
+static RecordType type_record_type() {
+    return RecordType(
+        RecordType::well_known_type,
+        span_from_cstr("T")
+    );
+}
+
+static size_t compute_record_size(const RecordType& type, const RecordPayload& payload)
+{
+    return MessageBuilder::compute_record_size(
+        Record(
+            type,
+            payload,
+            RecordID(),
+            false,
+            false
+        )
+    );
+}
+
+} // end of anonymous namespace
+
+
+SmartPoster::SmartPoster(const URI &uri) :
+    _uri(uri),
+    _action(),
+    _resource_size(0),
+    _action_set(false),
+    _resource_size_set(false)
+{ }
+
+void SmartPoster::set_title(const Text &text)
+{
+    _title = text;
+}
+
+void SmartPoster::set_icon(const Mime &icon)
+{
+    _icon = icon;
+}
+
+void SmartPoster::set_action(action_t action)
+{
+    _action = action;
+    _action_set = true;
+}
+
+void SmartPoster::set_resource_size(uint32_t size)
+{
+    _resource_size = size;
+    _resource_size_set = true;
+}
+
+void SmartPoster::set_resource_type(Span<const uint8_t> &type)
+{
+    _type.set_text(Text::UTF8, Span<const uint8_t>(), type);
+}
+
+bool SmartPoster::append_record(MessageBuilder &ndef_builder, bool is_last_record) const
+{
+    if (_uri.get_uri_field().empty()) {
+        return false;
+    }
+
+    struct PayloadBuilder : MessageBuilder::PayloadBuilder {
+        PayloadBuilder(const SmartPoster &sp) : sp(sp) { }
+
+        virtual size_t size() const
+        {
+            return sp.get_uri_record_size() +
+                sp.get_title_record_size() +
+                sp.get_icon_record_size() +
+                sp.get_action_record_size() +
+                sp.get_resource_size_record_size() +
+                sp.get_type_record_size();
+        }
+
+        virtual void build(const Span<uint8_t> &buffer) const
+        {
+            MessageBuilder smart_poster_builder(buffer);
+            sp.append_title(smart_poster_builder);
+            sp.append_icon(smart_poster_builder);
+            sp.append_resource_size(smart_poster_builder);
+            sp.append_type(smart_poster_builder);
+            sp.append_action(smart_poster_builder);
+            sp.append_uri(smart_poster_builder);
+        }
+
+        const SmartPoster &sp;
+    };
+
+    bool result = ndef_builder.append_record(
+        smart_poster_record_type(),
+        PayloadBuilder(*this),
+        is_last_record
+    );
+    return result;
+}
+
+void SmartPoster::append_uri(MessageBuilder& builder) const
+{
+    _uri.append_as_record(builder, true);
+}
+
+size_t SmartPoster::get_uri_record_size() const
+{
+    return _uri.get_record_size();
+}
+
+void SmartPoster::append_title(MessageBuilder& builder) const
+{
+    if (_title.get_text().empty()) {
+        return;
+    }
+    _title.append_as_record(builder);
+}
+
+size_t SmartPoster::get_title_record_size() const
+{
+    if (_title.get_text().empty()) {
+        return 0;
+    }
+
+    return _title.get_record_size();
+}
+
+void SmartPoster::append_icon(MessageBuilder& builder) const
+{
+    if (_icon.get_mime_content().empty()) {
+        return;
+    }
+    _icon.append_as_record(builder);
+}
+
+size_t SmartPoster::get_icon_record_size() const
+{
+    if (_icon.get_mime_content().empty()) {
+        return 0;
+    }
+
+    return _icon.get_record_size();
+}
+
+void SmartPoster::append_action(MessageBuilder& builder) const
+{
+    if (!_action_set) {
+        return;
+    }
+
+    const uint8_t action_value[1] = { _action };
+    builder.append_record(
+        action_record_type(),
+        action_value
+    );
+}
+
+size_t SmartPoster::get_action_record_size() const
+{
+    if (!_action_set) {
+        return 0;
+    }
+
+    const uint8_t action_value[1] = { _action };
+
+    return compute_record_size(
+        action_record_type(),
+        action_value
+    );
+}
+
+void SmartPoster::append_resource_size(MessageBuilder& builder) const
+{
+    if (!_resource_size_set) {
+        return;
+    }
+
+    uint8_t value[4];
+    std::reverse_copy(&_resource_size, &_resource_size + 4, value);
+
+    builder.append_record(
+        size_record_type(),
+        value
+    );
+}
+
+size_t SmartPoster::get_resource_size_record_size() const
+{
+    if (!_resource_size_set) {
+        return 0;
+    }
+
+    uint8_t value[4];
+
+    return compute_record_size(
+        size_record_type(),
+        value
+    );
+}
+
+void SmartPoster::append_type(MessageBuilder& builder) const
+{
+    if (_type.get_text().empty()) {
+        return;
+    }
+
+    builder.append_record(
+        type_record_type(),
+        _type.get_text()
+    );
+}
+
+size_t SmartPoster::get_type_record_size() const
+{
+    if (_type.get_text().empty()) {
+        return 0;
+    }
+
+    return compute_record_size(
+        type_record_type(),
+        _type.get_text()
+    );
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/SmartPoster.h	Mon Sep 24 17:09:42 2018 +0100
@@ -0,0 +1,140 @@
+/* mbed Microcontroller Library
+ * Copyright (c) 2018-2018 ARM Limited
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef SMARTPOSTER_H_
+#define SMARTPOSTER_H_
+
+#include "nfc/ndef/common/Text.h"
+#include "nfc/ndef/common/URI.h"
+#include "nfc/ndef/common/Mime.h"
+#include "nfc/ndef/MessageBuilder.h"
+
+/**
+ * Smart poster object.
+ *
+ * A smart poster is one of the basic use case of NFC. It encapsulates a URI to
+ * a resource and meta-data of the resource.
+ *
+ * Meta-data are optional, they can be:
+ *   - title: name of the resource
+ *   - icon: image/media associated to the resource
+ *   - action: Action the peer should execute upon reception of the smart poster
+ *   - size: The size of the resource.
+ *   - type: Mime type of the resource.
+ *
+ * @note It obeys to value semantic and can be copied around.
+ */
+class SmartPoster {
+public:
+    typedef mbed::nfc::ndef::common::Mime Mime;
+    typedef mbed::nfc::ndef::common::Text Text;
+    typedef mbed::nfc::ndef::common::URI URI;
+    typedef mbed::nfc::ndef::MessageBuilder MessageBuilder;
+
+    /**
+     * Type of actions that should be executed upon smart poster reception.
+     */
+    enum action_t {
+        EXECUTE,//!< EXECUTE
+        SAVE,   //!< SAVE
+        EDIT    //!< EDIT
+    };
+
+    /**
+     * Construct a smart poster.
+     *
+     * @param uri The URI to the resource.
+     */
+    SmartPoster(const URI &uri);
+
+    /**
+     * Set the title of the resource.
+     *
+     * @param text The title of the resource to set.
+     */
+    void set_title(const Text &text);
+
+    /**
+     * Set the icon of the resource.
+     *
+     * @param icon The icon to set.
+     */
+    void set_icon(const Mime &icon);
+
+    /**
+     * Set the action to trigger upon smart poster reception.
+     *
+     * @param action The action to do upon reception.
+     */
+    void set_action(action_t action);
+
+    /**
+     * Set the size of the resource.
+     *
+     * @param size The size of the resource.
+     */
+    void set_resource_size(uint32_t size);
+
+    /**
+     * Set the type of the resource.
+     *
+     * @param resource_type The type of the resource pointed by the URI.
+     */
+    void set_resource_type(mbed::Span<const uint8_t> &resource_type);
+
+    /**
+     * Append the smart poster as a ndef record.
+     *
+     * @param ndef_builder The message builder where the record is appended.
+     * @param is_last_record Indicates if this message is the last one.
+     *
+     * @return true if the message has been appended to the builder or false
+     * otherwise.
+     */
+    bool append_record(MessageBuilder &ndef_builder, bool is_last_record) const;
+
+private:
+    void append_uri(MessageBuilder &builder) const;
+    size_t get_uri_record_size() const;
+
+    void append_title(MessageBuilder &builder) const;
+    size_t get_title_record_size() const;
+
+    void append_icon(MessageBuilder &builder) const;
+    size_t get_icon_record_size() const;
+
+    void append_action(MessageBuilder &builder) const;
+    size_t get_action_record_size() const;
+
+    void append_resource_size(MessageBuilder &builder) const;
+    size_t get_resource_size_record_size() const;
+
+    void append_type(MessageBuilder &builder) const;
+    size_t get_type_record_size() const;
+
+    URI _uri;
+    Text _title;
+    Mime _icon;
+    action_t _action;
+    uint32_t _resource_size;
+    Text _type;
+
+    bool _action_set:1;
+    bool _resource_size_set:1;
+};
+
+
+#endif /* SMARTPOSTER_H_ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/main.cpp	Mon Sep 24 17:09:42 2018 +0100
@@ -0,0 +1,193 @@
+/* mbed Microcontroller Library
+ * Copyright (c) 2018-2018 ARM Limited
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdint.h>
+
+#include "events/EventQueue.h"
+
+#include "nfc/controllers/PN512Driver.h"
+#include "nfc/controllers/PN512SPITransportDriver.h"
+#include "nfc/NFCRemoteInitiator.h"
+#include "nfc/NFCController.h"
+
+#include "nfc/ndef/MessageBuilder.h"
+#include "nfc/ndef/common/util.h"
+
+#include "SmartPoster.h"
+
+using events::EventQueue;
+
+using mbed::Span;
+using mbed::nfc::NFCRemoteInitiator;
+using mbed::nfc::NFCController;
+using mbed::nfc::nfc_rf_protocols_bitmask_t;
+using mbed::nfc::ndef::MessageBuilder;
+using mbed::nfc::ndef::common::Text;
+using mbed::nfc::ndef::common::URI;
+using mbed::nfc::ndef::common::span_from_cstr;
+
+/**
+ * Manage the NFC discovery process and the local device operating in target mode.
+ *
+ * When a remote initiator has been discovered, it connects to it then reply
+ * to its ndef message request with a smart poster message that contains:
+ *   - A URI: https://www.mbed.com
+ *   - A title: mbed website
+ *   - An action: EXECUTE which opens the browser of the peer with the URI
+ *   transmitted.
+ */
+class NFCProcess : NFCRemoteInitiator::Delegate, NFCController::Delegate {
+public:
+    /**
+     * Construct a new NFCProcess objects.
+     *
+     * This function construct the NFC controller and wires it with the PN512
+     * driver.
+     *
+     * @param queue The event queue that will be used by the NFCController.
+     */
+    NFCProcess(events::EventQueue &queue) :
+        _pn512_transport(D11, D12, D13, D10, A1, A0),
+        _pn512_driver(&_pn512_transport),
+        _queue(queue),
+        _ndef_buffer(),
+        _nfc_controller(&_pn512_driver, &queue, _ndef_buffer)
+    { }
+
+    /**
+     * Initialise and configure the NFC controller.
+     *
+     * @return NFC_OK in case of success or a meaningful error code in case of
+     * failure.
+     */
+    nfc_err_t init()
+    {
+        nfc_err_t err = _nfc_controller.initialize();
+        if (err) {
+            return err;
+        }
+
+        // register callbacks
+        _nfc_controller.set_delegate(this);
+
+        nfc_rf_protocols_bitmask_t protocols = { 0 };
+        protocols.target_iso_dep = 1;
+        return _nfc_controller.configure_rf_protocols(protocols);
+    }
+
+    /**
+     * Start the discovery of peers.
+     *
+     * @return NFC_OK in case of success or a meaningful error code in case of
+     * failure.
+     */
+    nfc_err_t start_discovery()
+    {
+        return _nfc_controller.start_discovery();
+    }
+
+private:
+    /* ------------------------------------------------------------------------
+     * Implementation of NFCRemoteInitiator::Delegate
+     */
+    virtual void on_connected()
+    {
+        printf("Connected\r\n");
+    }
+
+    virtual void on_disconnected()
+    {
+        printf("Disconnected\r\n");
+
+        // reset the state of the remote initiator
+        _nfc_remote_initiator->set_delegate(NULL);
+        _nfc_remote_initiator.reset();
+
+        // restart peer discovery
+        _nfc_controller.start_discovery();
+    }
+
+    virtual void parse_ndef_message(const Span<const uint8_t> &buffer)
+    {
+        printf("Received an ndef message of size %d\r\n", buffer.size());
+    }
+
+    virtual size_t build_ndef_message(const Span<uint8_t> &buffer)
+    {
+        printf("Building SmartPoster message\r\n");
+
+        // build the smart poster object we want to send
+        SmartPoster smart_poster(
+            URI(URI::HTTPS_WWW, span_from_cstr("mbed.com"))
+        );
+        smart_poster.set_title(
+            Text(Text::UTF8, span_from_cstr("en-US"), span_from_cstr("mbed website"))
+        );
+        smart_poster.set_action(SmartPoster::EXECUTE);
+
+        // serialize the smart poster into an ndef message operating on the
+        // buffer in input.
+        MessageBuilder builder(buffer);
+        smart_poster.append_record(builder, /* last ? */ true);
+
+        return builder.get_message().size();
+    }
+
+    /* ------------------------------------------------------------------------
+     * Implementation of NFCController::Delegate
+     */
+    virtual void on_discovery_terminated(nfc_discovery_terminated_reason_t reason)
+    {
+        printf("Discovery terminated: %u\r\n", reason);
+        if(reason != nfc_discovery_terminated_completed) {
+            _nfc_controller.start_discovery();
+        }
+    }
+
+    virtual void on_nfc_initiator_discovered(const SharedPtr<NFCRemoteInitiator> &nfc_initiator)
+    {
+        printf("Initiator discovered\r\n");
+
+        // setup the local remote initiator
+        _nfc_remote_initiator = nfc_initiator;
+        _nfc_remote_initiator->set_delegate(this);
+        _nfc_remote_initiator->connect();
+    }
+
+    mbed::nfc::PN512SPITransportDriver _pn512_transport;
+    mbed::nfc::PN512Driver _pn512_driver;
+    EventQueue& _queue;
+    uint8_t _ndef_buffer[1024];
+    NFCController _nfc_controller;
+    SharedPtr<NFCRemoteInitiator> _nfc_remote_initiator;
+};
+
+int main()
+{
+    events::EventQueue queue;
+    NFCProcess nfc_process(queue);
+
+    nfc_err_t ret = nfc_process.init();
+    printf("Initialize: ret = %u\r\n", ret);
+
+    ret = nfc_process.start_discovery();
+    printf("Start Discovery: ret = %u\r\n", ret);
+
+    queue.dispatch_forever();
+
+    return 0;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-os.lib	Mon Sep 24 17:09:42 2018 +0100
@@ -0,0 +1,1 @@
+https://github.com/ARMmbed/mbed-os/#3fb5781af180c32a6062f050d59cdf93654b3e9f