mirror of https://github.com/ARMmbed/mbed-os.git
Simple commit wo history, review rework done, internal docs removed
parent
51b8d6e59d
commit
aa1e9acdb1
|
@ -0,0 +1,220 @@
|
|||
/* 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;
|
||||
|
||||
// todo: this class probably needs to be in the nfc module itself
|
||||
|
||||
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());
|
||||
}
|
||||
|
|
@ -0,0 +1,139 @@
|
|||
/* 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_ */
|
|
@ -0,0 +1,150 @@
|
|||
/*
|
||||
* Copyright (c) 2018 ARM Limited. All rights reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
* 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 <stdio.h>
|
||||
#include <stdarg.h>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <stdlib.h>
|
||||
#include "mbed.h"
|
||||
#include "mbed_events.h"
|
||||
#include "mbed-client-cli/ns_cmdline.h"
|
||||
#include "NFCEEPROMDriver.h"
|
||||
#include "nfctestshim.h"
|
||||
#include "nfccommands.h"
|
||||
#include "smartposter.h"
|
||||
|
||||
#if MBED_CONF_NFCEEPROM
|
||||
using mbed::nfc::NFCEEPROM;
|
||||
using mbed::nfc::NFCEEPROMDriver;
|
||||
#else
|
||||
#ifndef TARGET_PN512
|
||||
#warning [NOT_SUPPORTED] NFC not supported for this target
|
||||
#endif
|
||||
|
||||
#include "nfc/controllers/PN512Driver.h"
|
||||
#include "nfc/controllers/PN512SPITransportDriver.h"
|
||||
|
||||
#include "nfc/NFCRemoteInitiator.h"
|
||||
#include "nfc/NFCController.h"
|
||||
|
||||
using mbed::nfc::NFCRemoteInitiator;
|
||||
using mbed::nfc::NFCController;
|
||||
using mbed::nfc::nfc_rf_protocols_bitmask_t;
|
||||
#endif // MBED_CONF_NFCEEPROM
|
||||
|
||||
using mbed::Span;
|
||||
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;
|
||||
|
||||
|
||||
void wrap_printf(const char *f, va_list a) {
|
||||
vprintf(f, a);
|
||||
}
|
||||
|
||||
const char *errorcodes = // descriptions from nfc/stack/nfc_errors.h
|
||||
" 0 NFC_OK \n"
|
||||
" 1 NFC_ERR_UNKNOWN\n"
|
||||
" 2 NFC_ERR_LENGTH \n"
|
||||
" 3 NFC_ERR_NOT_FOUND\n"
|
||||
" 4 NFC_ERR_UNSUPPORTED\n"
|
||||
" 5 NFC_ERR_PARAMS \n"
|
||||
" 6 NFC_ERR_BUFFER_TOO_SMALL\n"
|
||||
" 7 NFC_ERR_TIMEOUT\n"
|
||||
" 8 NFC_ERR_CRC\n"
|
||||
" 9 NFC_ERR_NOPEER \n"
|
||||
"10 NFC_ERR_PARITY \n"
|
||||
"11 NFC_ERR_FIELD\n"
|
||||
"12 NFC_ERR_COLLISION\n"
|
||||
"13 NFC_ERR_WRONG_COMM \n"
|
||||
"14 NFC_ERR_PROTOCOL \n"
|
||||
"15 NFC_ERR_BUSY \n"
|
||||
"16 NFC_ERR_CONTROLLER \n"
|
||||
"17 NFC_ERR_HALTED \n"
|
||||
"18 NFC_ERR_MAC\n"
|
||||
"19 NFC_ERR_UNDERFLOW\n"
|
||||
"20 NFC_ERR_DISCONNECTED \n"
|
||||
"21 NFC_ERR_ABORTED\n";
|
||||
|
||||
// for easy manual UI interaction
|
||||
int seteasy(int argc, char *argv[]) {
|
||||
const char msg[][20] =
|
||||
{ "echo off", "set --retcode true", "set --vt100 off" };
|
||||
for (size_t i = 0; i < (sizeof(msg) / sizeof(msg[0])); i++) {
|
||||
cmd_exe((char*) msg[i]);
|
||||
}
|
||||
return (CMDLINE_RETCODE_SUCCESS);
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
cmd_init(&wrap_printf);
|
||||
cmd_add("getlastnfcerror", HandleTestCommand::cmd_get_last_nfc_error,
|
||||
"last NFC error code", errorcodes);
|
||||
cmd_add("setlastnfcerror", HandleTestCommand::cmd_set_last_nfc_error,
|
||||
"self-test", "for self-test only");
|
||||
cmd_add("initnfc", HandleTestCommand::cmd_init_nfc, "init NFC driver",
|
||||
"call first");
|
||||
cmd_add("init", HandleTestCommand::cmd_init_nfc, "alias initnfc",
|
||||
"call first");
|
||||
cmd_add("setsmartposter", HandleTestCommand::cmd_set_smartposter,
|
||||
"send smartposter NDEF", "<uri>");
|
||||
cmd_add("iseeprom", HandleTestCommand::cmd_get_conf_nfceeprom,
|
||||
"get NFC configEEPROM present",
|
||||
"true if config exists, else false");
|
||||
cmd_add("readmessage", HandleTestCommand::cmd_read_message,
|
||||
"read EEPROM else return last message", "returns hex dump");
|
||||
cmd_add("read", HandleTestCommand::cmd_read_message, "alias readmessage",
|
||||
"returns hex dump");
|
||||
cmd_add("erase", HandleTestCommand::cmd_erase,
|
||||
"erase EEPROM or clear last message", "erase entire flash/buffer");
|
||||
cmd_add("writelong", HandleTestCommand::cmd_write_long_ndef_message,
|
||||
"fill T NDEF with pattern up to <length>",
|
||||
"writelong <length> [messagetorepeat='thequickbrownfoxisadog']");
|
||||
cmd_add("start", HandleTestCommand::cmd_start_discovery,
|
||||
"start discovery [auto=autorestart|man=manual]",
|
||||
"loop restarts by default, man to disable");
|
||||
cmd_add("stop", HandleTestCommand::cmd_stop_discovery, "stop discovery",
|
||||
"[wait=0] with optional wait for session end");
|
||||
|
||||
cmd_add("getprotocols", HandleTestCommand::cmd_get_supported_rf_protocols,
|
||||
"get supported protocols", "returns CSV list, see setprotocols");
|
||||
cmd_add("setprotocols", HandleTestCommand::cmd_configure_rf_protocols,
|
||||
"set rf protocols", "-p [t1t]/[t2t]/[t3t]/[isodep]/[nfcdep]/[t5t]");
|
||||
cmd_add("easy", seteasy, "Use human readable terminal output",
|
||||
"echo off,vt100 off,return-codes visible");
|
||||
|
||||
#if MBED_CONF_NFCEEPROM
|
||||
cmd_printf("MBED NFC EEPROM defined\r\n");
|
||||
#else
|
||||
cmd_printf("MBED NFC Controller tests\r\n");
|
||||
#endif
|
||||
|
||||
#ifdef TARGET_M24SR
|
||||
cmd_printf("Using driver:M24SR\r\n");
|
||||
#endif
|
||||
#ifdef TARGET_PN512
|
||||
cmd_printf("Using driver:PN512\r\n");
|
||||
#endif
|
||||
|
||||
int c;
|
||||
HandleTestCommand handleCommands; // starts handling nfc messages
|
||||
while ((c = getc(stdin)) != EOF) {
|
||||
cmd_char_input(c);
|
||||
}
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
{
|
||||
"target_overrides": {
|
||||
"DISCO_L475VG_IOT01A": {
|
||||
"target.extra_labels_add": ["M24SR"],
|
||||
"MBED_NFC_M24SR.nfceeprom": true
|
||||
},
|
||||
"NUCLEO_F401RE": {
|
||||
"target.extra_labels_add": ["PN512"]
|
||||
},
|
||||
"NUCLEO_F746ZG": {
|
||||
"target.extra_labels_add": ["M24SR"],
|
||||
"MBED_NFC_M24SR.X_NUCLEO_NFC01A1": true,
|
||||
"MBED_NFC_M24SR.nfceeprom": true
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,231 @@
|
|||
/*
|
||||
* Copyright (c) 2018 ARM Limited. All rights reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
* 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 <string>
|
||||
#include <vector>
|
||||
#include <stdlib.h>
|
||||
#include "mbed.h"
|
||||
#include "mbed_events.h"
|
||||
#include "mbed-client-cli/ns_cmdline.h"
|
||||
#include "rtos\Thread.h"
|
||||
|
||||
#include "nfctestshim.h"
|
||||
|
||||
#include "nfccommands.h"
|
||||
|
||||
events::EventQueue nfcQueue;
|
||||
Thread nfcThread;
|
||||
NFCTestShim * pNFC_Test_Shim = NULL;
|
||||
|
||||
NFCTestShim* new_testshim() {
|
||||
#if MBED_CONF_NFCEEPROM
|
||||
mbed::nfc::NFCEEPROMDriver& eeprom_driver = get_eeprom_driver(nfcQueue);
|
||||
|
||||
return ( (NFCTestShim *)(new NFCProcessEEPROM(nfcQueue, eeprom_driver)) );
|
||||
#else
|
||||
return ((NFCTestShim *) (new NFCProcessController(nfcQueue)));
|
||||
#endif // EEPROM
|
||||
|
||||
}
|
||||
|
||||
void nfcRoutine() {
|
||||
nfcQueue.dispatch_forever();
|
||||
}
|
||||
|
||||
HandleTestCommand::HandleTestCommand() {
|
||||
osStatus status = nfcThread.start(callback(&nfcRoutine));
|
||||
MBED_ASSERT(status == osOK);
|
||||
}
|
||||
|
||||
int HandleTestCommand::cmd_set_last_nfc_error(int argc, char *argv[]) {
|
||||
if (argc <= 1) {
|
||||
cmd_printf("setlastnfcerror() invalid parameter(s)\r\n");
|
||||
return (CMDLINE_RETCODE_INVALID_PARAMETERS);
|
||||
} else {
|
||||
int value = strtol(argv[1], NULL, 10);
|
||||
nfcQueue.call(NFCTestShim::cmd_set_last_nfc_error, value);
|
||||
}
|
||||
return (CMDLINE_RETCODE_EXCUTING_CONTINUE);
|
||||
}
|
||||
|
||||
int HandleTestCommand::cmd_init_nfc(int argc, char *argv[]) {
|
||||
|
||||
if (pNFC_Test_Shim) {
|
||||
cmd_printf("WARN init called again!\r\n"); // only legal here, if eeprom driver stops talking
|
||||
} else {
|
||||
pNFC_Test_Shim = new_testshim();
|
||||
}
|
||||
nfcQueue.call(pNFC_Test_Shim, &NFCTestShim::cmd_init);
|
||||
return (CMDLINE_RETCODE_EXCUTING_CONTINUE);
|
||||
}
|
||||
|
||||
int HandleTestCommand::cmd_read_message(int argc, char *argv[]) {
|
||||
nfcQueue.call(pNFC_Test_Shim, &NFCTestShim::cmd_read_nfceeprom);
|
||||
|
||||
return (CMDLINE_RETCODE_EXCUTING_CONTINUE);
|
||||
}
|
||||
|
||||
int HandleTestCommand::cmd_set_smartposter(int argc, char *argv[]) {
|
||||
if (argc <= 1) {
|
||||
cmd_printf("setlastnfcerror() invalid parameter(s)\r\n");
|
||||
return (CMDLINE_RETCODE_INVALID_PARAMETERS);
|
||||
} else {
|
||||
// parse arg and queue it up
|
||||
char * uri = (char*) malloc(strlen(argv[1]) + 1);
|
||||
if (uri) {
|
||||
strcpy(uri, argv[1]);
|
||||
nfcQueue.call(pNFC_Test_Shim, &NFCTestShim::cmd_set_smartposter,
|
||||
uri); // called thread must free
|
||||
}
|
||||
else {
|
||||
cmd_printf("WARN out of memory!\r\n");
|
||||
return (CMDLINE_RETCODE_FAIL);
|
||||
}
|
||||
}
|
||||
return (CMDLINE_RETCODE_EXCUTING_CONTINUE);
|
||||
}
|
||||
|
||||
// todo: jira IOTPAN-295
|
||||
int HandleTestCommand::cmd_erase(int argc, char *argv[]) {
|
||||
nfcQueue.call(pNFC_Test_Shim, &NFCTestShim::cmd_erase);
|
||||
return (CMDLINE_RETCODE_EXCUTING_CONTINUE);
|
||||
}
|
||||
|
||||
int HandleTestCommand::cmd_write_long_ndef_message(int argc, char *argv[]) {
|
||||
size_t length, idx, sourceLength;
|
||||
static const char alphabet[] = "thequickbrownfoxjumpedoverthelazydog";
|
||||
char *data;
|
||||
const char *sourceMessage;
|
||||
|
||||
// expect 2 or 3 args "<cmd> <length> [optional-text]"
|
||||
if (argc < 2) {
|
||||
cmd_printf("supply length of message\r\n");
|
||||
return (CMDLINE_RETCODE_INVALID_PARAMETERS);
|
||||
}
|
||||
|
||||
int converted = sscanf(argv[1], "%d", &length);
|
||||
if (1 != converted) {
|
||||
cmd_printf("Cannot convert value to int\r\n");
|
||||
return (CMDLINE_RETCODE_INVALID_PARAMETERS);
|
||||
}
|
||||
data = (char*) malloc(length + 1);
|
||||
if (!data) {
|
||||
cmd_printf("WARN out of memory!\r\n");
|
||||
return (CMDLINE_RETCODE_FAIL);
|
||||
}
|
||||
if (argc > 2) {
|
||||
// user provided text to copy into text NDEF record
|
||||
sourceMessage = argv[2];
|
||||
} else {
|
||||
// use our internal default message to copy into the text NDEF
|
||||
sourceMessage = alphabet;
|
||||
}
|
||||
sourceLength = strlen(sourceMessage);
|
||||
for (idx = 0; idx < length; idx++) {
|
||||
data[idx] = sourceMessage[idx % sourceLength];
|
||||
}
|
||||
data[length] = '\0';
|
||||
|
||||
// method must release buffer
|
||||
nfcQueue.call(pNFC_Test_Shim, &NFCTestShim::cmd_write_long, data);
|
||||
return (CMDLINE_RETCODE_EXCUTING_CONTINUE);
|
||||
}
|
||||
|
||||
int HandleTestCommand::cmd_start_discovery(int argc, char *argv[]) {
|
||||
if ((argc > 1) && (0 == strcmp(argv[1], "man"))) {
|
||||
cmd_printf("User must restart discovery manually()\r\n");
|
||||
nfcQueue.call(pNFC_Test_Shim, &NFCTestShim::cmd_start_discovery, false);
|
||||
} else {
|
||||
cmd_printf("App will restart discovery loop on auto()\r\n");
|
||||
nfcQueue.call(pNFC_Test_Shim, &NFCTestShim::cmd_start_discovery, true);
|
||||
}
|
||||
return (CMDLINE_RETCODE_EXCUTING_CONTINUE);
|
||||
}
|
||||
|
||||
int HandleTestCommand::cmd_stop_discovery(int argc, char *argv[]) {
|
||||
nfcQueue.call(pNFC_Test_Shim, &NFCTestShim::cmd_stop_discovery);
|
||||
return (CMDLINE_RETCODE_EXCUTING_CONTINUE);
|
||||
}
|
||||
|
||||
int HandleTestCommand::cmd_get_supported_rf_protocols(int argc, char *argv[]) {
|
||||
nfcQueue.call(pNFC_Test_Shim, &NFCTestShim::cmd_get_rf_protocols);
|
||||
return (CMDLINE_RETCODE_EXCUTING_CONTINUE);
|
||||
}
|
||||
|
||||
bool HandleTestCommand::set_protocol_target(
|
||||
nfc_rf_protocols_bitmask_t & bitmask, const char *protocolName) {
|
||||
bool parsed = false;
|
||||
if (0 == strcmp(protocolName, "t1t")) {
|
||||
parsed = bitmask.target_t1t = true;
|
||||
}
|
||||
if (0 == strcmp(protocolName, "t2t")) {
|
||||
parsed = bitmask.target_t2t = true;
|
||||
}
|
||||
if (0 == strcmp(protocolName, "t3t")) {
|
||||
parsed = bitmask.target_t3t = true;
|
||||
}
|
||||
if (0 == strcmp(protocolName, "t5t")) {
|
||||
parsed = bitmask.target_t5t = true;
|
||||
}
|
||||
if (0 == strcmp(protocolName, "isodep")) {
|
||||
parsed = bitmask.target_iso_dep = true;
|
||||
}
|
||||
if (0 == strcmp(protocolName, "nfcdep")) {
|
||||
parsed = bitmask.target_nfc_dep = true;
|
||||
}
|
||||
return (parsed);
|
||||
}
|
||||
|
||||
int HandleTestCommand::cmd_configure_rf_protocols(int argc, char *argv[]) {
|
||||
nfc_rf_protocols_bitmask_t protocols = { 0 };
|
||||
|
||||
int argindex = argc;
|
||||
while (argindex > 1) {
|
||||
if (!set_protocol_target(protocols, argv[argindex - 1])) {
|
||||
cmd_printf("Unknown protocol %s", argv[argindex - 1]);
|
||||
return (CMDLINE_RETCODE_INVALID_PARAMETERS);
|
||||
}
|
||||
argindex--;
|
||||
}
|
||||
nfcQueue.call(pNFC_Test_Shim, &NFCTestShim::cmd_configure_rf_protocols,
|
||||
protocols);
|
||||
return (CMDLINE_RETCODE_EXCUTING_CONTINUE);
|
||||
}
|
||||
|
||||
// todo: implement
|
||||
int cmd_start_stop_discovery_wait_tag(int argc, char *argv[]) {
|
||||
|
||||
return (CMDLINE_RETCODE_COMMAND_NOT_IMPLEMENTED);
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////
|
||||
// boilerplate only
|
||||
|
||||
int cmd_is_iso7816_supported(int argc, char *argv[]) {
|
||||
return (CMDLINE_RETCODE_COMMAND_NOT_IMPLEMENTED);
|
||||
}
|
||||
|
||||
int cmd_add_iso7816_application(int argc, char *argv[]) {
|
||||
return (CMDLINE_RETCODE_COMMAND_NOT_IMPLEMENTED);
|
||||
}
|
||||
|
||||
int cmd_set_tagtype(int argc, char *argv[]) {
|
||||
return (CMDLINE_RETCODE_COMMAND_NOT_IMPLEMENTED);
|
||||
}
|
||||
|
||||
int cmd_get_tagtype(int argc, char *argv[]) {
|
||||
return (CMDLINE_RETCODE_COMMAND_NOT_IMPLEMENTED);
|
||||
}
|
||||
|
|
@ -0,0 +1,80 @@
|
|||
/*
|
||||
* Copyright (c) 2018 ARM Limited. All rights reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
* 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 _NFCCOMMANDS_H_INCLUDED
|
||||
#define _NFCCOMMANDS_H_INCLUDED
|
||||
|
||||
#if MBED_CONF_NFCEEPROM
|
||||
#include "nfcProcessEeprom.h"
|
||||
#else
|
||||
#include "nfcProcessCtrl.h"
|
||||
#endif
|
||||
|
||||
extern events::EventQueue nfcQueue;
|
||||
|
||||
// see https://support.microsoft.com/en-my/help/208427/maximum-url-length-is-2-083-characters-in-internet-explorer
|
||||
#define MAX_URL_LENGTH 2000
|
||||
|
||||
class HandleTestCommand {
|
||||
public:
|
||||
// start thread and handle queue
|
||||
HandleTestCommand();
|
||||
/* set corresponding mask bit on, return false if the supplied string cannot parse */
|
||||
static bool set_protocol_target(nfc_rf_protocols_bitmask_t & bitmask, const char *protocolName);
|
||||
|
||||
/* return and clear the last result code. Type "help getlastnfcerror" for a list of error codes */
|
||||
static int cmd_get_last_nfc_error(int argc, char *argv[]) {
|
||||
nfcQueue.call(NFCTestShim::cmd_get_last_nfc_error);
|
||||
return (CMDLINE_RETCODE_EXCUTING_CONTINUE);
|
||||
}
|
||||
|
||||
/* internal function to test getlastnfcerror */
|
||||
static int cmd_set_last_nfc_error(int argc, char *argv[]);
|
||||
|
||||
/* compile time flag */
|
||||
static int cmd_get_conf_nfceeprom(int argc, char *argv[]) {
|
||||
nfcQueue.call(NFCTestShim::cmd_get_conf_nfceeprom);
|
||||
return (CMDLINE_RETCODE_EXCUTING_CONTINUE);
|
||||
}
|
||||
|
||||
/* must be called before invoking any other calls */
|
||||
static int cmd_init_nfc(int argc, char *argv[]);
|
||||
/* write a smartposter url, 'Sp' NDEF to the target */
|
||||
static int cmd_set_smartposter(int argc, char *argv[]);
|
||||
/* erase EEPROM */
|
||||
static int cmd_erase(int argc, char *argv[]);
|
||||
|
||||
// controller driver methods:
|
||||
static int cmd_get_supported_rf_protocols(int argc, char *argv[]);
|
||||
static int cmd_configure_rf_protocols(int argc, char *argv[]);
|
||||
static int cmd_start_discovery(int argc, char *argv[]);
|
||||
static int cmd_stop_discovery(int argc, char *argv[]);
|
||||
|
||||
/* read raw EEPROM contents */
|
||||
static int cmd_read_message(int argc, char *argv[]);
|
||||
/* write a text 'T' NDEF message to the target */
|
||||
static int cmd_write_long_ndef_message(int argc, char *argv[]);
|
||||
|
||||
};
|
||||
|
||||
|
||||
// un-implemented or sparse support in drivers, so not covered
|
||||
int cmd_is_iso7816_supported(int argc, char *argv[]);
|
||||
int cmd_add_iso7816_application(int argc, char *argv[]);
|
||||
int cmd_set_tagtype(int argc, char *argv[]);
|
||||
int cmd_get_tagtype(int argc, char *argv[]);
|
||||
|
||||
#endif // _NFCCOMMANDS_H_INCLUDED
|
|
@ -0,0 +1,118 @@
|
|||
/*
|
||||
* Copyright (c) 2018 ARM Limited. All rights reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
* 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 _NFCPROCESS_H_INCLUDED
|
||||
#define _NFCPROCESS_H_INCLUDED
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
#include "nfc/ndef/MessageBuilder.h"
|
||||
#include "nfc/ndef/common/URI.h"
|
||||
#include "nfc/ndef/common/util.h"
|
||||
#include "nfctestshim.h"
|
||||
|
||||
#if MBED_CONF_NFCEEPROM
|
||||
#include "NFCEEPROM.h"
|
||||
#include "EEPROMDriver.h"
|
||||
#else
|
||||
#include "nfc/nfcdefinitions.h"
|
||||
#ifdef TARGET_PN512
|
||||
#include "nfc/controllers/PN512Driver.h"
|
||||
#include "nfc/controllers/PN512SPITransportDriver.h"
|
||||
#endif
|
||||
#include "nfc/NFCRemoteInitiator.h"
|
||||
#include "nfc/NFCController.h"
|
||||
#include "nfc/ndef/common/util.h"
|
||||
|
||||
#endif // MBED_CONF_NFCEEPROM
|
||||
|
||||
using mbed::nfc::ndef::MessageBuilder;
|
||||
using mbed::nfc::ndef::common::URI;
|
||||
using mbed::nfc::ndef::common::span_from_cstr;
|
||||
using mbed::Span;
|
||||
|
||||
|
||||
#if MBED_CONF_NFCEEPROM
|
||||
|
||||
using mbed::nfc::NFCEEPROM;
|
||||
using mbed::nfc::NFCEEPROMDriver;
|
||||
|
||||
class NFCProcessEEPROM : NFCTestShim , mbed::nfc::NFCEEPROM::Delegate
|
||||
{
|
||||
public:
|
||||
NFCProcessEEPROM(events::EventQueue& queue, NFCEEPROMDriver& eeprom_driver) ;
|
||||
nfc_err_t init();
|
||||
void queue_write_call();
|
||||
void queue_write_long_call();
|
||||
void queue_read_call();
|
||||
void queue_erase_call();
|
||||
|
||||
private:
|
||||
virtual void on_ndef_message_written(nfc_err_t result);
|
||||
virtual void on_ndef_message_read(nfc_err_t result);
|
||||
virtual void parse_ndef_message(const Span<const uint8_t> &buffer);
|
||||
virtual size_t build_ndef_message(const Span<uint8_t> &buffer);
|
||||
virtual void on_ndef_message_erased(nfc_err_t result);
|
||||
private:
|
||||
uint8_t _ndef_buffer[0x2000]; // if this buffer is smaller than the EEPROM, the driver may crash see IOTPAN-297
|
||||
NFCEEPROM _eeprom;
|
||||
EventQueue& _queue;
|
||||
};
|
||||
|
||||
#else // NFC Controller
|
||||
|
||||
class NFCProcessController : NFCTestShim, NFCRemoteInitiator::Delegate, NFCController::Delegate {
|
||||
public:
|
||||
NFCProcessController(events::EventQueue &queue);
|
||||
|
||||
nfc_err_t init();
|
||||
nfc_err_t start_discovery();
|
||||
nfc_err_t stop_discovery();
|
||||
void set_discovery_restart_auto() {_discovery_restart = true;};
|
||||
void set_discovery_restart_manual(){_discovery_restart = false;};
|
||||
nfc_rf_protocols_bitmask_t get_rf_protocols();
|
||||
nfc_err_t set_rf_protocols(nfc_rf_protocols_bitmask_t protocols);
|
||||
|
||||
virtual void parse_ndef_message(const Span<const uint8_t> &buffer);
|
||||
virtual size_t build_ndef_message(const Span<uint8_t> &buffer);
|
||||
const char *str_discovery_terminated_reason(nfc_discovery_terminated_reason_t reason);
|
||||
|
||||
|
||||
private:
|
||||
// these events are handled, to restart discovery
|
||||
virtual void on_connected();
|
||||
virtual void on_disconnected();
|
||||
virtual void on_discovery_terminated(nfc_discovery_terminated_reason_t reason);
|
||||
virtual void on_nfc_initiator_discovered(const SharedPtr<NFCRemoteInitiator> &nfc_initiator);
|
||||
|
||||
private:
|
||||
bool _discovery_restart;
|
||||
uint8_t _ndef_buffer[1024];
|
||||
mbed::nfc::PN512SPITransportDriver _pn512_transport;
|
||||
mbed::nfc::PN512Driver _pn512_driver;
|
||||
protected:
|
||||
EventQueue& _queue;
|
||||
private:
|
||||
NFCController _nfc_controller;
|
||||
SharedPtr<NFCRemoteInitiator> _nfc_remote_initiator;
|
||||
};
|
||||
#endif // TARGET_M24SR / else TARGET_PN512
|
||||
|
||||
|
||||
#endif // _NFCPROCESS_H_INCLUDED
|
|
@ -0,0 +1,183 @@
|
|||
/*
|
||||
* Copyright (c) 2018 ARM Limited. All rights reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
* 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 <stdio.h>
|
||||
#include <stdarg.h>
|
||||
#include <cstring>
|
||||
#include <string.h>
|
||||
#include "mbed.h"
|
||||
#include "mbed_events.h"
|
||||
#include "mbed-client-cli/ns_cmdline.h"
|
||||
|
||||
#include "nfc/stack/nfc_errors.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"
|
||||
|
||||
|
||||
#include "nfcProcessCtrl.h"
|
||||
#include "SmartPoster.h"
|
||||
|
||||
using mbed::Span;
|
||||
#if ! MBED_CONF_NFCEEPROM
|
||||
using mbed::nfc::nfc_rf_protocols_bitmask_t;
|
||||
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;
|
||||
using mbed::nfc::NFCController;
|
||||
|
||||
//class NFCProcessController : NFCRemoteInitiator::Delegate, NFCController::Delegate {
|
||||
|
||||
NFCProcessController::NFCProcessController(events::EventQueue &queue) :
|
||||
// pins: mosi, miso, sclk, ssel, irq, rst
|
||||
_pn512_transport(D11, D12, D13, D10, A1, A0), _pn512_driver(
|
||||
&_pn512_transport), _queue(queue), _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 NFCProcessController::init() {
|
||||
cmd_printf("init()\r\n");
|
||||
|
||||
// register callbacks
|
||||
_nfc_controller.set_delegate(this);
|
||||
return _nfc_controller.initialize();
|
||||
}
|
||||
|
||||
/**
|
||||
* Start the discovery of peers.
|
||||
*
|
||||
* @return NFC_OK in case of success or a meaningful error code in case of
|
||||
* failure.
|
||||
*/
|
||||
nfc_err_t NFCProcessController::start_discovery() {
|
||||
cmd_printf("start_discovery()\r\n");
|
||||
|
||||
return _nfc_controller.start_discovery();
|
||||
}
|
||||
|
||||
/**
|
||||
* Stop discovery.
|
||||
*
|
||||
* @return NFC_OK in case of success or a meaningful error code in case of
|
||||
* failure.
|
||||
*/
|
||||
nfc_err_t NFCProcessController::stop_discovery() {
|
||||
cmd_printf("stop_discovery()\r\n");
|
||||
return _nfc_controller.cancel_discovery();
|
||||
}
|
||||
|
||||
nfc_rf_protocols_bitmask_t NFCProcessController::get_rf_protocols() {
|
||||
cmd_printf("get_supported_rf_protocols()\r\n");
|
||||
return _nfc_controller.get_supported_rf_protocols();
|
||||
}
|
||||
|
||||
nfc_err_t NFCProcessController::set_rf_protocols(
|
||||
nfc_rf_protocols_bitmask_t protocols) {
|
||||
cmd_printf("configure_rf_protocols()\r\n");
|
||||
|
||||
return _nfc_controller.configure_rf_protocols(protocols);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------
|
||||
* Implementation of NFCRemoteInitiator::Delegate
|
||||
*/
|
||||
void NFCProcessController::on_connected() {
|
||||
cmd_printf("on_connected()\r\n");
|
||||
}
|
||||
|
||||
void NFCProcessController::on_disconnected() {
|
||||
cmd_printf("on_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();
|
||||
}
|
||||
|
||||
void NFCProcessController::parse_ndef_message(
|
||||
const Span<const uint8_t> &buffer) {
|
||||
size_t len = buffer.size();
|
||||
// copy remotely written message into our dummy buffer
|
||||
if (len <= sizeof(_ndef_write_buffer)) {
|
||||
cmd_printf("Store remote ndef message of size %d\r\n", len);
|
||||
memcpy(_ndef_write_buffer, buffer.data(), len);
|
||||
_ndef_write_buffer_used = len;
|
||||
} else {
|
||||
cmd_printf("Remote ndef message of size %d too large!\r\n", len);
|
||||
}
|
||||
}
|
||||
|
||||
size_t NFCProcessController::build_ndef_message(const Span<uint8_t> &buffer) {
|
||||
cmd_printf("Copying message %d bytes to query buffer\r\n",
|
||||
_ndef_write_buffer_used);
|
||||
memcpy(buffer.data(), _ndef_write_buffer, _ndef_write_buffer_used);
|
||||
for (size_t k = 0; k < _ndef_write_buffer_used; k++) {
|
||||
cmd_printf("%02x ", buffer[k]);
|
||||
}
|
||||
return _ndef_write_buffer_used;
|
||||
}
|
||||
|
||||
const char *NFCProcessController::str_discovery_terminated_reason(
|
||||
nfc_discovery_terminated_reason_t reason) {
|
||||
static const char* reasons[4] = { "completed", "cancelled", "rf error"};
|
||||
switch (reason) {
|
||||
case nfc_discovery_terminated_completed :
|
||||
case nfc_discovery_terminated_canceled:
|
||||
case nfc_discovery_terminated_rf_error:
|
||||
return reasons[reason];
|
||||
}
|
||||
return "unexpected!";
|
||||
}
|
||||
|
||||
|
||||
void NFCProcessController::on_discovery_terminated(
|
||||
nfc_discovery_terminated_reason_t reason) {
|
||||
cmd_printf("on_discovery_terminated(%s)\r\n",
|
||||
str_discovery_terminated_reason(reason));
|
||||
if (reason != nfc_discovery_terminated_completed
|
||||
&& this->_discovery_restart) {
|
||||
start_discovery();
|
||||
}
|
||||
}
|
||||
|
||||
void NFCProcessController::on_nfc_initiator_discovered(
|
||||
const SharedPtr<NFCRemoteInitiator> &nfc_initiator) {
|
||||
cmd_printf("on_nfc_initiator_discovered()\r\n");
|
||||
|
||||
// setup the local remote initiator
|
||||
_nfc_remote_initiator = nfc_initiator;
|
||||
_nfc_remote_initiator->set_delegate(this);
|
||||
_nfc_remote_initiator->connect();
|
||||
}
|
||||
|
||||
#endif // #if ! MBED_CONF_NFCEEPROM
|
||||
|
|
@ -0,0 +1,96 @@
|
|||
/*
|
||||
* Copyright (c) 2018 ARM Limited. All rights reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
* 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 _NFCPROCESS_H_INCLUDED
|
||||
#define _NFCPROCESS_H_INCLUDED
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
#include "nfc/ndef/MessageBuilder.h"
|
||||
#include "nfc/ndef/common/URI.h"
|
||||
#include "nfc/ndef/common/util.h"
|
||||
#include "nfctestshim.h"
|
||||
|
||||
#if !MBED_CONF_NFCEEPROM
|
||||
|
||||
#include "nfc/nfcdefinitions.h"
|
||||
#ifdef TARGET_PN512
|
||||
#include "nfc/controllers/PN512Driver.h"
|
||||
#include "nfc/controllers/PN512SPITransportDriver.h"
|
||||
#endif
|
||||
#include "nfc/NFCRemoteInitiator.h"
|
||||
#include "nfc/NFCController.h"
|
||||
#include "nfc/ndef/common/util.h"
|
||||
|
||||
|
||||
using mbed::nfc::ndef::MessageBuilder;
|
||||
using mbed::nfc::ndef::common::URI;
|
||||
using mbed::nfc::ndef::common::span_from_cstr;
|
||||
using mbed::Span;
|
||||
|
||||
|
||||
|
||||
class NFCProcessController: NFCTestShim,
|
||||
NFCRemoteInitiator::Delegate,
|
||||
NFCController::Delegate {
|
||||
public:
|
||||
NFCProcessController(events::EventQueue &queue);
|
||||
|
||||
nfc_err_t init();
|
||||
nfc_err_t start_discovery();
|
||||
nfc_err_t stop_discovery();
|
||||
nfc_rf_protocols_bitmask_t get_rf_protocols();
|
||||
nfc_err_t set_rf_protocols(nfc_rf_protocols_bitmask_t protocols);
|
||||
|
||||
virtual void parse_ndef_message(const Span<const uint8_t> &buffer);
|
||||
virtual size_t build_ndef_message(const Span<uint8_t> &buffer);
|
||||
const char *str_discovery_terminated_reason(
|
||||
nfc_discovery_terminated_reason_t reason);
|
||||
|
||||
private:
|
||||
// these events are handled, to restart discovery
|
||||
/**
|
||||
* Implementation of NFCRemoteEndpoint::Delegate */
|
||||
virtual void on_connected();
|
||||
/**
|
||||
* Implementation of NFCRemoteEndpoint::Delegate */
|
||||
virtual void on_disconnected();
|
||||
/**
|
||||
* Implementation of NFCController::Delegate */
|
||||
virtual void on_discovery_terminated(
|
||||
nfc_discovery_terminated_reason_t reason);
|
||||
/**
|
||||
* Implementation of NFCController::Delegate */
|
||||
virtual void on_nfc_initiator_discovered(
|
||||
const SharedPtr<NFCRemoteInitiator> &nfc_initiator);
|
||||
|
||||
private:
|
||||
|
||||
|
||||
mbed::nfc::PN512SPITransportDriver _pn512_transport;
|
||||
mbed::nfc::PN512Driver _pn512_driver;
|
||||
protected:
|
||||
EventQueue& _queue;
|
||||
private:
|
||||
NFCController _nfc_controller;
|
||||
SharedPtr<NFCRemoteInitiator> _nfc_remote_initiator;
|
||||
};
|
||||
#endif // Controller
|
||||
|
||||
#endif // _NFCPROCESS_H_INCLUDED
|
|
@ -0,0 +1,132 @@
|
|||
/*
|
||||
* Copyright (c) 2018 ARM Limited. All rights reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
* 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 <stdio.h>
|
||||
#include <stdarg.h>
|
||||
#include <cstring>
|
||||
#include <string.h>
|
||||
#include "mbed.h"
|
||||
#include "mbed_events.h"
|
||||
#include "mbed-client-cli/ns_cmdline.h"
|
||||
|
||||
#include "nfc/stack/nfc_errors.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"
|
||||
#if MBED_CONF_NFCEEPROM
|
||||
#include "NFCEEPROMDriver.h"
|
||||
|
||||
#include "nfcProcessEeprom.h"
|
||||
#include "SmartPoster.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;
|
||||
|
||||
// implements : mbed::nfc::NFCEEPROM::Delegate
|
||||
NFCProcessEEPROM::NFCProcessEEPROM(events::EventQueue& queue, NFCEEPROMDriver& eeprom_driver) :
|
||||
_eeprom(&eeprom_driver, &queue, _ndef_buffer),
|
||||
_queue(queue)
|
||||
{}
|
||||
|
||||
nfc_err_t NFCProcessEEPROM::init() {
|
||||
nfc_err_t err = _eeprom.initialize();
|
||||
if (err != NFC_OK) {
|
||||
cmd_printf("NFCProcessEEPROM::init() (error: %d)!\r\n", err);
|
||||
_queue.break_dispatch();
|
||||
} else {
|
||||
cmd_printf("NFCProcessEEPROM::init() OK\r\n");
|
||||
}
|
||||
_eeprom.set_delegate(this);
|
||||
return(err);
|
||||
}
|
||||
|
||||
void NFCProcessEEPROM::queue_write_call() {
|
||||
cmd_printf("NFCProcessEEPROM::queue_write_call() entry\r\n");
|
||||
_queue.call(&_eeprom, &NFCEEPROM::write_ndef_message);
|
||||
}
|
||||
|
||||
void NFCProcessEEPROM::queue_read_call() {
|
||||
cmd_printf("NFCProcessEEPROM::queue_read_call() entry\r\n");
|
||||
_queue.call(&_eeprom, &NFCEEPROM::read_ndef_message);
|
||||
}
|
||||
|
||||
void NFCProcessEEPROM::queue_erase_call() {
|
||||
cmd_printf("NFCProcessEEPROM::queue_erase_call() entry\r\n");
|
||||
_queue.call(&_eeprom, &NFCEEPROM::erase_ndef_message);
|
||||
}
|
||||
|
||||
void NFCProcessEEPROM::on_ndef_message_written(nfc_err_t result) {
|
||||
// todo: de-duplicate this code
|
||||
set_last_nfc_error(result);
|
||||
if (result == NFC_OK) {
|
||||
cmd_printf("message written successfully\r\n");
|
||||
} else {
|
||||
cmd_printf("Failed to write (error: %d)!\r\n", result);
|
||||
}
|
||||
// complete the async test method here
|
||||
cmd_ready(CMDLINE_RETCODE_SUCCESS);
|
||||
}
|
||||
|
||||
void NFCProcessEEPROM::on_ndef_message_read(nfc_err_t result) {
|
||||
set_last_nfc_error(result);
|
||||
if (result == NFC_OK) {
|
||||
cmd_printf("message read successfully\r\n");
|
||||
} else {
|
||||
cmd_printf("Failed to read (error: %d)!\r\n", result);
|
||||
}
|
||||
// complete the async test method here
|
||||
cmd_ready(CMDLINE_RETCODE_SUCCESS);
|
||||
}
|
||||
|
||||
void NFCProcessEEPROM::on_ndef_message_erased(nfc_err_t result)
|
||||
{
|
||||
// todo : de-duplicate/template this callback handler
|
||||
set_last_nfc_error(result);
|
||||
if (result == NFC_OK) {
|
||||
cmd_printf("message erased successfully\r\n");
|
||||
} else {
|
||||
cmd_printf("Failed to erase (error: %d)!\r\n", result);
|
||||
}
|
||||
// complete the async test method here
|
||||
cmd_ready(CMDLINE_RETCODE_SUCCESS);
|
||||
}
|
||||
|
||||
void NFCProcessEEPROM::parse_ndef_message(const Span<const uint8_t> &buffer) {
|
||||
cmd_printf("Received an ndef message of size %d\r\n", buffer.size());
|
||||
print_ndef_message(buffer, buffer.size());
|
||||
}
|
||||
|
||||
size_t NFCProcessEEPROM::build_ndef_message(const Span<uint8_t> &buffer) {
|
||||
cmd_printf("Copying ndef message %d bytes into buffer\r\n", _ndef_write_buffer_used);
|
||||
// make a copy into our buffer
|
||||
memcpy(buffer.data(), _ndef_write_buffer, _ndef_write_buffer_used);
|
||||
for (size_t k=0; k<_ndef_write_buffer_used; k++ ) {
|
||||
cmd_printf("%02x ", buffer[k] );
|
||||
}
|
||||
return _ndef_write_buffer_used;
|
||||
}
|
||||
|
||||
#endif // MBED_CONF_NFCEEPROM
|
||||
|
|
@ -0,0 +1,70 @@
|
|||
/*
|
||||
* Copyright (c) 2018 ARM Limited. All rights reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
* 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 _NFCPROCESS_H_INCLUDED
|
||||
#define _NFCPROCESS_H_INCLUDED
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
#include "nfc/ndef/MessageBuilder.h"
|
||||
#include "nfc/ndef/common/URI.h"
|
||||
#include "nfc/ndef/common/util.h"
|
||||
#include "nfctestshim.h"
|
||||
|
||||
#if MBED_CONF_NFCEEPROM
|
||||
#include "NFCEEPROM.h"
|
||||
#include "EEPROMDriver.h"
|
||||
|
||||
#endif // MBED_CONF_NFCEEPROM
|
||||
|
||||
using mbed::nfc::ndef::MessageBuilder;
|
||||
using mbed::nfc::ndef::common::URI;
|
||||
using mbed::nfc::ndef::common::span_from_cstr;
|
||||
using mbed::Span;
|
||||
|
||||
#if MBED_CONF_NFCEEPROM
|
||||
|
||||
using mbed::nfc::NFCEEPROM;
|
||||
using mbed::nfc::NFCEEPROMDriver;
|
||||
|
||||
class NFCProcessEEPROM : NFCTestShim , mbed::nfc::NFCEEPROM::Delegate
|
||||
{
|
||||
public:
|
||||
NFCProcessEEPROM(events::EventQueue& queue, NFCEEPROMDriver& eeprom_driver);
|
||||
nfc_err_t init();
|
||||
void queue_write_call();
|
||||
void queue_write_long_call();
|
||||
void queue_read_call();
|
||||
void queue_erase_call();
|
||||
|
||||
private:
|
||||
virtual void on_ndef_message_written(nfc_err_t result);
|
||||
virtual void on_ndef_message_read(nfc_err_t result);
|
||||
virtual void parse_ndef_message(const Span<const uint8_t> &buffer);
|
||||
virtual size_t build_ndef_message(const Span<uint8_t> &buffer);
|
||||
virtual void on_ndef_message_erased(nfc_err_t result);
|
||||
private:
|
||||
NFCEEPROM _eeprom;
|
||||
EventQueue& _queue;
|
||||
};
|
||||
|
||||
#endif // eeprom
|
||||
|
||||
|
||||
#endif // _NFCPROCESS_H_INCLUDED
|
|
@ -0,0 +1,295 @@
|
|||
/*
|
||||
* Copyright (c) 2018 ARM Limited. All rights reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
* 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 <stdio.h>
|
||||
#include <stdarg.h>
|
||||
#include <cstring>
|
||||
#include <string.h>
|
||||
#include "mbed.h"
|
||||
#include "mbed-client-cli/ns_cmdline.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"
|
||||
#include "nfc/nfcdefinitions.h"
|
||||
|
||||
#include "NFCEEPROMDriver.h"
|
||||
#include "nfcCommands.h"
|
||||
#include "nfctestshim.h"
|
||||
#include "SmartPoster.h"
|
||||
|
||||
using mbed::Span;
|
||||
using mbed::nfc::ndef::MessageBuilder;
|
||||
using mbed::nfc::ndef::RecordType;
|
||||
using mbed::nfc::ndef::common::span_from_cstr;
|
||||
using mbed::nfc::ndef::common::Text;
|
||||
using mbed::nfc::ndef::common::URI;
|
||||
using mbed::nfc::nfc_rf_protocols_bitmask_t;
|
||||
|
||||
// statics
|
||||
char NFCTestShim::long_string[0x2000];
|
||||
|
||||
int NFCTestShim::last_nfc_error = 0;
|
||||
#if MBED_CONF_NFCEEPROM
|
||||
int NFCTestShim::using_eeprom = true;
|
||||
#else
|
||||
int NFCTestShim::using_eeprom = false;
|
||||
#endif
|
||||
|
||||
NFCTestShim::NFCTestShim() :
|
||||
_ndef_write_buffer_used(0), ndef_poster_message(_ndef_write_buffer), _discovery_restart(
|
||||
true) // on disconnect, will restart discovery
|
||||
{
|
||||
}
|
||||
|
||||
// The last failed NFC API call status, gets cleared upon reading it.
|
||||
void NFCTestShim::get_last_nfc_error() {
|
||||
int last = last_nfc_error;
|
||||
last_nfc_error = 0;
|
||||
// return data to the plugin framework
|
||||
cmd_printf("{{lastnfcerror=%d}}\r\n", last);
|
||||
cmd_ready(CMDLINE_RETCODE_SUCCESS);
|
||||
}
|
||||
|
||||
void NFCTestShim::set_last_nfc_error(int err) {
|
||||
last_nfc_error = err;
|
||||
cmd_printf("\r\n{{lastnfcerror=%d}}\r\n", last_nfc_error);
|
||||
}
|
||||
|
||||
// if an NFC EEPROM driver is configured
|
||||
void NFCTestShim::get_conf_nfceeprom() {
|
||||
set_last_nfc_error(NFC_OK);
|
||||
cmd_printf("{{iseeprom=%s}}\r\n", (using_eeprom ? "true" : "false"));
|
||||
cmd_ready(CMDLINE_RETCODE_SUCCESS);
|
||||
}
|
||||
|
||||
void NFCTestShim::print_ndef_message(const Span<const uint8_t> &buffer,
|
||||
size_t length) {
|
||||
cmd_printf("{{nfcmessage=");
|
||||
for (size_t k = 0; k < length; k++) {
|
||||
cmd_printf("%02x ", buffer.data()[k]);
|
||||
}
|
||||
cmd_printf("}}\r\n");
|
||||
}
|
||||
|
||||
void NFCTestShim::cmd_init() {
|
||||
nfc_err_t ret = init();
|
||||
set_last_nfc_error(ret);
|
||||
|
||||
if (NFC_OK != ret) {
|
||||
cmd_ready(CMDLINE_RETCODE_FAIL);
|
||||
} else {
|
||||
cmd_ready(CMDLINE_RETCODE_SUCCESS);
|
||||
}
|
||||
}
|
||||
|
||||
void NFCTestShim::cmd_get_rf_protocols() {
|
||||
#if MBED_CONF_NFCEEPROM
|
||||
cmd_printf("EEPROM cannot get protocol()\r\n");
|
||||
set_last_nfc_error(NFC_ERR_UNSUPPORTED);
|
||||
cmd_ready(CMDLINE_RETCODE_INVALID_PARAMETERS);
|
||||
|
||||
#else
|
||||
nfc_rf_protocols_bitmask_t protocols =
|
||||
((NFCProcessController*) this)->get_rf_protocols();
|
||||
protocols.target_t1t = true;
|
||||
protocols.target_t2t = true;
|
||||
protocols.target_t3t = true;
|
||||
protocols.target_t5t = true;
|
||||
protocols.target_nfc_dep = true;
|
||||
static char strSupported[7 * 6 + 1] = "";
|
||||
if (protocols.target_t1t) {
|
||||
strcat(strSupported, "t1t,");
|
||||
}
|
||||
if (protocols.target_t2t) {
|
||||
strcat(strSupported, "t2t,");
|
||||
}
|
||||
if (protocols.target_t3t) {
|
||||
strcat(strSupported, "t3t,");
|
||||
}
|
||||
if (protocols.target_iso_dep) {
|
||||
strcat(strSupported, "isodep,");
|
||||
}
|
||||
if (protocols.target_nfc_dep) {
|
||||
strcat(strSupported, "nfcdep,");
|
||||
}
|
||||
if (protocols.target_t5t) {
|
||||
strcat(strSupported, "t5t,");
|
||||
}
|
||||
if (strlen(strSupported)) {
|
||||
strSupported[strlen(strSupported) - 1] = '\0'; // strip trailing comma
|
||||
}
|
||||
cmd_printf("{{protocols=%s}}", strSupported);
|
||||
set_last_nfc_error(NFC_OK);
|
||||
cmd_ready(CMDLINE_RETCODE_SUCCESS);
|
||||
#endif
|
||||
}
|
||||
|
||||
void NFCTestShim::cmd_configure_rf_protocols(
|
||||
nfc_rf_protocols_bitmask_t protocols) {
|
||||
#if MBED_CONF_NFCEEPROM
|
||||
cmd_printf("EEPROM cannot set protocol()\r\n");
|
||||
set_last_nfc_error(NFC_ERR_UNSUPPORTED);
|
||||
cmd_ready(CMDLINE_RETCODE_INVALID_PARAMETERS);
|
||||
#else
|
||||
|
||||
nfc_err_t err = ((NFCProcessController*) this)->set_rf_protocols(protocols);
|
||||
set_last_nfc_error(err);
|
||||
if (NFC_OK != err) {
|
||||
cmd_ready(CMDLINE_RETCODE_FAIL);
|
||||
} else {
|
||||
cmd_ready(CMDLINE_RETCODE_SUCCESS);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
// RETURNS: ICETEA error code asynchronously NFC error is set
|
||||
// {{bytes=XX XX XX XX.. }} are returned
|
||||
void NFCTestShim::cmd_read_nfceeprom() {
|
||||
#if MBED_CONF_NFCEEPROM
|
||||
((NFCProcessEEPROM*)this)->queue_read_call();
|
||||
cmd_printf("NFCTestShim::read_nfceeprom() exit\r\n");
|
||||
|
||||
#else
|
||||
// returns last message "written", since we cannot read
|
||||
print_ndef_message(_ndef_write_buffer, _ndef_write_buffer_used);
|
||||
set_last_nfc_error(NFC_OK);
|
||||
|
||||
cmd_printf("NFCTestShim::read_nfceeprom()\r\n");
|
||||
cmd_ready(CMDLINE_RETCODE_SUCCESS);
|
||||
#endif
|
||||
}
|
||||
|
||||
void NFCTestShim::cmd_erase() {
|
||||
|
||||
#if MBED_CONF_NFCEEPROM
|
||||
((NFCProcessEEPROM*)this)->queue_erase_call();
|
||||
|
||||
#else
|
||||
cmd_printf("erase %d bytes, last msg\r\n",
|
||||
(sizeof(_ndef_write_buffer) / sizeof(uint8_t)));
|
||||
_ndef_write_buffer_used = 0;
|
||||
memset(_ndef_write_buffer, 0, sizeof(_ndef_write_buffer) / sizeof(uint8_t));
|
||||
set_last_nfc_error(NFC_OK); // effectively a no-op
|
||||
cmd_ready(CMDLINE_RETCODE_SUCCESS);
|
||||
#endif
|
||||
}
|
||||
|
||||
// populate buffer with really long message - length checks to be done by driver only
|
||||
void NFCTestShim::cmd_write_long(char *data) {
|
||||
MessageBuilder builder(ndef_poster_message);
|
||||
|
||||
strcpy(NFCTestShim::long_string, data); //max_ndef - header - overheads
|
||||
Text text(Text::UTF8, span_from_cstr("en-US"),
|
||||
span_from_cstr((const char*) (NFCTestShim::long_string)));
|
||||
|
||||
text.append_as_record(builder, true);
|
||||
_ndef_write_buffer_used = builder.get_message().size();
|
||||
cmd_printf("Composed NDEF message %d bytes\r\n", _ndef_write_buffer_used);
|
||||
|
||||
#if MBED_CONF_NFCEEPROM
|
||||
((NFCProcessEEPROM*)this)->queue_write_call();
|
||||
#else
|
||||
// not on a wire, so the caller will store the message in a buffer
|
||||
set_last_nfc_error(NFC_OK);
|
||||
cmd_ready(CMDLINE_RETCODE_SUCCESS);
|
||||
#endif
|
||||
|
||||
cmd_printf("NFCTestShim::write_long() exit\r\n");
|
||||
free(data);
|
||||
}
|
||||
|
||||
// PARAM: uri - this method must free the passed pointer
|
||||
// RETURNS: ICETEA error code asynchronously NFC error is set
|
||||
// An interesting side use case would be to prompt to install an app from the appstore using the tag
|
||||
void NFCTestShim::cmd_set_smartposter(char *cmdUri) {
|
||||
MessageBuilder builder(ndef_poster_message);
|
||||
|
||||
uint8_t smart_poster_buffer[1024];
|
||||
MessageBuilder smart_poster_builder(smart_poster_buffer);
|
||||
|
||||
char* urlbegin = strstr(cmdUri, ".");
|
||||
urlbegin++;
|
||||
URI uri(URI::HTTPS_WWW, span_from_cstr(urlbegin));
|
||||
uri.append_as_record(smart_poster_builder, true);
|
||||
|
||||
builder.append_record(
|
||||
RecordType(RecordType::well_known_type, span_from_cstr("Sp")),
|
||||
smart_poster_builder.get_message(), true);
|
||||
|
||||
_ndef_write_buffer_used = builder.get_message().size();
|
||||
cmd_printf("Composed NDEF message %d bytes\r\n", _ndef_write_buffer_used);
|
||||
|
||||
#if MBED_CONF_NFCEEPROM
|
||||
((NFCProcessEEPROM*)this)->queue_write_call();
|
||||
#else
|
||||
// not on a wire, so the call just stores the message in a buffer
|
||||
set_last_nfc_error(NFC_OK);
|
||||
cmd_ready(CMDLINE_RETCODE_SUCCESS);
|
||||
#endif
|
||||
cmd_printf("NFCTestShim::setsmartposter() exit\r\n");
|
||||
free(cmdUri);
|
||||
}
|
||||
|
||||
// disabled in EEPROMs, overridden if controller present
|
||||
void NFCTestShim::cmd_start_discovery(bool manual) {
|
||||
#if MBED_CONF_NFCEEPROM
|
||||
cmd_printf("EEPROM cannot start_discovery()\r\n");
|
||||
set_last_nfc_error(NFC_ERR_UNSUPPORTED);
|
||||
cmd_ready(CMDLINE_RETCODE_INVALID_PARAMETERS);
|
||||
|
||||
#else
|
||||
|
||||
// todo: remove hard coded
|
||||
nfc_rf_protocols_bitmask_t protocols = { 0 };
|
||||
protocols.target_iso_dep = 1;
|
||||
|
||||
nfc_err_t err = ((NFCProcessController*) this)->set_rf_protocols(protocols);
|
||||
|
||||
if (manual) {
|
||||
this->set_discovery_restart_manual();
|
||||
} else {
|
||||
this->set_discovery_restart_auto();
|
||||
}
|
||||
err = this->start_discovery();
|
||||
set_last_nfc_error(err);
|
||||
if (NFC_OK != err) {
|
||||
cmd_ready(CMDLINE_RETCODE_FAIL);
|
||||
} else {
|
||||
cmd_ready(CMDLINE_RETCODE_SUCCESS);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
// disabled in EEPROMs, overridden if controller present
|
||||
void NFCTestShim::cmd_stop_discovery() {
|
||||
|
||||
#if MBED_CONF_NFCEEPROM
|
||||
cmd_printf("EEPROM cannot stop_discovery()\r\n");
|
||||
set_last_nfc_error(NFC_ERR_UNSUPPORTED);
|
||||
cmd_ready(CMDLINE_RETCODE_INVALID_PARAMETERS);
|
||||
#else
|
||||
nfc_err_t err = this->stop_discovery();
|
||||
set_last_nfc_error(err);
|
||||
if (NFC_OK != err) {
|
||||
cmd_ready(CMDLINE_RETCODE_FAIL);
|
||||
} else {
|
||||
cmd_ready(CMDLINE_RETCODE_SUCCESS);
|
||||
}
|
||||
|
||||
#endif
|
||||
}
|
||||
|
|
@ -0,0 +1,128 @@
|
|||
/*
|
||||
* Copyright (c) 2018 ARM Limited. All rights reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
* 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 _NFCTESTSHIM_H_INCLUDED
|
||||
#define _NFCTESTSHIM_H_INCLUDED
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
#include "mbed_config.h"
|
||||
#include "nfc/ndef/MessageBuilder.h"
|
||||
#include "nfc/ndef/common/URI.h"
|
||||
#include "nfc/ndef/common/util.h"
|
||||
#include "nfc/nfcdefinitions.h"
|
||||
|
||||
// all targets that have an EEPROM
|
||||
#if MBED_CONF_NFCEEPROM
|
||||
#define TEST_NFCEEPROM_TARGET
|
||||
#endif
|
||||
|
||||
// all targets that have a controller
|
||||
#if defined (TARGET_PN512)
|
||||
#define TEST_NFCCONTRL_TARGET
|
||||
#endif
|
||||
|
||||
#if MBED_CONF_NFCEEPROM
|
||||
#include "NFCEEPROM.h"
|
||||
#include "EEPROMDriver.h"
|
||||
|
||||
#else
|
||||
#ifdef TARGET_PN512
|
||||
#include "nfc/controllers/PN512Driver.h"
|
||||
#include "nfc/controllers/PN512SPITransportDriver.h"
|
||||
#endif
|
||||
#include "nfc/NFCRemoteInitiator.h"
|
||||
#include "nfc/NFCController.h"
|
||||
|
||||
using mbed::Span;
|
||||
using mbed::nfc::NFCRemoteInitiator;
|
||||
using mbed::nfc::NFCController;
|
||||
#endif // TEST_EEPROM_TARGET
|
||||
|
||||
using mbed::nfc::ndef::MessageBuilder;
|
||||
using mbed::nfc::ndef::common::URI;
|
||||
using mbed::nfc::ndef::common::span_from_cstr;
|
||||
using mbed::nfc::nfc_rf_protocols_bitmask_t;
|
||||
|
||||
class NFCTestShim {
|
||||
public:
|
||||
NFCTestShim();
|
||||
|
||||
static void cmd_get_last_nfc_error() {
|
||||
get_last_nfc_error();
|
||||
}
|
||||
;
|
||||
static void cmd_set_last_nfc_error(int err) {
|
||||
set_last_nfc_error(err);
|
||||
cmd_ready (CMDLINE_RETCODE_SUCCESS);
|
||||
}
|
||||
;
|
||||
static void cmd_get_conf_nfceeprom() {
|
||||
get_conf_nfceeprom();
|
||||
}
|
||||
;
|
||||
static void get_last_nfc_error();
|
||||
static void set_last_nfc_error(int err);
|
||||
static void get_conf_nfceeprom();
|
||||
static void print_ndef_message(const Span<const uint8_t> &buffer,
|
||||
size_t length);
|
||||
|
||||
void cmd_init();
|
||||
virtual nfc_err_t init() = 0;
|
||||
|
||||
void cmd_set_smartposter(char *cmdUri);
|
||||
void cmd_erase();
|
||||
void cmd_write_long(char *data);
|
||||
void cmd_read_nfceeprom();
|
||||
void cmd_start_discovery(bool manual = false);
|
||||
void cmd_stop_discovery();
|
||||
void cmd_configure_rf_protocols(nfc_rf_protocols_bitmask_t protocols);
|
||||
void cmd_get_rf_protocols();
|
||||
|
||||
protected:
|
||||
// implement/declare EEPROM and Controller model underlying common BH and delegate specializations
|
||||
virtual nfc_err_t set_rf_protocols(nfc_rf_protocols_bitmask_t protocols) {return NFC_ERR_UNSUPPORTED ;};
|
||||
virtual nfc_err_t start_discovery() {return NFC_ERR_UNSUPPORTED ;};
|
||||
virtual nfc_err_t stop_discovery() {return NFC_ERR_UNSUPPORTED ;};
|
||||
void set_discovery_restart_auto() {
|
||||
_discovery_restart = true;
|
||||
};
|
||||
void set_discovery_restart_manual() {
|
||||
_discovery_restart = false;
|
||||
};
|
||||
|
||||
|
||||
protected:
|
||||
size_t _ndef_write_buffer_used;
|
||||
Span<uint8_t> ndef_poster_message; // message to build and send
|
||||
uint8_t _ndef_write_buffer[0x2000]; // if this buffer is smaller than the EEPROM, the driver may crash see IOTPAN-297
|
||||
uint8_t _ndef_buffer[0x2000]; // driver buffer
|
||||
bool _discovery_restart;
|
||||
|
||||
private:
|
||||
static int last_nfc_error;
|
||||
|
||||
static int using_eeprom;
|
||||
static char long_string[0x2000];
|
||||
};
|
||||
|
||||
// forward declare single instance
|
||||
extern NFCTestShim * pNFC_Test_Shim;
|
||||
|
||||
#endif // _NFCTESTSHIM_H_INCLUDED
|
|
@ -0,0 +1,43 @@
|
|||
/*
|
||||
* Copyright (c) 2018 ARM Limited. All rights reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
* 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 <stdio.h>
|
||||
#include <stdarg.h>
|
||||
#include "mbed.h"
|
||||
|
||||
/**
|
||||
* Macros for setting console flow control.
|
||||
*/
|
||||
#define CONSOLE_FLOWCONTROL_RTS 1
|
||||
#define CONSOLE_FLOWCONTROL_CTS 2
|
||||
#define CONSOLE_FLOWCONTROL_RTSCTS 3
|
||||
#define mbed_console_concat_(x) CONSOLE_FLOWCONTROL_##x
|
||||
#define mbed_console_concat(x) mbed_console_concat_(x)
|
||||
#define CONSOLE_FLOWCONTROL mbed_console_concat(MBED_CONF_TARGET_CONSOLE_UART_FLOW_CONTROL)
|
||||
|
||||
#define SERIAL_CONSOLE_BAUD_RATE 115200
|
||||
|
||||
FileHandle *mbed::mbed_override_console(int) {
|
||||
static UARTSerial console(STDIO_UART_TX, STDIO_UART_RX,
|
||||
SERIAL_CONSOLE_BAUD_RATE);
|
||||
#if CONSOLE_FLOWCONTROL == CONSOLE_FLOWCONTROL_RTS
|
||||
console.set_flow_control(SerialBase::RTS, STDIO_UART_RTS, NC);
|
||||
#elif CONSOLE_FLOWCONTROL == CONSOLE_FLOWCONTROL_CTS
|
||||
console.set_flow_control(SerialBase::CTS, NC, STDIO_UART_CTS);
|
||||
#elif CONSOLE_FLOWCONTROL == CONSOLE_FLOWCONTROL_RTSCTS
|
||||
console.set_flow_control(SerialBase::RTSCTS, STDIO_UART_RTS, STDIO_UART_CTS);
|
||||
#endif
|
||||
return &console;
|
||||
}
|
|
@ -0,0 +1,75 @@
|
|||
"""
|
||||
Copyright 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.
|
||||
"""
|
||||
|
||||
|
||||
from icetea_lib.Plugin.PluginBase import PluginBase
|
||||
import re
|
||||
import os
|
||||
|
||||
class NfcTestParsers(PluginBase):
|
||||
# constructor
|
||||
def __init__(self):
|
||||
super(NfcTestParsers, self).__init__()
|
||||
|
||||
def get_parsers(self):
|
||||
return {
|
||||
'getlastnfcerror': self.trace_parser,
|
||||
'setlastnfcerror': self.trace_parser,
|
||||
'iseeprom': self.trace_parser,
|
||||
'initnfc': self.trace_parser, # all commands that return an NFC error code
|
||||
'readmessage' : self.trace_parser,
|
||||
'erase' : self.trace_parser,
|
||||
'writelong' : self.trace_parser,
|
||||
'stop' : self.trace_parser,
|
||||
'start' : self.trace_parser,
|
||||
'setsmartposter': self.trace_parser,
|
||||
'getprotocols': self.trace_parser,
|
||||
'setprotocols': self.trace_parser
|
||||
}
|
||||
|
||||
def trace_parser(self, response):
|
||||
results = {'iseeprom': None, # 'true' if EEPROM
|
||||
'lastnfcerror':None, # 0=OK >0 = error
|
||||
'nfcmessage':None, # NDEF array of bytes
|
||||
'protocols':None} # csv list
|
||||
respLines = response.lines
|
||||
for line in respLines:
|
||||
try:
|
||||
value = PluginBase.find_one(line, "{{lastnfcerror=([0-9]+)}}")
|
||||
if value is not False:
|
||||
results['lastnfcerror'] = int(value)
|
||||
# iseeprom
|
||||
value = PluginBase.find_one(line, "{{iseeprom=([\w]+)}}")
|
||||
if value is not False:
|
||||
if ("TRUE" == value.upper() or "1" == value):
|
||||
results['iseeprom'] = True
|
||||
else:
|
||||
results['iseeprom'] = False
|
||||
# nfcmessage (hex data dumps)
|
||||
data = PluginBase.find_one(line, "{{nfcmessage=([0-9a-f\s]*)}}")
|
||||
if data is not False:
|
||||
value = []
|
||||
for byte in data.split(' '):
|
||||
if bool(byte):
|
||||
value.append( int(byte, 16))
|
||||
results['nfcmessage'] = value
|
||||
# t1t,t2t,t3t,isodep,nfcdef,t5t
|
||||
value = PluginBase.find_one(line, "{{protocols=(([\w]*,?)*)}}")
|
||||
if value is not False:
|
||||
results['protocols'] = value # a csv list
|
||||
except re.error as e: # the framework gobbles errors in the plugin
|
||||
print("Regex error",e,"occured in",os.path.basename(__file__), "!!")
|
||||
raise e
|
||||
return results
|
|
@ -13,7 +13,10 @@ See the License for the specific language governing permissions and
|
|||
limitations under the License.
|
||||
"""
|
||||
from ip_test_parsers import IpTestParsers
|
||||
from nfc_test_parsers import NfcTestParsers
|
||||
|
||||
|
||||
plugins_to_load = {
|
||||
"ip_test_parsers": IpTestParsers
|
||||
"ip_test_parsers": IpTestParsers,
|
||||
"nfc_test_parsers": NfcTestParsers
|
||||
}
|
||||
|
|
|
@ -0,0 +1,319 @@
|
|||
# NFC tests.
|
||||
Internal document.
|
||||
|
||||
A CI test suite for NFC component. These tests validate card mbed emulation cases. The key use case is a NFC smart poster supporting comissioning workflow.
|
||||
The SUT (system under test) is the NFC target. Tests exercise the framework and NDEF transactions when a NFC controller driver is used, or when the stack is configured for an NFC EEPROM chip in the system integration.
|
||||
|
||||
This project is called CreamScone, which is an ice tea framework based cli-driven python test.
|
||||
|
||||
<!-- TOC -->
|
||||
- [NFC tests . CONFIDENTIAL](#nfc-tests-confidential)
|
||||
- [Overview](#overview)
|
||||
- [NFC System Testing high level design](#nfc-system-testing-high-level-design)
|
||||
- [Low level design](#low-level-design)
|
||||
- [User Guide](#user-guide)
|
||||
- [Test cases](#test-cases)
|
||||
- [cli commands](#cli-commands)
|
||||
- [How to](#how-to)
|
||||
- [Alternate NFC drivers note:](#alternate-nfc-drivers-note:)
|
||||
- [Running the tests](#running-the-tests)
|
||||
<!-- TOC -->
|
||||
|
||||
|
||||
# Overview
|
||||
A set of tests run in CI, which can provide:
|
||||
- Internal confidence
|
||||
- Faster iterations
|
||||
- More efficient work
|
||||
- Clear escalation path
|
||||
|
||||
A [Ice-tea](https://github.com/ARMmbed/mbed-os-5-docs/blob/development/docs/tools/testing/testing_icetea.md) based test suite. In it's simplest form, the suite merely drives API's for the NFC tag reader/writer, and validates a tag simulation running on an idle target, allows test cases in discovery, connection and read/write NDEF records.
|
||||
|
||||
In order to mitigate the costs associated with system testing, use existing frameworks or parts and make it easy to test each individually. The [nfcpy](https://nfcpy.readthedocs.io/) Python library is used as the core of the *CreamScone* component which uses a PN53* device [SCL3711 usb reader](https://www.identiv.com/products/smart-card-readers/rfid-nfc-contactless/scl3711/) over USB to read the mbed simulated tag. This library is used to drive host interactions because it is portable (windows/GNULinux.) Remote NFC interactions will raise events in the mbed application. Connection and read/write events which get handled in user application on the target get wired up to asyncronously return responses and the data values (NDEF messages) to the ice tea framework. These events and data are thus tested/checked in the code (python) running on host. The target test app wraps the API, allowing many new test-scenarios to be written purely in Python.
|
||||
|
||||
**NFC compliance**
|
||||
|
||||
This suite only assists in NFC forum compliance. Developers must self certify using test tools from a provider to uncover early issues and get an external test vendor to achieve certification.
|
||||
|
||||
**Mobiles and inter-op**
|
||||
|
||||
(Unimplemented) Describe test procedures using a mobile phone app for Android and for IOS.
|
||||
|
||||

|
||||
|
||||
Because the comissioning workflow application quality is the end goal, the NFC suite includes learnings to design the CI setup needed for future system testing that bring a mobile phone into the test-rig. The use of a mobile and bluetooth pairing as well as the continous integration system is not included.
|
||||
|
||||
|
||||
|
||||
# NFC System Testing high level design
|
||||
Mitigate risks identified, to the product from an internal view to supporting releases, and from customer development and production risks. In summary:
|
||||
- Architecture risks and Api breaks
|
||||
- Partner cannot NFC forum Certify
|
||||
- Partner driver has bugs
|
||||
- Code regressions in O/S
|
||||
- Arm mbed provided driver or HAL has bugs
|
||||
- Security vulnerabilities
|
||||
|
||||
In precis, “Empower engineers to efficiently ship quality code with confidence.”
|
||||
|
||||
**Design requirements:**
|
||||
- Identify and use tools to allow running in CI system, on many targets/configurations
|
||||
- Be portable (can run in the CI system) using NFC explorer boards in lab for correctly co-located targets.
|
||||
- Be able to set up and run locally in development
|
||||
|
||||
# Low level design
|
||||
**components**
|
||||
|
||||
An icetea suite [test_nfc.py](TEST_APPS\testcases\nfc\test_nfc.py)
|
||||
|
||||
Commandline (serial port) driven app [ice_device.py](TEST_APPS\testcases\nfc\ice_device.py) aka _'CreamScone'_ which allows manual interactions with the driver.
|
||||
|
||||
An icetea plugin [nfc_test_parsers.py](TEST_APPS\icetea_plugins\nfc_test_parsers.py)
|
||||
|
||||
MbedOS cli test app [main.cpp](TEST_APPS\device\nfcapp\main.cpp). The CLI commands return results asyncronously for most commands which get passed to and handled on a driver thread.
|
||||
|
||||
The SUT target is rebooted between tests, since test modify the target hardware state.
|
||||
|
||||
**Future:** A complete inter-op ready design expands to also include a switch-box to allow the reader to connect to NFC enabled targets nearby using flying cables and a sticky-back antenna. The switch allows selecting either alternative tags, or NFC peers. The switch can be controlled using GPIO either driven from spare IO pins on the target DUT itself (preferred option), or perhaps from a Raspberry pi.
|
||||
|
||||

|
||||
|
||||

|
||||
|
||||
|
||||
**Reference:**
|
||||
|
||||
https://github.com/ARMmbed/mbed-os/blob/master/docs/design-documents/nfc/nfc_design.md
|
||||
|
||||
https://github.com/ARMmbed/mbed-os/tree/master/features/nfc/nfc
|
||||
|
||||
https://github.com/ARMmbed/mbed-os-example-nfc
|
||||
|
||||
# User Guide
|
||||
This section covers the test case specification and how to run the test suite.
|
||||
|
||||
## Test cases
|
||||
CLI commands used by each test case describe the steps in a test.
|
||||
** Basic local only cases **
|
||||
- test_nfc_error_codes : inintnfc , setlastnfcerror \<n> , getlastnfcerror
|
||||
- Verify that the test CLI engine can initialize the stack, and can return NFC codes
|
||||
- test_nfc_eeprom : iseeprom
|
||||
- prints "true" if the target has an EEPROM configured stack, else prints "false" diagnostic only
|
||||
- test_nfc_get_controller_protocols
|
||||
- set nfc protocols supported
|
||||
- test_nfc_set_controller_protocols
|
||||
- get nfc protocols supported
|
||||
- test_nfc_setsmartposter : setsmartposter \<-u> \<url>
|
||||
- Sets a smartposter message, does not verify over wireless! (Only https protocol tested.)
|
||||
- test_nfc_erase : initnfc, erase, readmessage
|
||||
- Erase entire EEPROM, (behaviour for controller stack is null)
|
||||
- test_nfc_write_long : initnfc, erase, writelong \<n>, readmessage
|
||||
- Write a very large text T record, and verify expected length written
|
||||
- test_nfc_reprogrammed : iseeprom, initnfc, erase, wirelessly reprogram, wirelessly verify
|
||||
- Use a reader/writer to program the tag using the default M24SR chip password
|
||||
** End-to-End cases **
|
||||
- test_nfce2e_target_found
|
||||
- tag can actually be detected wireless
|
||||
test_nfce2e_type4_found
|
||||
- correct tag detected
|
||||
- test_nfce2e_discovery_loop
|
||||
- Start or Stop discovery loop or disable depending on stack
|
||||
test_nfce2e_read_stress
|
||||
- read large message from device
|
||||
test_nfce2e_reprogrammed
|
||||
- modify large message from device
|
||||
test_nfce2e_reprogrammed_stress
|
||||
- write moderate message wirelessly
|
||||
test_nfce2e_smartposter
|
||||
- as with the basic test, but wirelessly
|
||||
|
||||
** unimplemented due to limited support **
|
||||
- test_nfc_iso7816_supported
|
||||
- test_nfc_add_iso7816_application
|
||||
- test_nfc_set_tagtype
|
||||
- test_nfc_get_tagtype
|
||||
|
||||
|
||||
## cli commands
|
||||
cli commands take parameters, its possible to type help at the cli for a list of commands.
|
||||
```
|
||||
mbed sterm --baudrate 115200
|
||||
help
|
||||
...
|
||||
getlastnfcerror last NFC error code
|
||||
setlastnfcerror self-test
|
||||
initnfc init NFC driver
|
||||
setsmartposter send smartposter NDEF
|
||||
iseeprom NFC configEEPROM present
|
||||
readmessage read EEPROM else return last message
|
||||
erase erase EEPROM or clear last message
|
||||
writelong fill entire FILE with pattern
|
||||
...
|
||||
```
|
||||
Note: Most commands also return a NFC status value (type "getlastnfcerror help" in console) which allow us to build negative test cases.
|
||||
Note: Some commands only apply to NFC controllers, these commands fail with the appropriate not-supported code NFC_ERR_UNSUPPORTED and additionally return -2 error code to ice-tea.
|
||||
|
||||
**unimplemented CLI commands**
|
||||
commands that were not implemented in the test app
|
||||
- set/get tag type
|
||||
- get/set iso7816 app
|
||||
|
||||
**Excluded**
|
||||
- power consumption
|
||||
- throughput
|
||||
- memory consumption
|
||||
|
||||
## How to
|
||||
**Wirring diagram for NFC Explorer with PN512**
|
||||
|
||||
If using the Raspbery Pi explorer (PN512) board, use this pinout mapping diagram to connect the shield to the reference target. In this case a ST NucleoF401RE pinout is shown.
|
||||
```
|
||||
Nucleo F401RE Explore NFC
|
||||
(Arduino header) (pin1 on shield shown with a <|)
|
||||
+-------+ +-------+ +--------+
|
||||
| [NC] | | [B8] | |[ 2][ 1]|
|
||||
| [IOREF| | [B9] | |[ 4][ 3]|
|
||||
| [RST] | | [AVDD]| |[ 6][ 5]|
|
||||
1<---+ [3V3] | | [GND] | |[ 8][ 7]|
|
||||
| [5V] | | [A5] +--->23 |[10][ 9]|
|
||||
| [GND] | | [A6] +--->21 |[12][11]|
|
||||
25<--+ [GND] | | [A7] +--->19 |[14][13]|
|
||||
| [VIN] | | [B6] +--->3 |[16][15]|
|
||||
| | | [C7] | |[18][17]|
|
||||
26<--+ [A0] | | [A9] | |[20][19]|
|
||||
16<--+ [A1] | | [A9] | |[22][21]|
|
||||
| ... | | | |[24][23]|
|
||||
| | | [A8] | |[26][25]|
|
||||
+-------+ | ... | +--------+
|
||||
| |
|
||||
| |
|
||||
+-------+
|
||||
|
||||
Patch using jumper wires to the
|
||||
indicated pins on the Shield.
|
||||
|
||||
```
|
||||
Schematic (https://www.element14.com/community/docs/DOC-76384/l/explore-nfc-board-schematic)
|
||||
To change pinouts, if your reference design or shield pins differ for the PN512 controller driver, open nfcProcessCtrl.cpp and find the code
|
||||
```
|
||||
NFCProcessController::NFCProcessController(events::EventQueue &queue) :
|
||||
// pins: mosi, miso, sclk, ssel, irq, rst
|
||||
_pn512_transport(D11, D12, D13, D10, A1, A0), _pn512_driver(
|
||||
&_pn512_transport), _queue(queue), _nfc_controller(
|
||||
&_pn512_driver, &queue, _ndef_buffer) {
|
||||
}
|
||||
```
|
||||
modify pins as needed.
|
||||
|
||||
**Compilation target drivers**
|
||||
|
||||
If using the EEPROM driver, the mbed_app.json will contain
|
||||
```
|
||||
"target_overrides": {
|
||||
"DISCO_L475VG_IOT01A": {
|
||||
"target.extra_labels_add": ["M24SR"]
|
||||
}
|
||||
}
|
||||
...
|
||||
```
|
||||
If using the Explorer Shield or PN512 driver mbed_app.json will add
|
||||
```
|
||||
"target_overrides": {
|
||||
"NUCLEO_F401RE": {
|
||||
"target.extra_labels_add": ["PN512"]
|
||||
}
|
||||
}
|
||||
...
|
||||
```
|
||||
## Alternate NFC drivers note:
|
||||
|
||||
Please see the example json file .\TEST_APPS\testcases\nfc\mbed_app.json . The test does not check that you have any needed shield installed, so if it "hangs" at the point the "initnfc" command is used, the driver or shield may be the fault. The test assumes that MBED_CONF_NFCEEPROM is set to 1, if not it assumes that a controller driver is in use. To add support for other then PN512 and M24SR, it is required to add the support.
|
||||
|
||||
If the driver you add is for Eeprom, open nfccommands.cpp and find the code and modify line as shown +++
|
||||
```
|
||||
NFCTestShim* new_testshim() {
|
||||
#if MBED_CONF_NFCEEPROM
|
||||
--- mbed::nfc::NFCEEPROMDriver& eeprom_driver = get_eeprom_driver(nfcQueue);
|
||||
|
||||
+++ mbed::nfc::NFCEEPROMDriver& eeprom_driver = get_myeeprom_driver(nfcQueue);
|
||||
|
||||
return ( (NFCTestShim *)(new NFCProcessEEPROM(nfcQueue, eeprom_driver)) );
|
||||
#else
|
||||
return ((NFCTestShim *) (new NFCProcessController(nfcQueue)));
|
||||
#endif // EEPROM
|
||||
```
|
||||
|
||||
If the driver you add is a controller driver, open nfcProcessCtrl.cpp and find the code
|
||||
```
|
||||
NFCProcessController::NFCProcessController(events::EventQueue &queue) :
|
||||
// pins: mosi, miso, sclk, ssel, irq, rst
|
||||
_pn512_transport(D11, D12, D13, D10, A1, A0), _pn512_driver(
|
||||
&_pn512_transport), _queue(queue), _nfc_controller(
|
||||
&_pn512_driver, &queue, _ndef_buffer) {
|
||||
}
|
||||
```
|
||||
1. You will want to replace with a reference to the desired controller driver. Likewise this is where pinout hanges if using a supplied controller driver have to be made.
|
||||
2. Search for occurences of guard macro #ifdef TARGET_PN512 , and add guard code for your specific controller driver.
|
||||
|
||||
## Running the tests
|
||||
1. Wire an [explorer shield](https://cpc.farnell.com/nxp/explore-nfc/add-on-board-nfc-for-raspberry/dp/SC13404) up to and compile the target application.
|
||||
2. Provision the target, and verify that it responds with an _`action NDEF record http://www.mbed.com`_ by using a mobile phone to scan over the antenna.
|
||||
3. Install python (2.7) and install the nfcpy library, [see](https://nfcpy.readthedocs.io/en/latest/topics/get-started.html) . NFC reader can be connected to a serial port, or more commonly a USB dongle. Verify the dongle is functioning.
|
||||
4. Place the scanner near the explorer shield. Run various test program commands like so:
|
||||
- python ice_device -command describe
|
||||
|
||||
**run the suite**
|
||||
In a working folder, run
|
||||
|
||||
`git clone https://github.com/ARMmbed/mbed-os.git`
|
||||
|
||||
|
||||
|
||||
If using discovery and the M24SR driver, you need to:
|
||||
`git clone https://github.com/ARMmbed/mbed-nfc-m24sr.git'
|
||||
|
||||
|
||||
And copy the files something like this:
|
||||
`xcopy ..\mbed-nfc-m24sr\*.* .\eeprom_driver\'
|
||||
|
||||
To run the End2End tests, type:
|
||||
`mbed test --icetea -n test_nfce2e`
|
||||
|
||||
To run only the standalone (readerless tests if you do not have a card reader), type:
|
||||
`mbed test --icetea -n test_nfc_eeprom,test_nfc_error_codes,test_nfc_setsmartposter,test_nfc_erase,test_nfc_write_long`
|
||||
|
||||
**Using the app standalone**
|
||||
|
||||
The target app can accept commandline inputs over serial.
|
||||
```
|
||||
mbed sterm --baudrate 115200
|
||||
```
|
||||
|
||||
Note: If the target uses an EEPROM, it need not be powered/running, to be read, mbedOS is not running at that point.
|
||||
|
||||
**Device API error codes**
|
||||
You can issue the command "getlastnfcerror help" to see a list of error codes that are returned by most commands.
|
||||
```
|
||||
#define NFC_OK 0 ///< No error
|
||||
#define NFC_ERR_UNKNOWN 1 ///< Unknown error
|
||||
#define NFC_ERR_LENGTH 2 ///< Length of parameter is wrong
|
||||
#define NFC_ERR_NOT_FOUND 3 ///< Could not find item
|
||||
#define NFC_ERR_UNSUPPORTED 4 ///< This action is not supported
|
||||
#define NFC_ERR_PARAMS 5 ///< These parameters are not correct
|
||||
#define NFC_ERR_BUFFER_TOO_SMALL 6 ///< The buffer is too small to store all data (buffer overflow)
|
||||
#define NFC_ERR_TIMEOUT 7 ///< Timeout
|
||||
#define NFC_ERR_CRC 8 ///< Checksum does not match
|
||||
#define NFC_ERR_NOPEER 9 ///< No target/initiator in vicinity
|
||||
#define NFC_ERR_PARITY 10 ///< Parity error
|
||||
#define NFC_ERR_FIELD 11 ///< No RF field detected (or RF field lost)
|
||||
#define NFC_ERR_COLLISION 12 ///< Collision detected
|
||||
#define NFC_ERR_WRONG_COMM 13 ///< Communication error
|
||||
#define NFC_ERR_PROTOCOL 14 ///< Protocol is not conformant
|
||||
#define NFC_ERR_BUSY 15 ///< Resource is busy
|
||||
#define NFC_ERR_CONTROLLER 16 ///< Controller failure
|
||||
#define NFC_ERR_HALTED 17 ///< Target has been halted
|
||||
#define NFC_ERR_MAC 18 ///< MAC does not match
|
||||
#define NFC_ERR_UNDERFLOW 19 ///< Could not send data in time
|
||||
#define NFC_ERR_DISCONNECTED 20 ///< Link has disconnected
|
||||
#define NFC_ERR_ABORTED 21 ///< Command was aborted
|
||||
```
|
Binary file not shown.
After Width: | Height: | Size: 35 KiB |
Binary file not shown.
After Width: | Height: | Size: 28 KiB |
Binary file not shown.
After Width: | Height: | Size: 37 KiB |
|
@ -0,0 +1,94 @@
|
|||
# NFC test SDK comparison
|
||||
|
||||
A comparison of the SDKs exposed to manage NFC tags on Android IOs and Python module PyNFC.
|
||||
|
||||
<!-- TOC -->
|
||||
|
||||
- [NFC test SDK comparison](#nfc-test-sdk-comparison)
|
||||
- [Overview](#overview)
|
||||
- [Comparison](#comparison)
|
||||
- [IOS (objective C)](#ios-objective-c)
|
||||
- [Android (Java)](#android-java)
|
||||
- [pynfc (python)](#pynfc-python)
|
||||
- [Observe](#observe)
|
||||
|
||||
<!-- /TOC -->
|
||||
|
||||
# Overview
|
||||
A comparison which analyses NFC use cases on mobile, as background to the test case design/implementation in the comissioning workflow :NFC-Bluetooth-pairing application.
|
||||
- Analyse the [Apple API](https://developer.apple.com/documentation/corenfc)
|
||||
- Analyse the [Android API](https://developer.android.com/guide/topics/connectivity/nfc/advanced-nfc#java)
|
||||
- Python test [pynfc modules](https://nfcpy.readthedocs.io/en/latest/modules/index.html)
|
||||
|
||||
|
||||
# Comparison
|
||||
From the lowest level, each programmer interface has a definition for Errors, Link, NDEF, Tags and Sessions.
|
||||
Note: Comparisons are high level and use past experience and old docs.
|
||||
|
||||
|
||||
## IOS (objective C)
|
||||
1. Errors:
|
||||
are a struct with 3 members:<BR>
|
||||
int:value, <BR>struct:string:usererror<BR>struct:string:localized
|
||||
1. isodep:
|
||||
|
||||
not supported
|
||||
1. NDEF support parameters with
|
||||
|
||||
payload<BR>and Typename,
|
||||
4. Tags:
|
||||
|
||||
Are an Object representing tag
|
||||
5. Sessions are managed using
|
||||
|
||||
Delegate &callbacks
|
||||
|
||||
## Android (Java)
|
||||
1. Errors:
|
||||
|
||||
thrown as IOException with cause and message, there are no returned error datas
|
||||
2. isodep:
|
||||
|
||||
get/set communication parameters and RAW.
|
||||
3. NDEF:
|
||||
|
||||
Includes SNEP
|
||||
4. Tags :
|
||||
|
||||
(3)A,(3)B,(4)F,V and isoDep layer
|
||||
5. Sessions
|
||||
|
||||
Intents and Actions, runtime registration of PendingIntent() allows hooking using tag filters
|
||||
|
||||
## pynfc (python)
|
||||
1. Errors :
|
||||
|
||||
raises Exceptions nfc.clf.Error and others per class
|
||||
2. isodep:
|
||||
|
||||
get/set communication parameters and RAW.
|
||||
3. NDEF:
|
||||
|
||||
full implementation and types. Includes SNEP
|
||||
4. Tags :
|
||||
|
||||
1,2,(3)A,(3)B,(4)F isoDep layer
|
||||
5. Sessions :
|
||||
|
||||
using delegate class callbacks
|
||||
|
||||
# Observe
|
||||
Negative test cases would be better designed around the user cases, than around the implementations, base error conditions at the API layer look more like
|
||||
- UnsupportedTarget
|
||||
- Communication
|
||||
- Protocol
|
||||
- (w) Transmission
|
||||
- (w) Timeout
|
||||
- (w) BrokenLink
|
||||
- ValueError
|
||||
|
||||
Valuable test data cases shall be for valid and boundary cases for the smartposter NDEF record:
|
||||
- uri – URI string ASCII only
|
||||
- title – Smart poster title(s), (additional internationalizations with IANA codes not tested)
|
||||
- icons – omitted
|
||||
- action – The recommended action , a string
|
|
@ -0,0 +1,133 @@
|
|||
"""
|
||||
Copyright 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.
|
||||
"""
|
||||
|
||||
import time
|
||||
import nfc
|
||||
from nfc.clf import RemoteTarget
|
||||
import logging
|
||||
|
||||
logprefixnfc = "NFCPY: "
|
||||
|
||||
"""
|
||||
Wrap calls to nfcpi testing module, handle loading the driver
|
||||
"""
|
||||
|
||||
|
||||
def command_is(string, command):
|
||||
return string.split(' ')[0] == command
|
||||
|
||||
|
||||
def debug_nfc_data(key, value):
|
||||
"""
|
||||
print useful data values for the host/user {{in between}} easy to spot brackets.
|
||||
"""
|
||||
text = "{{%s=%s}}" % (key, value)
|
||||
logger.info(text)
|
||||
|
||||
|
||||
logging.basicConfig(level=logging.DEBUG) # read commandline value?
|
||||
logger = logging.getLogger()
|
||||
|
||||
|
||||
class NfcWrapper:
|
||||
"""
|
||||
Finds the NFC reader USB front-end and prepares it for use.
|
||||
"""
|
||||
def __init__(self):
|
||||
# will need a parameter here to help with libusb detection?
|
||||
# clf.open("usb:04e6:5591") will open the SCL3711-NFC
|
||||
logger.info("Initializing the NFC tag reader...")
|
||||
self.clf = nfc.ContactlessFrontend()
|
||||
if (self.clf.open("usb") ): # the NFC reader was not detected on any USB port!
|
||||
logger.info("NFC Frontend found OK")
|
||||
else:
|
||||
logger.error("The NFC reader was not detected on any USB port!")
|
||||
self.clfResponse = None
|
||||
|
||||
def clf_response(self):
|
||||
return self.clfResponse
|
||||
|
||||
def parse(self,line):
|
||||
logging.debug(line)
|
||||
parseok = False
|
||||
# find command and call the needed nfcWrapper method
|
||||
if command_is(line, "ping"):
|
||||
self.pong()
|
||||
parseok = True
|
||||
if command_is(line, "connect"):
|
||||
detectedTag = self.connect()
|
||||
debug_nfc_data("Connectedtag", detectedTag)
|
||||
parseok = True
|
||||
if command_is(line, "mute"):
|
||||
detectedTag = self.mute()
|
||||
parseok = True
|
||||
if command_is(line, "disconnect"):
|
||||
self.disconnect()
|
||||
parseok = True
|
||||
return parseok
|
||||
|
||||
"""return the detected tag, else timeout after interval"""
|
||||
def sense(self, target_options = ("106A","106B","212F")):
|
||||
logging.info(logprefixnfc + "detecting tags with options " + target_options)
|
||||
# todo filter using the target_options
|
||||
targets = self.clf.sense(RemoteTarget('106A'), RemoteTarget('106B'), RemoteTarget('212F'))
|
||||
self.clfResponse = targets
|
||||
return targets
|
||||
|
||||
def connect(self, target_options = ("106A","106B","212F")):
|
||||
# todo: decide on tag types to allow/filter
|
||||
after5s = lambda: time.time() - started > 5
|
||||
started = time.time()
|
||||
tag = self.clf.connect( rdwr={'on-connect': lambda tag: False},
|
||||
llcp={}, terminate = after5s)
|
||||
self.clfResponse = tag
|
||||
if tag: # None if timeout expires
|
||||
logging.info(logprefixnfc + str(tag))
|
||||
return tag
|
||||
|
||||
def mute(self):
|
||||
"""turn off the reader radio"""
|
||||
if self.clf.device:
|
||||
logging.info(logprefixnfc + "radio mute" + self.clf.device.product_name)
|
||||
self.clf.device.mute()
|
||||
|
||||
def disconnect(self):
|
||||
logging.info(logprefixnfc + "close frontend.")
|
||||
self.clf.close()
|
||||
|
||||
"""
|
||||
Handle interactions with the NFC reader, and singleton
|
||||
"""
|
||||
class ContactlessCommandRunner():
|
||||
|
||||
"""
|
||||
Lazy initialization singleton to open the reader once only - else when the framework scans for
|
||||
tests, it causes us to open the reader. This breaks the Windows driver.
|
||||
"""
|
||||
def __getattr__(self, name):
|
||||
if name == 'nfc':
|
||||
|
||||
if ContactlessCommandRunner.__nfc_wrapper is None:
|
||||
ContactlessCommandRunner.__nfc_wrapper = NfcWrapper()
|
||||
return ContactlessCommandRunner.__nfc_wrapper
|
||||
|
||||
__nfc_wrapper = None
|
||||
|
||||
# plumbing, calls a static instance for the reader object.
|
||||
def parse(self, line):
|
||||
return self.nfc.parse(line)
|
||||
|
||||
def clf_response(self):
|
||||
return self.nfc.clf_response()
|
|
@ -0,0 +1,70 @@
|
|||
"""
|
||||
Copyright 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.
|
||||
"""
|
||||
|
||||
# ice-tea cli commands decorator class
|
||||
|
||||
|
||||
from nfc_messages import NfcErrors
|
||||
import logging
|
||||
import icetea_lib.tools.asserts as asserts
|
||||
|
||||
class CliHelper():
|
||||
"""
|
||||
Helper method, checks the nfc SDK error-code for you, makes writing a negative test much easier
|
||||
Example:
|
||||
if (target_is_eeprom):
|
||||
nfc_command("dev1", "start", expected_retcode=-2, expected_nfc_error= NfcErrors.nfc_err_unsupported)
|
||||
else:
|
||||
nfc_command("dev1", "start")
|
||||
"""
|
||||
|
||||
def nfc_command(self, k, cmd, # pylint: disable=invalid-name
|
||||
wait=True,
|
||||
timeout=10,
|
||||
expected_retcode=0,
|
||||
asynchronous=False,
|
||||
report_cmd_fail=True,
|
||||
expected_nfc_error=NfcErrors.nfc_ok):
|
||||
response = self.command(k, cmd, wait, timeout, expected_retcode, asynchronous, report_cmd_fail)
|
||||
asserts.assertEqual(int(response.parsed['lastnfcerror']), expected_nfc_error.value)
|
||||
return response
|
||||
|
||||
@staticmethod
|
||||
def command_is(string, command):
|
||||
return string.split(' ')[0] == command
|
||||
|
||||
@staticmethod
|
||||
def debug_nfc_data(key, value):
|
||||
"""
|
||||
print useful data values for the host/user {{in between}} easy to spot brackets.
|
||||
"""
|
||||
text = "{{%s=%s}}" % (key, value)
|
||||
logging.Logger.info(text)
|
||||
|
||||
def assert_binary_equal(self, left, right, length):
|
||||
i = 0
|
||||
while i < length:
|
||||
asserts.assertEqual(left[i], ord(right[i]), ("Missmatch @offset %d 0x%x <> 0x%x" % (i, left[i], ord(right[i]))) )
|
||||
i = i + 1
|
||||
|
||||
def assert_text_equal(self, left, right, length):
|
||||
"""
|
||||
Asserts if the 2 buffers (Text) differ
|
||||
"""
|
||||
i = 0
|
||||
while i < length:
|
||||
asserts.assertEqual(ord(left[i]), ord(right[i]), ("Missmatch @offset %d %d <> %d" % (i, ord(left[i]), ord(right[i]))) )
|
||||
i = i + 1
|
||||
|
|
@ -0,0 +1,72 @@
|
|||
import nfc
|
||||
from enum import Enum
|
||||
import logging
|
||||
|
||||
|
||||
class NfcErrors(Enum):
|
||||
nfc_ok = 0
|
||||
nfc_err_unknown = 1
|
||||
nfc_err_length = 2
|
||||
nfc_err_not_found = 3
|
||||
nfc_err_unsupported = 4
|
||||
nfc_err_params = 5
|
||||
nfc_err_buffer_too_small= 6
|
||||
nfc_err_timeout = 7
|
||||
nfc_err_crc = 8
|
||||
nfc_err_nopeer = 9
|
||||
nfc_err_parity = 10
|
||||
nfc_err_field = 11
|
||||
nfc_err_collision = 12
|
||||
nfc_err_wrong_comm = 13
|
||||
nfc_err_protocol = 14
|
||||
nfc_err_busy = 15
|
||||
nfc_err_controller = 16
|
||||
nfc_err_halted = 17
|
||||
nfc_err_mac = 18
|
||||
nfc_err_underflow = 19
|
||||
nfc_err_disconnected = 20
|
||||
nfc_err_aborted = 21
|
||||
|
||||
|
||||
'''
|
||||
return a 'T'ext text ndef record
|
||||
'''
|
||||
def make_textrecord(text, language='en-US'):
|
||||
return nfc.ndef.Message(nfc.ndef.TextRecord(text, language))
|
||||
|
||||
'''
|
||||
Return an NDEF message
|
||||
resource -- url
|
||||
titles -- list of : colon delimited titles where an optional language code precedes the title -
|
||||
if lang codes are omitted, 'en' is assumed
|
||||
action -- one of default/save/exec/edit
|
||||
'''
|
||||
def make_smartposter(resource, titles, action = 'default'):
|
||||
record = nfc.ndef.SmartPosterRecord(resource)
|
||||
for title in titles:
|
||||
lang, text = title.split(':', 1) if ':' in title else ('en', title)
|
||||
record.title[lang] = text
|
||||
if not action in ('default', 'exec', 'save', 'edit'):
|
||||
logging.error("action not one of 'default', 'exec', 'save', 'edit'")
|
||||
return
|
||||
record.action = action
|
||||
|
||||
return nfc.ndef.Message(record)
|
||||
|
||||
|
||||
'''
|
||||
Program the provided NDEF messsage into the tag (authentication is not required)
|
||||
'''
|
||||
def program_remote_tag(message, tag):
|
||||
if not tag.ndef.is_writeable:
|
||||
logging.error("This Tag is not writeable.")
|
||||
return False
|
||||
tag.ndef.message = message
|
||||
logging.info("Programmed tag OK.")
|
||||
return True
|
||||
|
||||
'''
|
||||
Builds a long string by repeating a shorter string up to the required length
|
||||
'''
|
||||
def repeat_string_to_length(string_to_expand, length):
|
||||
return (string_to_expand * ((length/len(string_to_expand))+1))[:length]
|
|
@ -0,0 +1,293 @@
|
|||
"""
|
||||
Copyright 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.
|
||||
"""
|
||||
|
||||
|
||||
from icetea_lib.bench import Bench
|
||||
from nfc_clf_wrapper import ContactlessCommandRunner
|
||||
import nfc_messages
|
||||
import time
|
||||
from mbed_clitest.tools.tools import test_case
|
||||
import icetea_lib.tools.asserts as asserts
|
||||
from nfc_messages import NfcErrors
|
||||
from nfc_cli_helper import CliHelper
|
||||
|
||||
|
||||
class CreamSconeTests(Bench, CliHelper):
|
||||
"""
|
||||
This test wrapper requires a usb connected contactless card reader dongle, and allows E2E testing.
|
||||
See readme file for details
|
||||
"""
|
||||
def __init__(self, **kwargs):
|
||||
testcase_args = {
|
||||
'title':"NFC tests with a reader",
|
||||
'status':"development",
|
||||
'purpose':"NFC e2e",
|
||||
'component':["NFC"],
|
||||
'type':"regression",
|
||||
'requirements':{
|
||||
"duts": {
|
||||
'*': {
|
||||
"count": 1,
|
||||
"type": "hardware",
|
||||
"application": {
|
||||
"name": "TEST_APPS-device-nfcapp"
|
||||
}
|
||||
},
|
||||
"1": {"nick": "dev1"}
|
||||
}
|
||||
}
|
||||
}
|
||||
testcase_args.update(kwargs)
|
||||
Bench.__init__(self, **testcase_args)
|
||||
|
||||
def setup(self):
|
||||
try:
|
||||
self.clf = ContactlessCommandRunner()
|
||||
self.clf.parse("mute")
|
||||
except:
|
||||
raise asserts.TestStepFail("Could not find NFC reader")
|
||||
|
||||
def teardown(self):
|
||||
self.logger.info("Test teardown: Reboot target...")
|
||||
self.reset_dut()
|
||||
|
||||
|
||||
|
||||
@test_case(CreamSconeTests)
|
||||
def test_nfce2e_target_found(self):
|
||||
"""
|
||||
smoke - Our emulated tag is detectable
|
||||
"""
|
||||
|
||||
response = self.nfc_command("dev1", "iseeprom")
|
||||
eeprom = response.parsed['iseeprom']
|
||||
self.nfc_command("dev1", "initnfc")
|
||||
if not eeprom:
|
||||
self.nfc_command("dev1", "start")
|
||||
|
||||
self.clf.parse("connect")
|
||||
tag = self.clf.clf_response()
|
||||
asserts.assertNotNone(tag, "Could not connect to any tag")
|
||||
|
||||
|
||||
@test_case(CreamSconeTests)
|
||||
def test_nfce2e_type4_found(self):
|
||||
"""
|
||||
check - Type 4 tag is detected wirelessly
|
||||
NOTE: If the tage emulation does not default to type4, this test needs to be modified
|
||||
+++ self.nfc_command("dev1", "setprotocols t4t")
|
||||
or the assertion be adapated according to support desired level
|
||||
"""
|
||||
|
||||
response = self.nfc_command("dev1", "iseeprom")
|
||||
eeprom = response.parsed['iseeprom']
|
||||
self.nfc_command("dev1", "initnfc")
|
||||
if not eeprom:
|
||||
self.nfc_command("dev1", "start")
|
||||
|
||||
self.clf.parse("connect")
|
||||
tag = self.clf.clf_response()
|
||||
asserts.assertNotNone(tag, "Could not connect to any tag")
|
||||
|
||||
asserts.assertEqual(tag.type, 'Type4Tag', "Tag of type Type4Tag not found")
|
||||
|
||||
|
||||
@test_case(CreamSconeTests)
|
||||
def test_nfce2e_smartposter(self):
|
||||
"""
|
||||
check - Tag can be set and read via contactless
|
||||
"""
|
||||
expectedURI = "https://www.mbed.com" # ensure that these differ per test case
|
||||
|
||||
self.nfc_command("dev1", "initnfc")
|
||||
self.nfc_command("dev1", "erase")
|
||||
response = self.nfc_command("dev1", "iseeprom")
|
||||
eeprom = response.parsed['iseeprom']
|
||||
|
||||
self.logger.info("Target includes NFCEEPROM: %s" % eeprom)
|
||||
if not eeprom:
|
||||
self.nfc_command("dev1", "start")
|
||||
|
||||
# write poster tag to target
|
||||
self.command("dev1", "setsmartposter %s" % expectedURI)
|
||||
|
||||
self.clf.parse("connect")
|
||||
tag = self.clf.clf_response()
|
||||
asserts.assertNotNone(tag, "Could not connect to any tag")
|
||||
asserts.assertEqual(1, len(tag.ndef.records), "expected number NDEF records")
|
||||
|
||||
asserts.assertEqual(tag.ndef.records[0].__class__.__name__, "SmartposterRecord", "expected SmartposterRecord")
|
||||
asserts.assertEqual(expectedURI, tag.ndef.records[0].uri_records[0].uri, "expected exact URI")
|
||||
|
||||
|
||||
@test_case(CreamSconeTests)
|
||||
def test_nfce2e_reprogrammed(self):
|
||||
"""
|
||||
check - Tag can be programmed from a remote and read via contactless
|
||||
"""
|
||||
expectedURI = "https://www.google.com"
|
||||
|
||||
response = self.nfc_command("dev1", "iseeprom")
|
||||
eeprom = response.parsed['iseeprom']
|
||||
self.logger.info("Target includes NFCEEPROM: %s" % eeprom)
|
||||
|
||||
self.nfc_command("dev1", "initnfc")
|
||||
if not eeprom:
|
||||
self.nfc_command("dev1", "start")
|
||||
self.nfc_command("dev1", "erase")
|
||||
|
||||
# program a poster tag to target
|
||||
self.clf.parse("connect")
|
||||
tag = self.clf.clf_response()
|
||||
asserts.assertNotNone(tag, "Could not connect to any tag")
|
||||
smartposter = nfc_messages.make_smartposter(expectedURI, ["en-US:Other search engines exist"])
|
||||
nfc_messages.program_remote_tag(smartposter, tag)
|
||||
self.logger.info("Remote programmed %d bytes Smartposter" % len(str(smartposter)))
|
||||
|
||||
# read device
|
||||
self.clf.parse("connect")
|
||||
tag = self.clf.clf_response()
|
||||
asserts.assertNotNone(tag, "Could not re-connect to any tag")
|
||||
|
||||
asserts.assertEqual(tag.ndef.records[0].__class__.__name__, "SmartposterRecord", "expected SmartposterRecord")
|
||||
asserts.assertEqual(expectedURI, tag.ndef.records[0].uri_records[0].uri, "expected exact URI")
|
||||
self.clf.parse("mute") # disable radio
|
||||
|
||||
# verify in target
|
||||
response = self.nfc_command("dev1", "readmessage")
|
||||
|
||||
# check contents
|
||||
expected_message = str(smartposter)
|
||||
asserts.assertEqual(len(response.parsed['nfcmessage']), len(expected_message))
|
||||
self.assert_binary_equal(response.parsed['nfcmessage'], expected_message, len(expected_message))
|
||||
|
||||
|
||||
@test_case(CreamSconeTests)
|
||||
def test_nfce2e_read_stress(self):
|
||||
"""
|
||||
check - Large record can be read via contactless
|
||||
"""
|
||||
messageRep = 'thequickbrownfoxjumpedoverthelazydog' # repeating message written
|
||||
textLength = 2050 # 2K < x < 4K
|
||||
|
||||
# calculate actual message to compare to using the library
|
||||
expected_text = nfc_messages.repeat_string_to_length(messageRep, textLength)
|
||||
message = nfc_messages.make_textrecord( expected_text )
|
||||
|
||||
response = self.nfc_command("dev1", "iseeprom")
|
||||
eeprom = response.parsed['iseeprom']
|
||||
self.logger.info("Target includes NFCEEPROM: %s" % eeprom)
|
||||
|
||||
self.nfc_command("dev1", "initnfc")
|
||||
if not eeprom:
|
||||
self.nfc_command("dev1", "start")
|
||||
self.nfc_command("dev1", "erase")
|
||||
self.nfc_command("dev1", "writelong %d %s" % (textLength,messageRep))
|
||||
|
||||
self.clf.parse("connect")
|
||||
tag = self.clf.clf_response()
|
||||
asserts.assertNotNone(tag, "Could not connect to any tag")
|
||||
|
||||
# assert that read the eeprom contents gives correct data and length
|
||||
asserts.assertEqual(tag.ndef.records[0].__class__.__name__, "TextRecord", "expected TextRecord")
|
||||
asserts.assertEqual(len(tag.ndef.records[0].text), len(expected_text))
|
||||
self.assert_text_equal(tag.ndef.records[0].text, expected_text, len(expected_text))
|
||||
|
||||
|
||||
@test_case(CreamSconeTests)
|
||||
def test_nfce2e_reprogrammed_stress(self):
|
||||
"""
|
||||
check - Large record can be programmed from a remote and read via contactless
|
||||
"""
|
||||
messageRep = 'thequickbrownfoxjumpedoverthelazydog' # repeating message written
|
||||
textLength = 2050 # 2K < x < 4K
|
||||
|
||||
# calculate actual message to compare to using the library
|
||||
message = nfc_messages.make_textrecord( nfc_messages.repeat_string_to_length(messageRep, textLength))
|
||||
expected_message = str(message)
|
||||
|
||||
response = self.nfc_command("dev1", "iseeprom")
|
||||
eeprom = response.parsed['iseeprom']
|
||||
self.logger.info("Target includes NFCEEPROM: %s" % eeprom)
|
||||
|
||||
self.nfc_command("dev1", "initnfc")
|
||||
if not eeprom:
|
||||
self.nfc_command("dev1", "start")
|
||||
self.nfc_command("dev1", "erase")
|
||||
|
||||
# program a large tag to target wirelessly
|
||||
self.clf.parse("connect")
|
||||
tag = self.clf.clf_response()
|
||||
asserts.assertNotNone(tag, "Could not connect to any tag")
|
||||
nfc_messages.program_remote_tag(message, tag)
|
||||
self.logger.info("%d bytes chunk of data written to tag remotely" % len(str(message)))
|
||||
|
||||
# read device
|
||||
self.clf.parse("connect")
|
||||
tag = self.clf.clf_response()
|
||||
asserts.assertNotNone(tag, "Could not re-connect to any tag")
|
||||
self.clf.parse("mute") # disable the reader radio
|
||||
|
||||
# verify in target
|
||||
response = self.nfc_command("dev1", "readmessage")
|
||||
asserts.assertEqual(len(response.parsed['nfcmessage']), len(expected_message))
|
||||
self.assert_binary_equal(response.parsed['nfcmessage'], expected_message, len(expected_message))
|
||||
|
||||
|
||||
@test_case(CreamSconeTests)
|
||||
def test_nfce2e_discovery_loop(self):
|
||||
"""
|
||||
check - Controller discovery loop stop/start
|
||||
fails : blocked by an issue
|
||||
"""
|
||||
expectedURI = "https://www.nasa.com" # ensure that these differ per test case
|
||||
|
||||
response = self.command("dev1", "iseeprom") # will hold result from the init lib call
|
||||
eeprom = response.parsed['iseeprom']
|
||||
self.logger.info("Target includes NFCEEPROM: %s" % eeprom)
|
||||
|
||||
self.nfc_command("dev1", "initnfc") # this NOT automatically start discovery at the same time, the test command "start" must be used on a controller. (Eeeproms always have the loop enabled.)
|
||||
# By default, the test app automatically starts discovery loop again after a reader disconnects from the controller.
|
||||
# Automatic resume after disconnect can be turned off by using command "start man" , the default is "start auto" .
|
||||
|
||||
if not eeprom:
|
||||
self.clf.parse("connect")
|
||||
tag = self.clf.clf_response()
|
||||
asserts.assertNone(tag, "post-init: Tag discovery loop should be stopped!")
|
||||
self.nfc_command("dev1", "stop")
|
||||
time.sleep(1)
|
||||
|
||||
self.clf.parse("connect")
|
||||
tag = self.clf.clf_response()
|
||||
asserts.assertNone(tag, "post-stop: Tag discovery loop should be stopped!")
|
||||
self.nfc_command("dev1", "start")
|
||||
time.sleep(1)
|
||||
|
||||
self.clf.parse("connect")
|
||||
tag = self.clf.clf_response()
|
||||
asserts.assertNotNone(tag, "Could not connect to any tag")
|
||||
|
||||
self.clf.parse("mute")
|
||||
self.nfc_command("dev1", "stop")
|
||||
time.sleep(10)
|
||||
self.clf.parse("connect")
|
||||
tag = self.clf.clf_response()
|
||||
# test blocked by issue raised IOTPAN313 NFC Controller discovery can stop but cannot restart - PN512
|
||||
asserts.assertNone(tag, "post-restart: Tag discovery loop should be stopped!")
|
||||
|
||||
else:
|
||||
# eeprom, so not supported
|
||||
self.nfc_command("dev1", "start", expected_retcode=-2, expected_nfc_error= NfcErrors.nfc_err_unsupported )
|
||||
self.nfc_command("dev1", "stop", expected_retcode=-2, expected_nfc_error= NfcErrors.nfc_err_unsupported )
|
|
@ -0,0 +1,188 @@
|
|||
"""
|
||||
Copyright 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.
|
||||
"""
|
||||
|
||||
import time
|
||||
from icetea_lib.bench import Bench
|
||||
from mbed_clitest.tools.tools import test_case
|
||||
import icetea_lib.tools.asserts as asserts
|
||||
import nfc_messages
|
||||
from nfc_messages import NfcErrors
|
||||
from nfc_cli_helper import CliHelper
|
||||
|
||||
|
||||
"""
|
||||
Standalone (no NFC reader needed) tests, which cover API with no end-to-end checks.
|
||||
"""
|
||||
class CreamSconeSelfTests(Bench, CliHelper):
|
||||
def __init__(self, **kwargs):
|
||||
testcase_args = {
|
||||
'title':"NFC tests with no reader",
|
||||
'status':"development",
|
||||
'purpose':"NFC target-only checks",
|
||||
'component':["NFC"],
|
||||
'type':"smoke",
|
||||
'requirements':{
|
||||
"duts": {
|
||||
'*': {
|
||||
"count": 1,
|
||||
"type": "hardware",
|
||||
"application": {
|
||||
"name": "TEST_APPS-device-nfcapp"
|
||||
}
|
||||
},
|
||||
"1": {"nick": "dev1"}
|
||||
}
|
||||
}
|
||||
}
|
||||
testcase_args.update(kwargs)
|
||||
Bench.__init__(self, **testcase_args)
|
||||
|
||||
def setup(self):
|
||||
pass
|
||||
|
||||
def teardown(self):
|
||||
self.logger.info("Test teardown: Reboot target...")
|
||||
self.reset_dut()
|
||||
|
||||
|
||||
"""
|
||||
smoke - target app is running, and can exchange simple values
|
||||
"""
|
||||
@test_case(CreamSconeSelfTests)
|
||||
def test_nfc_error_codes(self):
|
||||
wally = NfcErrors.nfc_err_not_found
|
||||
for x in range(0, 3):
|
||||
self.nfc_command("dev1", "setlastnfcerror %d" % wally.value, expected_nfc_error=wally)
|
||||
self.nfc_command("dev1", "getlastnfcerror", expected_nfc_error=wally)
|
||||
|
||||
self.nfc_command("dev1", "setlastnfcerror %d" % 0)
|
||||
self.nfc_command("dev1", "getlastnfcerror")
|
||||
|
||||
|
||||
"""
|
||||
smoke - target app reports if NFC eeprom driver present
|
||||
"""
|
||||
@test_case(CreamSconeSelfTests)
|
||||
def test_nfc_eeprom(self):
|
||||
|
||||
response = self.command("dev1", "iseeprom") # will hold result from the init lib call
|
||||
self.logger.info("Target includes NFCEEPROM: %s" % response.parsed['iseeprom'])
|
||||
|
||||
"""
|
||||
check - Assert discovery can be started/stopped
|
||||
"""
|
||||
@test_case(CreamSconeSelfTests)
|
||||
def test_nfc_discovery(self):
|
||||
|
||||
self.nfc_command("dev1", "initnfc")
|
||||
|
||||
response = self.nfc_command("dev1", "iseeprom") # will hold result from the init lib call
|
||||
eeprom = response.parsed['iseeprom']
|
||||
self.logger.info("Target includes NFCEEPROM: %s" % eeprom)
|
||||
if not eeprom:
|
||||
self.nfc_command("dev1", "start")
|
||||
self.nfc_command("dev1", "stop")
|
||||
self.nfc_command("dev1", "start")
|
||||
self.nfc_command("dev1", "stop")
|
||||
else:
|
||||
# eeprom, so not supported
|
||||
self.nfc_command("dev1", "start", expected_retcode=-2, expected_nfc_error = NfcErrors.nfc_err_unsupported )
|
||||
self.nfc_command("dev1", "stop", expected_retcode=-2 , expected_nfc_error= NfcErrors.nfc_err_unsupported )
|
||||
|
||||
"""
|
||||
check - Create a SmartPoster but does not read it back
|
||||
"""
|
||||
@test_case(CreamSconeSelfTests)
|
||||
def test_nfc_setsmartposter(self):
|
||||
|
||||
self.nfc_command("dev1", "initnfc")
|
||||
self.nfc_command("dev1", "setsmartposter -u https://www.mbed.com")
|
||||
|
||||
@test_case(CreamSconeSelfTests)
|
||||
def test_nfc_erase(self):
|
||||
self.nfc_command("dev1", "initnfc")
|
||||
response = self.nfc_command("dev1", "iseeprom")
|
||||
eeprom = response.parsed['iseeprom']
|
||||
if eeprom:
|
||||
self.logger.info("Target includes NFCEEPROM: %s" % eeprom)
|
||||
|
||||
self.nfc_command("dev1", "erase", timeout=30)
|
||||
response = self.nfc_command("dev1", "readmessage")
|
||||
asserts.assertEqual(response.parsed['nfcmessage'] is None, True)
|
||||
|
||||
'''
|
||||
check - Build a long message by copying a string to stress the driver with a nominal buffer. Verify contents of entire message
|
||||
can be read back.
|
||||
'''
|
||||
@test_case(CreamSconeSelfTests)
|
||||
def test_nfc_write_long(self):
|
||||
messageRep = 'thequickbrownfoxjumpedoverthelazydog' # repeating message written
|
||||
textLength = 200 # 2K < x < 4K
|
||||
# calculate actual message to compare to using the library
|
||||
message = nfc_messages.make_textrecord( nfc_messages.repeat_string_to_length(messageRep, textLength))
|
||||
expected_message = str(message)
|
||||
|
||||
self.nfc_command("dev1", "initnfc")
|
||||
response = self.nfc_command("dev1", "iseeprom")
|
||||
eeprom = response.parsed['iseeprom']
|
||||
if eeprom:
|
||||
self.logger.info("Target includes NFCEEPROM: %s" % eeprom)
|
||||
|
||||
self.nfc_command("dev1", "erase")
|
||||
self.nfc_command("dev1", "writelong %d %s" % (textLength,messageRep))
|
||||
response = self.nfc_command("dev1", "readmessage")
|
||||
# assert that read the eeprom contents gives textlength bytes (including framing bytes which will vary)
|
||||
asserts.assertEqual(len(response.parsed['nfcmessage']), len(expected_message))
|
||||
i = 0
|
||||
# assert that read the eeprom contents gives thequickbrownfoxjumpedoverthelazydog repeated in loop
|
||||
while i < len(response.parsed['nfcmessage']):
|
||||
asserts.assertEqual(response.parsed['nfcmessage'][i], ord(expected_message[i]))
|
||||
i = i + 1
|
||||
|
||||
'''
|
||||
check - Query supported protocols if we have a controller
|
||||
'''
|
||||
@test_case(CreamSconeSelfTests)
|
||||
def test_nfc_get_controller_protocols(self):
|
||||
self.nfc_command("dev1", "initnfc")
|
||||
|
||||
response = self.nfc_command("dev1", "iseeprom")
|
||||
eeprom = response.parsed['iseeprom']
|
||||
if eeprom:
|
||||
self.logger.info("Test ignore - target includes NFCEEPROM: %s" % eeprom)
|
||||
else:
|
||||
response = self.nfc_command("dev1", "getprotocols")
|
||||
self.logger.info("Protocols = %s" % response.parsed['protocols'])
|
||||
|
||||
|
||||
'''
|
||||
Set used protocols if we have an controller
|
||||
'''
|
||||
@test_case(CreamSconeSelfTests)
|
||||
def test_nfc_set_controller_protocols(self):
|
||||
self.nfc_command("dev1", "initnfc")
|
||||
|
||||
response = self.nfc_command("dev1", "iseeprom")
|
||||
eeprom = response.parsed['iseeprom']
|
||||
if eeprom:
|
||||
self.logger.info("Test ignore - target includes NFCEEPROM: %s" % eeprom)
|
||||
else:
|
||||
response = self.nfc_command("dev1", "setprotocols t1t")
|
||||
response = self.nfc_command("dev1", "setprotocols t2t")
|
||||
response = self.nfc_command("dev1", "setprotocols t3t")
|
||||
response = self.nfc_command("dev1", "setprotocols isodep")
|
||||
response = self.nfc_command("dev1", "setprotocols nfcdep")
|
||||
response = self.nfc_command("dev1", "setprotocols t5t")
|
||||
response = self.nfc_command("dev1", "setprotocols t1t t2t t3t isodep nfcdep t5t")
|
Loading…
Reference in New Issue