diff options
author | Michael Zanetti <michael.zanetti@nokia.com> | 2011-08-24 14:09:22 +1000 |
---|---|---|
committer | Rohan McGovern <rohan.mcgovern@nokia.com> | 2011-08-24 14:10:36 +1000 |
commit | 29ba8297443cf76d4f647bde329d62c2a567c709 (patch) | |
tree | 88875199053cd88b3b3521c829277f209e815159 /src/nfc |
Initial commit.
From qt5connectivity.tar.gz, md5 317c149d6f8c07d09632353188582834
Diffstat (limited to 'src/nfc')
134 files changed, 24852 insertions, 0 deletions
diff --git a/src/nfc/checksum_p.h b/src/nfc/checksum_p.h new file mode 100644 index 00000000..48b761b9 --- /dev/null +++ b/src/nfc/checksum_p.h @@ -0,0 +1,68 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef CHECKSUM_P_H +#define CHECKSUM_P_H + +// Copied from qbytearray.cpp +// Modified to initialise the crc with 0x6363 instead of 0xffff and to not invert the final result. +static const quint16 crc_tbl[16] = { + 0x0000, 0x1081, 0x2102, 0x3183, + 0x4204, 0x5285, 0x6306, 0x7387, + 0x8408, 0x9489, 0xa50a, 0xb58b, + 0xc60c, 0xd68d, 0xe70e, 0xf78f +}; + +quint16 qNfcChecksum(const char *data, uint len) +{ + register quint16 crc = 0x6363; + uchar c; + const uchar *p = reinterpret_cast<const uchar *>(data); + while (len--) { + c = *p++; + crc = ((crc >> 4) & 0x0fff) ^ crc_tbl[((crc ^ c) & 15)]; + c >>= 4; + crc = ((crc >> 4) & 0x0fff) ^ crc_tbl[((crc ^ c) & 15)]; + } + return crc; +} + +#endif // CHECKSUM_P_H diff --git a/src/nfc/maemo6/adapter_interface.cpp b/src/nfc/maemo6/adapter_interface.cpp new file mode 100644 index 00000000..bb50f38e --- /dev/null +++ b/src/nfc/maemo6/adapter_interface.cpp @@ -0,0 +1,67 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +/* + * This file was generated by qdbusxml2cpp version 0.7 + * Command line was: qdbusxml2cpp -p adapter_interface_p.h:adapter_interface.cpp com.nokia.nfc.Adapter.xml + * + * qdbusxml2cpp is Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). + * + * This is an auto-generated file. + * This file may have been hand-edited. Look for HAND-EDIT comments + * before re-generating it. + */ + +#include "adapter_interface_p.h" + +/* + * Implementation of interface class ComNokiaNfcAdapterInterface + */ + +ComNokiaNfcAdapterInterface::ComNokiaNfcAdapterInterface(const QString &service, const QString &path, const QDBusConnection &connection, QObject *parent) + : QDBusAbstractInterface(service, path, staticInterfaceName(), connection, parent) +{ +} + +ComNokiaNfcAdapterInterface::~ComNokiaNfcAdapterInterface() +{ +} + diff --git a/src/nfc/maemo6/adapter_interface_p.h b/src/nfc/maemo6/adapter_interface_p.h new file mode 100644 index 00000000..57df898d --- /dev/null +++ b/src/nfc/maemo6/adapter_interface_p.h @@ -0,0 +1,192 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +/* + * This file was generated by qdbusxml2cpp version 0.7 and then hand edited + * Command line was: qdbusxml2cpp -p adapter_interface_p.h:adapter_interface.cpp com.nokia.nfc.Adapter.xml + * + * qdbusxml2cpp is Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). + * + */ + +#ifndef ADAPTER_INTERFACE_P_H +#define ADAPTER_INTERFACE_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include <QtCore/QObject> +#include <QtCore/QByteArray> +#include <QtCore/QList> +#include <QtCore/QMap> +#include <QtCore/QString> +#include <QtCore/QStringList> +#include <QtCore/QVariant> +#include <QtDBus/QtDBus> + +/* + * Proxy class for interface com.nokia.nfc.Adapter + */ +class ComNokiaNfcAdapterInterface: public QDBusAbstractInterface +{ + Q_OBJECT +public: + static inline const char *staticInterfaceName() + { return "com.nokia.nfc.Adapter"; } + +public: + ComNokiaNfcAdapterInterface(const QString &service, const QString &path, const QDBusConnection &connection, QObject *parent = 0); + + ~ComNokiaNfcAdapterInterface(); + + Q_PROPERTY(bool Discovering READ discovering) + inline bool discovering() { + QDBusReply<QVariantMap> reply = GetProperties(); + if (!reply.isValid()) + return false; + + return reply.value().value(QLatin1String("Discovering")).toBool(); + } + + Q_PROPERTY(QString State READ state WRITE setState) + inline QString state() { + QDBusReply<QVariantMap> reply = GetProperties(); + if (!reply.isValid()) + return QString(); + + return reply.value().value(QLatin1String("State")).toString(); + } + + inline void setState(const QString &value) + { SetProperty(QLatin1String("State"), QDBusVariant(qVariantFromValue(value))); } + + Q_PROPERTY(QStringList TagTechnologies READ tagTechnologies) + inline QStringList tagTechnologies() + { + QDBusReply<QVariantMap> reply = GetProperties(); + if (!reply.isValid()) + return QStringList(); + + return reply.value().value(QLatin1String("TagTechnologies")).toStringList(); + } + +public Q_SLOTS: // METHODS + inline QDBusPendingReply<> CancelAccessRequest(const QDBusObjectPath &in0, const QString &in1) + { + QList<QVariant> argumentList; + argumentList << QVariant::fromValue(in0) << QVariant::fromValue(in1); + return asyncCallWithArgumentList(QLatin1String("CancelAccessRequest"), argumentList); + } + + inline QDBusPendingReply<> CancelHandoverRequest(const QString &in0) + { + QList<QVariant> argumentList; + argumentList << QVariant::fromValue(in0); + return asyncCallWithArgumentList(QLatin1String("CancelHandoverRequest"), argumentList); + } + + inline QDBusPendingReply<QVariantMap> GetProperties() + { + QList<QVariant> argumentList; + return asyncCallWithArgumentList(QLatin1String("GetProperties"), argumentList); + } + + inline QDBusPendingReply<> RegisterUIAgent(const QDBusObjectPath &in0) + { + QList<QVariant> argumentList; + argumentList << QVariant::fromValue(in0); + return asyncCallWithArgumentList(QLatin1String("RegisterUIAgent"), argumentList); + } + + inline QDBusPendingReply<> RequestAccess(const QDBusObjectPath &in0, const QString &in1) + { + QList<QVariant> argumentList; + argumentList << QVariant::fromValue(in0) << QVariant::fromValue(in1); + return asyncCallWithArgumentList(QLatin1String("RequestAccess"), argumentList); + } + + inline QDBusPendingReply<> RequestHandover(const QDBusObjectPath &in0, const QString &in1, const QString &in2) + { + QList<QVariant> argumentList; + argumentList << QVariant::fromValue(in0) << QVariant::fromValue(in1) << QVariant::fromValue(in2); + return asyncCallWithArgumentList(QLatin1String("RequestHandover"), argumentList); + } + + inline QDBusPendingReply<> SetProperty(const QString &in0, const QDBusVariant &in1) + { + QList<QVariant> argumentList; + argumentList << QVariant::fromValue(in0) << QVariant::fromValue(in1); + return asyncCallWithArgumentList(QLatin1String("SetProperty"), argumentList); + } + + inline QDBusPendingReply<> UnregisterUIAgent(const QDBusObjectPath &in0) + { + QList<QVariant> argumentList; + argumentList << QVariant::fromValue(in0); + return asyncCallWithArgumentList(QLatin1String("UnregisterUIAgent"), argumentList); + } + +Q_SIGNALS: // SIGNALS + void HandoverCarrierSelected(const QString &in0); + void HandoverCompleted(const QString &in0, const QDBusVariant &in1); + void HandoverFailed(const QString &in0); + void HandoverStarted(); + void PropertyChanged(const QString &in0, const QDBusVariant &in1); + void TargetDetected(const QDBusObjectPath &in0); + void TargetLost(const QDBusObjectPath &in0); +}; + +namespace com { + namespace nokia { + namespace nfc { + typedef ::ComNokiaNfcAdapterInterface Adapter; + } + } +} +#endif diff --git a/src/nfc/maemo6/com.nokia.nfc.AccessRequestor.xml b/src/nfc/maemo6/com.nokia.nfc.AccessRequestor.xml new file mode 100644 index 00000000..655448d2 --- /dev/null +++ b/src/nfc/maemo6/com.nokia.nfc.AccessRequestor.xml @@ -0,0 +1,14 @@ +<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN" "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd"> +<node name="/foo"> + <interface name="com.nokia.nfc.AccessRequestor"> + <method name="AccessFailed"> + <arg type="o" direction="in"/> + <arg type="s" direction="in"/> + <arg type="s" direction="in"/> + </method> + <method name="AccessGranted"> + <arg type="o" direction="in"/> + <arg type="s" direction="in"/> + </method> + </interface> +</node> diff --git a/src/nfc/maemo6/com.nokia.nfc.Adapter.xml b/src/nfc/maemo6/com.nokia.nfc.Adapter.xml new file mode 100644 index 00000000..3e3d3c85 --- /dev/null +++ b/src/nfc/maemo6/com.nokia.nfc.Adapter.xml @@ -0,0 +1,59 @@ +<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN" "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd"> +<node name="/com/nokia/nfc/0/nfc0"> + <interface name="com.nokia.nfc.Adapter"> + <method name="GetProperties"> + <arg type="a{sv}" direction="out"/> + <annotation name="com.trolltech.QtDBus.QtTypeName.Out0" value="QVariantMap"/> + </method> + <method name="SetProperty"> + <arg type="s" direction="in"/> + <arg type="v" direction="in"/> + </method> + <method name="RequestHandover"> + <arg type="o" direction="in"/> + <arg type="s" direction="in"/> + <arg type="s" direction="in"/> + </method> + <method name="CancelHandoverRequest"> + <arg type="s" direction="in"/> + </method> + <method name="RequestAccess"> + <arg type="o" direction="in"/> + <arg type="s" direction="in"/> + </method> + <method name="CancelAccessRequest"> + <arg type="o" direction="in"/> + <arg type="s" direction="in"/> + </method> + <method name="RegisterUIAgent"> + <arg type="o" direction="in"/> + </method> + <method name="UnregisterUIAgent"> + <arg type="o" direction="in"/> + </method> + <signal name="PropertyChanged"> + <arg type="s"/> + <arg type="v"/> + </signal> + <signal name="TargetDetected"> + <arg type="o"/> + </signal> + <signal name="TargetLost"> + <arg type="o"/> + </signal> + <signal name="HandoverStarted"/> + <signal name="HandoverCarrierSelected"> + <arg type="s"/> + </signal> + <signal name="HandoverCompleted"> + <arg type="s"/> + <arg type="v"/> + </signal> + <signal name="HandoverFailed"> + <arg type="s"/> + </signal> + <property name="State" type="s" access="readwrite"/> + <property name="Discovering" type="b" access="read"/> + <property name="TagTechnologies" type="as" access="read"/> + </interface> +</node> diff --git a/src/nfc/maemo6/com.nokia.nfc.Device.xml b/src/nfc/maemo6/com.nokia.nfc.Device.xml new file mode 100644 index 00000000..17acc5d0 --- /dev/null +++ b/src/nfc/maemo6/com.nokia.nfc.Device.xml @@ -0,0 +1,19 @@ +<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN" "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd"> +<node name="/com/nokia/nfc/0/nfc0/target_DE_AD_BE_EF"> + <interface name="com.nokia.nfc.Device"> + <method name="GetProperties"> + <arg type="a{sv}" direction="out"/> + <annotation name="com.trolltech.QtDBus.QtTypeName.Out0" value="QVariantMap"/> + </method> + <method name="SetProperty"> + <arg type="s" direction="in"/> + <arg type="v" direction="in"/> + </method> + <signal name="PropertyChanged"> + <arg type="s"/> + <arg type="v"/> + </signal> + <property name="UID" type="s" access="read"/> + </interface> +</node> + diff --git a/src/nfc/maemo6/com.nokia.nfc.LLCPRequestor.xml b/src/nfc/maemo6/com.nokia.nfc.LLCPRequestor.xml new file mode 100644 index 00000000..cf4f625a --- /dev/null +++ b/src/nfc/maemo6/com.nokia.nfc.LLCPRequestor.xml @@ -0,0 +1,22 @@ +<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN" "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd"> +<node name="/foo"> + <interface name="com.nokia.nfc.LLCPRequestor"> + <method name="Accept"> + <arg type="v" direction="in"/> + <arg type="v" direction="in"/> + <arg type="h" direction="in"/> + <arg type="a{sv}" direction="in"/> + </method> + <method name="Connect"> + <arg type="v" direction="in"/> + <arg type="v" direction="in"/> + <arg type="h" direction="in"/> + <arg type="a{sv}" direction="in"/> + </method> + <method name="Socket"> + <arg type="v" direction="in"/> + <arg type="h" direction="in"/> + <arg type="a{sv}" direction="in"/> + </method> + </interface> +</node> diff --git a/src/nfc/maemo6/com.nokia.nfc.Manager.xml b/src/nfc/maemo6/com.nokia.nfc.Manager.xml new file mode 100644 index 00000000..cdc8fae8 --- /dev/null +++ b/src/nfc/maemo6/com.nokia.nfc.Manager.xml @@ -0,0 +1,47 @@ +<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN" "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd"> +<node name="/"> + <interface name="com.nokia.nfc.Manager"> + <method name="GetProperties"> + <arg type="a{sv}" direction="out"/> + <annotation name="com.trolltech.QtDBus.QtTypeName.Out0" value="QVariantMap"/> + </method> + <method name="SetProperty"> + <arg type="s" direction="in"/> + <arg type="v" direction="in"/> + </method> + <method name="ListAdapters"> + <arg type="ao" direction="out"/> + </method> + <method name="FindAdapter"> + <arg type="s" direction="in"/> + <arg type="o" direction="out"/> + </method> + <method name="DefaultAdapter"> + <arg type="o" direction="out"/> + </method> + <method name="RegisterNDEFHandler"> + <arg type="s" direction="in"/> + <arg type="s" direction="in"/> + <arg type="o" direction="in"/> + <arg type="s" direction="in"/> + <arg type="s" direction="in"/> + <arg type="s" direction="in"/> + </method> + <method name="UnregisterNDEFHandler"> + <arg type="s" direction="in"/> + <arg type="s" direction="in"/> + <arg type="o" direction="in"/> + </method> + <signal name="AdapterAdded"> + <arg type="o"/> + </signal> + <signal name="AdapterRemoved"> + <arg type="o"/> + </signal> + <signal name="DefaultAdapterChanged"> + <arg type="o"/> + </signal> + <property name="LogLevel" type="s" access="readwrite"/> + </interface> +</node> + diff --git a/src/nfc/maemo6/com.nokia.nfc.NDEFHandler.xml b/src/nfc/maemo6/com.nokia.nfc.NDEFHandler.xml new file mode 100644 index 00000000..8b4fdd45 --- /dev/null +++ b/src/nfc/maemo6/com.nokia.nfc.NDEFHandler.xml @@ -0,0 +1,10 @@ +<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN" "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd"> +<node name="/foo"> + <interface name="com.nokia.nfc.NDEFHandler"> + <method name="NDEFData"> + <arg type="o" direction="in"/> + <arg type="ay" direction="in"/> + </method> + </interface> +</node> + diff --git a/src/nfc/maemo6/com.nokia.nfc.SecureElement.xml b/src/nfc/maemo6/com.nokia.nfc.SecureElement.xml new file mode 100644 index 00000000..702f3b2a --- /dev/null +++ b/src/nfc/maemo6/com.nokia.nfc.SecureElement.xml @@ -0,0 +1,34 @@ +<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN" "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd"> +<node name="/com/nokia/nfc/0/nfc0/se0"> + <interface name="com.nokia.nfc.SecureElement"> + <method name="GetProperties"> + <arg type="a{sv}" direction="out"/> + <annotation name="com.trolltech.QtDBus.QtTypeName.Out0" value="QVariantMap"/> + </method> + <method name="RequestAccess"/> + <method name="ReleaseAccess"/> + <method name="Activate"/> + <method name="Deactivate"/> + <method name="SetActivationLevel"> + <arg type="v" direction="in"/> + </method> + <method name="RawRequest"> + <arg type="ay" direction="in"/> + <arg type="ay" direction="out"/> + </method> + <signal name="PropertyChanged"> + <arg type="s"/> + <arg type="v"/> + </signal> + <signal name="TransactionStarted"> + <arg type="s"/> + </signal> + <signal name="TransactionEnded"> + <arg type="s"/> + <arg type="s"/> + </signal> + <property name="State" type="s" access="read"/> + <property name="ActivationLevel" type="s" access="read"/> + </interface> +</node> + diff --git a/src/nfc/maemo6/com.nokia.nfc.Tag.xml b/src/nfc/maemo6/com.nokia.nfc.Tag.xml new file mode 100644 index 00000000..4d24850f --- /dev/null +++ b/src/nfc/maemo6/com.nokia.nfc.Tag.xml @@ -0,0 +1,28 @@ +<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN" "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd"> +<node name="/com/nokia/nfc/0/nfc0/target_DE_AD_BE_EF"> + <interface name="com.nokia.nfc.Tag"> + <method name="GetProperties"> + <arg type="a{sv}" direction="out"/> + <annotation name="com.trolltech.QtDBus.QtTypeName.Out0" value="QVariantMap"/> + </method> + <method name="SetProperty"> + <arg type="s" direction="in"/> + <arg type="v" direction="in"/> + </method> + <method name="ReadNDEFData"> + <arg type="aay" direction="out"/> + <annotation name="com.trolltech.QtDBus.QtTypeName.Out0" value="QList<QByteArray>"/> + </method> + <method name="WriteNDEFData"> + <arg type="aay" direction="in"/> + <annotation name="com.trolltech.QtDBus.QtTypeName.In0" value="QList<QByteArray>"/> + </method> + <signal name="PropertyChanged"> + <arg type="s"/> + <arg type="v"/> + </signal> + <property name="UID" type="s" access="read"/> + <property name="Technology" type="s" access="read"/> + </interface> +</node> + diff --git a/src/nfc/maemo6/com.nokia.nfc.Target.xml b/src/nfc/maemo6/com.nokia.nfc.Target.xml new file mode 100644 index 00000000..a5fa2308 --- /dev/null +++ b/src/nfc/maemo6/com.nokia.nfc.Target.xml @@ -0,0 +1,20 @@ +<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN" "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd"> +<node name="/com/nokia/nfc/0/nfc0/target_DE_AD_BE_EF"> + <interface name="com.nokia.nfc.Target"> + <method name="GetProperties"> + <arg type="a{sv}" direction="out"/> + <annotation name="com.trolltech.QtDBus.QtTypeName.Out0" value="QVariantMap"/> + </method> + <method name="SetProperty"> + <arg type="s" direction="in"/> + <arg type="v" direction="in"/> + </method> + <signal name="PropertyChanged"> + <arg type="s"/> + <arg type="v"/> + </signal> + <property name="Type" type="s" access="read"/> + <property name="State" type="s" access="read"/> + </interface> +</node> + diff --git a/src/nfc/maemo6/device_interface.cpp b/src/nfc/maemo6/device_interface.cpp new file mode 100644 index 00000000..69b2c930 --- /dev/null +++ b/src/nfc/maemo6/device_interface.cpp @@ -0,0 +1,67 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +/* + * This file was generated by qdbusxml2cpp version 0.7 + * Command line was: qdbusxml2cpp -p device_interface_p.h:device_interface.cpp com.nokia.nfc.Device.xml + * + * qdbusxml2cpp is Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). + * + * This is an auto-generated file. + * This file may have been hand-edited. Look for HAND-EDIT comments + * before re-generating it. + */ + +#include "device_interface_p.h" + +/* + * Implementation of interface class ComNokiaNfcDeviceInterface + */ + +ComNokiaNfcDeviceInterface::ComNokiaNfcDeviceInterface(const QString &service, const QString &path, const QDBusConnection &connection, QObject *parent) + : QDBusAbstractInterface(service, path, staticInterfaceName(), connection, parent) +{ +} + +ComNokiaNfcDeviceInterface::~ComNokiaNfcDeviceInterface() +{ +} + diff --git a/src/nfc/maemo6/device_interface_p.h b/src/nfc/maemo6/device_interface_p.h new file mode 100644 index 00000000..ff2d5604 --- /dev/null +++ b/src/nfc/maemo6/device_interface_p.h @@ -0,0 +1,122 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +/* + * This file was generated by qdbusxml2cpp version 0.7 and then hand edited + * Command line was: qdbusxml2cpp -p device_interface_p.h:device_interface.cpp com.nokia.nfc.Device.xml + * + * qdbusxml2cpp is Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). + * + */ + +#ifndef DEVICE_INTERFACE_P_H +#define DEVICE_INTERFACE_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include <QtCore/QObject> +#include <QtCore/QByteArray> +#include <QtCore/QList> +#include <QtCore/QMap> +#include <QtCore/QString> +#include <QtCore/QStringList> +#include <QtCore/QVariant> +#include <QtDBus/QtDBus> + +/* + * Proxy class for interface com.nokia.nfc.Device + */ +class ComNokiaNfcDeviceInterface: public QDBusAbstractInterface +{ + Q_OBJECT +public: + static inline const char *staticInterfaceName() + { return "com.nokia.nfc.Device"; } + +public: + ComNokiaNfcDeviceInterface(const QString &service, const QString &path, const QDBusConnection &connection, QObject *parent = 0); + + ~ComNokiaNfcDeviceInterface(); + + Q_PROPERTY(QString UID READ uID) + inline QString uID() { + QDBusReply<QVariantMap> reply = GetProperties(); + if (!reply.isValid()) + return QString(); + + return reply.value().value(QLatin1String("UID")).toString(); + } + +public Q_SLOTS: // METHODS + inline QDBusPendingReply<QVariantMap> GetProperties() + { + QList<QVariant> argumentList; + return asyncCallWithArgumentList(QLatin1String("GetProperties"), argumentList); + } + + inline QDBusPendingReply<> SetProperty(const QString &in0, const QDBusVariant &in1) + { + QList<QVariant> argumentList; + argumentList << QVariant::fromValue(in0) << QVariant::fromValue(in1); + return asyncCallWithArgumentList(QLatin1String("SetProperty"), argumentList); + } + +Q_SIGNALS: // SIGNALS + void PropertyChanged(const QString &in0, const QDBusVariant &in1); +}; + +namespace com { + namespace nokia { + namespace nfc { + typedef ::ComNokiaNfcDeviceInterface Device; + } + } +} +#endif diff --git a/src/nfc/maemo6/generate b/src/nfc/maemo6/generate new file mode 100755 index 00000000..fa7260d5 --- /dev/null +++ b/src/nfc/maemo6/generate @@ -0,0 +1,8 @@ +#!/bin/sh + +qdbusxml2cpp -p adapter_interface_p.h:adapter_interface.cpp com.nokia.nfc.Adapter.xml + +qdbusxml2cpp -p target_interface_p.h:target_interface.cpp com.nokia.nfc.Target.xml +qdbusxml2cpp -p tag_interface_p.h:tag_interface.cpp com.nokia.nfc.Tag.xml +qdbusxml2cpp -p device_interface_p.h:device_interface.cpp com.nokia.nfc.Device.xml + diff --git a/src/nfc/maemo6/socketrequestor.cpp b/src/nfc/maemo6/socketrequestor.cpp new file mode 100644 index 00000000..b7595bc8 --- /dev/null +++ b/src/nfc/maemo6/socketrequestor.cpp @@ -0,0 +1,704 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "socketrequestor_p.h" + +#include <QtCore/QMutex> +#include <QtCore/QHash> +#include <QtCore/QSocketNotifier> +#include <QtCore/QStringList> +#include <QtCore/QElapsedTimer> +#include <QtCore/QCoreApplication> +#include <QtDBus/QDBusObjectPath> + +#include <dbus/dbus.h> + +#include <sys/select.h> +#include <errno.h> + +struct WatchNotifier +{ + DBusWatch *watch; + QSocketNotifier *readNotifier; + QSocketNotifier *writeNotifier; +}; + +static QVariant getVariantFromDBusMessage(DBusMessageIter *iter) +{ + dbus_bool_t bool_data; + dbus_int32_t int32_data; + dbus_uint32_t uint32_data; + dbus_int64_t int64_data; + dbus_uint64_t uint64_data; + char *str_data; + char char_data; + int argtype = dbus_message_iter_get_arg_type(iter); + + switch (argtype) { + case DBUS_TYPE_BOOLEAN: { + dbus_message_iter_get_basic(iter, &bool_data); + QVariant variant((bool)bool_data); + return variant; + } + case DBUS_TYPE_ARRAY: { + // Handle all arrays here + int elem_type = dbus_message_iter_get_element_type(iter); + DBusMessageIter array_iter; + + dbus_message_iter_recurse(iter, &array_iter); + + if (elem_type == DBUS_TYPE_BYTE) { + QByteArray byte_array; + do { + dbus_message_iter_get_basic(&array_iter, &char_data); + byte_array.append(char_data); + } while (dbus_message_iter_next(&array_iter)); + QVariant variant(byte_array); + return variant; + } else if (elem_type == DBUS_TYPE_STRING) { + QStringList str_list; + do { + dbus_message_iter_get_basic(&array_iter, &str_data); + str_list.append(str_data); + } while (dbus_message_iter_next(&array_iter)); + QVariant variant(str_list); + return variant; + } else { + QVariantList variantList; + do { + variantList << getVariantFromDBusMessage(&array_iter); + } while (dbus_message_iter_next(&array_iter)); + QVariant variant(variantList); + return variant; + } + break; + } + case DBUS_TYPE_BYTE: { + dbus_message_iter_get_basic(iter, &char_data); + QChar ch(char_data); + QVariant variant(ch); + return variant; + } + case DBUS_TYPE_INT32: { + dbus_message_iter_get_basic(iter, &int32_data); + QVariant variant((int)int32_data); + return variant; + } + case DBUS_TYPE_UINT32: { + dbus_message_iter_get_basic(iter, &uint32_data); + QVariant variant((uint)uint32_data); + return variant; + } + case DBUS_TYPE_OBJECT_PATH: + case DBUS_TYPE_STRING: { + dbus_message_iter_get_basic(iter, &str_data); + QString str(str_data); + QVariant variant(str); + return variant; + } + case DBUS_TYPE_INT64: { + dbus_message_iter_get_basic(iter, &int64_data); + QVariant variant((qlonglong)int64_data); + return variant; + } + case DBUS_TYPE_UINT64: { + dbus_message_iter_get_basic(iter, &uint64_data); + QVariant variant((qulonglong)uint64_data); + return variant; + } + case DBUS_TYPE_DICT_ENTRY: + case DBUS_TYPE_STRUCT: { + // Handle all structs here + DBusMessageIter struct_iter; + dbus_message_iter_recurse(iter, &struct_iter); + + QVariantList variantList; + do { + variantList << getVariantFromDBusMessage(&struct_iter); + } while (dbus_message_iter_next(&struct_iter)); + QVariant variant(variantList); + return variant; + } + case DBUS_TYPE_VARIANT: { + DBusMessageIter variant_iter; + dbus_message_iter_recurse(iter, &variant_iter); + + return getVariantFromDBusMessage(&variant_iter); + } + case DBUS_TYPE_UNIX_FD: { + dbus_message_iter_get_basic(iter, &uint32_data); + QVariant variant((uint)uint32_data); + return variant; + } + + default: + qWarning("Unsupported DBUS type: %d\n", argtype); + } + + return QVariant(); +} + +class SocketRequestorPrivate : public QObject +{ + Q_OBJECT + +public: + SocketRequestorPrivate(); + ~SocketRequestorPrivate(); + + DBusHandlerResult messageFilter(DBusConnection *connection, DBusMessage *message); + void addWatch(DBusWatch *watch); + + void registerObject(const QString &path, SocketRequestor *object); + void unregisterObject(const QString &path); + + Q_INVOKABLE void sendRequestAccess(const QString &adaptor, const QString &path, + const QString &kind); + Q_INVOKABLE void sendCancelAccessRequest(const QString &adaptor, const QString &path, + const QString &kind); + + bool waitForDBusSignal(int msecs); + +private: + bool parseAccessFailed(DBusMessage *message, SocketRequestor *socketRequestor); + bool parseAccessGranted(DBusMessage *message, SocketRequestor *socketRequestor); + bool parseAcceptConnect(DBusMessage *message, SocketRequestor *socketRequestor, + const char *member); + bool parseSocket(DBusMessage *message, SocketRequestor *socketRequestor, const char *member); + bool parseErrorDenied(DBusMessage *message, SocketRequestor *socketRequestor); + +private slots: + void socketRead(); + void socketWrite(); + +private: + QMutex m_mutex; + DBusConnection *m_dbusConnection; + QHash<QString, SocketRequestor *> m_dbusObjects; + QMap<quint32, SocketRequestor *> m_pendingCalls; + QList<WatchNotifier> m_watchNotifiers; +}; + +Q_GLOBAL_STATIC(SocketRequestorPrivate, socketRequestorPrivate) + +static DBusHandlerResult dbusFilter(DBusConnection *connection, DBusMessage *message, + void *userData) +{ + SocketRequestorPrivate *s = static_cast<SocketRequestorPrivate *>(userData); + return s->messageFilter(connection, message); +} + +static dbus_bool_t dbusWatch(DBusWatch *watch, void *data) +{ + SocketRequestorPrivate *s = static_cast<SocketRequestorPrivate *>(data); + s->addWatch(watch); + + return true; +} + +SocketRequestorPrivate::SocketRequestorPrivate() +{ + DBusError error; + dbus_error_init(&error); + m_dbusConnection = dbus_bus_get_private(DBUS_BUS_SYSTEM, &error); + dbus_connection_add_filter(m_dbusConnection, &dbusFilter, this, 0); + dbus_connection_set_watch_functions(m_dbusConnection, dbusWatch, 0, 0, this, 0); + dbus_error_free(&error); +} + +SocketRequestorPrivate::~SocketRequestorPrivate() +{ + dbus_connection_close(m_dbusConnection); + dbus_connection_unref(m_dbusConnection); +} + +DBusHandlerResult SocketRequestorPrivate::messageFilter(DBusConnection *connection, + DBusMessage *message) +{ + QMutexLocker locker(&m_mutex); + + foreach (const WatchNotifier &watchNotifier, m_watchNotifiers) + watchNotifier.writeNotifier->setEnabled(true); + + if (connection != m_dbusConnection) + return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; + + SocketRequestor *socketRequestor; + const QString path = QString::fromUtf8(dbus_message_get_path(message)); + quint32 serial = dbus_message_get_reply_serial(message); + if (!path.isEmpty() && serial == 0) + socketRequestor = m_dbusObjects.value(path); + else if (path.isEmpty() && serial != 0) + socketRequestor = m_pendingCalls.take(serial); + else + return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; + + enum { + NotHandled, + Handled, + HandledSendReply + } handled; + + if (dbus_message_is_method_call(message, "com.nokia.nfc.AccessRequestor", "AccessFailed")) + handled = parseAccessFailed(message, socketRequestor) ? HandledSendReply : NotHandled; + else if (dbus_message_is_method_call(message, "com.nokia.nfc.AccessRequestor", "AccessGranted")) + handled = parseAccessGranted(message, socketRequestor) ? HandledSendReply : NotHandled; + else if (dbus_message_is_method_call(message, "com.nokia.nfc.LLCPRequestor", "Accept")) + handled = parseAcceptConnect(message, socketRequestor, "accept") ? HandledSendReply : NotHandled; + else if (dbus_message_is_method_call(message, "com.nokia.nfc.LLCPRequestor", "Connect")) + handled = parseAcceptConnect(message, socketRequestor, "connect") ? HandledSendReply : NotHandled; + else if (dbus_message_is_method_call(message, "com.nokia.nfc.LLCPRequestor", "Socket")) + handled = parseSocket(message, socketRequestor, "socket") ? HandledSendReply : NotHandled; + else if (dbus_message_is_error(message, "com.nokia.nfc.Error.Denied")) + handled = parseErrorDenied(message, socketRequestor) ? Handled : NotHandled; + else + handled = NotHandled; + + if (handled == NotHandled) + return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; + + if (handled == HandledSendReply) { + DBusMessage *reply = dbus_message_new_method_return(message); + quint32 serial; + dbus_connection_send(connection, reply, &serial); + } + + return DBUS_HANDLER_RESULT_HANDLED; +} + +bool SocketRequestorPrivate::parseErrorDenied(DBusMessage *message, + SocketRequestor *socketRequestor) +{ + Q_UNUSED(message); + + QMetaObject::invokeMethod(socketRequestor, "accessFailed", + Q_ARG(QDBusObjectPath, QDBusObjectPath()), + Q_ARG(QString, QLatin1String("")), + Q_ARG(QString, QLatin1String("Access denied"))); + return true; +} + +bool SocketRequestorPrivate::parseAccessFailed(DBusMessage *message, + SocketRequestor *socketRequestor) +{ + Q_UNUSED(message); + + // m_mutex is locked in messageFilter() + + DBusMessageIter args; + + if (!dbus_message_iter_init(message, &args)) + return false; + + // read DBus Object Path + QVariant objectPath = getVariantFromDBusMessage(&args); + + if (!dbus_message_iter_next(&args)) + return false; + + // read DBus kind string + QVariant kind = getVariantFromDBusMessage(&args); + + if (!dbus_message_iter_next(&args)) + return false; + + // read DBus error string + QVariant errorString = getVariantFromDBusMessage(&args); + + QMetaObject::invokeMethod(socketRequestor, "accessFailed", + Q_ARG(QDBusObjectPath, QDBusObjectPath(objectPath.toString())), + Q_ARG(QString, kind.toString()), + Q_ARG(QString, errorString.toString())); + return true; +} + +bool SocketRequestorPrivate::parseAccessGranted(DBusMessage *message, + SocketRequestor *socketRequestor) +{ + Q_UNUSED(message); + + // m_mutex is locked in messageFilter() + + DBusMessageIter args; + + if (!dbus_message_iter_init(message, &args)) + return false; + + // read DBus Object Path + QVariant objectPath = getVariantFromDBusMessage(&args); + + if (!dbus_message_iter_next(&args)) + return false; + + // read access kind + QVariant kind = getVariantFromDBusMessage(&args); + + QMetaObject::invokeMethod(socketRequestor, "accessGranted", + Q_ARG(QDBusObjectPath, QDBusObjectPath(objectPath.toString())), + Q_ARG(QString, kind.toString())); + return true; +} + +bool SocketRequestorPrivate::parseAcceptConnect(DBusMessage *message, + SocketRequestor *socketRequestor, + const char *member) +{ + // m_mutex is locked in messageFilter() + + DBusMessageIter args; + + if (!dbus_message_iter_init(message, &args)) + return false; + + // read DBus Variant (lsap) + QVariant lsap = getVariantFromDBusMessage(&args); + + if (!dbus_message_iter_next(&args)) + return false; + // read DBus Variant (rsap) + QVariant rsap = getVariantFromDBusMessage(&args); + + if (!dbus_message_iter_next(&args)) + return false; + + // read socket fd + QVariant fd = getVariantFromDBusMessage(&args); + + if (!dbus_message_iter_next(&args)) + return false; + + // read DBus a{sv} into QVariantMap + QVariant prop = getVariantFromDBusMessage(&args); + QVariantMap properties; + foreach (const QVariant &v, prop.toList()) { + QVariantList vl = v.toList(); + if (vl.length() != 2) + continue; + + properties.insert(vl.first().toString(), vl.at(1)); + } + + QMetaObject::invokeMethod(socketRequestor, member, Q_ARG(QDBusVariant, QDBusVariant(lsap)), + Q_ARG(QDBusVariant, QDBusVariant(rsap)), + Q_ARG(int, fd.toInt()), Q_ARG(QVariantMap, properties)); + + return true; +} + +bool SocketRequestorPrivate::parseSocket(DBusMessage *message, SocketRequestor *socketRequestor, + const char *member) +{ + // m_mutex is locked in messageFilter() + + DBusMessageIter args; + + if (!dbus_message_iter_init(message, &args)) + return false; + + // read DBus Variant (lsap) + QVariant lsap = getVariantFromDBusMessage(&args); + + if (!dbus_message_iter_next(&args)) + return false; + + // read socket fd + QVariant fd = getVariantFromDBusMessage(&args); + + if (!dbus_message_iter_next(&args)) + return false; + + // read DBus a{sv} into QVariantMap + QVariant prop = getVariantFromDBusMessage(&args); + QVariantMap properties; + foreach (const QVariant &v, prop.toList()) { + QVariantList vl = v.toList(); + if (vl.length() != 2) + continue; + + properties.insert(vl.first().toString(), vl.at(1)); + } + + QMetaObject::invokeMethod(socketRequestor, member, Q_ARG(QDBusVariant, QDBusVariant(lsap)), + Q_ARG(int, fd.toInt()), Q_ARG(QVariantMap, properties)); + + return true; +} + +void SocketRequestorPrivate::addWatch(DBusWatch *watch) +{ + QMutexLocker locker(&m_mutex); + + int fd = dbus_watch_get_unix_fd(watch); + + WatchNotifier watchNotifier; + watchNotifier.watch = watch; + + watchNotifier.readNotifier = new QSocketNotifier(fd, QSocketNotifier::Read, this); + connect(watchNotifier.readNotifier, SIGNAL(activated(int)), this, SLOT(socketRead())); + watchNotifier.writeNotifier = new QSocketNotifier(fd, QSocketNotifier::Write, this); + connect(watchNotifier.writeNotifier, SIGNAL(activated(int)), this, SLOT(socketWrite())); + + m_watchNotifiers.append(watchNotifier); +} + +void SocketRequestorPrivate::socketRead() +{ + QMutexLocker locker(&m_mutex); + + QList<DBusWatch *> pendingWatches; + + foreach (const WatchNotifier &watchNotifier, m_watchNotifiers) { + if (watchNotifier.readNotifier != sender()) + continue; + + pendingWatches.append(watchNotifier.watch); + } + + DBusConnection *connection = m_dbusConnection; + locker.unlock(); + + foreach (DBusWatch *watch, pendingWatches) + dbus_watch_handle(watch, DBUS_WATCH_READABLE); + + while (dbus_connection_dispatch(connection) == DBUS_DISPATCH_DATA_REMAINS); +} + +void SocketRequestorPrivate::socketWrite() +{ + QMutexLocker locker(&m_mutex); + + QList<DBusWatch *> pendingWatches; + + foreach (const WatchNotifier &watchNotifier, m_watchNotifiers) { + if (watchNotifier.writeNotifier != sender()) + continue; + + watchNotifier.writeNotifier->setEnabled(false); + pendingWatches.append(watchNotifier.watch); + } + + locker.unlock(); + + foreach (DBusWatch *watch, pendingWatches) + dbus_watch_handle(watch, DBUS_WATCH_WRITABLE); +} + +void SocketRequestorPrivate::registerObject(const QString &path, SocketRequestor *object) +{ + QMutexLocker locker(&m_mutex); + + m_dbusObjects.insert(path, object); +} + +void SocketRequestorPrivate::unregisterObject(const QString &path) +{ + QMutexLocker locker(&m_mutex); + + m_dbusObjects.remove(path); +} + +void SocketRequestorPrivate::sendRequestAccess(const QString &adaptor, const QString &path, + const QString &kind) +{ + QMutexLocker locker(&m_mutex); + + foreach (const WatchNotifier &watchNotifier, m_watchNotifiers) + watchNotifier.writeNotifier->setEnabled(true); + + DBusMessage *message; + DBusMessageIter args; + + message = dbus_message_new_method_call("com.nokia.nfc", adaptor.toLocal8Bit(), + "com.nokia.nfc.Adapter", "RequestAccess"); + + if (!message) + return; + + dbus_message_iter_init_append(message, &args); + const QByteArray p = path.toUtf8(); + const char *pData = p.constData(); + if (!dbus_message_iter_append_basic(&args, DBUS_TYPE_OBJECT_PATH, &pData)) { + dbus_message_unref(message); + return; + } + + const QByteArray k = kind.toUtf8(); + const char *kData = k.constData(); + if (!dbus_message_iter_append_basic(&args, DBUS_TYPE_STRING, &kData)) { + dbus_message_unref(message); + return; + } + + quint32 serial; + dbus_connection_send(m_dbusConnection, message, &serial); + + dbus_message_unref(message); + + m_pendingCalls.insert(serial, m_dbusObjects.value(path)); +} + +void SocketRequestorPrivate::sendCancelAccessRequest(const QString &adaptor, const QString &path, + const QString &kind) +{ + QMutexLocker locker(&m_mutex); + + foreach (const WatchNotifier &watchNotifier, m_watchNotifiers) + watchNotifier.writeNotifier->setEnabled(true); + + DBusMessage *message; + DBusMessageIter args; + + message = dbus_message_new_method_call("com.nokia.nfc", adaptor.toLocal8Bit(), + "com.nokia.nfc.Adapter", "CancelAccessRequest"); + + if (!message) + return; + + dbus_message_iter_init_append(message, &args); + const QByteArray p = path.toUtf8(); + const char *pData = p.constData(); + if (!dbus_message_iter_append_basic(&args, DBUS_TYPE_OBJECT_PATH, &pData)) { + dbus_message_unref(message); + return; + } + + const QByteArray k = kind.toUtf8(); + const char *kData = k.constData(); + if (!dbus_message_iter_append_basic(&args, DBUS_TYPE_STRING, &kData)) { + dbus_message_unref(message); + return; + } + + quint32 serial; + dbus_connection_send(m_dbusConnection, message, &serial); + + dbus_message_unref(message); +} + +bool SocketRequestorPrivate::waitForDBusSignal(int msecs) +{ + dbus_connection_flush(m_dbusConnection); + + fd_set rfds; + FD_ZERO(&rfds); + + int nfds = -1; + foreach (const WatchNotifier &watchNotifier, m_watchNotifiers) { + FD_SET(watchNotifier.readNotifier->socket(), &rfds); + nfds = qMax(nfds, watchNotifier.readNotifier->socket()); + } + + timeval timeout; + timeout.tv_sec = msecs / 1000; + timeout.tv_usec = (msecs % 1000) * 1000; + + // timeout can not be 0 or else select will return an error + if (msecs == 0) + timeout.tv_usec = 1000; + + int result = -1; + // on Linux timeout will be updated by select, but _not_ on other systems + result = ::select(nfds + 1, &rfds, 0, 0, &timeout); + if (result == -1 && errno != EINTR) + return false; + + foreach (const WatchNotifier &watchNotifier, m_watchNotifiers) { + if (FD_ISSET(watchNotifier.readNotifier->socket(), &rfds)) { + QMetaObject::invokeMethod(watchNotifier.readNotifier, "activated", + Q_ARG(int, watchNotifier.readNotifier->socket())); + } + } + + return true; +} + + +SocketRequestor::SocketRequestor(const QString &adaptor, QObject *parent) +: QObject(parent), m_adaptor(adaptor) +{ + + +} + +SocketRequestor::~SocketRequestor() +{ +} + +void SocketRequestor::requestAccess(const QString &path, const QString &kind) +{ + SocketRequestorPrivate *s = socketRequestorPrivate(); + + s->registerObject(path, this); + + QMetaObject::invokeMethod(s, "sendRequestAccess", Qt::QueuedConnection, + Q_ARG(QString, m_adaptor), Q_ARG(QString, path), + Q_ARG(QString, kind)); +} + +void SocketRequestor::cancelAccessRequest(const QString &path, const QString &kind) +{ + SocketRequestorPrivate *s = socketRequestorPrivate(); + + s->unregisterObject(path); + + QMetaObject::invokeMethod(s, "sendCancelAccessRequest", Qt::QueuedConnection, + Q_ARG(QString, m_adaptor), Q_ARG(QString, path), + Q_ARG(QString, kind)); +} + +bool SocketRequestor::waitForDBusSignal(int msecs) +{ + SocketRequestorPrivate *s = socketRequestorPrivate(); + + // Send queued method calls, i.e. requestAccess() and cancelAccessRequest(). + QCoreApplication::sendPostedEvents(s, QEvent::MetaCall); + + // Wait for DBus signal. + bool result = socketRequestorPrivate()->waitForDBusSignal(msecs); + + // Send queued method calls, i.e. those from DBus. + QCoreApplication::sendPostedEvents(this, QEvent::MetaCall); + + return result; +} + +#include <moc_socketrequestor_p.cpp> +#include <socketrequestor.moc> diff --git a/src/nfc/maemo6/socketrequestor_p.h b/src/nfc/maemo6/socketrequestor_p.h new file mode 100644 index 00000000..25c46865 --- /dev/null +++ b/src/nfc/maemo6/socketrequestor_p.h @@ -0,0 +1,90 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +/* + The private API defined in this file is temporary. It should be removed when Qt can handle + passing unix file descriptors over DBus. Most likely in Qt 4.8. +*/ + +#ifndef SOCKETREQUESTOR_P_H +#define SOCKETREQUESTOR_P_H + +#include <qconnectivityglobal.h> + +#include <QtCore/QObject> +#include <QtCore/QVariantMap> + +QT_FORWARD_DECLARE_CLASS(QDBusObjectPath) +QT_FORWARD_DECLARE_CLASS(QDBusVariant) + +class DBusConnection; + +QT_BEGIN_HEADER + +class SocketRequestor : public QObject +{ + Q_OBJECT + +public: + explicit SocketRequestor(const QString &adaptor, QObject *parent = 0); + ~SocketRequestor(); + + void requestAccess(const QString &path, const QString &kind); + void cancelAccessRequest(const QString &path, const QString &kind); + + bool waitForDBusSignal(int msecs); + +signals: + void accessFailed(const QDBusObjectPath &targetPath, const QString &kind, + const QString &error); + void accessGranted(const QDBusObjectPath &targetPath, const QString &accessKind); + + void accept(const QDBusVariant &lsap, const QDBusVariant &rsap, int fd, const QVariantMap &properties); + void connect(const QDBusVariant &lsap, const QDBusVariant &rsap, int fd, const QVariantMap &properties); + void socket(const QDBusVariant &lsap, int fd, const QVariantMap &properties); + +private: + const QString m_adaptor; +}; + +QT_END_HEADER + +#endif // SOCKETREQUESTOR_P_H diff --git a/src/nfc/maemo6/tag_interface.cpp b/src/nfc/maemo6/tag_interface.cpp new file mode 100644 index 00000000..61f3b05c --- /dev/null +++ b/src/nfc/maemo6/tag_interface.cpp @@ -0,0 +1,67 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +/* + * This file was generated by qdbusxml2cpp version 0.7 + * Command line was: qdbusxml2cpp -p tag_interface_p.h:tag_interface.cpp com.nokia.nfc.Tag.xml + * + * qdbusxml2cpp is Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). + * + * This is an auto-generated file. + * This file may have been hand-edited. Look for HAND-EDIT comments + * before re-generating it. + */ + +#include "tag_interface_p.h" + +/* + * Implementation of interface class ComNokiaNfcTagInterface + */ + +ComNokiaNfcTagInterface::ComNokiaNfcTagInterface(const QString &service, const QString &path, const QDBusConnection &connection, QObject *parent) + : QDBusAbstractInterface(service, path, staticInterfaceName(), connection, parent) +{ +} + +ComNokiaNfcTagInterface::~ComNokiaNfcTagInterface() +{ +} + diff --git a/src/nfc/maemo6/tag_interface_p.h b/src/nfc/maemo6/tag_interface_p.h new file mode 100644 index 00000000..f7bdec57 --- /dev/null +++ b/src/nfc/maemo6/tag_interface_p.h @@ -0,0 +1,158 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +/* + * This file was generated by qdbusxml2cpp version 0.7 and then hand edited + * Command line was: qdbusxml2cpp -p tag_interface_p.h:tag_interface.cpp com.nokia.nfc.Tag.xml + * + * qdbusxml2cpp is Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). + * + */ + +#ifndef TAG_INTERFACE_P_H +#define TAG_INTERFACE_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include <QtCore/QObject> +#include <QtCore/QByteArray> +#include <QtCore/QList> +#include <QtCore/QMap> +#include <QtCore/QString> +#include <QtCore/QStringList> +#include <QtCore/QVariant> +#include <QtDBus/QtDBus> + +Q_DECLARE_METATYPE(QList<QByteArray>) + +/* + * Proxy class for interface com.nokia.nfc.Tag + */ +class ComNokiaNfcTagInterface: public QDBusAbstractInterface +{ + Q_OBJECT +public: + static inline const char *staticInterfaceName() + { return "com.nokia.nfc.Tag"; } + +public: + ComNokiaNfcTagInterface(const QString &service, const QString &path, const QDBusConnection &connection, QObject *parent = 0); + + ~ComNokiaNfcTagInterface(); + + Q_PROPERTY(uint Size READ size) + inline uint size() + { + QDBusReply<QVariantMap> reply = GetProperties(); + if (!reply.isValid()) + return 0; + + return reply.value().value(QLatin1String("Size")).toUInt(); + } + + Q_PROPERTY(QString Technology READ technology) + inline QString technology() + { + QDBusReply<QVariantMap> reply = GetProperties(); + if (!reply.isValid()) + return QString(); + + return reply.value().value(QLatin1String("Technology")).toString(); + } + + Q_PROPERTY(QString UID READ uID) + inline QString uID() + { + QDBusReply<QVariantMap> reply = GetProperties(); + if (!reply.isValid()) + return QString(); + + return reply.value().value(QLatin1String("UID")).toString(); + } + +public Q_SLOTS: // METHODS + inline QDBusPendingReply<QVariantMap> GetProperties() + { + QList<QVariant> argumentList; + return asyncCallWithArgumentList(QLatin1String("GetProperties"), argumentList); + } + + inline QDBusPendingReply<QList<QByteArray> > ReadNDEFData() + { + QList<QVariant> argumentList; + return asyncCallWithArgumentList(QLatin1String("ReadNDEFData"), argumentList); + } + + inline QDBusPendingReply<> SetProperty(const QString &in0, const QDBusVariant &in1) + { + QList<QVariant> argumentList; + argumentList << QVariant::fromValue(in0) << QVariant::fromValue(in1); + return asyncCallWithArgumentList(QLatin1String("SetProperty"), argumentList); + } + + inline QDBusPendingReply<> WriteNDEFData(const QList<QByteArray> &in0) + { + QList<QVariant> argumentList; + argumentList << QVariant::fromValue(in0); + return asyncCallWithArgumentList(QLatin1String("WriteNDEFData"), argumentList); + } + +Q_SIGNALS: // SIGNALS + void PropertyChanged(const QString &in0, const QDBusVariant &in1); +}; + +namespace com { + namespace nokia { + namespace nfc { + typedef ::ComNokiaNfcTagInterface Tag; + } + } +} +#endif diff --git a/src/nfc/maemo6/target_interface.cpp b/src/nfc/maemo6/target_interface.cpp new file mode 100644 index 00000000..ce64a6f2 --- /dev/null +++ b/src/nfc/maemo6/target_interface.cpp @@ -0,0 +1,67 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +/* + * This file was generated by qdbusxml2cpp version 0.7 + * Command line was: qdbusxml2cpp -p target_interface_p.h:target_interface.cpp com.nokia.nfc.Target.xml + * + * qdbusxml2cpp is Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). + * + * This is an auto-generated file. + * This file may have been hand-edited. Look for HAND-EDIT comments + * before re-generating it. + */ + +#include "target_interface_p.h" + +/* + * Implementation of interface class ComNokiaNfcTargetInterface + */ + +ComNokiaNfcTargetInterface::ComNokiaNfcTargetInterface(const QString &service, const QString &path, const QDBusConnection &connection, QObject *parent) + : QDBusAbstractInterface(service, path, staticInterfaceName(), connection, parent) +{ +} + +ComNokiaNfcTargetInterface::~ComNokiaNfcTargetInterface() +{ +} + diff --git a/src/nfc/maemo6/target_interface_p.h b/src/nfc/maemo6/target_interface_p.h new file mode 100644 index 00000000..a4a7dced --- /dev/null +++ b/src/nfc/maemo6/target_interface_p.h @@ -0,0 +1,133 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +/* + * This file was generated by qdbusxml2cpp version 0.7 and then hand edited + * Command line was: qdbusxml2cpp -p target_interface_p.h:target_interface.cpp com.nokia.nfc.Target.xml + * + * qdbusxml2cpp is Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). + * + */ + +#ifndef TARGET_INTERFACE_P_H +#define TARGET_INTERFACE_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include <QtCore/QObject> +#include <QtCore/QByteArray> +#include <QtCore/QList> +#include <QtCore/QMap> +#include <QtCore/QString> +#include <QtCore/QStringList> +#include <QtCore/QVariant> +#include <QtDBus/QtDBus> + +/* + * Proxy class for interface com.nokia.nfc.Target + */ +class ComNokiaNfcTargetInterface: public QDBusAbstractInterface +{ + Q_OBJECT +public: + static inline const char *staticInterfaceName() + { return "com.nokia.nfc.Target"; } + +public: + ComNokiaNfcTargetInterface(const QString &service, const QString &path, const QDBusConnection &connection, QObject *parent = 0); + + ~ComNokiaNfcTargetInterface(); + + Q_PROPERTY(QString State READ state) + inline QString state() + { + QDBusReply<QVariantMap> reply = GetProperties(); + if (!reply.isValid()) + return QString(); + + return reply.value().value(QLatin1String("State")).toString(); + } + + Q_PROPERTY(QString Type READ type) + inline QString type() + { + QDBusReply<QVariantMap> reply = GetProperties(); + if (!reply.isValid()) + return QString(); + + return reply.value().value(QLatin1String("Type")).toString(); + } + +public Q_SLOTS: // METHODS + inline QDBusPendingReply<QVariantMap> GetProperties() + { + QList<QVariant> argumentList; + return asyncCallWithArgumentList(QLatin1String("GetProperties"), argumentList); + } + + inline QDBusPendingReply<> SetProperty(const QString &in0, const QDBusVariant &in1) + { + QList<QVariant> argumentList; + argumentList << QVariant::fromValue(in0) << QVariant::fromValue(in1); + return asyncCallWithArgumentList(QLatin1String("SetProperty"), argumentList); + } + +Q_SIGNALS: // SIGNALS + void PropertyChanged(const QString &in0, const QDBusVariant &in1); +}; + +namespace com { + namespace nokia { + namespace nfc { + typedef ::ComNokiaNfcTargetInterface Target; + } + } +} +#endif diff --git a/src/nfc/nfc.pro b/src/nfc/nfc.pro new file mode 100644 index 00000000..2616e096 --- /dev/null +++ b/src/nfc/nfc.pro @@ -0,0 +1,210 @@ +load(qt_module) + +TARGET = QtNfc +QPRO_PWD = $PWD + +CONFIG += module +MODULE_PRI = ../../modules/qt_nfc.pri + +QT = core + +DEFINES += QT_BUILD_NFC_LIB QT_MAKEDLL + +load(qt_module_config) + +PUBLIC_HEADERS += \ + qnearfieldmanager.h \ + qnearfieldtarget.h \ + qndefrecord.h \ + qndefnfctextrecord.h \ + qndefmessage.h \ + qndeffilter.h \ + qndefnfcurirecord.h \ + qnearfieldtagtype1.h \ + qnearfieldtagtype2.h \ + qllcpsocket.h \ + qnearfieldtagtype3.h \ + qnearfieldtagtype4.h \ + qllcpserver.h \ + qdeclarativendefrecord.h + +PRIVATE_HEADERS += \ + qndefrecord_p.h \ + qnearfieldtarget_p.h \ + qnearfieldmanager_p.h \ + qtlv_p.h \ + checksum_p.h + +SOURCES += \ + qnearfieldmanager.cpp \ + qnearfieldtarget.cpp \ + qndefrecord.cpp \ + qndefnfctextrecord.cpp \ + qndefmessage.cpp \ + qndeffilter.cpp \ + qndefnfcurirecord.cpp \ + qnearfieldtagtype1.cpp \ + qnearfieldtagtype2.cpp \ + qnearfieldtagtype3.cpp \ + qllcpsocket.cpp \ + qnearfieldtagtype4.cpp \ + qtlv.cpp \ + qllcpserver.cpp \ + qdeclarativendefrecord.cpp + +maemo6|meego { + NFC_BACKEND_AVAILABLE = yes + + QT *= dbus + + DBUS_INTERFACES += \ + maemo6/com.nokia.nfc.Manager.xml + + DBUS_ADAPTORS += \ + maemo6/com.nokia.nfc.AccessRequestor.xml \ + maemo6/com.nokia.nfc.NDEFHandler.xml + + # work around bug in Qt + dbus_interface_source.depends = ${QMAKE_FILE_OUT_BASE}.h + dbus_adaptor_source.depends = ${QMAKE_FILE_OUT_BASE}.h + + # Link against libdbus until Qt has support for passing file descriptors over DBus. + CONFIG += link_pkgconfig + DEFINES += DBUS_API_SUBJECT_TO_CHANGE + PKGCONFIG += dbus-1 + + PRIVATE_HEADERS += \ + qnearfieldmanager_maemo6_p.h \ + qnearfieldtarget_maemo6_p.h \ + qllcpsocket_maemo6_p.h \ + qllcpserver_maemo6_p.h \ + maemo6/adapter_interface_p.h \ + maemo6/target_interface_p.h \ + maemo6/tag_interface_p.h \ + maemo6/device_interface_p.h \ + maemo6/socketrequestor_p.h + + SOURCES += \ + qnearfieldmanager_maemo6.cpp \ + qnearfieldtarget_maemo6.cpp \ + qllcpsocket_maemo6_p.cpp \ + qllcpserver_maemo6_p.cpp \ + maemo6/adapter_interface.cpp \ + maemo6/target_interface.cpp \ + maemo6/tag_interface.cpp \ + maemo6/device_interface.cpp \ + maemo6/socketrequestor.cpp + + OTHER_FILES += \ + $$DBUS_INTERFACES \ + $$DBUS_ADAPTORS \ + maemo6/com.nokia.nfc.Adapter.xml \ + maemo6/com.nokia.nfc.Target.xml \ + maemo6/com.nokia.nfc.Tag.xml \ + maemo6/com.nokia.nfc.Device.xml \ + maemo6/com.nokia.nfc.LLCPRequestor.xml + + # Add OUT_PWD to INCLUDEPATH so that creator picks up headers for generated files + # This is not needed for the build otherwise. + INCLUDEPATH += $$OUT_PWD +} + +simulator { + NFC_BACKEND_AVAILABLE = yes + + QT *= gui + + PRIVATE_HEADERS += \ + qnearfieldmanagervirtualbase_p.h \ + qnearfieldmanager_simulator_p.h \ + qllcpsocket_simulator_p.h \ + qllcpserver_simulator_p.h + + SOURCES += \ + qnearfieldmanagervirtualbase.cpp \ + qnearfieldmanager_simulator.cpp \ + qllcpsocket_simulator_p.cpp \ + qllcpserver_simulator_p.cpp +} + +contains(nfc_symbian_enabled, yes):symbian { + NFC_BACKEND_AVAILABLE = yes + + QT += serviceframework + + PRIVATE_HEADERS += \ + qnearfieldmanager_symbian_p.h \ + qnearfieldtagtype1_symbian_p.h \ + qnearfieldtagtype2_symbian_p.h \ + qllcpsocket_symbian_p.h \ + qllcpserver_symbian_p.h \ + qllcpstate_symbian_p.h \ + qnearfieldtagtype3_symbian_p.h \ + qnearfieldtagtype4_symbian_p.h \ + qnearfieldtagmifare_symbian_p.h \ + qnearfieldllcpdevice_symbian_p.h \ + symbian/nearfieldmanager_symbian.h \ + symbian/nearfieldtag_symbian.h \ + symbian/nearfieldndeftarget_symbian.h \ + symbian/nearfieldtargetfactory_symbian.h \ + symbian/nearfieldutility_symbian.h \ + symbian/llcpserver_symbian.h \ + symbian/llcpsockettype1_symbian.h \ + symbian/llcpsockettype2_symbian.h \ + symbian/nearfieldtagimpl_symbian.h \ + symbian/nearfieldtagasyncrequest_symbian.h \ + symbian/nearfieldtagndefoperationcallback_symbian.h \ + symbian/nearfieldtagoperationcallback_symbian.h \ + symbian/nearfieldtagndefrequest_symbian.h \ + symbian/nearfieldtagcommandrequest_symbian.h \ + symbian/nearfieldtagcommandsrequest_symbian.h \ + symbian/debug.h \ + symbian/nearfieldtagimplcommon_symbian.h + + SOURCES += \ + qnearfieldmanager_symbian.cpp \ + qnearfieldtagtype1_symbian.cpp \ + qnearfieldtagtype2_symbian.cpp \ + qllcpsocket_symbian_p.cpp \ + qllcpserver_symbian_p.cpp \ + qllcpstate_symbian_p.cpp \ + qnearfieldtagtype3_symbian.cpp \ + qnearfieldtagtype4_symbian.cpp \ + qnearfieldtagmifare_symbian.cpp \ + qnearfieldllcpdevice_symbian.cpp \ + symbian/nearfieldmanager_symbian.cpp \ + symbian/nearfieldtag_symbian.cpp \ + symbian/nearfieldndeftarget_symbian.cpp \ + symbian/nearfieldtargetfactory_symbian.cpp \ + symbian/nearfieldutility_symbian.cpp \ + symbian/llcpserver_symbian.cpp \ + symbian/llcpsockettype1_symbian.cpp \ + symbian/llcpsockettype2_symbian.cpp \ + symbian/nearfieldtagasyncrequest_symbian.cpp \ + symbian/nearfieldtagndefrequest_symbian.cpp \ + symbian/nearfieldtagcommandrequest_symbian.cpp \ + symbian/nearfieldtagcommandsrequest_symbian.cpp \ + symbian/nearfieldtagimplcommon_symbian.cpp + + INCLUDEPATH += $${EPOCROOT}epoc32/include/mw + + LIBS += -lnfc -lndef -lndefaccess -lnfcdiscoveryservice -lllcp -lnfctagextension +} + +isEmpty(NFC_BACKEND_AVAILABLE) { + # unsupported platform stub + + PRIVATE_HEADERS += \ + qllcpsocket_p.h \ + qllcpserver_p.h \ + qnearfieldmanagerimpl_p.h + + SOURCES += \ + qllcpsocket_p.cpp \ + qllcpserver_p.cpp \ + qnearfieldmanagerimpl_p.cpp +} + +INCLUDEPATH += $$PWD + +HEADERS += $$PUBLIC_HEADERS $$PRIVATE_HEADERS diff --git a/src/nfc/qdeclarativendefrecord.cpp b/src/nfc/qdeclarativendefrecord.cpp new file mode 100644 index 00000000..6b974084 --- /dev/null +++ b/src/nfc/qdeclarativendefrecord.cpp @@ -0,0 +1,272 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qdeclarativendefrecord.h" + +#include <QtCore/QMap> +#include <QtCore/QRegExp> + +/*! + \class QDeclarativeNdefRecord + \brief The QDeclarativeNdefRecord class implements the NdefRecord element in QML. + + \ingroup connectivity-nfc + \inmodule QtConnectivity + \since 5.0 + + \sa NdefRecord + + The QDeclarativeNdefRecord class is the base class for all NdefRecord elements in QML. To + support a new NDEF record type in QML subclass this class and expose new properties, member + functions and signals appropriate for the new record type. The following must be done to + create a new NDEF record type in QML: + + \list + \o The subclass must have a Q_OBJECT macro in its declaration. + \o The subclass must have an \l {Q_INVOKABLE}{invokable} constructor that takes a + QNdefRecord and a QObject pointer. + \o The subclass must be declared as an NDEF record by expanding the Q_DECLARE_NDEFRECORD() + macro in the implementation file of the subclass. + \o The subclass must be registered with QML. + \endlist + + For example the declaration of such a class may look like the following. + + \snippet snippets/connectivity/foorecord.h Foo declaration + + Within the implementation file the Q_DECLARE_NDEFRECORD() macro is expanded: + + \snippet snippets/connectivity/foorecord.cpp Declare foo record + + Finially the application or plugin code calls qmlRegisterType(): + + \code + qmlRegisterType<QDeclarativeNdefFooRecord>(uri, 1, 0, "NdefFooRecord"); + \endcode +*/ + +/*! + \qmlclass NdefRecord QDeclarativeNdefRecord + \brief The NdefRecord element represents a record in an NDEF message. + + \ingroup connectivity-qml + \inmodule QtConnectivity + + \sa NdefFilter + \sa NearField + + \sa QNdefRecord + + The NdefRecord element is the base element for all NDEF record elements in QML. It contains + a single property holding the type of record. + + This class is not intended to be used directly, but extended from C++. + + \sa QDeclarativeNdefRecord +*/ + +/*! + \qmlproperty string NdefRecord::recordType + + This property holds the fully qualified record type of the NDEF record. The fully qualified + record type includes the NIS and NSS prefixes. +*/ + +/*! + \fn void QDeclarativeNdefRecord::recordTypeChanged() + + This signal is emitted when the record type changes. +*/ + +/*! + \property QDeclarativeNdefRecord::recordType + + This property hold the record type of the NDEF record that this class represents. +*/ + +/*! + \macro Q_DECLARE_NDEFRECORD(className, typeNameFormat, type) + \relates QDeclarativeNdefRecord + + This macro ensures that \a className is declared as the class implementing the NDEF record + identified by \a typeNameFormat and \a type. + + This macro should be expanded in the implementation file for \a className. +*/ + +static QMap<QString, const QMetaObject *> registeredNdefRecordTypes; + +class QDeclarativeNdefRecordPrivate +{ +public: + QNdefRecord record; +}; + +static QString urnForRecordType(QNdefRecord::TypeNameFormat typeNameFormat, const QByteArray &type) +{ + switch (typeNameFormat) { + case QNdefRecord::NfcRtd: + return QLatin1String("urn:nfc:wkt:") + type; + case QNdefRecord::ExternalRtd: + return QLatin1String("urn:nfc:ext:") + type; + case QNdefRecord::Mime: + return QLatin1String("urn:nfc:mime:") + type; + default: + return QString(); + } +} + +/*! + \internal +*/ +void qRegisterNdefRecordTypeHelper(const QMetaObject *metaObject, + QNdefRecord::TypeNameFormat typeNameFormat, + const QByteArray &type) +{ + registeredNdefRecordTypes.insert(urnForRecordType(typeNameFormat, type), metaObject); +} + +/*! + \internal +*/ +QDeclarativeNdefRecord *qNewDeclarativeNdefRecordForNdefRecord(const QNdefRecord &record) +{ + const QString urn = urnForRecordType(record.typeNameFormat(), record.type()); + + QMapIterator<QString, const QMetaObject *> i(registeredNdefRecordTypes); + while (i.hasNext()) { + i.next(); + + QRegExp ex(i.key()); + if (!ex.exactMatch(urn)) + continue; + + const QMetaObject *metaObject = i.value(); + if (!metaObject) + continue; + + return static_cast<QDeclarativeNdefRecord *>(metaObject->newInstance( + Q_ARG(QNdefRecord, record), Q_ARG(QObject *, 0))); + } + + return new QDeclarativeNdefRecord(record); +} + +/*! + Constructs a new empty QDeclarativeNdefRecord with \a parent. +*/ +QDeclarativeNdefRecord::QDeclarativeNdefRecord(QObject *parent) +: QObject(parent), d_ptr(new QDeclarativeNdefRecordPrivate) +{ +} + +/*! + Constructs a new QDeclarativeNdefRecord representing \a record. The parent of the newly + constructed object will be set to \a parent. +*/ +QDeclarativeNdefRecord::QDeclarativeNdefRecord(const QNdefRecord &record, QObject *parent) +: QObject(parent), d_ptr(new QDeclarativeNdefRecordPrivate) +{ + d_ptr->record = record; +} + +/*! + Returns the fully qualified record type of the record. The fully qualified record type + includes both the NIS and NSS prefixes. +*/ +QString QDeclarativeNdefRecord::recordType() const +{ + Q_D(const QDeclarativeNdefRecord); + + if (d->record.typeNameFormat() == QNdefRecord::Empty) + return QString(); + + return urnForRecordType(d->record.typeNameFormat(), d->record.type()); +} + +/*! + Sets the record type to \a type if it is not currently equal to \a type; otherwise does + nothing. If the record type is set the recordTypeChanged() signal will be emitted. +*/ +void QDeclarativeNdefRecord::setRecordType(const QString &type) +{ + if (type == recordType()) + return; + + Q_D(QDeclarativeNdefRecord); + + if (type.startsWith(QLatin1String("urn:nfc:wkt:"))) { + d->record.setTypeNameFormat(QNdefRecord::NfcRtd); + d->record.setType(type.mid(12).toUtf8()); + } else if (type.startsWith(QLatin1String("urn:nfc:ext:"))) { + d->record.setTypeNameFormat(QNdefRecord::ExternalRtd); + d->record.setType(type.mid(12).toUtf8()); + } else if (type.startsWith(QLatin1String("urn:nfc:mime:"))) { + d->record.setTypeNameFormat(QNdefRecord::Mime); + d->record.setType(type.mid(13).toUtf8()); + } else { + qWarning("Don't know how to decode NDEF type %s\n", qPrintable(type)); + } + + emit recordTypeChanged(); +} + +/*! + Returns a copy of the record. +*/ +QNdefRecord QDeclarativeNdefRecord::record() const +{ + Q_D(const QDeclarativeNdefRecord); + + return d->record; +} + +/*! + Sets the record to \a record. +*/ +void QDeclarativeNdefRecord::setRecord(const QNdefRecord &record) +{ + Q_D(QDeclarativeNdefRecord); + + d->record = record; +} + +#include "moc_qdeclarativendefrecord.cpp" diff --git a/src/nfc/qdeclarativendefrecord.h b/src/nfc/qdeclarativendefrecord.h new file mode 100644 index 00000000..8448b196 --- /dev/null +++ b/src/nfc/qdeclarativendefrecord.h @@ -0,0 +1,96 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QDECLARATIVENDEFRECORD_P_H +#define QDECLARATIVENDEFRECORD_P_H + +#include <QtCore/QObject> +#include <QtCore/QMetaType> + +#include <qndefrecord.h> + +QT_BEGIN_HEADER + +class QDeclarativeNdefRecordPrivate; + +class Q_CONNECTIVITY_EXPORT QDeclarativeNdefRecord : public QObject +{ + Q_OBJECT + Q_DECLARE_PRIVATE(QDeclarativeNdefRecord) + + Q_PROPERTY(QString recordType READ recordType WRITE setRecordType NOTIFY recordTypeChanged) + +public: + explicit QDeclarativeNdefRecord(QObject *parent = 0); + explicit QDeclarativeNdefRecord(const QNdefRecord &record, QObject *parent = 0); + + QString recordType() const; + void setRecordType(const QString &t); + + QNdefRecord record() const; + void setRecord(const QNdefRecord &record); + +signals: + void recordTypeChanged(); + +private: + QDeclarativeNdefRecordPrivate *d_ptr; +}; + +void Q_CONNECTIVITY_EXPORT qRegisterNdefRecordTypeHelper(const QMetaObject *metaObject, + QNdefRecord::TypeNameFormat typeNameFormat, + const QByteArray &type); + +Q_CONNECTIVITY_EXPORT QDeclarativeNdefRecord *qNewDeclarativeNdefRecordForNdefRecord(const QNdefRecord &record); + +template<typename T> +bool qRegisterNdefRecordType(QNdefRecord::TypeNameFormat typeNameFormat, const QByteArray &type) +{ + qRegisterNdefRecordTypeHelper(&T::staticMetaObject, typeNameFormat, type); + return true; +} + +#define Q_DECLARE_NDEFRECORD(className, typeNameFormat, type) \ +static bool _q_##className##_registered = qRegisterNdefRecordType<className>(typeNameFormat, type); + +QT_END_HEADER + +#endif // QDECLARATIVENDEFRECORD_P_H diff --git a/src/nfc/qllcpserver.cpp b/src/nfc/qllcpserver.cpp new file mode 100644 index 00000000..f7f165e6 --- /dev/null +++ b/src/nfc/qllcpserver.cpp @@ -0,0 +1,203 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qllcpserver.h" + +#if defined(QT_SIMULATOR) +#include "qllcpserver_simulator_p.h" +#elif defined(Q_OS_SYMBIAN) +#include "qllcpserver_symbian_p.h" +#elif defined(Q_WS_MAEMO_6) || defined(Q_WS_MEEGO) +#include "qllcpserver_maemo6_p.h" +#else +#include "qllcpserver_p.h" +#endif + +/*! + \class QLlcpServer + \brief The QLlcpServer class provides an NFC LLCP socket based server. + + \ingroup connectivity-nfc + \inmodule QtConnectivity + \since 5.0 + + This class makes it possible to accept incoming LLCP socket connections. + + Call listen() to have the server start listening for incoming connections on a specified port. + The newConnection() signal is then emitted each time a client connects to the server. + + Call nextPendingConnection() to accept the pending connection as a connected QLlcpSocket. The + function returns a pointer to a QLlcpSocket that can be used for communicating with the client. + + If an error occurs, serverError() returns the type of error, and errorString() can be called to + get a human readable description of what happened. + + When listening for connections, the port which the server is listening on is available through + serverPort(). + + Calling close() makes QLlcpServer stop listening for incoming connections. +*/ + +/*! + \fn QLlcpServer::newConnection() + + This signal is emitted every time a new connection is available. + + \sa hasPendingConnections(), nextPendingConnection() +*/ + +/*! + Constructs a new NFC LLCP server with \a parent. +*/ +QLlcpServer::QLlcpServer(QObject *parent) +: QObject(parent), d_ptr(new QLlcpServerPrivate(this)) +{ +} + +/*! + Destroys the NFC LLCP server. +*/ +QLlcpServer::~QLlcpServer() +{ + delete d_ptr; +} + +/*! + Tells the server to listen for incoming connections on \a serviceUri. If the server is + currently listening then it will return false. Returns true on success; otherwise returns + false. + + serviceUri() will return the \a serviceUri that is passed into listen. + + serverPort() will return the port that is assigned to the server. + + \sa serverPort(), isListening(), close() +*/ +bool QLlcpServer::listen(const QString &serviceUri) +{ + Q_D(QLlcpServer); + + return d->listen(serviceUri); +} + +/*! + Returns true if the server is listening for incoming connections; otherwise returns false. +*/ +bool QLlcpServer::isListening() const +{ + Q_D(const QLlcpServer); + + return d->isListening(); +} + +/*! + Stops listening for incoming connections. +*/ +void QLlcpServer::close() +{ + Q_D(QLlcpServer); + + d->close(); +} + +/*! + Returns the LLCP service URI that the server is listening on. +*/ +QString QLlcpServer::serviceUri() const +{ + Q_D(const QLlcpServer); + + return d->serviceUri(); +} + +/*! + Returns the LLCP port associated with the service URI that the server is listening on. + + \note This call is not supported on all platforms and will return 0 on these platforms. +*/ +quint8 QLlcpServer::serverPort() const +{ + Q_D(const QLlcpServer); + + return d->serverPort(); +} + +/*! + Returns true if the server has a pending connection; otherwise returns false. + + \sa nextPendingConnection() +*/ +bool QLlcpServer::hasPendingConnections() const +{ + Q_D(const QLlcpServer); + + return d->hasPendingConnections(); +} + +/*! + Returns the next pending connection as a connected QLlcpSocket object. + + The socket is created as a child of the server, which means that it is automatically deleted + when the QLlcpServer object is destroyed. It is still a good idea to delete the object + explicitly when you are done with it, to avoid wasting memory. + + 0 is returned if this function is called when there are no pending connections. + + \sa hasPendingConnections(), newConnection() +*/ +QLlcpSocket *QLlcpServer::nextPendingConnection() +{ + Q_D(QLlcpServer); + + return d->nextPendingConnection(); +} + +/*! + Returns the last error that occurred. +*/ +QLlcpSocket::SocketError QLlcpServer::serverError() const +{ + Q_D(const QLlcpServer); + + return d->serverError(); +} + +#include "moc_qllcpserver.cpp" diff --git a/src/nfc/qllcpserver.h b/src/nfc/qllcpserver.h new file mode 100644 index 00000000..7a43b237 --- /dev/null +++ b/src/nfc/qllcpserver.h @@ -0,0 +1,86 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QLLCPSERVER_H +#define QLLCPSERVER_H + +#include "../qtconnectivityglobal.h" + +#include <qllcpsocket.h> + +#include <QtCore/QObject> + +QT_BEGIN_HEADER + +class QLlcpServerPrivate; + +class Q_CONNECTIVITY_EXPORT QLlcpServer : public QObject +{ + Q_OBJECT + Q_DECLARE_PRIVATE(QLlcpServer) + +public: + explicit QLlcpServer(QObject *parent = 0); + virtual ~QLlcpServer(); + + bool listen(const QString &serviceUri); + bool isListening() const; + + void close(); + + QString serviceUri() const; + quint8 serverPort() const; + + virtual bool hasPendingConnections() const; + virtual QLlcpSocket *nextPendingConnection(); + + QLlcpSocket::SocketError serverError() const; + +Q_SIGNALS: + void newConnection(); + +private: + QLlcpServerPrivate *d_ptr; +}; + +QT_END_HEADER + +#endif // QLLCPSERVER_H diff --git a/src/nfc/qllcpserver_maemo6_p.cpp b/src/nfc/qllcpserver_maemo6_p.cpp new file mode 100644 index 00000000..2b964bc1 --- /dev/null +++ b/src/nfc/qllcpserver_maemo6_p.cpp @@ -0,0 +1,198 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qllcpserver_maemo6_p.h" + +#include "manager_interface.h" +#include "maemo6/adapter_interface_p.h" +#include "qllcpsocket_maemo6_p.h" +#include "maemo6/socketrequestor_p.h" + +using namespace com::nokia::nfc; + +static QAtomicInt requestorId = 0; +static const char * const requestorBasePath = "/com/nokia/nfc/llcpserver/"; + +QLlcpServerPrivate::QLlcpServerPrivate(QLlcpServer *q) +: q_ptr(q), + m_connection(QDBusConnection::connectToBus(QDBusConnection::SystemBus, QUuid::createUuid())), + m_socketRequestor(0) +{ +} + +bool QLlcpServerPrivate::listen(const QString &serviceUri) +{ + if (m_requestorPath.isEmpty()) { + m_requestorPath = QLatin1String(requestorBasePath) + + QString::number(requestorId.fetchAndAddOrdered(1)); + } + + Manager manager(QLatin1String("com.nokia.nfc"), QLatin1String("/"), m_connection); + QDBusObjectPath defaultAdapterPath = manager.DefaultAdapter(); + + if (!m_socketRequestor) { + m_socketRequestor = new SocketRequestor(defaultAdapterPath.path(), this); + + connect(m_socketRequestor, SIGNAL(accessFailed(QDBusObjectPath,QString,QString)), + this, SLOT(AccessFailed(QDBusObjectPath,QString,QString))); + connect(m_socketRequestor, SIGNAL(accessGranted(QDBusObjectPath,QString)), + this, SLOT(AccessGranted(QDBusObjectPath,QString))); + connect(m_socketRequestor, SIGNAL(accept(QDBusVariant,QDBusVariant,int,QVariantMap)), + this, SLOT(Accept(QDBusVariant,QDBusVariant,int,QVariantMap))); + connect(m_socketRequestor, SIGNAL(connect(QDBusVariant,QDBusVariant,int,QVariantMap)), + this, SLOT(Connect(QDBusVariant,QDBusVariant,int,QVariantMap))); + connect(m_socketRequestor, SIGNAL(socket(QDBusVariant,int,QVariantMap)), + this, SLOT(Socket(QDBusVariant,int,QVariantMap))); + } + + if (m_socketRequestor) { + QString accessKind(QLatin1String("device.llcp.co.server:") + serviceUri); + m_socketRequestor->requestAccess(m_requestorPath, accessKind); + + m_serviceUri = serviceUri; + } else { + m_error = QLlcpSocket::SocketResourceError; + + m_serviceUri.clear(); + } + + return !m_serviceUri.isEmpty(); +} + +bool QLlcpServerPrivate::isListening() const +{ + return !m_serviceUri.isEmpty(); +} + +void QLlcpServerPrivate::close() +{ + QString accessKind(QLatin1String("device.llcp.co.server:") + m_serviceUri); + + m_socketRequestor->cancelAccessRequest(m_requestorPath, accessKind); + + m_serviceUri.clear(); +} + +QString QLlcpServerPrivate::serviceUri() const +{ + return m_serviceUri; +} + +quint8 QLlcpServerPrivate::serverPort() const +{ + return 0; +} + +bool QLlcpServerPrivate::hasPendingConnections() const +{ + return !m_pendingSockets.isEmpty(); +} + +QLlcpSocket *QLlcpServerPrivate::nextPendingConnection() +{ + if (m_pendingSockets.isEmpty()) + return 0; + + QPair<int, QVariantMap> parameters = m_pendingSockets.takeFirst(); + + QLlcpSocketPrivate *socketPrivate = + new QLlcpSocketPrivate(m_connection, parameters.first, parameters.second); + + QLlcpSocket *socket = new QLlcpSocket(socketPrivate, 0); + + return socket; +} + +QLlcpSocket::SocketError QLlcpServerPrivate::serverError() const +{ + return QLlcpSocket::UnknownSocketError; +} + +void QLlcpServerPrivate::AccessFailed(const QDBusObjectPath &targetPath, const QString &kind, + const QString &error) +{ + Q_UNUSED(targetPath); + Q_UNUSED(kind); + Q_UNUSED(error); + + m_serviceUri.clear(); + + m_error = QLlcpSocket::SocketAccessError; +} + +void QLlcpServerPrivate::AccessGranted(const QDBusObjectPath &targetPath, + const QString &accessKind) +{ + Q_UNUSED(targetPath); + Q_UNUSED(accessKind); +} + +void QLlcpServerPrivate::Accept(const QDBusVariant &lsap, const QDBusVariant &rsap, + int fd, const QVariantMap &properties) +{ + Q_UNUSED(lsap); + Q_UNUSED(rsap); + Q_UNUSED(properties); + + Q_Q(QLlcpServer); + + m_pendingSockets.append(qMakePair(fd, properties)); + + emit q->newConnection(); +} + +void QLlcpServerPrivate::Connect(const QDBusVariant &lsap, const QDBusVariant &rsap, + int readFd, const QVariantMap &properties) +{ + Q_UNUSED(lsap); + Q_UNUSED(rsap); + Q_UNUSED(readFd); + Q_UNUSED(properties); +} + +void QLlcpServerPrivate::Socket(const QDBusVariant &lsap, int fd, const QVariantMap &properties) +{ + Q_UNUSED(lsap); + Q_UNUSED(fd); + Q_UNUSED(properties); +} + +#include "moc_qllcpserver_maemo6_p.cpp" diff --git a/src/nfc/qllcpserver_maemo6_p.h b/src/nfc/qllcpserver_maemo6_p.h new file mode 100644 index 00000000..0543f321 --- /dev/null +++ b/src/nfc/qllcpserver_maemo6_p.h @@ -0,0 +1,109 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QLLCPSERVER_MAEMO6_P_H +#define QLLCPSERVER_MAEMO6_P_H + +#include <qconnectivityglobal.h> + +#include "qllcpserver.h" + +#include <QtDBus/QDBusConnection> + +QT_FORWARD_DECLARE_CLASS(QDBusObjectPath) +QT_FORWARD_DECLARE_CLASS(QDBusVariant) + +class AccessRequestorAdaptor; +class LLCPRequestorAdaptor; + +class SocketRequestor; + +class QLlcpServerPrivate : public QObject +{ + Q_OBJECT + + Q_DECLARE_PUBLIC(QLlcpServer) + +public: + QLlcpServerPrivate(QLlcpServer *q); + + bool listen(const QString &serviceUri); + bool isListening() const; + + void close(); + + QString serviceUri() const; + quint8 serverPort() const; + + bool hasPendingConnections() const; + QLlcpSocket *nextPendingConnection(); + + QLlcpSocket::SocketError serverError() const; + +private slots: + // com.nokia.nfc.AccessRequestor + void AccessFailed(const QDBusObjectPath &targetPath, const QString &kind, + const QString &error); + void AccessGranted(const QDBusObjectPath &targetPath, const QString &accessKind); + + // com.nokia.nfc.LLCPRequestor + void Accept(const QDBusVariant &lsap, const QDBusVariant &rsap, int fd, + const QVariantMap &properties); + void Connect(const QDBusVariant &lsap, const QDBusVariant &rsap, int fd, + const QVariantMap &properties); + void Socket(const QDBusVariant &lsap, int fd, const QVariantMap &properties); + +private: + QLlcpServer *q_ptr; + + QDBusConnection m_connection; + + QString m_serviceUri; + + QString m_requestorPath; + SocketRequestor *m_socketRequestor; + + QList<QPair<int, QVariantMap> > m_pendingSockets; + + QLlcpSocket::SocketError m_error; +}; + +#endif // QLLCPSERVER_MAEMO6_P_H diff --git a/src/nfc/qllcpserver_p.cpp b/src/nfc/qllcpserver_p.cpp new file mode 100644 index 00000000..1e21ee34 --- /dev/null +++ b/src/nfc/qllcpserver_p.cpp @@ -0,0 +1,92 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qllcpserver_p.h" + +QLlcpServerPrivate::QLlcpServerPrivate(QLlcpServer *q) +: q_ptr(q) +{ +} + +QLlcpServerPrivate::~QLlcpServerPrivate() +{ +} + +bool QLlcpServerPrivate::listen(const QString &serviceUri) +{ + Q_UNUSED(serviceUri); + + return false; +} + +bool QLlcpServerPrivate::isListening() const +{ + return false; +} + +void QLlcpServerPrivate::close() +{ +} + +QString QLlcpServerPrivate::serviceUri() const +{ + return QString(); +} + +quint8 QLlcpServerPrivate::serverPort() const +{ + return 0; +} + +bool QLlcpServerPrivate::hasPendingConnections() const +{ + return false; +} + +QLlcpSocket *QLlcpServerPrivate::nextPendingConnection() +{ + return 0; +} + +QLlcpSocket::SocketError QLlcpServerPrivate::serverError() const +{ + return QLlcpSocket::UnknownSocketError; +} diff --git a/src/nfc/qllcpserver_p.h b/src/nfc/qllcpserver_p.h new file mode 100644 index 00000000..e0a57ec3 --- /dev/null +++ b/src/nfc/qllcpserver_p.h @@ -0,0 +1,74 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QLLCPSERVER_P_H +#define QLLCPSERVER_P_H + +#include "../qtconnectivityglobal.h" + +#include "qllcpserver.h" + +class QLlcpServerPrivate +{ + Q_DECLARE_PUBLIC(QLlcpServer) + +public: + QLlcpServerPrivate(QLlcpServer *q); + ~QLlcpServerPrivate(); + + bool listen(const QString &serviceUri); + bool isListening() const; + + void close(); + + QString serviceUri() const; + quint8 serverPort() const; + + bool hasPendingConnections() const; + QLlcpSocket *nextPendingConnection(); + + QLlcpSocket::SocketError serverError() const; + +private: + QLlcpServer *q_ptr; +}; + +#endif // QLLCPSERVER_P_H diff --git a/src/nfc/qllcpserver_simulator_p.cpp b/src/nfc/qllcpserver_simulator_p.cpp new file mode 100644 index 00000000..5ef6f963 --- /dev/null +++ b/src/nfc/qllcpserver_simulator_p.cpp @@ -0,0 +1,88 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qllcpserver_simulator_p.h" + +QLlcpServerPrivate::QLlcpServerPrivate(QLlcpServer *q) +: q_ptr(q) +{ +} + +bool QLlcpServerPrivate::listen(const QString &serviceUri) +{ + Q_UNUSED(serviceUri); + + return false; +} + +bool QLlcpServerPrivate::isListening() const +{ + return false; +} + +void QLlcpServerPrivate::close() +{ +} + +QString QLlcpServerPrivate::serviceUri() const +{ + return QString(); +} + +quint8 QLlcpServerPrivate::serverPort() const +{ + return 0; +} + +bool QLlcpServerPrivate::hasPendingConnections() const +{ + return false; +} + +QLlcpSocket *QLlcpServerPrivate::nextPendingConnection() +{ + return 0; +} + +QLlcpSocket::SocketError QLlcpServerPrivate::serverError() const +{ + return QLlcpSocket::UnknownSocketError; +} diff --git a/src/nfc/qllcpserver_simulator_p.h b/src/nfc/qllcpserver_simulator_p.h new file mode 100644 index 00000000..dfda5b5d --- /dev/null +++ b/src/nfc/qllcpserver_simulator_p.h @@ -0,0 +1,71 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QLLCPSERVER_P_H +#define QLLCPSERVER_P_H + +#include <qconnectivityglobal.h> + +#include "qllcpserver.h" + +class QLlcpServerPrivate +{ +public: + QLlcpServerPrivate(QLlcpServer *q); + + bool listen(const QString &serviceUri); + bool isListening() const; + + void close(); + + QString serviceUri() const; + quint8 serverPort() const; + + bool hasPendingConnections() const; + QLlcpSocket *nextPendingConnection(); + + QLlcpSocket::SocketError serverError() const; + +private: + QLlcpServer *q_ptr; +}; + +#endif // QLLCPSERVER_P_H diff --git a/src/nfc/qllcpserver_symbian_p.cpp b/src/nfc/qllcpserver_symbian_p.cpp new file mode 100644 index 00000000..4497ae15 --- /dev/null +++ b/src/nfc/qllcpserver_symbian_p.cpp @@ -0,0 +1,160 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qllcpserver_symbian_p.h" +#include "symbian/llcpserver_symbian.h" +#include "symbian/llcpsockettype2_symbian.h" +#include "symbian/nearfieldutility_symbian.h" + +#include "symbian/debug.h" + +QLlcpServerPrivate::QLlcpServerPrivate(QLlcpServer *q) + :q_ptr(q) +{ + BEGIN + QT_TRAP_THROWING(m_symbianbackend = CLlcpServer::NewL(*this)); + END +} +QLlcpServerPrivate::~QLlcpServerPrivate() +{ + BEGIN + close(); + delete m_symbianbackend; + END +} + +bool QLlcpServerPrivate::listen(const QString &serviceUri) +{ + BEGIN + LOG(serviceUri); + HBufC8* uri = NULL; + TRAPD(err, uri = QNFCNdefUtility::QString2HBufC8L(serviceUri)); + if(err != KErrNone) + { + return false; + } + bool ret = m_symbianbackend->Listen(*uri); + + delete uri; + END + return ret; +} + +bool QLlcpServerPrivate::isListening() const +{ + BEGIN + END + return m_symbianbackend->isListening(); +} + +/*! + Stops listening for incoming connections. +*/ +void QLlcpServerPrivate::close() +{ + BEGIN + m_symbianbackend->StopListening(); + qDeleteAll(m_pendingConnections); + m_pendingConnections.clear(); + END +} + +QString QLlcpServerPrivate::serviceUri() const +{ + BEGIN + const TDesC8& uri= m_symbianbackend->serviceUri(); + + QString ret = QNFCNdefUtility::TDesC82QStringL(uri); + LOG("QLlcpServerPrivate::serviceUri() ret="<<ret); + END + return ret; + +} + +quint8 QLlcpServerPrivate::serverPort() const +{ + BEGIN + END + return 0; +} + +bool QLlcpServerPrivate::hasPendingConnections() const +{ + BEGIN + END + return m_symbianbackend->hasPendingConnections(); +} + +void QLlcpServerPrivate::invokeNewConnection() +{ + BEGIN + Q_Q(QLlcpServer); + emit q->newConnection(); + END +} + +QLlcpSocket *QLlcpServerPrivate::nextPendingConnection() +{ + BEGIN + QLlcpSocket* qSocket = NULL; + CLlcpSocketType2* socket_symbian = m_symbianbackend->nextPendingConnection(); + if (socket_symbian) + { + QLlcpSocketPrivate *qSocket_p = new QLlcpSocketPrivate(socket_symbian); + qSocket = new QLlcpSocket(qSocket_p,NULL); + qSocket_p->attachCallbackHandler(qSocket); + socket_symbian->AttachCallbackHandler(qSocket_p); + QPointer<QLlcpSocket> p(qSocket); + m_pendingConnections.append(p); + } + END + return qSocket; +} + +QLlcpSocket::SocketError QLlcpServerPrivate::serverError() const +{ + BEGIN + END + return QLlcpSocket::UnknownSocketError; +} + +//EOF + diff --git a/src/nfc/qllcpserver_symbian_p.h b/src/nfc/qllcpserver_symbian_p.h new file mode 100644 index 00000000..e8d67654 --- /dev/null +++ b/src/nfc/qllcpserver_symbian_p.h @@ -0,0 +1,86 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QLLCPSERVER_SYMBIAN_P_H +#define QLLCPSERVER_SYMBIAN_P_H + +#include <qconnectivityglobal.h> +#include "qllcpserver.h" +#include <QList> +#include <QPointer> + +class CLlcpServer; +class CLlcpSocketType2; +class QLlcpSocket; + +QT_BEGIN_HEADER + +class QLlcpServerPrivate +{ + Q_DECLARE_PUBLIC(QLlcpServer) +public: + QLlcpServerPrivate(QLlcpServer *q); + ~QLlcpServerPrivate(); + + bool listen(const QString &serviceUri); + bool isListening() const; + + void close(); + + QString serviceUri() const; + quint8 serverPort() const; + + bool hasPendingConnections() const; + QLlcpSocket *nextPendingConnection(); + QLlcpSocket::SocketError serverError() const; + +public: + void invokeNewConnection(); + +private: + CLlcpServer* m_symbianbackend; + QLlcpServer *q_ptr; + QList<QPointer<QLlcpSocket> > m_pendingConnections; +}; + +QT_END_HEADER + +#endif // QLLCPSERVER_P_H diff --git a/src/nfc/qllcpsocket.cpp b/src/nfc/qllcpsocket.cpp new file mode 100644 index 00000000..5b7e9e65 --- /dev/null +++ b/src/nfc/qllcpsocket.cpp @@ -0,0 +1,404 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qllcpsocket.h" + +#if defined(QT_SIMULATOR) +#include "qllcpsocket_simulator_p.h" +#elif defined(Q_OS_SYMBIAN) +#include "qllcpsocket_symbian_p.h" +#elif defined(Q_WS_MAEMO_6) || defined(Q_WS_MEEGO) +#include "qllcpsocket_maemo6_p.h" +#else +#include "qllcpsocket_p.h" +#endif + +/*! + \class QLlcpSocket + \brief The QLlcpSocket class provides an NFC LLCP socket. + \since 5.0 + + \ingroup connectivity-nfc + \inmodule QtConnectivity + + NFC LLCP protocol is a peer-to-peer communication protocol between two NFC compliant devices. +*/ + +/*! + \enum QLlcpSocket::SocketError + + This enum describes the errors that can occur. The most recent error can be retrieved through a + call to error(). + + \value UnknownSocketError An unidentified error has occurred. + \value RemoteHostClosedError The remote host closed the connection. + \value SocketAccessError The socket operation failed because the application lacked the + required privileges. + \value SocketResourceError The local system ran out of resources (e.g., too many sockets). +*/ + +/*! + \enum QLlcpSocket::SocketState + + This enum describes the different state in which a socket can be. + + \value UnconnectedState The socket is not connected. + \value ConnectingState The socket has started establishing a connection. + \value ConnectedState A connection is established. + \value ClosingState The socket is about to close. + \value BoundState The socket is bound to a local port (for servers). + \value ListeningState The socket is listening for incoming connections (for internal use). +*/ + +/*! + \fn QLlcpSocket::connected() + + This signal is emitted after connectToService() has been called and a connection has been + successfully established. + + \sa connectToService(), disconnected() +*/ + +/*! + \fn QLlcpSocket::disconnected() + + This signal is emitted when the socket has been disconnected. + + \sa disconnectFromService(), +*/ + +/*! + \fn QLlcpSocket::error(QLlcpSocket::SocketError socketError) + + This signal is emitted when an error occurs. The \a socketError parameter describes the error. +*/ + +/*! + \fn QLlcpSocket::stateChanged(QLlcpSocket::SocketState socketState) + + This signal is emitted when the state of the socket changes. The \a socketState parameter + describes the new state. +*/ + +/*! + Construct a new unconnected LLCP socket with \a parent. +*/ +QLlcpSocket::QLlcpSocket(QObject *parent) +: QIODevice(parent), d_ptr(new QLlcpSocketPrivate(this)) +{ + setOpenMode(QIODevice::NotOpen); +} + +/*! + \internal +*/ +QLlcpSocket::QLlcpSocket(QLlcpSocketPrivate *d, QObject *parent) +: QIODevice(parent), d_ptr(d) +{ + setOpenMode(QIODevice::ReadWrite); + d_ptr->q_ptr = this; +} + +/*! + Destroys the LLCP socket. +*/ +QLlcpSocket::~QLlcpSocket() +{ + delete d_ptr; +} + +/*! + Connects to the service identified by the URI \a serviceUri on \a target. +*/ +void QLlcpSocket::connectToService(QNearFieldTarget *target, const QString &serviceUri) +{ + Q_D(QLlcpSocket); + + d->connectToService(target, serviceUri); +} + +/*! + Disconnects the socket. +*/ +void QLlcpSocket::disconnectFromService() +{ + Q_D(QLlcpSocket); + + d->disconnectFromService(); +} + +/*! + Disconnects the socket. +*/ +void QLlcpSocket::close() +{ + Q_D(QLlcpSocket); + + QIODevice::close(); + + d->disconnectFromService(); +} + +/*! + Binds the LLCP socket to local \a port. Returns true on success; otherwise returns false. +*/ +bool QLlcpSocket::bind(quint8 port) +{ + Q_D(QLlcpSocket); + + return d->bind(port); +} + +/*! + Returns true if at least one datagram (service data units) is waiting to be read; otherwise + returns false. + + \sa pendingDatagramSize(), readDatagram() +*/ +bool QLlcpSocket::hasPendingDatagrams() const +{ + Q_D(const QLlcpSocket); + + return d->hasPendingDatagrams(); +} + +/*! + Returns the size of the first pending datagram (service data unit). If there is no datagram + available, this function returns -1. + + \sa hasPendingDatagrams(), readDatagram() +*/ +qint64 QLlcpSocket::pendingDatagramSize() const +{ + Q_D(const QLlcpSocket); + + return d->pendingDatagramSize(); +} + +/*! + Sends the datagram at \a data of size \a size to the service that this socket is connected to. + Returns the number of bytes sent on success; otherwise return -1; +*/ +qint64 QLlcpSocket::writeDatagram(const char *data, qint64 size) +{ + Q_D(QLlcpSocket); + + return d->writeDatagram(data, size); +} + +/*! + \reimp + + Always returns true. +*/ +bool QLlcpSocket::isSequential() const +{ + return true; +} + +/*! + \overload + + Sends the datagram \a datagram to the service that this socket is connected to. +*/ +qint64 QLlcpSocket::writeDatagram(const QByteArray &datagram) +{ + Q_D(QLlcpSocket); + + return d->writeDatagram(datagram); +} + +/*! + Receives a datagram no larger than \a maxSize bytes and stores it in \a data. The sender's + details are stored in \a target and \a port (unless the pointers are 0). + + Returns the size of the datagram on success; otherwise returns -1. + + If maxSize is too small, the rest of the datagram will be lost. To avoid loss of data, call + pendingDatagramSize() to determine the size of the pending datagram before attempting to read + it. If maxSize is 0, the datagram will be discarded. + + \sa writeDatagram(), hasPendingDatagrams(), pendingDatagramSize() +*/ +qint64 QLlcpSocket::readDatagram(char *data, qint64 maxSize, QNearFieldTarget **target, + quint8 *port) +{ + Q_D(QLlcpSocket); + + return d->readDatagram(data, maxSize, target, port); +} + +/*! + Sends the datagram at \a data of size \a size to the service identified by the URI + \a port on \a target. Returns the number of bytes sent on success; otherwise returns -1. + + \sa readDatagram() +*/ +qint64 QLlcpSocket::writeDatagram(const char *data, qint64 size, QNearFieldTarget *target, + quint8 port) +{ + Q_D(QLlcpSocket); + + return d->writeDatagram(data, size, target, port); +} + +/*! + \overload + + Sends the datagram \a datagram to the service identified by the URI \a port on \a target. +*/ +qint64 QLlcpSocket::writeDatagram(const QByteArray &datagram, QNearFieldTarget *target, + quint8 port) +{ + Q_D(QLlcpSocket); + + return d->writeDatagram(datagram, target, port); +} + +/*! + Returns the type of error that last occurred. +*/ +QLlcpSocket::SocketError QLlcpSocket::error() const +{ + Q_D(const QLlcpSocket); + + return d->error(); +} + +/*! + Returns the state of the socket. +*/ +QLlcpSocket::SocketState QLlcpSocket::state() const +{ + Q_D(const QLlcpSocket); + + return d->state(); +} + +/*! + \reimp +*/ +qint64 QLlcpSocket::bytesAvailable() const +{ + Q_D(const QLlcpSocket); + + return d->bytesAvailable() + QIODevice::bytesAvailable(); +} + +/*! + \reimp +*/ +bool QLlcpSocket::canReadLine() const +{ + Q_D(const QLlcpSocket); + + return d->canReadLine() || QIODevice::canReadLine(); +} + +/*! + \reimp +*/ +bool QLlcpSocket::waitForReadyRead(int msecs) +{ + Q_D(QLlcpSocket); + + return d->waitForReadyRead(msecs); +} + +/*! + \reimp +*/ +bool QLlcpSocket::waitForBytesWritten(int msecs) +{ + Q_D(QLlcpSocket); + + return d->waitForBytesWritten(msecs); +} + +/*! + Waits until the socket is connected, up to \a msecs milliseconds. If the connection has been + established, this function returns true; otherwise it returns false. In the case where it + returns false, you can call error() to determine the cause of the error. + + If msecs is -1, this function will not time out. +*/ +bool QLlcpSocket::waitForConnected(int msecs) +{ + Q_D(QLlcpSocket); + + return d->waitForConnected(msecs); +} + +/*! + Waits until the socket is disconnected, up to \a msecs milliseconds. If the connection has been + disconnected, this function returns true; otherwise it returns false. In the case where it + returns false, you can call error() to determine the cause of the error. + + If msecs is -1, this function will not time out. +*/ +bool QLlcpSocket::waitForDisconnected(int msecs) +{ + Q_D(QLlcpSocket); + + return d->waitForDisconnected(msecs); +} + +/*! + \internal +*/ +qint64 QLlcpSocket::readData(char *data, qint64 maxlen) +{ + Q_D(QLlcpSocket); + + return d->readData(data, maxlen); +} + +/*! + \internal +*/ +qint64 QLlcpSocket::writeData(const char *data, qint64 len) +{ + Q_D(QLlcpSocket); + + return d->writeData(data, len); +} + +#include <moc_qllcpsocket.cpp> diff --git a/src/nfc/qllcpsocket.h b/src/nfc/qllcpsocket.h new file mode 100644 index 00000000..7e916b95 --- /dev/null +++ b/src/nfc/qllcpsocket.h @@ -0,0 +1,131 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QLLCPSOCKET_H +#define QLLCPSOCKET_H + +#include "../qtconnectivityglobal.h" + +#include <QtCore/QIODevice> +#include <QtNetwork/QAbstractSocket> + +QT_BEGIN_HEADER + +class QNearFieldTarget; +class QLlcpSocketPrivate; + +class Q_CONNECTIVITY_EXPORT QLlcpSocket : public QIODevice +{ + Q_OBJECT + Q_DECLARE_PRIVATE(QLlcpSocket) + + friend class QLlcpServerPrivate; + +public: + enum SocketState { + UnconnectedState = QAbstractSocket::UnconnectedState, + ConnectingState = QAbstractSocket::ConnectingState, + ConnectedState = QAbstractSocket::ConnectedState, + ClosingState = QAbstractSocket::ClosingState, + BoundState = QAbstractSocket::BoundState, + ListeningState = QAbstractSocket::ListeningState + }; + + enum SocketError { + UnknownSocketError = QAbstractSocket::UnknownSocketError, + RemoteHostClosedError = QAbstractSocket::RemoteHostClosedError, + SocketAccessError = QAbstractSocket::SocketAccessError, + SocketResourceError = QAbstractSocket::SocketResourceError + }; + + explicit QLlcpSocket(QObject *parent = 0); + ~QLlcpSocket(); + + void connectToService(QNearFieldTarget *target, const QString &serviceUri); + void disconnectFromService(); + + void close(); + + bool bind(quint8 port); + + bool hasPendingDatagrams() const; + qint64 pendingDatagramSize() const; + + qint64 writeDatagram(const char *data, qint64 size); + qint64 writeDatagram(const QByteArray &datagram); + + qint64 readDatagram(char *data, qint64 maxSize, + QNearFieldTarget **target = 0, quint8 *port = 0); + qint64 writeDatagram(const char *data, qint64 size, + QNearFieldTarget *target, quint8 port); + qint64 writeDatagram(const QByteArray &datagram, QNearFieldTarget *target, quint8 port); + + SocketError error() const; + SocketState state() const; + + qint64 bytesAvailable() const; + bool canReadLine() const; + + bool waitForReadyRead(int msecs = 30000); + bool waitForBytesWritten(int msecs = 30000); + virtual bool waitForConnected(int msecs = 30000); + virtual bool waitForDisconnected(int msecs = 30000); + bool isSequential() const; + +Q_SIGNALS: + void connected(); + void disconnected(); + void error(QLlcpSocket::SocketError socketError); + void stateChanged(QLlcpSocket::SocketState socketState); + +protected: + qint64 readData(char *data, qint64 maxlen); + qint64 writeData(const char *data, qint64 len); + +private: + QLlcpSocket(QLlcpSocketPrivate *d, QObject *parent); + + QLlcpSocketPrivate *d_ptr; +}; + +QT_END_HEADER + +#endif // QLLCPSOCKET_H diff --git a/src/nfc/qllcpsocket_maemo6_p.cpp b/src/nfc/qllcpsocket_maemo6_p.cpp new file mode 100644 index 00000000..a2cd15f6 --- /dev/null +++ b/src/nfc/qllcpsocket_maemo6_p.cpp @@ -0,0 +1,638 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qllcpsocket_maemo6_p.h" + +#include "manager_interface.h" +#include "maemo6/adapter_interface_p.h" +#include "maemo6/socketrequestor_p.h" + +#include <QtCore/QSocketNotifier> +#include <QtCore/QAtomicInt> + +#include <errno.h> +#include <signal.h> + +using namespace com::nokia::nfc; + +static QAtomicInt requestorId = 0; +static const char * const requestorBasePath = "/com/nokia/nfc/llcpclient/"; + +QLlcpSocketPrivate::QLlcpSocketPrivate(QLlcpSocket *q) +: q_ptr(q), + m_connection(QDBusConnection::connectToBus(QDBusConnection::SystemBus, QUuid::createUuid())), + m_port(0), m_socketRequestor(0), m_fd(-1), m_readNotifier(0), m_writeNotifier(0), + m_pendingBytes(0), m_state(QLlcpSocket::UnconnectedState), + m_error(QLlcpSocket::UnknownSocketError) +{ +} + +QLlcpSocketPrivate::QLlcpSocketPrivate(const QDBusConnection &connection, int fd, + const QVariantMap &properties) +: q_ptr(0), m_properties(properties), m_connection(connection), m_port(0), m_socketRequestor(0), + m_fd(fd), m_pendingBytes(0), + m_state(QLlcpSocket::ConnectedState), m_error(QLlcpSocket::UnknownSocketError) +{ + m_readNotifier = new QSocketNotifier(m_fd, QSocketNotifier::Read, this); + connect(m_readNotifier, SIGNAL(activated(int)), this, SLOT(_q_readNotify())); + m_writeNotifier = new QSocketNotifier(m_fd, QSocketNotifier::Write, this); + connect(m_writeNotifier, SIGNAL(activated(int)), this, SLOT(_q_bytesWritten())); +} + +QLlcpSocketPrivate::~QLlcpSocketPrivate() +{ + delete m_readNotifier; + delete m_writeNotifier; +} + +void QLlcpSocketPrivate::connectToService(QNearFieldTarget *target, const QString &serviceUri) +{ + Q_UNUSED(target); + + Q_Q(QLlcpSocket); + + m_state = QLlcpSocket::ConnectingState; + emit q->stateChanged(m_state); + + initializeRequestor(); + + if (m_socketRequestor) { + m_serviceUri = serviceUri; + m_port = 0; + + QString accessKind(QLatin1String("device.llcp.co.client:") + serviceUri); + + m_socketRequestor->requestAccess(m_requestorPath, accessKind); + } else { + setSocketError(QLlcpSocket::SocketResourceError); + + m_state = QLlcpSocket::UnconnectedState; + emit q->stateChanged(m_state); + } +} + +void QLlcpSocketPrivate::disconnectFromService() +{ + Q_Q(QLlcpSocket); + + m_state = QLlcpSocket::ClosingState; + emit q->stateChanged(m_state); + + delete m_readNotifier; + m_readNotifier = 0; + delete m_writeNotifier; + m_writeNotifier = 0; + m_pendingBytes = 0; + ::close(m_fd); + m_fd = -1; + + if (m_socketRequestor) { + QString accessKind(QLatin1String("device.llcp.co.client:") + m_serviceUri); + + Manager manager(QLatin1String("com.nokia.nfc"), QLatin1String("/"), m_connection); + QDBusObjectPath defaultAdapterPath = manager.DefaultAdapter(); + + m_socketRequestor->cancelAccessRequest(m_requestorPath, accessKind); + } + + m_state = QLlcpSocket::UnconnectedState; + q->setOpenMode(QIODevice::NotOpen); + emit q->stateChanged(m_state); + emit q->disconnected(); +} + +bool QLlcpSocketPrivate::bind(quint8 port) +{ + initializeRequestor(); + + if (!m_socketRequestor) + return false; + + m_serviceUri.clear(); + m_port = port; + + const QString accessKind(QLatin1String("device.llcp.cl:") + QString::number(port)); + + m_socketRequestor->requestAccess(m_requestorPath, accessKind); + + return waitForBound(30000); +} + +bool QLlcpSocketPrivate::hasPendingDatagrams() const +{ + return !m_receivedDatagrams.isEmpty(); +} + +qint64 QLlcpSocketPrivate::pendingDatagramSize() const +{ + if (m_receivedDatagrams.isEmpty()) + return -1; + + if (m_state == QLlcpSocket::BoundState) + return m_receivedDatagrams.first().length() - 1; + else + return m_receivedDatagrams.first().length(); +} + +qint64 QLlcpSocketPrivate::writeDatagram(const char *data, qint64 size) +{ + if (m_state != QLlcpSocket::ConnectedState) + return -1; + + return writeData(data, size); +} + +qint64 QLlcpSocketPrivate::writeDatagram(const QByteArray &datagram) +{ + if (m_state != QLlcpSocket::ConnectedState) + return -1; + + if (uint(datagram.length()) > m_properties.value(QLatin1String("RemoteMIU"), 128).toUInt()) + return -1; + + return writeData(datagram.constData(), datagram.size()); +} + +qint64 QLlcpSocketPrivate::readDatagram(char *data, qint64 maxSize, + QNearFieldTarget **target, quint8 *port) +{ + Q_UNUSED(target); + + if (m_state == QLlcpSocket::ConnectedState) { + return readData(data, maxSize); + } else if (m_state == QLlcpSocket::BoundState) { + return readData(data, maxSize, port); + } + + return -1; +} + +qint64 QLlcpSocketPrivate::writeDatagram(const char *data, qint64 size, + QNearFieldTarget *target, quint8 port) +{ + Q_UNUSED(target); + + if (m_state != QLlcpSocket::BoundState) + return -1; + + if (m_properties.value(QLatin1String("RemoteMIU"), 128).toUInt() < size) + return -1; + + if (m_properties.value(QLatin1String("LocalMIU"), 128).toUInt() < size) + return -1; + + QByteArray datagram; + datagram.append(port); + datagram.append(data, size); + + m_pendingBytes += datagram.size() - 1; + m_writeNotifier->setEnabled(true); + + return ::write(m_fd, datagram.constData(), datagram.size()) - 1; +} + +qint64 QLlcpSocketPrivate::writeDatagram(const QByteArray &datagram, + QNearFieldTarget *target, quint8 port) +{ + Q_UNUSED(target); + + if (m_state != QLlcpSocket::BoundState) + return -1; + + if (m_properties.value(QLatin1String("RemoteMIU"), 128).toInt() < datagram.size()) + return -1; + + if (m_properties.value(QLatin1String("LocalMIU"), 128).toInt() < datagram.size()) + return -1; + + QByteArray d; + d.append(port); + d.append(datagram); + + m_pendingBytes += datagram.size() - 1; + m_writeNotifier->setEnabled(true); + + return ::write(m_fd, d.constData(), d.size()) - 1; +} + +QLlcpSocket::SocketError QLlcpSocketPrivate::error() const +{ + return m_error; +} + +QLlcpSocket::SocketState QLlcpSocketPrivate::state() const +{ + return m_state; +} + +qint64 QLlcpSocketPrivate::readData(char *data, qint64 maxlen, quint8 *port) +{ + if (m_receivedDatagrams.isEmpty()) + return 0; + + const QByteArray datagram = m_receivedDatagrams.takeFirst(); + + if (m_state == QLlcpSocket::BoundState) { + if (port) + *port = datagram.at(0); + + qint64 size = qMin(maxlen, qint64(datagram.length() - 1)); + memcpy(data, datagram.constData() + 1, size); + return size; + } else { + if (port) + *port = 0; + + qint64 size = qMin(maxlen, qint64(datagram.length())); + memcpy(data, datagram.constData(), size); + return size; + } +} + +qint64 QLlcpSocketPrivate::writeData(const char *data, qint64 len) +{ + Q_Q(QLlcpSocket); + + qint64 remoteMiu = m_properties.value(QLatin1String("RemoteMIU"), 128).toLongLong(); + qint64 localMiu = m_properties.value(QLatin1String("LocalMIU"), 128).toLongLong(); + qint64 miu = qMin(remoteMiu, localMiu); + + m_writeNotifier->setEnabled(true); + + ssize_t wrote = ::write(m_fd, data, qMin(miu, len)); + if (wrote == -1) { + if (errno == EAGAIN) + return 0; + + setSocketError(QLlcpSocket::RemoteHostClosedError); + q->disconnectFromService(); + return -1; + } + + m_pendingBytes += wrote; + return wrote; +} + +qint64 QLlcpSocketPrivate::bytesAvailable() const +{ + qint64 available = 0; + foreach (const QByteArray &datagram, m_receivedDatagrams) + available += datagram.length(); + + // less source port + if (m_state == QLlcpSocket::BoundState) + available -= m_receivedDatagrams.count(); + + return available; +} + +bool QLlcpSocketPrivate::canReadLine() const +{ + if (m_state == QLlcpSocket::BoundState) + return false; + + foreach (const QByteArray &datagram, m_receivedDatagrams) { + if (datagram.contains('\n')) + return true; + } + + return false; +} + +bool QLlcpSocketPrivate::waitForReadyRead(int msec) +{ + if (bytesAvailable()) + return true; + + fd_set fds; + FD_ZERO(&fds); + FD_SET(m_fd, &fds); + + timeval timeout; + timeout.tv_sec = msec / 1000; + timeout.tv_usec = (msec % 1000) * 1000; + + // timeout can not be 0 or else select will return an error. + if (0 == msec) + timeout.tv_usec = 1000; + + int result = -1; + // on Linux timeout will be updated by select, but _not_ on other systems. + QElapsedTimer timer; + timer.start(); + while (!bytesAvailable() && (-1 == msec || timer.elapsed() < msec)) { + result = ::select(m_fd + 1, &fds, 0, 0, &timeout); + if (result > 0) + _q_readNotify(); + + if (-1 == result && errno != EINTR) { + setSocketError(QLlcpSocket::UnknownSocketError); + break; + } + } + + return bytesAvailable(); +} + +bool QLlcpSocketPrivate::waitForBytesWritten(int msec) +{ + fd_set fds; + FD_ZERO(&fds); + FD_SET(m_fd, &fds); + + timeval timeout; + timeout.tv_sec = msec / 1000; + timeout.tv_usec = (msec % 1000) * 1000; + + // timeout can not be 0 or else select will return an error. + if (0 == msec) + timeout.tv_usec = 1000; + + int result = -1; + // on Linux timeout will be updated by select, but _not_ on other systems. + QElapsedTimer timer; + timer.start(); + while (-1 == msec || timer.elapsed() < msec) { + result = ::select(m_fd + 1, 0, &fds, 0, &timeout); + if (result > 0) + return true; + if (-1 == result && errno != EINTR) { + setSocketError(QLlcpSocket::UnknownSocketError); + return false; + } + } + + // timeout expired + return false; +} + +bool QLlcpSocketPrivate::waitForConnected(int msecs) +{ + if (m_state != QLlcpSocket::ConnectingState) + return m_state == QLlcpSocket::ConnectedState; + + QElapsedTimer timer; + timer.start(); + while (m_state == QLlcpSocket::ConnectingState && (msecs == -1 || timer.elapsed() < msecs)) { + if (!m_socketRequestor->waitForDBusSignal(qMax(msecs - timer.elapsed(), qint64(0)))) { + setSocketError(QLlcpSocket::UnknownSocketError); + break; + } + } + + // Possibly not needed. + QCoreApplication::sendPostedEvents(this, QEvent::MetaCall); + + return m_state == QLlcpSocket::ConnectedState; +} + +bool QLlcpSocketPrivate::waitForDisconnected(int msec) +{ + if (m_state == QLlcpSocket::UnconnectedState) + return true; + + fd_set fds; + FD_ZERO(&fds); + FD_SET(m_fd, &fds); + + timeval timeout; + timeout.tv_sec = msec / 1000; + timeout.tv_usec = (msec % 1000) * 1000; + + // timeout can not be 0 or else select will return an error. + if (0 == msec) + timeout.tv_usec = 1000; + + int result = -1; + // on Linux timeout will be updated by select, but _not_ on other systems. + QElapsedTimer timer; + timer.start(); + while (m_state != QLlcpSocket::UnconnectedState && (-1 == msec || timer.elapsed() < msec)) { + result = ::select(m_fd + 1, &fds, 0, 0, &timeout); + if (result > 0) + _q_readNotify(); + + if (-1 == result && errno != EINTR) { + setSocketError(QLlcpSocket::UnknownSocketError); + break; + } + } + + return m_state == QLlcpSocket::UnconnectedState; +} + +bool QLlcpSocketPrivate::waitForBound(int msecs) +{ + if (m_state == QLlcpSocket::BoundState) + return true; + + QElapsedTimer timer; + timer.start(); + while (m_state != QLlcpSocket::BoundState && (msecs == -1 || timer.elapsed() < msecs)) { + if (!m_socketRequestor->waitForDBusSignal(qMax(msecs - timer.elapsed(), qint64(0)))) + return false; + } + + // Possibly not needed. + QCoreApplication::sendPostedEvents(this, QEvent::MetaCall); + + return m_state == QLlcpSocket::BoundState; +} + +void QLlcpSocketPrivate::AccessFailed(const QDBusObjectPath &targetPath, const QString &kind, + const QString &error) +{ + Q_UNUSED(targetPath); + Q_UNUSED(kind); + Q_UNUSED(error); + + Q_Q(QLlcpSocket); + + setSocketError(QLlcpSocket::SocketAccessError); + + m_state = QLlcpSocket::UnconnectedState; + emit q->stateChanged(m_state); +} + +void QLlcpSocketPrivate::AccessGranted(const QDBusObjectPath &targetPath, + const QString &accessKind) +{ + Q_UNUSED(targetPath); + Q_UNUSED(accessKind); +} + +void QLlcpSocketPrivate::Accept(const QDBusVariant &lsap, const QDBusVariant &rsap, + int fd, const QVariantMap &properties) +{ + Q_UNUSED(lsap); + Q_UNUSED(rsap); + Q_UNUSED(fd); + Q_UNUSED(properties); +} + +void QLlcpSocketPrivate::Connect(const QDBusVariant &lsap, const QDBusVariant &rsap, + int fd, const QVariantMap &properties) +{ + Q_UNUSED(lsap); + Q_UNUSED(rsap); + + m_fd = fd; + + m_readNotifier = new QSocketNotifier(m_fd, QSocketNotifier::Read, this); + connect(m_readNotifier, SIGNAL(activated(int)), this, SLOT(_q_readNotify())); + m_writeNotifier = new QSocketNotifier(m_fd, QSocketNotifier::Write, this); + connect(m_writeNotifier, SIGNAL(activated(int)), this, SLOT(_q_bytesWritten())); + + m_properties = properties; + + Q_Q(QLlcpSocket); + + q->setOpenMode(QIODevice::ReadWrite); + + m_state = QLlcpSocket::ConnectedState; + emit q->stateChanged(m_state); + emit q->connected(); +} + +void QLlcpSocketPrivate::Socket(const QDBusVariant &lsap, int fd, const QVariantMap &properties) +{ + m_fd = fd; + m_port = lsap.variant().toUInt(); + + m_readNotifier = new QSocketNotifier(m_fd, QSocketNotifier::Read, this); + connect(m_readNotifier, SIGNAL(activated(int)), this, SLOT(_q_readNotify())); + m_writeNotifier = new QSocketNotifier(m_fd, QSocketNotifier::Write, this); + connect(m_writeNotifier, SIGNAL(activated(int)), this, SLOT(_q_bytesWritten())); + + m_properties = properties; + + Q_Q(QLlcpSocket); + + m_state = QLlcpSocket::BoundState; + emit q->stateChanged(m_state); +} + +void QLlcpSocketPrivate::_q_readNotify() +{ + Q_Q(QLlcpSocket); + + QByteArray datagram; + datagram.resize(m_properties.value(QLatin1String("LocalMIU"), 128).toUInt()); + + int readFromDevice = ::read(m_fd, datagram.data(), datagram.size()); + if (readFromDevice <= 0) { + m_readNotifier->setEnabled(false); + + setSocketError(QLlcpSocket::RemoteHostClosedError); + + q->disconnectFromService(); + q->setOpenMode(QIODevice::NotOpen); + } else { + m_receivedDatagrams.append(datagram.left(readFromDevice)); + emit q->readyRead(); + } +} + +void QLlcpSocketPrivate::_q_bytesWritten() +{ + Q_Q(QLlcpSocket); + + m_writeNotifier->setEnabled(false); + + emit q->bytesWritten(m_pendingBytes); + m_pendingBytes = 0; +} + +void QLlcpSocketPrivate::setSocketError(QLlcpSocket::SocketError socketError) +{ + Q_Q(QLlcpSocket); + + QLatin1String c("QLlcpSocket"); + + m_error = socketError; + switch (socketError) { + case QLlcpSocket::UnknownSocketError: + q->setErrorString(QLlcpSocket::tr("%1: Unknown error %2").arg(c).arg(errno)); + break; + case QLlcpSocket::RemoteHostClosedError: + q->setErrorString(QLlcpSocket::tr("%1: Remote closed").arg(c)); + break; + case QLlcpSocket::SocketAccessError: + q->setErrorString(QLlcpSocket::tr("%1: Socket access error")); + break; + case QLlcpSocket::SocketResourceError: + q->setErrorString(QLlcpSocket::tr("%1: Socket resource error")); + break; + } + + emit q->error(m_error); +} + +void QLlcpSocketPrivate::initializeRequestor() +{ + if (m_socketRequestor) + return; + + if (m_requestorPath.isEmpty()) { + m_requestorPath = QLatin1String(requestorBasePath) + + QString::number(requestorId.fetchAndAddOrdered(1)); + } + + Manager manager(QLatin1String("com.nokia.nfc"), QLatin1String("/"), m_connection); + QDBusObjectPath defaultAdapterPath = manager.DefaultAdapter(); + + if (!m_socketRequestor) { + m_socketRequestor = new SocketRequestor(defaultAdapterPath.path(), this); + + connect(m_socketRequestor, SIGNAL(accessFailed(QDBusObjectPath,QString,QString)), + this, SLOT(AccessFailed(QDBusObjectPath,QString,QString))); + connect(m_socketRequestor, SIGNAL(accessGranted(QDBusObjectPath,QString)), + this, SLOT(AccessGranted(QDBusObjectPath,QString))); + connect(m_socketRequestor, SIGNAL(accept(QDBusVariant,QDBusVariant,int,QVariantMap)), + this, SLOT(Accept(QDBusVariant,QDBusVariant,int,QVariantMap))); + connect(m_socketRequestor, SIGNAL(connect(QDBusVariant,QDBusVariant,int,QVariantMap)), + this, SLOT(Connect(QDBusVariant,QDBusVariant,int,QVariantMap))); + connect(m_socketRequestor, SIGNAL(socket(QDBusVariant,int,QVariantMap)), + this, SLOT(Socket(QDBusVariant,int,QVariantMap))); + } +} + +#include "moc_qllcpsocket_maemo6_p.cpp" diff --git a/src/nfc/qllcpsocket_maemo6_p.h b/src/nfc/qllcpsocket_maemo6_p.h new file mode 100644 index 00000000..bfece31f --- /dev/null +++ b/src/nfc/qllcpsocket_maemo6_p.h @@ -0,0 +1,143 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QLLCPSOCKET_MAEMO6_P_H +#define QLLCPSOCKET_MAEMO6_P_H + +#include <qconnectivityglobal.h> + +#include "qllcpsocket.h" + +#include <QtDBus/QDBusConnection> + +QT_FORWARD_DECLARE_CLASS(QDBusObjectPath) +QT_FORWARD_DECLARE_CLASS(QDBusVariant) +QT_FORWARD_DECLARE_CLASS(QSocketNotifier) + +class AccessRequestorAdaptor; +class LLCPRequestorAdaptor; + +class SocketRequestor; + +class QLlcpSocketPrivate : public QObject +{ + Q_OBJECT + + Q_DECLARE_PUBLIC(QLlcpSocket) + +public: + QLlcpSocketPrivate(QLlcpSocket *q); + QLlcpSocketPrivate(const QDBusConnection &connection, int fd, const QVariantMap &properties); + ~QLlcpSocketPrivate(); + + void connectToService(QNearFieldTarget *target, const QString &serviceUri); + void disconnectFromService(); + + bool bind(quint8 port); + + bool hasPendingDatagrams() const; + qint64 pendingDatagramSize() const; + + qint64 writeDatagram(const char *data, qint64 size); + qint64 writeDatagram(const QByteArray &datagram); + + qint64 readDatagram(char *data, qint64 maxSize, + QNearFieldTarget **target = 0, quint8 *port = 0); + qint64 writeDatagram(const char *data, qint64 size, + QNearFieldTarget *target, quint8 port); + qint64 writeDatagram(const QByteArray &datagram, QNearFieldTarget *target, quint8 port); + + QLlcpSocket::SocketError error() const; + QLlcpSocket::SocketState state() const; + + qint64 readData(char *data, qint64 maxlex, quint8 *port = 0); + qint64 writeData(const char *data, qint64 len); + + qint64 bytesAvailable() const; + bool canReadLine() const; + + bool waitForReadyRead(int msecs); + bool waitForBytesWritten(int msecs); + bool waitForConnected(int msecs); + bool waitForDisconnected(int msecs); + bool waitForBound(int msecs); + +private slots: + // com.nokia.nfc.AccessRequestor + void AccessFailed(const QDBusObjectPath &targetPath, const QString &kind, + const QString &error); + void AccessGranted(const QDBusObjectPath &targetPath, const QString &accessKind); + + // com.nokia.nfc.LLCPRequestor + void Accept(const QDBusVariant &lsap, const QDBusVariant &rsap, int fd, const QVariantMap &properties); + void Connect(const QDBusVariant &lsap, const QDBusVariant &rsap, int fd, const QVariantMap &properties); + void Socket(const QDBusVariant &lsap, int fd, const QVariantMap &properties); + + void _q_readNotify(); + void _q_bytesWritten(); + +private: + void setSocketError(QLlcpSocket::SocketError socketError); + void initializeRequestor(); + + QLlcpSocket *q_ptr; + QVariantMap m_properties; + QList<QByteArray> m_receivedDatagrams; + + QDBusConnection m_connection; + + QString m_serviceUri; + quint8 m_port; + + QString m_requestorPath; + + SocketRequestor *m_socketRequestor; + + int m_fd; + QSocketNotifier *m_readNotifier; + QSocketNotifier *m_writeNotifier; + qint64 m_pendingBytes; + + QLlcpSocket::SocketState m_state; + QLlcpSocket::SocketError m_error; +}; + +#endif // QLLCPSOCKET_MAEMO6_P_H diff --git a/src/nfc/qllcpsocket_p.cpp b/src/nfc/qllcpsocket_p.cpp new file mode 100644 index 00000000..820cbb64 --- /dev/null +++ b/src/nfc/qllcpsocket_p.cpp @@ -0,0 +1,190 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qllcpsocket_p.h" + +QLlcpSocketPrivate::QLlcpSocketPrivate(QLlcpSocket *q) +: q_ptr(q) +{ +} + +QLlcpSocketPrivate::~QLlcpSocketPrivate() +{ + +} + +void QLlcpSocketPrivate::connectToService(QNearFieldTarget *target, const QString &serviceUri) +{ + Q_UNUSED(target); + Q_UNUSED(serviceUri); +} + +void QLlcpSocketPrivate::disconnectFromService() +{ +} + +bool QLlcpSocketPrivate::bind(quint8 port) +{ + Q_UNUSED(port); + + return false; +} + +bool QLlcpSocketPrivate::hasPendingDatagrams() const +{ + return false; +} + +qint64 QLlcpSocketPrivate::pendingDatagramSize() const +{ + return -1; +} + +qint64 QLlcpSocketPrivate::writeDatagram(const char *data, qint64 size) +{ + Q_UNUSED(data); + Q_UNUSED(size); + + return -1; +} + +qint64 QLlcpSocketPrivate::writeDatagram(const QByteArray &datagram) +{ + Q_UNUSED(datagram); + + return -1; +} + +qint64 QLlcpSocketPrivate::readDatagram(char *data, qint64 maxSize, + QNearFieldTarget **target, quint8 *port) +{ + Q_UNUSED(data); + Q_UNUSED(maxSize); + Q_UNUSED(target); + Q_UNUSED(port); + + return -1; +} + +qint64 QLlcpSocketPrivate::writeDatagram(const char *data, qint64 size, + QNearFieldTarget *target, quint8 port) +{ + Q_UNUSED(data); + Q_UNUSED(size); + Q_UNUSED(target); + Q_UNUSED(port); + + return -1; +} + +qint64 QLlcpSocketPrivate::writeDatagram(const QByteArray &datagram, + QNearFieldTarget *target, quint8 port) +{ + Q_UNUSED(datagram); + Q_UNUSED(target); + Q_UNUSED(port); + + return -1; +} + +QLlcpSocket::SocketError QLlcpSocketPrivate::error() const +{ + return QLlcpSocket::UnknownSocketError; +} + +QLlcpSocket::SocketState QLlcpSocketPrivate::state() const +{ + return QLlcpSocket::UnconnectedState; +} + +qint64 QLlcpSocketPrivate::readData(char *data, qint64 maxlen) +{ + Q_UNUSED(data); + Q_UNUSED(maxlen); + + return -1; +} + +qint64 QLlcpSocketPrivate::writeData(const char *data, qint64 len) +{ + Q_UNUSED(data); + Q_UNUSED(len); + + return -1; +} + +qint64 QLlcpSocketPrivate::bytesAvailable() const +{ + return 0; +} + +bool QLlcpSocketPrivate::canReadLine() const +{ + return false; +} + +bool QLlcpSocketPrivate::waitForReadyRead(int msecs) +{ + Q_UNUSED(msecs); + + return false; +} + +bool QLlcpSocketPrivate::waitForBytesWritten(int msecs) +{ + Q_UNUSED(msecs); + + return false; +} + +bool QLlcpSocketPrivate::waitForConnected(int msecs) +{ + Q_UNUSED(msecs); + + return false; +} + +bool QLlcpSocketPrivate::waitForDisconnected(int msecs) +{ + Q_UNUSED(msecs); + + return false; +} diff --git a/src/nfc/qllcpsocket_p.h b/src/nfc/qllcpsocket_p.h new file mode 100644 index 00000000..2dde2c1c --- /dev/null +++ b/src/nfc/qllcpsocket_p.h @@ -0,0 +1,93 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QLLCPSOCKET_P_H +#define QLLCPSOCKET_P_H + +#include "../qtconnectivityglobal.h" + +#include "qllcpsocket.h" + +class QLlcpSocketPrivate +{ + Q_DECLARE_PUBLIC(QLlcpSocket) + +public: + QLlcpSocketPrivate(QLlcpSocket *q); + + ~QLlcpSocketPrivate(); + + void connectToService(QNearFieldTarget *target, const QString &serviceUri); + void disconnectFromService(); + + bool bind(quint8 port); + + bool hasPendingDatagrams() const; + qint64 pendingDatagramSize() const; + + qint64 writeDatagram(const char *data, qint64 size); + qint64 writeDatagram(const QByteArray &datagram); + + qint64 readDatagram(char *data, qint64 maxSize, + QNearFieldTarget **target = 0, quint8 *port = 0); + qint64 writeDatagram(const char *data, qint64 size, + QNearFieldTarget *target, quint8 port); + qint64 writeDatagram(const QByteArray &datagram, QNearFieldTarget *target, quint8 port); + + QLlcpSocket::SocketError error() const; + QLlcpSocket::SocketState state() const; + + qint64 readData(char *data, qint64 maxlen); + qint64 writeData(const char *data, qint64 len); + + qint64 bytesAvailable() const; + bool canReadLine() const; + + bool waitForReadyRead(int msecs); + bool waitForBytesWritten(int msecs); + bool waitForConnected(int msecs); + bool waitForDisconnected(int msecs); + +private: + QLlcpSocket *q_ptr; +}; + +#endif // QLLCPSOCKET_P_H diff --git a/src/nfc/qllcpsocket_simulator_p.cpp b/src/nfc/qllcpsocket_simulator_p.cpp new file mode 100644 index 00000000..2749c250 --- /dev/null +++ b/src/nfc/qllcpsocket_simulator_p.cpp @@ -0,0 +1,186 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qllcpsocket_simulator_p.h" + +QLlcpSocketPrivate::QLlcpSocketPrivate(QLlcpSocket *q) +: q_ptr(q) +{ +} + +void QLlcpSocketPrivate::connectToService(QNearFieldTarget *target, const QString &serviceUri) +{ + Q_UNUSED(target); + Q_UNUSED(serviceUri); +} + +void QLlcpSocketPrivate::disconnectFromService() +{ +} + +bool QLlcpSocketPrivate::bind(quint8 port) +{ + Q_UNUSED(port); + + return false; +} + +bool QLlcpSocketPrivate::hasPendingDatagrams() const +{ + return false; +} + +qint64 QLlcpSocketPrivate::pendingDatagramSize() const +{ + return -1; +} + +qint64 QLlcpSocketPrivate::writeDatagram(const char *data, qint64 size) +{ + Q_UNUSED(data); + Q_UNUSED(size); + + return -1; +} + +qint64 QLlcpSocketPrivate::writeDatagram(const QByteArray &datagram) +{ + Q_UNUSED(datagram); + + return -1; +} + +qint64 QLlcpSocketPrivate::readDatagram(char *data, qint64 maxSize, + QNearFieldTarget **target, quint8 *port) +{ + Q_UNUSED(data); + Q_UNUSED(maxSize); + Q_UNUSED(target); + Q_UNUSED(port); + + return -1; +} + +qint64 QLlcpSocketPrivate::writeDatagram(const char *data, qint64 size, + QNearFieldTarget *target, quint8 port) +{ + Q_UNUSED(data); + Q_UNUSED(size); + Q_UNUSED(target); + Q_UNUSED(port); + + return -1; +} + +qint64 QLlcpSocketPrivate::writeDatagram(const QByteArray &datagram, + QNearFieldTarget *target, quint8 port) +{ + Q_UNUSED(datagram); + Q_UNUSED(target); + Q_UNUSED(port); + + return -1; +} + +QLlcpSocket::SocketError QLlcpSocketPrivate::error() const +{ + return QLlcpSocket::UnknownSocketError; +} + +QLlcpSocket::SocketState QLlcpSocketPrivate::state() const +{ + return QLlcpSocket::UnconnectedState; +} + +qint64 QLlcpSocketPrivate::readData(char *data, qint64 maxlen) +{ + Q_UNUSED(data); + Q_UNUSED(maxlen); + + return -1; +} + +qint64 QLlcpSocketPrivate::writeData(const char *data, qint64 len) +{ + Q_UNUSED(data); + Q_UNUSED(len); + + return -1; +} + +qint64 QLlcpSocketPrivate::bytesAvailable() const +{ + return 0; +} + +bool QLlcpSocketPrivate::canReadLine() const +{ + return false; +} + +bool QLlcpSocketPrivate::waitForReadyRead(int msecs) +{ + Q_UNUSED(msecs); + + return false; +} + +bool QLlcpSocketPrivate::waitForBytesWritten(int msecs) +{ + Q_UNUSED(msecs); + + return false; +} + +bool QLlcpSocketPrivate::waitForConnected(int msecs) +{ + Q_UNUSED(msecs); + + return false; +} + +bool QLlcpSocketPrivate::waitForDisconnected(int msecs) +{ + Q_UNUSED(msecs); + + return false; +} + diff --git a/src/nfc/qllcpsocket_simulator_p.h b/src/nfc/qllcpsocket_simulator_p.h new file mode 100644 index 00000000..e232eda8 --- /dev/null +++ b/src/nfc/qllcpsocket_simulator_p.h @@ -0,0 +1,91 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QLLCPSOCKET_P_H +#define QLLCPSOCKET_P_H + +#include <qconnectivityglobal.h> + +#include "qllcpsocket.h" + +class QLlcpSocketPrivate +{ + Q_DECLARE_PUBLIC(QLlcpSocket) + +public: + QLlcpSocketPrivate(QLlcpSocket *q); + + void connectToService(QNearFieldTarget *target, const QString &serviceUri); + void disconnectFromService(); + + bool bind(quint8 port); + + bool hasPendingDatagrams() const; + qint64 pendingDatagramSize() const; + + qint64 writeDatagram(const char *data, qint64 size); + qint64 writeDatagram(const QByteArray &datagram); + + qint64 readDatagram(char *data, qint64 maxSize, + QNearFieldTarget **target = 0, quint8 *port = 0); + qint64 writeDatagram(const char *data, qint64 size, + QNearFieldTarget *target, quint8 port); + qint64 writeDatagram(const QByteArray &datagram, QNearFieldTarget *target, quint8 port); + + QLlcpSocket::SocketError error() const; + QLlcpSocket::SocketState state() const; + + qint64 readData(char *data, qint64 maxlen); + qint64 writeData(const char *data, qint64 len); + + qint64 bytesAvailable() const; + bool canReadLine() const; + + bool waitForReadyRead(int msecs); + bool waitForBytesWritten(int msecs); + bool waitForConnected(int msecs); + bool waitForDisconnected(int msecs); + +private: + QLlcpSocket *q_ptr; +}; + +#endif // QLLCPSOCKET_P_H diff --git a/src/nfc/qllcpsocket_symbian_p.cpp b/src/nfc/qllcpsocket_symbian_p.cpp new file mode 100644 index 00000000..ccf637f0 --- /dev/null +++ b/src/nfc/qllcpsocket_symbian_p.cpp @@ -0,0 +1,409 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qllcpsocket_symbian_p.h" +#include "qllcpstate_symbian_p.h" +#include "symbian/llcpsockettype1_symbian.h" +#include "symbian/llcpsockettype2_symbian.h" +#include "symbian/nearfieldutility_symbian.h" +#include "symbian/debug.h" + +/*! + Constructor +*/ +QLlcpSocketPrivate::QLlcpSocketPrivate(QLlcpSocket *q) + : m_symbianSocketType1(NULL), + m_symbianSocketType2(NULL), + m_error(QLlcpSocket::UnknownSocketError), + q_ptr(q), + m_emittedReadyRead(false), + m_emittedBytesWritten(false), + m_writeDatagramRefCount(0) +{ + BEGIN + m_unconnectedState = new QLLCPUnconnected(this); + m_connectingState = new QLLCPConnecting(this); + m_connectedState = new QLLCPConnected(this); + m_bindState = new QLLCPBind(this); + + m_state = m_unconnectedState; + END +} + + +/*! + Destructor +*/ +QLlcpSocketPrivate::~QLlcpSocketPrivate() +{ + BEGIN + Q_Q(QLlcpSocket); + if (q->isOpen()) { + q->close(); + } + + delete m_unconnectedState; + delete m_connectingState; + delete m_connectedState; + delete m_bindState; + delete m_symbianSocketType1; + delete m_symbianSocketType2; + END +} + +/*! + Construct the socket and set as connected state from llcp server side +*/ +QLlcpSocketPrivate::QLlcpSocketPrivate(CLlcpSocketType2* socketType2_symbian) + : m_symbianSocketType1(NULL), + m_symbianSocketType2(socketType2_symbian), + m_error(QLlcpSocket::UnknownSocketError), + m_emittedReadyRead(false), + m_emittedBytesWritten(false), + m_writeDatagramRefCount(0) +{ + BEGIN + m_unconnectedState = new QLLCPUnconnected(this); + m_connectingState = new QLLCPConnecting(this); + m_connectedState = new QLLCPConnected(this); + m_bindState = new QLLCPBind(this); + + m_state = m_connectedState; + + END +} + +void QLlcpSocketPrivate::connectToService(QNearFieldTarget *target, const QString &serviceUri) +{ + BEGIN + Q_Q(QLlcpSocket); + if (!q->isOpen()) + { + bool ret = q->open(QIODevice::ReadWrite | QIODevice::Unbuffered); + if (false == ret) + invokeError(); + } + m_state->ConnectToService(target,serviceUri); + END +} + +void QLlcpSocketPrivate::disconnectFromService() +{ + BEGIN + m_state->DisconnectFromService(); + + Q_Q(QLlcpSocket); + if (q->isOpen()) + { + q->close(); + } + END +} + +void QLlcpSocketPrivate::invokeConnected() +{ + BEGIN + Q_Q(QLlcpSocket); + + if (m_state->state() == QLlcpSocket::ConnectingState) + { + changeState(getConnectedState()); + invokeStateChanged(QLlcpSocket::ConnectedState); + emit q->connected(); + } + END +} + +void QLlcpSocketPrivate::invokeReadyRead() +{ + BEGIN + Q_Q(QLlcpSocket); + //If called from within a slot connected to the readyRead() signal, + //readyRead() will not be reemitted. + LOG("m_emittedReadyRead: " << m_emittedReadyRead); + + if (!m_emittedReadyRead){ + m_emittedReadyRead = true; + LOG("readyRead signal has been emitted!"); + emit q->readyRead(); + m_emittedReadyRead = false; + } + END +} + +void QLlcpSocketPrivate::attachCallbackHandler(QLlcpSocket *q) +{ + BEGIN + q_ptr = q; + if (!q->isOpen()) + { + bool ret = q->open(QIODevice::ReadWrite | QIODevice::Unbuffered); + if (false == ret) + invokeError(); + } + END +} + +qint64 QLlcpSocketPrivate::bytesAvailable() const +{ + BEGIN + qint64 bytes = 0; + if (m_symbianSocketType2 != NULL) + { + bytes = m_symbianSocketType2->BytesAvailable(); + } + END + return bytes; +} + +bool QLlcpSocketPrivate::canReadLine() const +{ + return false; +} + +void QLlcpSocketPrivate::invokeBytesWritten(qint64 bytes) +{ + BEGIN + Q_Q(QLlcpSocket); + if (!m_emittedBytesWritten){ + m_emittedBytesWritten = true; + emit q->bytesWritten(bytes); + m_emittedBytesWritten = false; + } + END +} + +void QLlcpSocketPrivate::invokeStateChanged(QLlcpSocket::SocketState socketState) +{ + BEGIN + Q_Q(QLlcpSocket); + emit q->stateChanged(socketState); + END +} + +void QLlcpSocketPrivate::invokeError() +{ + BEGIN + Q_Q(QLlcpSocket); + emit q->error(QLlcpSocket::UnknownSocketError); + END +} + +void QLlcpSocketPrivate::invokeDisconnected() +{ + BEGIN + Q_Q(QLlcpSocket); + emit q->disconnected(); + END +} + +/*! + Only used at connectless mode, create type1 socket if necessary. +*/ +bool QLlcpSocketPrivate::bind(quint8 port) +{ + BEGIN_END + return m_state->Bind(port); +} + +/*! + Returns true if at least one datagram is waiting to be read; + otherwise returns false. +*/ +bool QLlcpSocketPrivate::hasPendingDatagrams() const +{ + BEGIN + bool val = false; + if (m_symbianSocketType1) + { + val = m_symbianSocketType1->HasPendingDatagrams(); + } + + END + return val; +} + +/*! + Returns the size of the first pending connectionless datagram. If there is + no datagram available, this function returns -1. +*/ +qint64 QLlcpSocketPrivate::pendingDatagramSize() const +{ + BEGIN + qint64 val = -1; + if (m_symbianSocketType1) + { + val = m_symbianSocketType1->PendingDatagramSize(); + } + + END + return val; +} + +CLlcpSocketType1* QLlcpSocketPrivate::socketType1Instance() +{ + if (NULL == m_symbianSocketType1) + { + TRAPD(err, m_symbianSocketType1 = CLlcpSocketType1::NewL(*this)); + if (KErrNone != err) { + m_symbianSocketType1 = NULL; + } + } + return m_symbianSocketType1; +} + +CLlcpSocketType2* QLlcpSocketPrivate::socketType2Instance() +{ + if (NULL == m_symbianSocketType2) + { + TRAPD(err, m_symbianSocketType2 = CLlcpSocketType2::NewL(this)); + if (KErrNone != err) { + m_symbianSocketType2 = NULL; + } + } + return m_symbianSocketType2; +} + +/*! + Connection-Oriented Style +*/ +qint64 QLlcpSocketPrivate::writeDatagram(const char *data, qint64 size) +{ + BEGIN + qint64 val = -1; + val = m_state->WriteDatagram(data,size); + END + return val; +} + +/*! + Connection-Oriented Style +*/ +qint64 QLlcpSocketPrivate::writeDatagram(const QByteArray &datagram) +{ + BEGIN_END + return writeDatagram(datagram.constData(),datagram.size()); +} + +/*! + Used for Both Connection-Less & Connection-Oriented Style + As for Connection-Oriented mode, can not pass in the port & target parameters. +*/ +qint64 QLlcpSocketPrivate::readDatagram(char *data, qint64 maxSize, + QNearFieldTarget **target, quint8 *port) +{ + BEGIN + qint64 val = m_state->ReadDatagram(data,maxSize,target,port); + END + return val; +} + +qint64 QLlcpSocketPrivate::writeDatagram(const char *data, qint64 size, + QNearFieldTarget *target, quint8 port) +{ + BEGIN + qint64 val = m_state->WriteDatagram(data,size,target,port); + END + + return val; +} + +qint64 QLlcpSocketPrivate::writeDatagram(const QByteArray &datagram, + QNearFieldTarget *target, quint8 port) +{ + BEGIN_END + return writeDatagram(datagram.constData(),datagram.size(),target,port); +} + +QLlcpSocket::SocketError QLlcpSocketPrivate::error() const +{ + BEGIN_END + return m_error; +} + +QLlcpSocket::SocketState QLlcpSocketPrivate::state() const +{ + BEGIN_END + return m_state->state(); +} + +qint64 QLlcpSocketPrivate::readData(char *data, qint64 maxlen) +{ + BEGIN_END + return readDatagram(data,maxlen); +} + +qint64 QLlcpSocketPrivate::writeData(const char *data, qint64 len) +{ + BEGIN_END + return writeDatagram(data,len); +} + +bool QLlcpSocketPrivate::waitForReadyRead(int msecs) +{ + BEGIN_END + return m_state->WaitForReadyRead(msecs); +} + +bool QLlcpSocketPrivate::waitForBytesWritten(int msecs) +{ + BEGIN_END + return m_state->WaitForBytesWritten(msecs); +} + +bool QLlcpSocketPrivate::waitForConnected(int msecs) +{ + BEGIN_END + return m_state->WaitForConnected(msecs); +} + +bool QLlcpSocketPrivate::waitForDisconnected(int msecs) +{ + BEGIN_END + return m_state->WaitForDisconnected(msecs); +} + +void QLlcpSocketPrivate::changeState(QLLCPSocketState* state) +{ + m_state = state; + BEGIN_END +} + diff --git a/src/nfc/qllcpsocket_symbian_p.h b/src/nfc/qllcpsocket_symbian_p.h new file mode 100644 index 00000000..8b4cebe4 --- /dev/null +++ b/src/nfc/qllcpsocket_symbian_p.h @@ -0,0 +1,153 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QLLCPSOCKET_P_H +#define QLLCPSOCKET_P_H + +#include <qconnectivityglobal.h> +#include "qllcpsocket.h" + +#include <QtCore/QObject> +#include <QSharedPointer> + +class CLlcpSocketType1; +class CLlcpSocketType2; + +QT_BEGIN_HEADER + +class QLLCPSocketState; + +class QLlcpSocketPrivate +{ + Q_DECLARE_PUBLIC(QLlcpSocket) + +public: + + QLlcpSocketPrivate(QLlcpSocket *q); + QLlcpSocketPrivate(CLlcpSocketType2* socketType2_symbian); + ~QLlcpSocketPrivate(); + +public: //Implementation of QLlcpSocket API + void connectToService(QNearFieldTarget *target, const QString &serviceUri); + void disconnectFromService(); + + bool bind(quint8 port); + + bool hasPendingDatagrams() const; + qint64 pendingDatagramSize() const; + + qint64 writeDatagram(const char *data, qint64 size); + qint64 writeDatagram(const QByteArray &datagram); + + qint64 readDatagram(char *data, qint64 maxSize, + QNearFieldTarget **target = 0, quint8 *port = 0); + qint64 writeDatagram(const char *data, qint64 size, + QNearFieldTarget *target, quint8 port); + qint64 writeDatagram(const QByteArray &datagram, QNearFieldTarget *target, quint8 port); + + QLlcpSocket::SocketError error() const; + QLlcpSocket::SocketState state() const; + + qint64 readData(char *data, qint64 maxlen); + qint64 writeData(const char *data, qint64 len); + + qint64 bytesAvailable() const; + bool canReadLine() const; + + bool waitForReadyRead(int msecs); + bool waitForBytesWritten(int msecs); + bool waitForConnected(int msecs); + bool waitForDisconnected(int msecs); + void attachCallbackHandler(QLlcpSocket *q); + +public: + CLlcpSocketType1* socketType1Instance(); + CLlcpSocketType2* socketType2Instance(); + CLlcpSocketType1* socketType1Handler() {return m_symbianSocketType1;} + CLlcpSocketType2* socketType2Handler() {return m_symbianSocketType2;} + + QLlcpSocket* qllcpsocket(CLlcpSocketType2*); + +public: + enum State { + ListeningState = QAbstractSocket::ListeningState, + }; + +public: + void invokeReadyRead(); + void invokeBytesWritten(qint64 bytes) ; + void invokeStateChanged(QLlcpSocket::SocketState socketState); + void invokeError(); + void invokeDisconnected(); + void invokeConnected(); + +// state machine part +public: + void changeState(QLLCPSocketState*); + QLLCPSocketState* getUnconnectedState() { return m_unconnectedState;} + QLLCPSocketState* getConnectedState() { return m_connectedState;} + QLLCPSocketState* getConnectingState() { return m_connectingState;} + QLLCPSocketState* getBindState() { return m_bindState;} + +private: + CLlcpSocketType1* m_symbianSocketType1; // own + CLlcpSocketType2* m_symbianSocketType2; // own + +private: + QLlcpSocket::SocketError m_error; + QLLCPSocketState* m_state; // not own + QLLCPSocketState* m_unconnectedState; // own + QLLCPSocketState* m_connectedState; // own + QLLCPSocketState* m_connectingState; // own + QLLCPSocketState* m_bindState; // own + + QLlcpSocket *q_ptr; // not own + + bool m_emittedReadyRead; + bool m_emittedBytesWritten; + +public: + int m_writeDatagramRefCount; +}; + +QT_END_HEADER + +#endif // QLLCPSOCKET_P_H diff --git a/src/nfc/qllcpstate_symbian_p.cpp b/src/nfc/qllcpstate_symbian_p.cpp new file mode 100644 index 00000000..35b03cc0 --- /dev/null +++ b/src/nfc/qllcpstate_symbian_p.cpp @@ -0,0 +1,551 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +#include "qllcpsocket_symbian_p.h" +#include "qllcpstate_symbian_p.h" +#include "symbian/llcpsockettype1_symbian.h" +#include "symbian/llcpsockettype2_symbian.h" +#include "symbian/nearfieldutility_symbian.h" + +#include "symbian/debug.h" + +QLLCPSocketState::QLLCPSocketState(QLlcpSocketPrivate* socket) + :m_socket(socket) +{} + +/*! + Connection-Less Mode +*/ +bool QLLCPUnconnected::Bind(quint8 port) +{ + BEGIN + bool ret = false; + if (connectionType2 == m_socketType) { + return ret; + } + + CLlcpSocketType1* socketHandler = m_socket->socketType1Instance(); + if (socketHandler != NULL ) + { + if (connectionUnknown == m_socketType) + { + m_socketType = connectionType1; + } + + if (socketHandler->Bind(port)) + { + ret = true; + m_socket->changeState(m_socket->getBindState()); + m_socket->invokeStateChanged(QLlcpSocket::BoundState); + } + } + END + return ret; +} + +/*! + Connection-Less Mode +*/ +bool QLLCPUnconnected::WaitForBytesWritten(int msecs) +{ + BEGIN + bool ret = false; + if (connectionType1 != m_socketType) { + return ret; + } + + ret = WaitForBytesWrittenType1Private(msecs); + END + return ret; +} + +bool QLLCPUnconnected::WaitForDisconnected(int msecs) +{ + Q_UNUSED(msecs); + BEGIN_END + return true; +} + +/*! + Connection-Less Mode +*/ +bool QLLCPBind::WaitForBytesWritten(int msecs) +{ + BEGIN + bool ret = WaitForBytesWrittenType1Private(msecs); + END + return ret; +} + +/*! + Failitator function for Connection-Less Mode +*/ +bool QLLCPSocketState::WaitForBytesWrittenType1Private(int msecs) +{ + bool ret = false; + + qDebug() << "m_writeDatagramRefCount: " << m_socket->m_writeDatagramRefCount; + if (m_socket->m_writeDatagramRefCount <= 0) + { + return ret; + } + + CLlcpSocketType1* socketHandler = m_socket->socketType1Instance(); + if (socketHandler != NULL) + { + ret = socketHandler->WaitForBytesWritten(msecs); + } + return ret; +} + +/*! + Connection-Less Mode +*/ +bool QLLCPBind::WaitForReadyRead(int msecs) +{ + BEGIN + bool ret = false; + CLlcpSocketType1* socketHandler = m_socket->socketType1Instance(); + if (socketHandler != NULL && socketHandler->HasPendingDatagrams()) + { + ret = true; + } + END + return ret; +} + +/*! + Connection-Less Mode +*/ +qint64 QLLCPUnconnected::WriteDatagram(const char *data, qint64 size, + QNearFieldTarget *target, quint8 port) +{ + BEGIN + Q_UNUSED(target); + qint64 val = -1; + + if (connectionType2 == m_socketType){ + return val; + } + + CLlcpSocketType1* socketHandler = m_socket->socketType1Instance(); + + if (socketHandler != NULL) + { + if (connectionUnknown == m_socketType) + { + m_socketType = connectionType1; + } + TPtrC8 myDescriptor((const TUint8*)data, size); + val = socketHandler->StartWriteDatagram(myDescriptor, port); + } + END + + return val; +} + +/*! + Connection-Less Mode +*/ +qint64 QLLCPBind::WriteDatagram(const char *data, qint64 size, + QNearFieldTarget *target, quint8 port) +{ + BEGIN + Q_UNUSED(target); + qint64 val = -1; + CLlcpSocketType1* socketHandler = m_socket->socketType1Instance(); + if (socketHandler != NULL) + { + TPtrC8 myDescriptor((const TUint8*)data, size); + val = socketHandler->StartWriteDatagram(myDescriptor, port); + } + END + return val; +} + +/*! + Connection-Oriented Mode - Client side socket write +*/ +qint64 QLLCPConnected::WriteDatagram(const char *data, qint64 size) +{ + BEGIN + qint64 val = -1; + CLlcpSocketType2* socketHandler = m_socket->socketType2Handler(); + if (socketHandler != NULL) + { + TPtrC8 myDescriptor((const TUint8*)data, size); + val = socketHandler->StartWriteDatagram(myDescriptor); + } + END + return val; +} + +/*! + Connection-Oriented Mode +*/ +bool QLLCPConnected::WaitForBytesWritten(int msecs) +{ + BEGIN + bool ret = false; + CLlcpSocketType2* socketHandler = m_socket->socketType2Handler(); + if (socketHandler != NULL) + { + ret = socketHandler->WaitForBytesWritten(msecs); + } + END + return ret; +} + +/*! + Connection-Oriented Mode +*/ +bool QLLCPConnected::WaitForReadyRead(int msecs) +{ + BEGIN + bool ret = false; + CLlcpSocketType2* socketHandler = m_socket->socketType2Handler(); + if (socketHandler != NULL) + { + ret = socketHandler->WaitForReadyRead(msecs); + } + END + return ret; +} + +/*! + Connection-Less Mode +*/ +qint64 QLLCPBind::ReadDatagram(char *data, qint64 maxSize, + QNearFieldTarget **target, quint8 *port) +{ + BEGIN + + Q_UNUSED(target); + qint64 val = -1; + + CLlcpSocketType1* socketHandler = m_socket->socketType1Instance(); + + if (socketHandler != NULL) + { + TPtr8 ptr((TUint8*)data, (TInt)maxSize); + if (port == NULL){ + val = socketHandler->ReadDatagram(ptr); + } + else { + val = socketHandler->ReadDatagram(ptr, *port); + } + } + + END + return val; +} + + +/*! + Connection-Oriented Mode - Client side socket read +*/ +qint64 QLLCPConnected::ReadDatagram(char *data, qint64 maxSize,QNearFieldTarget **target, quint8 *port ) +{ + BEGIN + qint64 val = -1; + + if ( port != NULL || ( target != NULL && *target != NULL )) + { + return val; + } + + CLlcpSocketType2* socketHandler = m_socket->socketType2Handler(); + if (socketHandler != NULL) + { + // The length of the descriptor is set to zero + // and its maximum length is set to maxSize + TPtr8 ptr((TUint8*)data, (TInt)maxSize); + + bool ret = socketHandler->ReceiveData(ptr); + if(ret) { + val = ptr.Length(); + } + } + + END + return val; +} + +/*! + Connection-Oriented Mode +*/ +void QLLCPConnected::DisconnectFromService() +{ + BEGIN + DisconnectFromServiceType2Private(); + END + return; +} + +/*! + Connection-Oriented Mode +*/ +void QLLCPConnecting::DisconnectFromService() +{ + BEGIN + DisconnectFromServiceType2Private(); + END + return; +} + +void QLLCPSocketState::DisconnectFromServiceType2Private() +{ + BEGIN + CLlcpSocketType2* socketHandler = m_socket->socketType2Handler(); + if (NULL != socketHandler) + { + if (socketHandler->DisconnectFromService() == KErrNone) + { + m_socket->changeState(m_socket->getUnconnectedState()); + m_socket->invokeStateChanged(QLlcpSocket::UnconnectedState); + } + else + { + m_socket->invokeError(); + } + } + else + { + m_socket->invokeError(); + } + END +} + +/*! + Connection-Oriented Mode +*/ +void QLLCPUnconnected::DisconnectFromService() +{ + BEGIN_END + return; +} + +/*! + Connection-Oriented Mode +*/ +bool QLLCPConnecting::WaitForConnected(int msecs) +{ + BEGIN + bool ret = false; + CLlcpSocketType2* socketHandler = m_socket->socketType2Handler(); + if (socketHandler != NULL) + { + ret = socketHandler->WaitForConnected(msecs); + } + END + return ret; +} + +/*! + Connection-Oriented Mode +*/ +bool QLLCPConnecting::WaitForBytesWritten(int) +{ + return false; +} + +/*! + Connection-Oriented Mode +*/ +void QLLCPUnconnected::ConnectToService(QNearFieldTarget *target, const QString &serviceUri) +{ + BEGIN + if (connectionType1 == m_socketType){ + m_socket->invokeError(); + END + return; + } + + CLlcpSocketType2* socketHandler = m_socket->socketType2Instance(); + + if (socketHandler != NULL) + { + if (connectionUnknown == m_socketType) + { + m_socketType = connectionType2; + } + + TRAPD(err, socketHandler->ConnectToServiceL(serviceUri)); + if (KErrNone == err) + { + m_socket->changeState(m_socket->getConnectingState()); + m_socket->invokeStateChanged(QLlcpSocket::ConnectingState); + } + else + { + m_socket->invokeError(); + } + + } + else + { + m_socket->invokeError(); + } + + END +} + +/*! + Connection-Oriented Mode +*/ +void QLLCPConnecting::ConnectToService(QNearFieldTarget *target, const QString &serviceUri) + { + Q_UNUSED(target); + Q_UNUSED(serviceUri); + m_socket->invokeError(); + qWarning("QLlcpSocket::connectToService() called when already connecting"); + BEGIN_END + return; + } + +/*! + Connection-Oriented Mode +*/ +void QLLCPConnected::ConnectToService(QNearFieldTarget *target, const QString &serviceUri) + { + Q_UNUSED(target); + Q_UNUSED(serviceUri); + m_socket->invokeError(); + qWarning("QLlcpSocket::connectToService() called when already connected"); + BEGIN_END + return; + } + +/*! + Constructors +*/ +QLLCPUnconnected::QLLCPUnconnected(QLlcpSocketPrivate* aSocket) + :QLLCPSocketState(aSocket), + m_socketType(connectionUnknown) +{} + + +QLLCPBind::QLLCPBind(QLlcpSocketPrivate* aSocket) + :QLLCPSocketState(aSocket) +{} + +QLLCPConnecting::QLLCPConnecting(QLlcpSocketPrivate* aSocket) + :QLLCPSocketState(aSocket) +{} + +QLLCPConnected::QLLCPConnected(QLlcpSocketPrivate* aSocket) + :QLLCPSocketState(aSocket) +{} + +qint64 QLLCPSocketState::ReadDatagram(char *data, qint64 maxSize, + QNearFieldTarget **target, quint8 *port) +{ + Q_UNUSED(data); + Q_UNUSED(maxSize); + Q_UNUSED(target); + Q_UNUSED(port); + BEGIN_END + return -1; +} + +/*! + State base class default implementation +*/ +qint64 QLLCPSocketState::WriteDatagram(const char *data, qint64 size, + QNearFieldTarget *target, quint8 port) +{ + Q_UNUSED(data); + Q_UNUSED(size); + Q_UNUSED(target); + Q_UNUSED(port); + BEGIN_END + return -1; +} + +qint64 QLLCPSocketState::WriteDatagram(const char *data, qint64 size) +{ + Q_UNUSED(data); + Q_UNUSED(size); + BEGIN_END + return -1; +} + +bool QLLCPSocketState::Bind(quint8 port) +{ + Q_UNUSED(port); + BEGIN_END + return false; +} + + bool QLLCPSocketState::WaitForReadyRead(int msecs) + { + Q_UNUSED(msecs); + BEGIN_END + return false; + } + +bool QLLCPSocketState::WaitForConnected(int msecs) +{ + Q_UNUSED(msecs); + BEGIN_END + return false; +} + +bool QLLCPSocketState::WaitForDisconnected(int msecs) +{ + Q_UNUSED(msecs); + BEGIN_END + return false; +} + +void QLLCPSocketState::ConnectToService(QNearFieldTarget *target, const QString &serviceUri) +{ + Q_UNUSED(target); + Q_UNUSED(serviceUri); + m_socket->invokeError(); + BEGIN_END +} + +void QLLCPSocketState::DisconnectFromService() +{ + m_socket->invokeError(); + BEGIN_END +} + diff --git a/src/nfc/qllcpstate_symbian_p.h b/src/nfc/qllcpstate_symbian_p.h new file mode 100644 index 00000000..38d6bb17 --- /dev/null +++ b/src/nfc/qllcpstate_symbian_p.h @@ -0,0 +1,171 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QLLCPSOCKETSTATE_P_H +#define QLLCPSOCKETSTATE_P_H + +#include <qconnectivityglobal.h> +#include "qllcpsocket.h" + +#include <QtCore/QObject> + +QT_BEGIN_HEADER + +class QLlcpSocketPrivate; + +/*! + \QLLCPSocketState +*/ +class QLLCPSocketState +{ +public: + explicit QLLCPSocketState(QLlcpSocketPrivate*); + +public: + virtual QLlcpSocket::SocketState state() const = 0; + virtual bool WaitForBytesWritten(int) = 0; + +public: + virtual qint64 ReadDatagram(char *data, qint64 maxSize, + QNearFieldTarget **target = NULL, quint8 *port = NULL); + virtual qint64 WriteDatagram(const char *data, qint64 size, + QNearFieldTarget *target, quint8 port); + virtual qint64 WriteDatagram(const char *data, qint64 size); + + virtual bool Bind(quint8 port); + virtual void ConnectToService(QNearFieldTarget *target, const QString &serviceUri); + virtual void DisconnectFromService(); + virtual bool WaitForReadyRead(int); + virtual bool WaitForConnected(int); + virtual bool WaitForDisconnected(int); + +protected: + bool WaitForBytesWrittenType1Private(int); + void DisconnectFromServiceType2Private(); +public: + QLlcpSocketPrivate* m_socket; +}; + +/*! + \QLLCPUnconnected +*/ +class QLLCPUnconnected: public QLLCPSocketState +{ +public: + explicit QLLCPUnconnected(QLlcpSocketPrivate*); + +public: // from base class + QLlcpSocket::SocketState state() const {return QLlcpSocket::UnconnectedState;} + bool Bind(quint8 port); + void ConnectToService(QNearFieldTarget *target, const QString &serviceUri); + void DisconnectFromService(); + qint64 WriteDatagram(const char *data, qint64 size, + QNearFieldTarget *target, quint8 port); + bool WaitForBytesWritten(int); + bool WaitForDisconnected(int); + +public: +public: + enum SocketType + { + connectionType1 = 1, // ConnectionLess mode + connectionType2 = 2, // ConnectionOriented mode + connectionUnknown = -1 + }; + SocketType m_socketType; +}; + +/*! + \QLLCPConnecting +*/ +class QLLCPConnecting: public QLLCPSocketState +{ +public: + explicit QLLCPConnecting(QLlcpSocketPrivate*); + +public: + QLLCPSocketState* Instance(QLlcpSocketPrivate* aSocket); + +public: // from base class + QLlcpSocket::SocketState state() const {return QLlcpSocket::ConnectingState;} + void ConnectToService(QNearFieldTarget *target, const QString &serviceUri); + void DisconnectFromService(); + bool WaitForConnected(int); + bool WaitForBytesWritten(int); +}; + +/*! + \QLLCPConnecting +*/ +class QLLCPConnected: public QLLCPSocketState +{ +public: + explicit QLLCPConnected(QLlcpSocketPrivate*); + +public: // from base class + QLlcpSocket::SocketState state() const {return QLlcpSocket::ConnectedState;} + void ConnectToService(QNearFieldTarget *target, const QString &serviceUri); + void DisconnectFromService(); + qint64 WriteDatagram(const char *data, qint64 size); + qint64 ReadDatagram(char *data, qint64 maxSize, QNearFieldTarget **target = NULL, quint8 *port = NULL); + bool WaitForBytesWritten(int msecs); + bool WaitForReadyRead(int msecs); +}; + +/*! + \QLLCPBind +*/ +class QLLCPBind: public QLLCPSocketState + { +public: + explicit QLLCPBind(QLlcpSocketPrivate*); + +public://from base class + QLlcpSocket::SocketState state() const {return QLlcpSocket::BoundState;} + qint64 WriteDatagram(const char *data, qint64 size,QNearFieldTarget *target, quint8 port); + qint64 ReadDatagram(char *data, qint64 maxSize,QNearFieldTarget **target = 0, quint8 *port = 0); + bool WaitForBytesWritten(int msecs); + bool WaitForReadyRead(int msecs); + }; + +QT_END_HEADER + +#endif //QLLCPSTATE_P_H diff --git a/src/nfc/qndeffilter.cpp b/src/nfc/qndeffilter.cpp new file mode 100644 index 00000000..ce25c4ab --- /dev/null +++ b/src/nfc/qndeffilter.cpp @@ -0,0 +1,202 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qndeffilter.h" + +#include <QtCore/QList> + +/*! + \class QNdefFilter + \brief The QNdefFilter class provides a filter for matching NDEF messages. + + \ingroup connectivity-nfc + \inmodule QtConnectivity + \since 5.0 + + The QNdefFilter encapsulates the structure of an NDEF message and is used by + QNearFieldManager::registerNdefMessageHandler() to match NDEF message that have a particular + structure. + + The following filter matches NDEF messages that contain a single smart poster record: + + \code + QNdefFilter filter; + filter.append(QNdefRecord::NfcRtd, "Sp"); + \endcode + + The following filter matches NDEF messages that contain a URI, a localized piece of text and an + optional JPEG image. The order of the records must be in the order specified: + + \code + QNdefFilter filter; + filter.setOrderMatch(true); + filter.appendRecord(QNdefRecord::NfcRtd, "U"); + filter.appendRecord<QNdefNfcTextRecord>(); + filter.appendRecord(QNdefRecord::Mime, "image/jpeg", 0, 1); + \endcode +*/ + +/*! + \fn void QNdefFilter::appendRecord(unsigned int min, unsigned int max) + + Appends a record matching the template parameter to the NDEF filter. The record must occur + between \a min and \a max times in the NDEF message. +*/ + +class QNdefFilterPrivate : public QSharedData +{ +public: + QNdefFilterPrivate(); + + bool orderMatching; + QList<QNdefFilter::Record> filterRecords; +}; + +QNdefFilterPrivate::QNdefFilterPrivate() +: orderMatching(false) +{ +} + +/*! + Constructs a new NDEF filter. +*/ +QNdefFilter::QNdefFilter() +: d(new QNdefFilterPrivate) +{ +} + +/*! + constructs a new NDEF filter that is a copy of \a other. +*/ +QNdefFilter::QNdefFilter(const QNdefFilter &other) +: d(other.d) +{ +} + +/*! + Destroys the NDEF filter. +*/ +QNdefFilter::~QNdefFilter() +{ +} + +/*! + Assigns \a other to this filter and returns a reference to this filter. +*/ +QNdefFilter &QNdefFilter::operator=(const QNdefFilter &other) +{ + if (d != other.d) + d = other.d; + + return *this; +} + +/*! + Clears the filter. +*/ +void QNdefFilter::clear() +{ + d->orderMatching = false; + d->filterRecords.clear(); +} + +/*! + Sets the ording requirements of the filter. If \a on is true the filter will only match if the + order of records in the filter matches the order of the records in the NDEF message. If \a on + is false the order of the records is not taken into account when matching. + + By default record order is not taken into account. +*/ +void QNdefFilter::setOrderMatch(bool on) +{ + d->orderMatching = on; +} + +/*! + Returns true if the filter takes NDEF record order into account when matching; otherwise + returns false. +*/ +bool QNdefFilter::orderMatch() const +{ + return d->orderMatching; +} + +/*! + Appends a record with type name format \a typeNameFormat and type \a type to the NDEF filter. + The record must occur between \a min and \a max times in the NDEF message. +*/ +void QNdefFilter::appendRecord(QNdefRecord::TypeNameFormat typeNameFormat, const QByteArray &type, + unsigned int min, unsigned int max) +{ + QNdefFilter::Record record; + + record.typeNameFormat = typeNameFormat; + record.type = type; + record.minimum = min; + record.maximum = max; + + d->filterRecords.append(record); +} + +/*! + Appends \a record to the NDEF filter. +*/ +void QNdefFilter::appendRecord(const Record &record) +{ + d->filterRecords.append(record); +} + +/*! + Returns the NDEF record at index \a i. +*/ +QNdefFilter::Record QNdefFilter::recordAt(int i) const +{ + return d->filterRecords.at(i); +} + +/*! + Returns the number of NDEF records in the filter. +*/ +int QNdefFilter::recordCount() const +{ + return d->filterRecords.count(); +} + diff --git a/src/nfc/qndeffilter.h b/src/nfc/qndeffilter.h new file mode 100644 index 00000000..5cc92863 --- /dev/null +++ b/src/nfc/qndeffilter.h @@ -0,0 +1,98 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QNDEFFILTER_H +#define QNDEFFILTER_H + +#include "../qtconnectivityglobal.h" + +#include <QtCore/QSharedDataPointer> + +#include <qndefrecord.h> + +QT_BEGIN_HEADER + +class QNdefFilterPrivate; +class Q_CONNECTIVITY_EXPORT QNdefFilter +{ +public: + QNdefFilter(); + QNdefFilter(const QNdefFilter &other); + ~QNdefFilter(); + + void clear(); + + void setOrderMatch(bool on); + bool orderMatch() const; + + struct Record { + QNdefRecord::TypeNameFormat typeNameFormat; + QByteArray type; + unsigned int minimum; + unsigned int maximum; + }; + + template<typename T> + void appendRecord(unsigned int min = 1, unsigned int max = 1); + void appendRecord(QNdefRecord::TypeNameFormat typeNameFormat, const QByteArray &type, + unsigned int min = 1, unsigned int max = 1); + void appendRecord(const Record &record); + + int recordCount() const; + Record recordAt(int i) const; + + QNdefFilter &operator=(const QNdefFilter &other); + +private: + QSharedDataPointer<QNdefFilterPrivate> d; +}; + +template <typename T> +void QNdefFilter::appendRecord(unsigned int min, unsigned int max) +{ + T record; + + appendRecord(record.typeNameFormat(), record.type(), min, max); +} + +QT_END_HEADER + +#endif // QNDEFFILTER_H diff --git a/src/nfc/qndefmessage.cpp b/src/nfc/qndefmessage.cpp new file mode 100644 index 00000000..532e8bff --- /dev/null +++ b/src/nfc/qndefmessage.cpp @@ -0,0 +1,319 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qndefmessage.h" +#include "qndefrecord_p.h" + +/*! + \class QNdefMessage + \brief The QNdefMessage class provides an NFC NDEF message. + + \ingroup connectivity-nfc + \inmodule QtConnectivity + \since 5.0 + + A QNdefMessage is a collection of 0 or more QNdefRecords. QNdefMessage inherits from + QList<QNdefRecord> and therefore the standard QList functions can be used to manipulate the + NDEF records in the message. + + NDEF messages can be parsed from a byte array conforming to the NFC Data Exchange Format + technical specification by using the fromByteArray() static function. Conversely QNdefMessages + can be converted into a byte array with the toByteArray() function. +*/ + +/*! + \fn QNdefMessage::QNdefMessage() + + Constructs a new empty NDEF message. +*/ + +/*! + \fn QNdefMessage::QNdefMessage(const QNdefRecord &record) + + Constructs a new NDEF message containing a single record \a record. +*/ + +/*! + \fn QNdefMessage::QNdefMessage(const QNdefMessage &message) + + Constructs a new NDEF message that is a copy of \a message. +*/ + +/*! + \fn QNdefMessage::QNdefMessage(const QList<QNdefRecord> &records) + + Constructs a new NDEF message that contains all of the records in \a records. +*/ + +/*! + Returns an NDEF message parsed from the contents of \a message. + + The \a message parameter is interpreted as the raw message format defined in the NFC Data + Exchange Format technical specification. + + If a parse error occurs an empty NDEF message is returned. +*/ +QNdefMessage QNdefMessage::fromByteArray(const QByteArray &message) +{ + QNdefMessage result; + + bool seenMessageBegin = false; + bool seenMessageEnd = false; + + QByteArray partialChunk; + QNdefRecord record; + + QByteArray::const_iterator i = message.begin(); + while (i < message.constEnd()) { + quint8 flags = *i; + + bool messageBegin = flags & 0x80; + bool messageEnd = flags & 0x40; + + bool cf = flags & 0x20; + bool sr = flags & 0x10; + bool il = flags & 0x08; + quint8 typeNameFormat = flags & 0x07; + + if (messageBegin && seenMessageBegin) { + qWarning("Got message begin but already parsed some records"); + return QNdefMessage(); + } else if (!messageBegin && !seenMessageBegin) { + qWarning("Haven't got message begin yet"); + return QNdefMessage(); + } else if (messageBegin && !seenMessageBegin) { + seenMessageBegin = true; + } + if (messageEnd && seenMessageEnd) { + qWarning("Got message end but already parsed final record"); + return QNdefMessage(); + } else if (messageEnd && !seenMessageEnd) { + seenMessageEnd = true; + } + if (cf && (typeNameFormat != 0x06) && !partialChunk.isEmpty()) { + qWarning("partial chunk not empty or typeNameFormat not 0x06 as expected"); + return QNdefMessage(); + } + + int headerLength = 1; + headerLength += (sr) ? 1 : 4; + headerLength += (il) ? 1 : 0; + + if (i + headerLength >= message.constEnd()) { + qWarning("Unexpected end of message"); + return QNdefMessage(); + } + + quint8 typeLength = *(++i); + + if ((typeNameFormat == 0x06) && (typeLength != 0)) { + qWarning("Invalid chunked data, TYPE_LENGTH != 0"); + return QNdefMessage(); + } + + quint32 payloadLength; + if (sr) + payloadLength = *(++i); + else { + payloadLength = quint8(*(++i)) << 24; + payloadLength |= quint8(*(++i)) << 16; + payloadLength |= quint8(*(++i)) << 8; + payloadLength |= quint8(*(++i)) << 0; + } + + quint8 idLength; + if (il) + idLength = *(++i); + else + idLength = 0; + + int contentLength = typeLength + payloadLength + idLength; + if (i + contentLength >= message.constEnd()) { + qWarning("Unexpected end of message"); + return QNdefMessage(); + } + + if ((typeNameFormat == 0x06) && (idLength != 0)) { + qWarning("Invalid chunked data, IL != 0"); + return QNdefMessage(); + } + + if (typeNameFormat != 0x06) + record.setTypeNameFormat(QNdefRecord::TypeNameFormat(typeNameFormat)); + + if (typeLength > 0) { + QByteArray type(++i, typeLength); + record.setType(type); + i += typeLength - 1; + } + + if (idLength > 0) { + QByteArray id(++i, idLength); + record.setId(id); + i += idLength - 1; + } + + if (payloadLength > 0) { + QByteArray payload(++i, payloadLength); + + + if (cf) { + // chunked payload, except last + partialChunk.append(payload); + } else if (typeNameFormat == 0x06) { + // last chunk of chunked payload + record.setPayload(partialChunk + payload); + partialChunk.clear(); + } else { + // non-chunked payload + record.setPayload(payload); + } + + i += payloadLength - 1; + } + + if (!cf) + result.append(record); + + if (!cf && seenMessageEnd) + break; + + // move to start of next record + ++i; + } + + if (!seenMessageBegin && !seenMessageEnd) { + qWarning("Malformed NDEF Message, missing begin or end."); + return QNdefMessage(); + } + + return result; +} + +/*! + Returns true if this NDEF message is equivalent to \a other; otherwise returns false. + + An empty message (i.e. isEmpty() returns true) is equivalent to a NDEF message containing a + single record of type QNdefRecord::Empty. +*/ +bool QNdefMessage::operator==(const QNdefMessage &other) const +{ + // both records are empty + if (isEmpty() && other.isEmpty()) + return true; + + // compare empty to really empty + if (isEmpty() && other.count() == 1 && other.first().typeNameFormat() == QNdefRecord::Empty) + return true; + if (other.isEmpty() && count() == 1 && first().typeNameFormat() == QNdefRecord::Empty) + return true; + + if (count() != other.count()) + return false; + + for (int i = 0; i < count(); ++i) { + if (at(i) != other.at(i)) + return false; + } + + return true; +} + +/*! + Returns the NDEF message as a byte array. + + The return value of this function conforms to the format defined in the NFC Data Exchange + Format technical specification. +*/ +QByteArray QNdefMessage::toByteArray() const +{ + // An empty message is treated as a message containing a single empty record. + if (isEmpty()) + return QNdefMessage(QNdefRecord()).toByteArray(); + + QByteArray m; + + for (int i = 0; i < count(); ++i) { + const QNdefRecord &record = at(i); + + quint8 flags = record.typeNameFormat(); + + if (i == 0) + flags |= 0x80; + if (i == count() - 1) + flags |= 0x40; + + // cf (chunked records) not supported yet + + if (record.payload().length() < 255) + flags |= 0x10; + + if (!record.id().isEmpty()) + flags |= 0x08; + + m.append(flags); + m.append(record.type().length()); + + if (flags & 0x10) { + m.append(quint8(record.payload().length())); + } else { + quint32 length = record.payload().length(); + m.append(length >> 24); + m.append(length >> 16); + m.append(length >> 8); + m.append(length & 0x000000ff); + } + + if (flags & 0x08) + m.append(record.id().length()); + + if (!record.type().isEmpty()) + m.append(record.type()); + + if (!record.id().isEmpty()) + m.append(record.id()); + + if (!record.payload().isEmpty()) + m.append(record.payload()); + } + + return m; +} diff --git a/src/nfc/qndefmessage.h b/src/nfc/qndefmessage.h new file mode 100644 index 00000000..e6aef623 --- /dev/null +++ b/src/nfc/qndefmessage.h @@ -0,0 +1,75 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QNDEFMESSAGE_H +#define QNDEFMESSAGE_H + +#include "../qtconnectivityglobal.h" + +#include <qndefrecord.h> + +#include <QtCore/QVector> +#include <QtCore/QSet> +#include <QtCore/QList> +#include <QtCore/QMetaType> + +QT_BEGIN_HEADER + +class Q_CONNECTIVITY_EXPORT QNdefMessage : public QList<QNdefRecord> +{ +public: + inline QNdefMessage() { } + inline explicit QNdefMessage(const QNdefRecord &record) { append(record); } + inline QNdefMessage(const QNdefMessage &message) : QList<QNdefRecord>(message) { } + inline QNdefMessage(const QList<QNdefRecord> &records) : QList<QNdefRecord>(records) { } + + bool operator==(const QNdefMessage &other) const; + + QByteArray toByteArray() const; + + static QNdefMessage fromByteArray(const QByteArray &message); +}; + +Q_DECLARE_METATYPE(QNdefMessage) + +QT_END_HEADER + +#endif // QNDEFMESSAGE_H diff --git a/src/nfc/qndefnfctextrecord.cpp b/src/nfc/qndefnfctextrecord.cpp new file mode 100644 index 00000000..b9146f9a --- /dev/null +++ b/src/nfc/qndefnfctextrecord.cpp @@ -0,0 +1,189 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <qndefnfctextrecord.h> + +#include <QtCore/QTextCodec> +#include <QtCore/QLocale> + +/*! + \class QNdefNfcTextRecord + \brief The QNdefNfcTextRecord class provides an NFC RTD-Text + + \ingroup connectivity-nfc + \inmodule QtConnectivity + \since 5.0 + + RTD-Text encapsulates a user displayable text record. +*/ + +/*! + \enum QNdefNfcTextRecord::Encoding + + This enum describes the text encoding standard used. + + \value Utf8 The text is encoded with UTF-8. + \value Utf16 The text is encoding with UTF-16. +*/ + +/*! + Returns the locale of the text record. +*/ +QString QNdefNfcTextRecord::locale() const +{ + const QByteArray p = payload(); + + if (p.isEmpty()) + return QString(); + + quint8 status = p.at(0); + + quint8 codeLength = status & 0x3f; + + return QString::fromAscii(p.constData() + 1, codeLength); +} + +/*! + Sets the locale of the text record to \a locale. +*/ +void QNdefNfcTextRecord::setLocale(const QString &locale) +{ + QByteArray p = payload(); + + quint8 status = p.isEmpty() ? 0 : p.at(0); + + quint8 codeLength = status & 0x3f; + + quint8 newStatus = (status & 0xd0) | locale.length(); + + p[0] = newStatus; + p.replace(1, codeLength, locale.toAscii()); + + setPayload(p); +} + +/*! + Returns the contents of the text record as a string. +*/ +QString QNdefNfcTextRecord::text() const +{ + const QByteArray p = payload(); + + if (p.isEmpty()) + return QString(); + + quint8 status = p.at(0); + + bool utf16 = status & 0x80; + quint8 codeLength = status & 0x3f; + + QTextCodec *codec = QTextCodec::codecForName(utf16 ? "UTF-16BE" : "UTF-8"); + + return codec->toUnicode(p.constData() + 1 + codeLength, p.length() - 1 - codeLength); +} + +/*! + Sets the contents of the text record to \a text. +*/ +void QNdefNfcTextRecord::setText(const QString text) +{ + if (payload().isEmpty()) + setLocale(QLocale().name()); + + QByteArray p = payload(); + + quint8 status = p.at(0); + + bool utf16 = status & 0x80; + quint8 codeLength = status & 0x3f; + + p.truncate(1 + codeLength); + + QTextCodec *codec = QTextCodec::codecForName(utf16 ? "UTF-16BE" : "UTF-8"); + + p += codec->fromUnicode(text); + + setPayload(p); +} + +/*! + Returns the encoding of the contents. +*/ +QNdefNfcTextRecord::Encoding QNdefNfcTextRecord::encoding() const +{ + if (payload().isEmpty()) + return Utf8; + + QByteArray p = payload(); + + quint8 status = p.at(0); + + bool utf16 = status & 0x80; + + if (utf16) + return Utf16; + else + return Utf8; +} + +/*! + Sets the enconding of the contents to \a encoding. +*/ +void QNdefNfcTextRecord::setEncoding(Encoding encoding) +{ + QByteArray p = payload(); + + quint8 status = p.isEmpty() ? 0 : p.at(0); + + QString string = text(); + + if (encoding == Utf8) + status &= ~0x80; + else + status |= 0x80; + + p[0] = status; + + setPayload(p); + + setText(string); +} + diff --git a/src/nfc/qndefnfctextrecord.h b/src/nfc/qndefnfctextrecord.h new file mode 100644 index 00000000..2333e3ff --- /dev/null +++ b/src/nfc/qndefnfctextrecord.h @@ -0,0 +1,75 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QNDEFNFCTEXTRECORD_H +#define QNDEFNFCTEXTRECORD_H + +#include "../qtconnectivityglobal.h" + +#include <qndefrecord.h> + +QT_BEGIN_HEADER + +class Q_CONNECTIVITY_EXPORT QNdefNfcTextRecord : public QNdefRecord +{ +public: + Q_DECLARE_NDEF_RECORD(QNdefNfcTextRecord, QNdefRecord::NfcRtd, "T", QByteArray(1, char(0))) + + QString locale() const; + void setLocale(const QString &locale); + + QString text() const; + void setText(const QString text); + + enum Encoding { + Utf8, + Utf16 + }; + + Encoding encoding() const; + void setEncoding(Encoding encoding); +}; + +Q_DECLARE_ISRECORDTYPE_FOR_NDEF_RECORD(QNdefNfcTextRecord, QNdefRecord::NfcRtd, "T") + +QT_END_HEADER + +#endif // QNDEFNFCTEXTRECORD_H diff --git a/src/nfc/qndefnfcurirecord.cpp b/src/nfc/qndefnfcurirecord.cpp new file mode 100644 index 00000000..4a495d2d --- /dev/null +++ b/src/nfc/qndefnfcurirecord.cpp @@ -0,0 +1,142 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qndefnfcurirecord.h" + +#include <QtCore/QString> +#include <QtCore/QUrl> + +#include <QtCore/QDebug> + +/*! + \class QNdefNfcUriRecord + \brief The QNdefNfcUriRecord class provides an NFC RTD-URI + + \ingroup connectivity-nfc + \inmodule QtConnectivity + \since 5.0 + + RTD-URI encapsulates a URI. +*/ + +static const char * const abbreviations[] = { + 0, + "http://www.", + "https://www.", + "http://", + "https://", + "tel:", + "mailto:", + "ftp://anonymous:anonymous@", + "ftp://ftp.", + "ftps://", + "sftp://", + "smb://", + "nfs://", + "ftp://", + "dav://", + "news:", + "telnet://", + "imap:", + "rtsp://", + "urn:", + "pop:", + "sip:", + "sips:", + "tftp:", + "btspp://", + "btl2cap://", + "btgoep://", + "tcpobex://", + "irdaobex://", + "file://", + "urn:epc:id:", + "urn:epc:tag:", + "urn:epc:pat:", + "urn:epc:raw:", + "urn:epc:", + "urn:nfc:", +}; + +/*! + Returns the URI of this URI record. +*/ +QUrl QNdefNfcUriRecord::uri() const +{ + const QByteArray p = payload(); + + if (p.isEmpty()) + return QUrl(); + + quint8 code = p.at(0); + if (code >= sizeof(abbreviations) / sizeof(*abbreviations)) + code = 0; + + return QUrl(QLatin1String(abbreviations[code]) + QString::fromUtf8(p.mid(1), p.length() - 1)); +} + +/*! + Sets the URI of this URI record to \a uri. +*/ +void QNdefNfcUriRecord::setUri(const QUrl &uri) +{ + int abbrevs = sizeof(abbreviations) / sizeof(*abbreviations); + + for (int i = 1; i < abbrevs; ++i) { + if (uri.toString().startsWith(QLatin1String(abbreviations[i]))) { + QByteArray p; + + p[0] = i; + p += uri.toString().mid(qstrlen(abbreviations[i])).toUtf8(); + + setPayload(p); + + return; + } + } + + QByteArray p; + p[0] = 0; + p += uri.toString().toUtf8(); + + setPayload(p); +} + diff --git a/src/nfc/qndefnfcurirecord.h b/src/nfc/qndefnfcurirecord.h new file mode 100644 index 00000000..10bddff7 --- /dev/null +++ b/src/nfc/qndefnfcurirecord.h @@ -0,0 +1,66 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QNDEFNFCURIRECORD_H +#define QNDEFNFCURIRECORD_H + +#include "../qtconnectivityglobal.h" + +#include <qndefrecord.h> + +QT_FORWARD_DECLARE_CLASS(QUrl) + +QT_BEGIN_HEADER + +class Q_CONNECTIVITY_EXPORT QNdefNfcUriRecord : public QNdefRecord +{ +public: + Q_DECLARE_NDEF_RECORD(QNdefNfcUriRecord, QNdefRecord::NfcRtd, "U", QByteArray(0, char(0))) + + QUrl uri() const; + void setUri(const QUrl &uri); +}; + +Q_DECLARE_ISRECORDTYPE_FOR_NDEF_RECORD(QNdefNfcUriRecord, QNdefRecord::NfcRtd, "U") + +QT_END_HEADER + +#endif // QNDEFNFCURIRECORD_H diff --git a/src/nfc/qndefrecord.cpp b/src/nfc/qndefrecord.cpp new file mode 100644 index 00000000..4db78e2b --- /dev/null +++ b/src/nfc/qndefrecord.cpp @@ -0,0 +1,349 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#include "qndefrecord.h" +#include "qndefrecord_p.h" + +#include <QtCore/QHash> + +/*! + \class QNdefRecord + \brief The QNdefRecord class provides an NFC NDEF record. + + \ingroup connectivity-nfc + \inmodule QtConnectivity + \since 5.0 + + QNdefRecord and derived classes are used to parse the contents of + \l {QNdefMessage}{NDEF messages} and create new NDEF messages. + + Use typeNameFormat(), userTypeNameFormat(), setTypeNameFormat() and setUserTypeNameFormat() to + get and set the type name format of the NDEF record. + + Use type() and setType() to get and set the type of the NDEF record. + + Use id() and setId() to get and set the id of the NDEF record. + + Use payload() and setPayload() to get and set the NDEF record payload. isEmpty() can be used + to test if the payload is empty. + + QNdefRecord is an implicitly shared class. This means you can efficiently convert between + QNdefRecord and specialized record classes. The isRecordType() template function can be used + to test if a conversion is possible. The following example shows how to test if a QNdefRecord + is an NFC RTD Text record and extract the text information from it. + + \snippet snippets/connectivity/nfc.cpp Record conversion + + \section1 Creating specialized NDEF record classes + + Specialized NDEF record classes can be easily created with the Q_DECLARE_NDEF_RECORD() and + Q_DECLARE_ISRECORDTYPE_FOR_NDEF_RECORD() macros. The following example shows the class + declaration of the hypothetical \i {example.com:f} record type that encapsulates a single int + property foo. + + \snippet snippets/connectivity/nfc.cpp Specialized class definition + + The developer only needs to provide implementations for the \c {foo()} and \c {setFoo()} + functions that parse and set the contents of the NDEF record's payload. +*/ + +/*! + \enum QNdefRecord::TypeNameFormat + + This enum describes the type name format of an NDEF record. + + \value Empty An empty NDEF record, the record does not contain a payload + \value NfcRtd The NDEF record type is defined by an NFC RTD Specification + \value Mime The NDEF record type follows the construct described in RFC 2046 + \value Uri The NDEF record type follows the construct described in RFC 3986 + \value ExternalRtd The NDEF record type follows the construct for external type names + described the NFC RTD Specification + \value Unknown The type of the record is unknown and should be treated similar to content + with MIME type 'application/octet-stream' without further context +*/ + +/*! + \fn bool QNdefRecord::isRecordType() const + + Returns true if the NDEF record is of the specified record type; otherwise returns false. +*/ + +/*! + \fn bool QNdefRecord::operator!=(const QNdefRecord &other) const + + Returns true if this NDEF record does not equal \a other; otherwise return false. +*/ + +/*! + \macro Q_DECLARE_NDEF_RECORD(className, typeNameFormat, type, initialPayload) + \relates QNdefRecord + + This macro declares default and copy constructors for specialized NDEF record classes. + + \a className is the name of the specialized class, \a typeNameFormat is the appropriate + QNdefRecord::TypeNameFormat for the custom type and \a type is the type without the NID or NSS + prefixes. That is \i {example.com:f} not \i {urn:nfc:ext:example.com:f}. \a initialPayload + is the initial payload of an empty record, it must be a QByteArray or a type that can be + implicitly converted into a QByteArray. + + See the section on \l {Creating specialized NDEF record classes} for details. + + \sa Q_DECLARE_ISRECORDTYPE_FOR_NDEF_RECORD() +*/ + +/*! + \macro Q_DECLARE_ISRECORDTYPE_FOR_NDEF_RECORD(className, typeNameFormat, type) + \relates QNdefRecord + + This macro declares a template specialization for the QNdefRecord::isRecordType() function. + + This macro should be used in the header file directly after the definition of a specialized + NDEF record class. + + \a className is the name of the specialized class, \a typeNameFormat is the appropriate + QNdefRecord::TypeNameFormat for the custom type and \a type is the type without the NID or NSS + prefixes. That is \i {example.com:f} not \i {urn:nfc:ext:example.com:f}. + + See the secton on \l {Creating specialized NDEF record classes} for details. + + \sa Q_DECLARE_NDEF_RECORD() +*/ + +uint qHash(const QNdefRecord &key) +{ + return qHash(key.type() + key.id() + key.payload()); +} + +/*! + Constructs a new empty NDEF record. +*/ +QNdefRecord::QNdefRecord() +{ +} + +/*! + Constructs a new NDEF record that is a copy of \a other. +*/ +QNdefRecord::QNdefRecord(const QNdefRecord &other) +{ + d = other.d; +} + +/*! + \internal + + Constructs an NDEF record that is a copy of \a other if \a other is of the expected type name + format identified by \a typeNameFormat and type as identified by \a type; otherwise an empty + NDEF record of the expected type name format and type is created. +*/ +QNdefRecord::QNdefRecord(const QNdefRecord &other, TypeNameFormat typeNameFormat, + const QByteArray &type) +{ + if (other.d->typeNameFormat == quint8(typeNameFormat) && other.d->type == type) { + d = other.d; + } else { + d = new QNdefRecordPrivate; + d->typeNameFormat = typeNameFormat; + d->type = type; + } +} + +/*! + \internal + + Constructs an NDEF record with a type name format identified by \a typeNameFormat and type as + identified by \a type. +*/ +QNdefRecord::QNdefRecord(TypeNameFormat typeNameFormat, const QByteArray &type) +: d(new QNdefRecordPrivate) +{ + d->typeNameFormat = typeNameFormat; + d->type = type; +} + +/*! + Destroys the NDEF record. +*/ +QNdefRecord::~QNdefRecord() +{ +} + +/*! + Assigns this NDEF record to \a other. +*/ +QNdefRecord &QNdefRecord::operator=(const QNdefRecord &other) +{ + if (this != &other) + d = other.d; + + return *this; +} + +/*! + Sets the type name format of the NDEF record to \a typeNameFormat. +*/ +void QNdefRecord::setTypeNameFormat(TypeNameFormat typeNameFormat) +{ + if (!d) + d = new QNdefRecordPrivate; + + d->typeNameFormat = typeNameFormat; +} + +/*! + Returns the type name format of the NDEF record. +*/ +QNdefRecord::TypeNameFormat QNdefRecord::typeNameFormat() const +{ + if (!d) + return Empty; + + if (d->typeNameFormat > 0x05) + return Unknown; + + return TypeNameFormat(d->typeNameFormat); +} + +/*! + Sets the type of the NDEF record to \a type. +*/ +void QNdefRecord::setType(const QByteArray &type) +{ + if (!d) + d = new QNdefRecordPrivate; + + d->type = type; +} + +/*! + Returns the type of the NDEF record. +*/ +QByteArray QNdefRecord::type() const +{ + if (!d) + return QByteArray(); + + return d->type; +} + +/*! + Sets the id of the NDEF record to \a id. +*/ +void QNdefRecord::setId(const QByteArray &id) +{ + if (!d) + d = new QNdefRecordPrivate; + + d->id = id; +} + +/*! + Returns the id of the NDEF record. +*/ +QByteArray QNdefRecord::id() const +{ + if (!d) + return QByteArray(); + + return d->id; +} + +/*! + Sets the payload of the NDEF record to \a payload. +*/ +void QNdefRecord::setPayload(const QByteArray &payload) +{ + if (!d) + d = new QNdefRecordPrivate; + + d->payload = payload; +} + +/*! + Returns the payload of the NDEF record. +*/ +QByteArray QNdefRecord::payload() const +{ + if (!d) + return QByteArray(); + + return d->payload; +} + +/*! + Returns true if the NDEF record contains an empty payload; otherwise return false. + + This is equivalent to calling \c {payload().isEmpty()}. +*/ +bool QNdefRecord::isEmpty() const +{ + if (!d) + return true; + + return d->payload.isEmpty(); +} + +/*! + Returns true if \a other and this NDEF record are the same. +*/ +bool QNdefRecord::operator==(const QNdefRecord &other) const +{ + if (d == other.d) + return true; + + if (!d || !other.d) + return false; + + if (d->typeNameFormat != other.d->typeNameFormat) + return false; + + if (d->type != other.d->type) + return false; + + if (d->id != other.d->id) + return false; + + if (d->payload != other.d->payload) + return false; + + return true; +} diff --git a/src/nfc/qndefrecord.h b/src/nfc/qndefrecord.h new file mode 100644 index 00000000..31d0e94c --- /dev/null +++ b/src/nfc/qndefrecord.h @@ -0,0 +1,118 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QNDEFRECORD_H +#define QNDEFRECORD_H + +#include "../qtconnectivityglobal.h" + +#include <QtCore/QSharedDataPointer> +#include <QtCore/QByteArray> + +QT_BEGIN_HEADER + +class QNdefRecordPrivate; + +class Q_CONNECTIVITY_EXPORT QNdefRecord +{ +public: + enum TypeNameFormat { + Empty = 0x00, + NfcRtd = 0x01, + Mime = 0x02, + Uri = 0x03, + ExternalRtd = 0x04, + Unknown = 0x05 + }; + + QNdefRecord(); + ~QNdefRecord(); + + QNdefRecord(const QNdefRecord &other); + QNdefRecord &operator=(const QNdefRecord &other); + + void setTypeNameFormat(TypeNameFormat typeNameFormat); + TypeNameFormat typeNameFormat() const; + + void setType(const QByteArray &type); + QByteArray type() const; + + void setId(const QByteArray &id); + QByteArray id() const; + + void setPayload(const QByteArray &payload); + QByteArray payload() const; + + bool isEmpty() const; + + template <typename T> + inline bool isRecordType() const + { + T dummy; + return (typeNameFormat() == dummy.typeNameFormat() && type() == dummy.type()); + } + + bool operator==(const QNdefRecord &other) const; + inline bool operator!=(const QNdefRecord &other) const { return !operator==(other); } + +protected: + QNdefRecord(const QNdefRecord &other, TypeNameFormat typeNameFormat, const QByteArray &type); + QNdefRecord(TypeNameFormat typeNameFormat, const QByteArray &type); + +private: + QSharedDataPointer<QNdefRecordPrivate> d; +}; + +#define Q_DECLARE_NDEF_RECORD(className, typeNameFormat, type, initialPayload) \ + className() : QNdefRecord(typeNameFormat, type) { setPayload(initialPayload); } \ + className(const QNdefRecord &other) : QNdefRecord(other, typeNameFormat, type) { } + +#define Q_DECLARE_ISRECORDTYPE_FOR_NDEF_RECORD(className, typeNameFormat_, type_) \ + template<> inline bool QNdefRecord::isRecordType<className>() const\ + { \ + return (typeNameFormat() == typeNameFormat_ && type() == type_); \ + } + +uint qHash(const QNdefRecord &key); + +QT_END_HEADER + +#endif // QNDEFRECORD_H diff --git a/src/nfc/qndefrecord_p.h b/src/nfc/qndefrecord_p.h new file mode 100644 index 00000000..ff279d68 --- /dev/null +++ b/src/nfc/qndefrecord_p.h @@ -0,0 +1,63 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#ifndef QNDEFRECORD_P_H +#define QNDEFRECORD_P_H + +#include "../qtconnectivityglobal.h" + +#include <QtCore/QSharedData> +#include <QtCore/QByteArray> + +class QNdefRecordPrivate : public QSharedData +{ +public: + //bool messageBegin : 1; + //bool messageEnd : 1; + unsigned int typeNameFormat : 3; + + QByteArray type; + QByteArray id; + QByteArray payload; +}; + +#endif // QNDEFRECORD_P_H diff --git a/src/nfc/qnearfieldllcpdevice_symbian.cpp b/src/nfc/qnearfieldllcpdevice_symbian.cpp new file mode 100644 index 00000000..38f9968c --- /dev/null +++ b/src/nfc/qnearfieldllcpdevice_symbian.cpp @@ -0,0 +1,69 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qnearfieldllcpdevice_symbian_p.h" + +QNearFieldLlcpDeviceSymbian::QNearFieldLlcpDeviceSymbian(RNfcServer& nfcServer, QObject *parent) + : QNearFieldTarget(parent), mNfcServer(nfcServer) +{ + setAccessMethods(QNearFieldTarget::LlcpAccess); +} + +QByteArray QNearFieldLlcpDeviceSymbian::uid() const +{ + return QByteArray(); +} + +QNearFieldTarget::Type QNearFieldLlcpDeviceSymbian::type() const +{ + return QNearFieldTarget::NfcForumDevice; +} + +QNearFieldTarget::AccessMethods QNearFieldLlcpDeviceSymbian::accessMethods() const +{ + return QNearFieldTarget::LlcpAccess; +} + +void QNearFieldLlcpDeviceSymbian::setAccessMethods(const QNearFieldTarget::AccessMethods& accessMethods) +{ +} + +#include "moc_qnearfieldllcpdevice_symbian_p.cpp" diff --git a/src/nfc/qnearfieldllcpdevice_symbian_p.h b/src/nfc/qnearfieldllcpdevice_symbian_p.h new file mode 100644 index 00000000..e4ecb639 --- /dev/null +++ b/src/nfc/qnearfieldllcpdevice_symbian_p.h @@ -0,0 +1,69 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#ifndef QNEARFIELDLLCPDEVICE_H +#define QNEARFIELDLLCPDEVICE_H + +#include <qnearfieldtarget.h> +#include <nfcserver.h> + +QT_BEGIN_HEADER + +class QNearFieldLlcpDeviceSymbian : public QNearFieldTarget +{ + Q_OBJECT +public: + explicit QNearFieldLlcpDeviceSymbian(RNfcServer& nfcServer, QObject *parent = 0); + QByteArray uid() const; + Type type() const; + AccessMethods accessMethods() const; + void setAccessMethods(const AccessMethods& accessMethods); + + RNfcServer& nfcServer() {return mNfcServer;} + +private: + RNfcServer& mNfcServer; +}; + +QT_END_HEADER + +#endif // QNEARFIELDLLCPDEVICE_H diff --git a/src/nfc/qnearfieldmanager.cpp b/src/nfc/qnearfieldmanager.cpp new file mode 100644 index 00000000..2d9fb60e --- /dev/null +++ b/src/nfc/qnearfieldmanager.cpp @@ -0,0 +1,554 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qnearfieldmanager.h" +#include "qnearfieldmanager_p.h" + +#if defined(QT_SIMULATOR) +#include "qnearfieldmanager_simulator_p.h" +#elif defined(Q_OS_SYMBIAN) +#include "qnearfieldmanager_symbian_p.h" +#elif defined(Q_WS_MAEMO_6) || defined (Q_WS_MEEGO) +#include "qnearfieldmanager_maemo6_p.h" +#else +#include "qnearfieldmanagerimpl_p.h" +#endif + +#include <QtCore/QMetaType> +#include <QtCore/QMetaMethod> + +/*! + \class QNearFieldManager + \brief The QNearFieldManager class provides access to notifications for NFC events. + + \ingroup connectivity-nfc + \inmodule QtConnectivity + \since 5.0 + + NFC Forum devices support two modes of communications. The first mode, peer-to-peer + communications, is used to communicate between two NFC Forum devices. The second mode, + master/slave communications, is used to communicate between an NFC Forum device and an NFC + Forum Tag or Contactless Card. The targetDetected() signal is emitted when a target device + enters communications range. Communications can be initiated from the slot connected to this + signal. + + NFC Forum devices generally operate as the master in master/slave communications. Some devices + are also capable of operating as the slave, so called Card Emulation mode. In this mode the + local NFC device emulates a NFC Forum Tag or Contactless Card and can be used to perform + transactions. The transaction happens entirely within a secure element on the device and only a + notification of the transaction is provided. The transactionDetected() signal is emitted + whenever a transaction occurs. + + NFC Forum Tags can contain one or more messages in a standardized format. These messages are + encapsulated by the QNdefMessage class. Use the registerNdefMessageHandler() functions to + register message handlers with particular criteria. Handlers can be unregistered with the + unregisterNdefMessageHandler() function. + + Applications can connect to the targetDetected() and targetLost() signals to get notified when + an NFC Forum Device or NFC Forum Tag enters or leaves proximity. Before these signals are + emitted target detection must be started with the startTargetDetection() function, which takes + a parameter to limit the type of device or tags detected. Target detection can be stopped with + the stopTargetDetection() function. Before a detected target can be accessed it is necessary to + request access rights. This must be done before the target device is touched. The + setTargetAccessModes() function is used to set the types of access the application wants to + perform on the detected target. When access is no longer required the target access modes + should be set to NoTargetAccess as other applications may be blocked from accessing targets. + The current target access modes can be retried with the targetAccessModes() function. + + + \section2 Automatically launching NDEF message handlers + + It is possible to pre-register an application to receive NDEF messages matching a given + criteria. This is useful to get the system to automatically launch your application when a + matching NDEF message is received. This removes the need to have the user manually launch NDEF + handling applications, prior to touching a tag, or to have those applications always running + and using system resources. + + The process of registering the handler is different on each platform. The platform specifics + are documented in the sections below. Qt Mobility provides a tool, \c {ndefhandlergen}, to + generate the platform specific registration files. The output of \c {ndefhandlergen -help} is + reproduced here for convenience: + + \code + Generate platform specific NFC message handler registration files. + Usage: nfcxmlgen [options] + + -template TEMPLATE Template to use. + -appname APPNAME Name of the application. + -apppath APPPATH Path to installed application binary. + -datatype DATATYPE URN of the NDEF message type to match. + -match MATCHSTRING Platform specific match string. + + The -datatype and -match options are mutually exclusive. + + Available templates: maemo6, symbian + \endcode + + A typical invocation of the \c ndefhandlergen tool for Symbian^3 target: + + \code + ndefhandlergen -template symbian -appname myapplication -datatype urn:nfc:ext:com.example:f + \endcode + + and for Maemo6 target: + + \code + ndefhandlergen -template maemo6 -appname myapplication -apppath /usr/bin/myapplication -datatype urn:nfc:ext:com.example:f + \endcode + + Once the application has been registered as an NDEF message handler, the application only needs + to call the registerNdefMessageHandler() function: + + \code + QNearFieldManager *manager = new QNearFieldManager; + manager->registerNdefMessageHandler(this, + SLOT(handleNdefMessage(QNdefMessage,QNearFieldTarget))); + \endcode + + \section3 Symbian^3 + + On Symbian^3 an xml file needs to be created and installed into a particular directory on the + device. The format of the xml is given below. + + \quotefile tools/ndefhandlergen/templates/symbian/symbian.xml + + The \i {%APPNAME%} tags need to be changed to match the name of the application. The + \i description xml tags should be used to describe the application, however these values are + not used. The \i {%DATATYPE%} tag must be set with the NDEF record type to match For example + the following would be used to match NDEF messages that contain a RTD-URI record: + + \code + <customproperty key="datatype">urn:nfc:wkt:U</customproperty> + \endcode + + The following would be used to match NDEF messages that contain a custom type + urn:nfc:ext:example.com:f: + + \code + <customproperty key="datatype">urn:nfc:ext:com.example:f</customproperty> + \endcode + + The value of the \i customproperty xml tag can be set to any valid match string supported by + the Symbian^3 platform. + + It is recommended to name the xml file after the application package name. For example + myapplication.xml. To install the above xml file into the correct location the following should + be added to the application .pro file: + + \code + symbian { + ndefhandler.sources = myapplication.xml + ndefhandler.path = /private/2002AC7F/import/ + DEPLOYMENT += ndefhandler + } + \endcode + + \section3 Maemo6 + + On Maemo6 the NDEF message handler notifications are passed over D-Bus. Registration of the + NDEF message match criteria is done via a D-Bus call. The application must also ensure that it + has registered a D-Bus service name so that the application can be automatically launched when + a notification message is sent to the registered service. + + To register the D-Bus service the two files need to be created and installed into particular + directories on the device. The first file is the D-Bus bus configuration file: + + \quotefile tools/ndefhandlergen/templates/maemo6/maemo6.conf + + The \i {%APPNAME%} tag must be replaced with the name of your application binary. + + The second file is a D-Bus service file which is used by the D-Bus daemon to launch your + application. + + \quotefile tools/ndefhandlergen/templates/maemo6/maemo6.service + + The \i {%APPNAME%} tag must be replace with the name of your application binary and the + \i {%APPPATH%} tag must be replaced with the path to your installed application binary. + + It is recommended to name these files after the application package name. For example + myapplication.conf and myapplication.service. To install the above files into the correct + location the following should be added to the application .pro file: + + \code + maemo6 { + ndefhandler_conf.sources = myapplication.conf + ndefhandler_conf.path = /etc/dbus-1/system.d/ + + ndefhandler_service.sources = myapplication.service + ndefhandler_service.path = /usr/share/dbus-1/system-services/ + + DEPLOYMENT += ndefhandler_conf ndefhandler_service + } + \endcode + + The NDEF message handler is registered with the following D-Bus command. Applications should + ensure that the following command (or similar) is executed once at installation time. For + example in the packages post-installation script. + + \quotefile tools/ndefhandlergen/templates/maemo6/maemo6.postinst + + The \i {%APPNAME%} string must be replaced with the name of the application binary. The + \i {%DATATYPE%} string must be replaced with the NDEF record type to match. For example the + following would be used to match NDEF messages that contain a RTD-URI record: + + \code + string:"urn:nfc:wkt:U[1:*];" + \endcode + + The following would be used to match NDEF messages that contain a custom type + urn:nfc:ext:example.com:f: + + \code + string:"urn:nfc:ext:example.com:f[1:*];" + \endcode + + Note that \c {[1:*]} indicates one or more records of the specified type must be in the NDEF + message. The value of the datatype string argument can be set to any valid match string + supported by the Maemo6 platform. + + The NDEF message handler should be unregistered at uninstallation time. For example in the + packages pre-removal script. + + \quotefile tools/ndefhandlergen/templates/maemo6/maemo6.prerm + + The \i {%APPNAME%} string must be replace with the name of the application binary. +*/ + +/*! + \enum QNearFieldManager::TargetAccessMode + + This enum describes the different access modes an application can have. + + \value NoTargetAccess The application cannot access NFC capabilities. + \value NdefReadTargetAccess The application can read NDEF messages from targets by calling + QNearFieldTarget::readNdefMessages(). + \value NdefWriteTargetAccess The application can write NDEF messages to targets by calling + QNearFieldTarget::writeNdefMessages(). + \value TagTypeSpecificTargetAccess The application can access targets using raw commands by + calling QNearFieldTarget::sendCommand(). +*/ + +/*! + \fn void QNearFieldManager::targetDetected(QNearFieldTarget *target) + + This signal is emitted whenever a target is detected. The \a target parameter represents the + detected target. + + This signal will be emitted for all detected targets. + + QNearFieldManager maintains ownership of \a target, however, it will not be destroyed until + the QNearFieldManager destructor is called. Ownership may be transferred by calling + setParent(). + + Do not delete \a target from the slot connected to this signal, instead call deleteLater(). + + \note that if \a target is deleted before it moves out of proximity the targetLost() signal + will not be emitted. + + \sa targetLost() +*/ + +/*! + \fn void QNearFieldManager::targetLost(QNearFieldTarget *target) + + This signal is emitted whenever a target moves out of proximity. The \a target parameter + represents the lost target. + + Do not delete \a target from the slot connected to this signal, instead use deleteLater(). + + \sa QNearFieldTarget::disconnected() +*/ + +/*! + \fn void QNearFieldManager::transactionDetected(const QByteArray &applicationIdentifier) + + This signal is emitted when ever a transaction is performed with the application identified by + \a applicationIdentifier. + + The \a applicationIdentifier is a byte array of up to 16 bytes as defined by ISO 7816-4 and + uniquely identifies the application and application vendor that was involved in the + transaction. +*/ + +/*! + Constructs a new near field manager with \a parent. +*/ +QNearFieldManager::QNearFieldManager(QObject *parent) +: QObject(parent), d_ptr(new QNearFieldManagerPrivateImpl) +{ + connect(d_ptr, SIGNAL(targetDetected(QNearFieldTarget*)), + this, SIGNAL(targetDetected(QNearFieldTarget*))); + connect(d_ptr, SIGNAL(targetLost(QNearFieldTarget*)), + this, SIGNAL(targetLost(QNearFieldTarget*))); +} + +/*! + \internal + + Constructs a new near field manager with the specified \a backend and with \a parent. + + \note: This constructor is only enable for internal builds and is used for testing the + simulator backend. +*/ +QNearFieldManager::QNearFieldManager(QNearFieldManagerPrivate *backend, QObject *parent) +: QObject(parent), d_ptr(backend) +{ + connect(d_ptr, SIGNAL(targetDetected(QNearFieldTarget*)), + this, SIGNAL(targetDetected(QNearFieldTarget*))); + connect(d_ptr, SIGNAL(targetLost(QNearFieldTarget*)), + this, SIGNAL(targetLost(QNearFieldTarget*))); +} + +/*! + Destroys the near field manager. +*/ +QNearFieldManager::~QNearFieldManager() +{ + delete d_ptr; +} + +/*! + Returns true if NFC functionality is available; otherwise returns false. +*/ +bool QNearFieldManager::isAvailable() const +{ + Q_D(const QNearFieldManager); + + return d->isAvailable(); +} + +/*! + Starts detecting targets of type \a targetTypes. Returns true if target detection is + successfully started; otherwise returns false. + + Causes the targetDetected() signal to be emitted when a target with a type in \a targetTypes is + within proximity. If \a targetTypes is empty targets of all types will be detected. + + \sa stopTargetDetection() +*/ +bool QNearFieldManager::startTargetDetection(const QList<QNearFieldTarget::Type> &targetTypes) +{ + Q_D(QNearFieldManager); + + if (targetTypes.isEmpty()) + return d->startTargetDetection(QList<QNearFieldTarget::Type>() << QNearFieldTarget::AnyTarget); + else + return d->startTargetDetection(targetTypes); +} + +/*! + \overload + + Starts detecting targets of type \a targetType. Returns true if target detection is + successfully started; otherwise returns false. Causes the targetDetected() signal to be emitted + when a target with the type \a targetType is within proximity. +*/ +bool QNearFieldManager::startTargetDetection(QNearFieldTarget::Type targetType) +{ + return startTargetDetection(QList<QNearFieldTarget::Type>() << targetType); +} + +/*! + Stops detecting targets. The targetDetected() signal will no longer be emitted until another + call to startTargetDetection() is made. +*/ +void QNearFieldManager::stopTargetDetection() +{ + Q_D(QNearFieldManager); + + d->stopTargetDetection(); +} + +static QMetaMethod methodForSignature(QObject *object, const char *method) +{ + QByteArray normalizedMethod = QMetaObject::normalizedSignature(method); + + if (!QMetaObject::checkConnectArgs(SIGNAL(targetDetected(QNdefMessage,QNearFieldTarget*)), + normalizedMethod)) { + qWarning("Signatures do not match: %s:%d\n", __FILE__, __LINE__); + return QMetaMethod(); + } + + quint8 memcode = (normalizedMethod.at(0) - '0') & 0x03; + normalizedMethod = normalizedMethod.mid(1); + + int index; + switch (memcode) { + case QSLOT_CODE: + index = object->metaObject()->indexOfSlot(normalizedMethod.constData()); + break; + case QSIGNAL_CODE: + index = object->metaObject()->indexOfSignal(normalizedMethod.constData()); + break; + case QMETHOD_CODE: + index = object->metaObject()->indexOfMethod(normalizedMethod.constData()); + break; + default: + index = -1; + } + + if (index == -1) + return QMetaMethod(); + + return object->metaObject()->method(index); +} + +/*! + Registers \a object to receive notifications on \a method when a tag has been detected and has + an NDEF record that matches \a typeNameFormat and \a type. The \a method on \a object should + have the prototype + 'void targetDetected(const QNdefMessage &message, QNearFieldTarget *target)'. + + Returns an identifier, which can be used to unregister the handler, on success; otherwise + returns -1. + + \note The \i target parameter of \a method may not be available on all platforms, in which case + \i target will be 0. +*/ + +int QNearFieldManager::registerNdefMessageHandler(QNdefRecord::TypeNameFormat typeNameFormat, + const QByteArray &type, + QObject *object, const char *method) +{ + QMetaMethod metaMethod = methodForSignature(object, method); + if (!metaMethod.enclosingMetaObject()) + return -1; + + QNdefFilter filter; + filter.appendRecord(typeNameFormat, type); + + Q_D(QNearFieldManager); + + return d->registerNdefMessageHandler(filter, object, metaMethod); +} + +/*! + \fn int QNearFieldManager::registerNdefMessageHandler(QObject *object, const char *method) + + Registers \a object to receive notifications on \a method when a tag has been detected and has + an NDEF message that matches a pre-registered message format. The \a method on \a object should + have the prototype + 'void targetDetected(const QNdefMessage &message, QNearFieldTarget *target)'. + + Returns an identifier, which can be used to unregister the handler, on success; otherwise + returns -1. + + This function is used to register a QNearFieldManager instance to receive notifications when a + NDEF message matching a pre-registered message format is received. See the section on + \l {Automatically launching NDEF message handlers}. + + \note The \i target parameter of \a method may not be available on all platforms, in which case + \i target will be 0. +*/ +int QNearFieldManager::registerNdefMessageHandler(QObject *object, const char *method) +{ + QMetaMethod metaMethod = methodForSignature(object, method); + if (!metaMethod.enclosingMetaObject()) + return -1; + + Q_D(QNearFieldManager); + + return d->registerNdefMessageHandler(object, metaMethod); +} + +/*! + Registers \a object to receive notifications on \a method when a tag has been detected and has + an NDEF message that matches \a filter is detected. The \a method on \a object should have the + prototype 'void targetDetected(const QNdefMessage &message, QNearFieldTarget *target)'. + + Returns an identifier, which can be used to unregister the handler, on success; otherwise + returns -1. + + \note The \i target parameter of \a method may not be available on all platforms, in which case + \i target will be 0. +*/ +int QNearFieldManager::registerNdefMessageHandler(const QNdefFilter &filter, + QObject *object, const char *method) +{ + QMetaMethod metaMethod = methodForSignature(object, method); + if (!metaMethod.enclosingMetaObject()) + return -1; + + Q_D(QNearFieldManager); + + return d->registerNdefMessageHandler(filter, object, metaMethod); +} + +/*! + Unregisters the target detect handler identified by \a handlerId. + + Returns true on success; otherwise returns false. +*/ +bool QNearFieldManager::unregisterNdefMessageHandler(int handlerId) +{ + Q_D(QNearFieldManager); + + return d->unregisterNdefMessageHandler(handlerId); +} + +/*! + Sets the requested target access modes to \a accessModes. +*/ +void QNearFieldManager::setTargetAccessModes(TargetAccessModes accessModes) +{ + Q_D(QNearFieldManager); + + TargetAccessModes removedModes = ~accessModes & d->m_requestedModes; + if (removedModes) + d->releaseAccess(removedModes); + + TargetAccessModes newModes = accessModes & ~d->m_requestedModes; + if (newModes) + d->requestAccess(newModes); +} + +/*! + Returns current requested target access modes. +*/ +QNearFieldManager::TargetAccessModes QNearFieldManager::targetAccessModes() const +{ + Q_D(const QNearFieldManager); + + return d->m_requestedModes; +} + +#include "moc_qnearfieldmanager.cpp" +#include "moc_qnearfieldmanager_p.cpp" diff --git a/src/nfc/qnearfieldmanager.h b/src/nfc/qnearfieldmanager.h new file mode 100644 index 00000000..9d3826de --- /dev/null +++ b/src/nfc/qnearfieldmanager.h @@ -0,0 +1,116 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QNEARFIELDMANAGER_H +#define QNEARFIELDMANAGER_H + +#include "../qtconnectivityglobal.h" + +#include <QtCore/QObject> + +#include <qnearfieldtarget.h> +#include <qndefrecord.h> +#include <qndeffilter.h> + +QT_BEGIN_HEADER + +class QNearFieldManagerPrivate; +class Q_CONNECTIVITY_EXPORT QNearFieldManager : public QObject +{ + Q_OBJECT + Q_DECLARE_PRIVATE(QNearFieldManager) + +public: + enum TargetAccessMode { + NoTargetAccess = 0x00, + NdefReadTargetAccess = 0x01, + NdefWriteTargetAccess = 0x02, + TagTypeSpecificTargetAccess = 0x04, + }; + Q_DECLARE_FLAGS(TargetAccessModes, TargetAccessMode) + + explicit QNearFieldManager(QObject *parent = 0); + explicit QNearFieldManager(QNearFieldManagerPrivate *backend, QObject *parent = 0); + ~QNearFieldManager(); + + bool isAvailable() const; + + void setTargetAccessModes(TargetAccessModes accessModes); + TargetAccessModes targetAccessModes() const; + + bool startTargetDetection(const QList<QNearFieldTarget::Type> &targetTypes); + bool startTargetDetection(QNearFieldTarget::Type targetType = QNearFieldTarget::AnyTarget); + void stopTargetDetection(); + + template<typename T> + int registerNdefMessageHandler(QObject *object, const char *method); + int registerNdefMessageHandler(QObject *object, const char *method); + int registerNdefMessageHandler(QNdefRecord::TypeNameFormat typeNameFormat, + const QByteArray &type, + QObject *object, const char *method); + int registerNdefMessageHandler(const QNdefFilter &filter, + QObject *object, const char *method); + + bool unregisterNdefMessageHandler(int handlerId); + +Q_SIGNALS: + void targetDetected(QNearFieldTarget *target); + void targetLost(QNearFieldTarget *target); + void transactionDetected(const QByteArray &applicationIdentifier); + +private: + QNearFieldManagerPrivate *d_ptr; +}; + +template<typename T> +int QNearFieldManager::registerNdefMessageHandler(QObject *object, const char *method) +{ + T record; + + return registerNdefMessageHandler(record.userTypeNameFormat(), record.type(), + object, method); +} + +Q_DECLARE_OPERATORS_FOR_FLAGS(QNearFieldManager::TargetAccessModes) + +QT_END_HEADER + +#endif // QNEARFIELDMANAGER_H diff --git a/src/nfc/qnearfieldmanager_emulator.cpp b/src/nfc/qnearfieldmanager_emulator.cpp new file mode 100644 index 00000000..0f42437c --- /dev/null +++ b/src/nfc/qnearfieldmanager_emulator.cpp @@ -0,0 +1,102 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qnearfieldmanager_emulator_p.h" +#include "qnearfieldtarget_emulator_p.h" + +#include "qndefmessage.h" +#include "qtlv_p.h" + +#include <QtCore/QDebug> + +QNearFieldManagerPrivateImpl::QNearFieldManagerPrivateImpl() +{ + TagActivator *tagActivator = TagActivator::instance(); + + tagActivator->initialize(); + + connect(tagActivator, SIGNAL(tagActivated(TagBase*)), this, SLOT(tagActivated(TagBase*))); + connect(tagActivator, SIGNAL(tagDeactivated(TagBase*)), this, SLOT(tagDeactivated(TagBase*))); +} + +QNearFieldManagerPrivateImpl::~QNearFieldManagerPrivateImpl() +{ +} + +bool QNearFieldManagerPrivateImpl::isAvailable() const +{ + return true; +} + +void QNearFieldManagerPrivateImpl::reset() +{ + TagActivator::instance()->reset(); +} + +void QNearFieldManagerPrivateImpl::tagActivated(TagBase *tag) +{ + QNearFieldTarget *target = m_targets.value(tag).data(); + if (!target) { + if (dynamic_cast<NfcTagType1 *>(tag)) + target = new TagType1(tag, this); + else if (dynamic_cast<NfcTagType2 *>(tag)) + target = new TagType2(tag, this); + else + qFatal("Unknown emulator tag type"); + + m_targets.insert(tag, target); + } + + targetActivated(target); +} + +void QNearFieldManagerPrivateImpl::tagDeactivated(TagBase *tag) +{ + QNearFieldTarget *target = m_targets.value(tag).data(); + if (!target) { + m_targets.remove(tag); + return; + } + + targetDeactivated(target); +} + + diff --git a/src/nfc/qnearfieldmanager_emulator_p.h b/src/nfc/qnearfieldmanager_emulator_p.h new file mode 100644 index 00000000..4d303991 --- /dev/null +++ b/src/nfc/qnearfieldmanager_emulator_p.h @@ -0,0 +1,76 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QNEARFIELDMANAGER_EMULATOR_H +#define QNEARFIELDMANAGER_EMULATOR_H + +#include "qnearfieldmanagervirtualbase_p.h" +#include "qnearfieldtarget.h" +#include "qndeffilter.h" + +#include <QtCore/QObject> +#include <QtCore/QWeakPointer> + +class TagBase; +class QNearFieldManagerPrivateImpl : public QNearFieldManagerPrivateVirtualBase +{ + Q_OBJECT + +public: + QNearFieldManagerPrivateImpl(); + ~QNearFieldManagerPrivateImpl(); + + bool isAvailable() const; + + void reset(); + +private slots: + void tagActivated(TagBase *tag); + void tagDeactivated(TagBase *tag); + +private: + void ndefReceived(const QNdefMessage &message, QNearFieldTarget *target); + + QMap<TagBase *, QWeakPointer<QNearFieldTarget> > m_targets; + +}; + +#endif // QNEARFIELDMANAGER_EMULATOR_H diff --git a/src/nfc/qnearfieldmanager_maemo6.cpp b/src/nfc/qnearfieldmanager_maemo6.cpp new file mode 100644 index 00000000..a8c21bac --- /dev/null +++ b/src/nfc/qnearfieldmanager_maemo6.cpp @@ -0,0 +1,449 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qnearfieldmanager_maemo6_p.h" +#include "qnearfieldtarget_maemo6_p.h" +#include "manager_interface.h" +#include "maemo6/adapter_interface_p.h" +#include "maemo6/target_interface_p.h" +#include "maemo6/tag_interface_p.h" +#include "ndefhandler_adaptor.h" +#include "accessrequestor_adaptor.h" + +#include <qnearfieldtagtype1.h> + +#include <QtDBus/QDBusConnection> + +using namespace com::nokia::nfc; + +static QAtomicInt handlerId = 0; +static const char * const registeredHandlerPath = "/com/nokia/nfc/ndefhandler"; +static const char * const accessRequesterPath = "/com/nokia/nfc/accessRequester/"; +static const char * const connectionUuid = "46a15ee4-b5ce-4395-9d76-c440cc3838c6"; + +static inline bool matchesTarget(QNearFieldTarget::Type type, + const QList<QNearFieldTarget::Type> &types) +{ + return types.contains(type) || types.contains(QNearFieldTarget::AnyTarget); +} + +NdefHandler::NdefHandler(QNearFieldManagerPrivateImpl *manager, const QString &serviceName, + const QString &path, QObject *object, const QMetaMethod &method) +: m_manager(manager), m_adaptor(0), m_object(object), m_method(method), + m_serviceName(serviceName), m_path(path) +{ + QDBusConnection handlerConnection = + QDBusConnection::connectToBus(QDBusConnection::SystemBus, connectionUuid); + if (serviceName != handlerConnection.baseService()) { + handlerConnection = QDBusConnection::connectToBus(QDBusConnection::SystemBus, serviceName); + + if (!handlerConnection.registerService(serviceName)) + return; + } + + m_adaptor = new NDEFHandlerAdaptor(this); + + if (!handlerConnection.registerObject(path, this)) { + delete m_adaptor; + m_adaptor = 0; + } +} + +NdefHandler::~NdefHandler() +{ + delete m_adaptor; +} + +bool NdefHandler::isValid() const +{ + return m_adaptor; +} + +QString NdefHandler::serviceName() const +{ + return m_serviceName; +} + +QString NdefHandler::path() const +{ + return m_path; +} + +void NdefHandler::NDEFData(const QDBusObjectPath &target, const QByteArray &message) +{ + m_method.invoke(m_object, Q_ARG(QNdefMessage, QNdefMessage::fromByteArray(message)), + Q_ARG(QNearFieldTarget *, m_manager->targetForPath(target.path()))); +} + +QNearFieldManagerPrivateImpl::QNearFieldManagerPrivateImpl() +: m_connection(QDBusConnection::connectToBus(QDBusConnection::SystemBus, + QLatin1String(connectionUuid))), + m_accessAgent(0) +{ + qDBusRegisterMetaType<QList<QByteArray> >(); + + m_manager = new Manager(QLatin1String("com.nokia.nfc"), QLatin1String("/"), m_connection); + + QDBusObjectPath defaultAdapterPath = m_manager->DefaultAdapter(); + + m_adapter = new Adapter(QLatin1String("com.nokia.nfc"), defaultAdapterPath.path(), + m_connection); + + if (!m_adapter->isValid()) + return; +} + +QNearFieldManagerPrivateImpl::~QNearFieldManagerPrivateImpl() +{ + foreach (int id, m_registeredHandlers.keys()) + unregisterNdefMessageHandler(id); + + delete m_manager; + delete m_adapter; +} + +bool QNearFieldManagerPrivateImpl::isAvailable() const +{ + return m_manager->isValid(); +} + +bool QNearFieldManagerPrivateImpl::startTargetDetection(const QList<QNearFieldTarget::Type> &targetTypes) +{ + m_detectTargetTypes = targetTypes; + + connect(m_adapter, SIGNAL(TargetDetected(QDBusObjectPath)), + this, SLOT(_q_targetDetected(QDBusObjectPath))); + connect(m_adapter, SIGNAL(TargetLost(QDBusObjectPath)), + this, SLOT(_q_targetLost(QDBusObjectPath))); + + return true; +} + +void QNearFieldManagerPrivateImpl::stopTargetDetection() +{ + m_detectTargetTypes.clear(); + + disconnect(m_adapter, SIGNAL(TargetDetected(QDBusObjectPath)), + this, SLOT(_q_targetDetected(QDBusObjectPath))); + disconnect(m_adapter, SIGNAL(TargetLost(QDBusObjectPath)), + this, SLOT(_q_targetLost(QDBusObjectPath))); +} + +QNearFieldTarget *QNearFieldManagerPrivateImpl::targetForPath(const QString &path) +{ + QNearFieldTarget *nearFieldTarget = m_targets.value(path).data(); + + if (!nearFieldTarget) { + Target *target = new Target(QLatin1String("com.nokia.nfc"), path, m_connection); + + const QString type = target->type(); + + if (type == QLatin1String("tag")) { + Tag *tag = new Tag(QLatin1String("com.nokia.nfc"), path, m_connection); + + const QString tagTechnology = tag->technology(); + if (tagTechnology == QLatin1String("jewel")) + nearFieldTarget = new TagType1(this, target, tag); + else if (tagTechnology == QLatin1String("mifare-ul")) + nearFieldTarget = new TagType2(this, target, tag); + else if (tagTechnology == QLatin1String("felica")) + nearFieldTarget = new TagType3(this, target, tag); + else if (tagTechnology == QLatin1String("iso-4a")) + nearFieldTarget = new TagType4(this, target, tag); + else + nearFieldTarget = new NearFieldTarget<QNearFieldTarget>(this, target, tag); + } else if (type == QLatin1String("device")) { + Device *device = new Device(QLatin1String("com.nokia.nfc"), path, m_connection); + nearFieldTarget = new NearFieldTarget<QNearFieldTarget>(this, target, device); + } + + if (nearFieldTarget) + m_targets.insert(path, nearFieldTarget); + } + + return nearFieldTarget; +} + +int QNearFieldManagerPrivateImpl::registerNdefMessageHandler(const QString &filter, + QObject *object, + const QMetaMethod &method) +{ + int id = handlerId.fetchAndAddOrdered(1); + const QString handlerPath = + QLatin1String(registeredHandlerPath) + QLatin1Char('/') + QString::number(id); + + NdefHandler *handler = new NdefHandler(this, m_connection.baseService(), + handlerPath, object, method); + if (!handler->isValid()) { + delete handler; + return -1; + } + + QDBusPendingReply<> reply = + m_manager->RegisterNDEFHandler(QLatin1String("system"), + m_connection.baseService(), + QDBusObjectPath(handlerPath), + QLatin1String("any"), + filter, + QCoreApplication::applicationName()); + + if (reply.isError()) { + delete handler; + return -1; + } + + m_registeredHandlers[id] = handler; + + return id; +} + +int QNearFieldManagerPrivateImpl::registerNdefMessageHandler(QObject *object, + const QMetaMethod &method) +{ + QFileInfo fi(qApp->applicationFilePath()); + const QString serviceName = QLatin1String("com.nokia.qt.nfc.") + fi.baseName(); + + int id = handlerId.fetchAndAddOrdered(1); + + const QString handlerPath = QLatin1String(registeredHandlerPath); + + NdefHandler *handler = new NdefHandler(this, serviceName, handlerPath, object, method); + if (!handler->isValid()) { + delete handler; + return -1; + } + + m_registeredHandlers[id] = handler; + + return id; +} + +int QNearFieldManagerPrivateImpl::registerNdefMessageHandler(const QNdefFilter &filter, + QObject *object, + const QMetaMethod &method) +{ + QString matchString; + + if (filter.orderMatch()) + matchString += QLatin1String("sequence:"); + else + matchString += QLatin1String("unordered:"); + + for (int i = 0; i < filter.recordCount(); ++i) { + QNdefFilter::Record record = filter.recordAt(i); + + QString type; + + switch (record.typeNameFormat) { + case QNdefRecord::NfcRtd: + type = QLatin1String("urn:nfc:wkt:") + record.type; + break; + case QNdefRecord::ExternalRtd: + type = QLatin1String("urn:nfc:ext:") + record.type; + break; + case QNdefRecord::Mime: + type = record.type; + break; + default: + qWarning("Unsupported filter type"); + return -1; + } + + matchString += QLatin1Char('\'') + type + QLatin1Char('\''); + matchString += QLatin1Char('['); + + if (record.minimum == UINT_MAX) + matchString += QLatin1Char('*'); + else + matchString += QString::number(record.minimum); + + matchString += QLatin1Char(':'); + + if (record.maximum == UINT_MAX) + matchString += QLatin1Char('*'); + else + matchString += QString::number(record.maximum); + + matchString += QLatin1Char(']'); + + if (i == filter.recordCount() - 1) + matchString += QLatin1Char(';'); + else + matchString += QLatin1Char(','); + } + + return registerNdefMessageHandler(matchString, object, method); +} + +bool QNearFieldManagerPrivateImpl::unregisterNdefMessageHandler(int id) +{ + if (id < 0) + return false; + + NdefHandler *handler = m_registeredHandlers.take(id); + + QDBusPendingReply<> reply = m_manager->UnregisterNDEFHandler(QLatin1String("system"), + handler->serviceName(), + QDBusObjectPath(handler->path())); + + delete handler; + + return true; +} + +static QStringList accessModesToKind(QNearFieldManager::TargetAccessModes accessModes) +{ + QStringList kind; + + if (accessModes & QNearFieldManager::NdefReadTargetAccess) + kind.append(QLatin1String("tag.ndef.read")); + + if (accessModes & QNearFieldManager::NdefWriteTargetAccess) + kind.append(QLatin1String("tag.ndef.write")); + + if (accessModes & QNearFieldManager::TagTypeSpecificTargetAccess) + kind.append(QLatin1String("tag.raw")); + + return kind; +} + +void QNearFieldManagerPrivateImpl::requestAccess(QNearFieldManager::TargetAccessModes accessModes) +{ + const QString requesterPath = + QLatin1String(accessRequesterPath) + QString::number(quintptr(this)); + + if (!m_accessAgent) { + m_accessAgent = new AccessRequestorAdaptor(this); + if (!m_connection.registerObject(requesterPath, this)) { + delete m_accessAgent; + m_accessAgent = 0; + return; + } + } + + foreach (const QString &kind, accessModesToKind(accessModes)) + m_adapter->RequestAccess(QDBusObjectPath(requesterPath), kind); + + QNearFieldManagerPrivate::requestAccess(accessModes); +} + +void QNearFieldManagerPrivateImpl::releaseAccess(QNearFieldManager::TargetAccessModes accessModes) +{ + const QString requesterPath = + QLatin1String(accessRequesterPath) + QString::number(quintptr(this)); + + foreach (const QString &kind, accessModesToKind(accessModes)) + m_adapter->CancelAccessRequest(QDBusObjectPath(requesterPath), kind); + + QNearFieldManagerPrivate::releaseAccess(accessModes); +} + +void QNearFieldManagerPrivateImpl::AccessFailed(const QDBusObjectPath &target, const QString &kind, + const QString &error) +{ + qDebug() << "Access for" << target.path() << kind << "failed with error:" << error; +} + +void QNearFieldManagerPrivateImpl::AccessGranted(const QDBusObjectPath &target, + const QString &kind) +{ + Q_UNUSED(kind); + + if (m_pendingDetectedTargets.contains(target.path())) { + m_pendingDetectedTargets[target.path()].stop(); + m_pendingDetectedTargets.remove(target.path()); + } + + emitTargetDetected(target.path()); +} + +void QNearFieldManagerPrivateImpl::timerEvent(QTimerEvent *event) +{ + QMutableMapIterator<QString, QBasicTimer> i(m_pendingDetectedTargets); + while (i.hasNext()) { + i.next(); + + if (i.value().timerId() == event->timerId()) { + i.value().stop(); + + const QString target = i.key(); + + i.remove(); + + emitTargetDetected(target); + + break; + } + } +} + +void QNearFieldManagerPrivateImpl::emitTargetDetected(const QString &targetPath) +{ + QNearFieldTarget *target = targetForPath(targetPath); + if (target && matchesTarget(target->type(), m_detectTargetTypes)) + emit targetDetected(target); +} + +void QNearFieldManagerPrivateImpl::_q_targetDetected(const QDBusObjectPath &targetPath) +{ + if (!m_requestedModes) + emitTargetDetected(targetPath.path()); + else + m_pendingDetectedTargets[targetPath.path()].start(500, this); +} + +void QNearFieldManagerPrivateImpl::_q_targetLost(const QDBusObjectPath &targetPath) +{ + QNearFieldTarget *nearFieldTarget = m_targets.value(targetPath.path()).data(); + + // haven't seen target so just drop this event + if (!nearFieldTarget) { + // We either haven't seen target (started after target was detected by system) or the + // application deleted the target. Remove from map and don't emit anything. + m_targets.remove(targetPath.path()); + return; + } + + if (matchesTarget(nearFieldTarget->type(), m_detectTargetTypes)) + emit targetLost(nearFieldTarget); +} + +#include "moc_qnearfieldmanager_maemo6_p.cpp" diff --git a/src/nfc/qnearfieldmanager_maemo6_p.h b/src/nfc/qnearfieldmanager_maemo6_p.h new file mode 100644 index 00000000..f342398a --- /dev/null +++ b/src/nfc/qnearfieldmanager_maemo6_p.h @@ -0,0 +1,144 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QNEARFIELDMANAGER_MAEMO6_P_H +#define QNEARFIELDMANAGER_MAEMO6_P_H + +#include "qnearfieldmanager_p.h" +#include "qnearfieldmanager.h" +#include "qnearfieldtarget.h" + +#include <QtCore/QWeakPointer> +#include <QtCore/QMap> +#include <QtCore/QPair> +#include <QtCore/QMetaMethod> +#include <QtCore/QBasicTimer> + +#include <QtDBus/QDBusConnection> + +QT_FORWARD_DECLARE_CLASS(QDBusObjectPath) + +class ComNokiaNfcManagerInterface; +class ComNokiaNfcAdapterInterface; +class NDEFHandlerAdaptor; +class AccessRequestorAdaptor; + +class QNearFieldManagerPrivateImpl; + +class NdefHandler : public QObject +{ + Q_OBJECT + +public: + NdefHandler(QNearFieldManagerPrivateImpl *manager, const QString &serviceName, + const QString &path, QObject *object, const QMetaMethod &method); + ~NdefHandler(); + + bool isValid() const; + + QString serviceName() const; + QString path() const; + +private: + Q_INVOKABLE void NDEFData(const QDBusObjectPath &target, const QByteArray &message); + + QNearFieldManagerPrivateImpl *m_manager; + NDEFHandlerAdaptor *m_adaptor; + QObject *m_object; + QMetaMethod m_method; + QString m_serviceName; + QString m_path; +}; + +class QNearFieldManagerPrivateImpl : public QNearFieldManagerPrivate +{ + Q_OBJECT + +public: + QNearFieldManagerPrivateImpl(); + ~QNearFieldManagerPrivateImpl(); + + bool isAvailable() const; + + bool startTargetDetection(const QList<QNearFieldTarget::Type> &targetTypes); + void stopTargetDetection(); + + QNearFieldTarget *targetForPath(const QString &path); + + int registerNdefMessageHandler(const QString &filter, + QObject *object, const QMetaMethod &method); + int registerNdefMessageHandler(QObject *object, const QMetaMethod &method); + int registerNdefMessageHandler(const QNdefFilter &filter, + QObject *object, const QMetaMethod &method); + bool unregisterNdefMessageHandler(int handlerId); + + void requestAccess(QNearFieldManager::TargetAccessModes accessModes); + void releaseAccess(QNearFieldManager::TargetAccessModes accessModes); + + // Access Agent Adaptor + Q_INVOKABLE void AccessFailed(const QDBusObjectPath &target, const QString &kind, + const QString &error); + Q_INVOKABLE void AccessGranted(const QDBusObjectPath &target, const QString &kind); + +protected: + void timerEvent(QTimerEvent *event); + +private slots: + void emitTargetDetected(const QString &targetPath); + void _q_targetDetected(const QDBusObjectPath &targetPath); + void _q_targetLost(const QDBusObjectPath &targetPath); + +private: + QDBusConnection m_connection; + ComNokiaNfcManagerInterface *m_manager; + ComNokiaNfcAdapterInterface *m_adapter; + + QList<QNearFieldTarget::Type> m_detectTargetTypes; + QMap<QString, QWeakPointer<QNearFieldTarget> > m_targets; + + AccessRequestorAdaptor *m_accessAgent; + + QMap<int, NdefHandler *> m_registeredHandlers; + + QMap<QString, QBasicTimer> m_pendingDetectedTargets; +}; + +#endif // QNEARFIELDMANAGER_MAEMO6_P_H diff --git a/src/nfc/qnearfieldmanager_p.h b/src/nfc/qnearfieldmanager_p.h new file mode 100644 index 00000000..648a1978 --- /dev/null +++ b/src/nfc/qnearfieldmanager_p.h @@ -0,0 +1,129 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QNEARFIELDMANAGER_P_H +#define QNEARFIELDMANAGER_P_H + +#include "qnearfieldmanager.h" +#include "qnearfieldtarget.h" +#include "qndefrecord.h" + +#include "../qtconnectivityglobal.h" + +#include <QtCore/QObject> + +QT_BEGIN_HEADER + +class QNdefFilter; + +class QM_AUTOTEST_EXPORT QNearFieldManagerPrivate : public QObject +{ + Q_OBJECT + +public: + explicit QNearFieldManagerPrivate(QObject *parent = 0) + : QObject(parent) + { + } + + ~QNearFieldManagerPrivate() + { + } + + virtual bool isAvailable() const + { + return false; + } + + virtual bool startTargetDetection(const QList<QNearFieldTarget::Type> &targetTypes) + { + Q_UNUSED(targetTypes); + + return false; + } + + virtual void stopTargetDetection() + { + } + + virtual int registerNdefMessageHandler(QObject *object, const QMetaMethod &/*method*/) + { + Q_UNUSED(object); + + return -1; + } + + virtual int registerNdefMessageHandler(const QNdefFilter &/*filter*/, + QObject *object, const QMetaMethod &/*method*/) + { + Q_UNUSED(object); + + return -1; + } + + virtual bool unregisterNdefMessageHandler(int handlerId) + { + Q_UNUSED(handlerId); + + return false; + } + + virtual void requestAccess(QNearFieldManager::TargetAccessModes accessModes) + { + m_requestedModes |= accessModes; + } + + virtual void releaseAccess(QNearFieldManager::TargetAccessModes accessModes) + { + m_requestedModes &= ~accessModes; + } + +signals: + void targetDetected(QNearFieldTarget *target); + void targetLost(QNearFieldTarget *target); + +public: + QNearFieldManager::TargetAccessModes m_requestedModes; +}; + +QT_END_HEADER + +#endif // QNEARFIELDMANAGER_P_H diff --git a/src/nfc/qnearfieldmanager_simulator.cpp b/src/nfc/qnearfieldmanager_simulator.cpp new file mode 100644 index 00000000..1d7f5318 --- /dev/null +++ b/src/nfc/qnearfieldmanager_simulator.cpp @@ -0,0 +1,204 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qnearfieldmanager_simulator_p.h" +#include "qnearfieldmanager.h" +#include "qnearfieldtarget_p.h" +#include "qnearfieldtagtype1.h" +#include "qndefmessage.h" + +#include <mobilityconnection_p.h> +#include <QtGui/private/qsimulatordata_p.h> + +#include <QtCore/QCoreApplication> + +using namespace QtSimulatorPrivate; + +namespace Simulator { + +class TagType1 : public QNearFieldTagType1 +{ +public: + TagType1(const QByteArray &uid, QObject *parent); + ~TagType1(); + + QByteArray uid() const; + + AccessMethods accessMethods() const; + + RequestId sendCommand(const QByteArray &command); + bool waitForRequestCompleted(const RequestId &id, int msecs = 5000); + +private: + QByteArray m_uid; +}; + +TagType1::TagType1(const QByteArray &uid, QObject *parent) +: QNearFieldTagType1(parent), m_uid(uid) +{ +} + +TagType1::~TagType1() +{ +} + +QByteArray TagType1::uid() const +{ + return m_uid; +} + +QNearFieldTarget::AccessMethods TagType1::accessMethods() const +{ + return NdefAccess | TagTypeSpecificAccess; +} + +QNearFieldTarget::RequestId TagType1::sendCommand(const QByteArray &command) +{ + quint16 crc = qNfcChecksum(command.constData(), command.length()); + + RequestId id(new RequestIdPrivate); + + MobilityConnection *connection = MobilityConnection::instance(); + QByteArray response = + RemoteMetacall<QByteArray>::call(connection->sendSocket(), WaitSync, "nfcSendCommand", + command + char(crc & 0xff) + char(crc >> 8)); + + if (response.isEmpty()) { + QMetaObject::invokeMethod(this, "error", Qt::QueuedConnection, + Q_ARG(QNearFieldTarget::Error, NoResponseError), + Q_ARG(QNearFieldTarget::RequestId, id)); + return id; + } + + // check crc + if (qNfcChecksum(response.constData(), response.length()) != 0) { + QMetaObject::invokeMethod(this, "error", Qt::QueuedConnection, + Q_ARG(QNearFieldTarget::Error, ChecksumMismatchError), + Q_ARG(QNearFieldTarget::RequestId, id)); + return id; + } + + response.chop(2); + + QMetaObject::invokeMethod(this, "handleResponse", Qt::QueuedConnection, + Q_ARG(QNearFieldTarget::RequestId, id), Q_ARG(QByteArray, response)); + + return id; +} + +bool TagType1::waitForRequestCompleted(const RequestId &id, int msecs) +{ + QCoreApplication::sendPostedEvents(this, QEvent::MetaCall); + + return QNearFieldTagType1::waitForRequestCompleted(id, msecs); +} + +class NfcConnection : public QObject +{ + Q_OBJECT + +public: + NfcConnection(); + virtual ~NfcConnection(); + +signals: + void targetEnteringProximity(const QByteArray &uid); + void targetLeavingProximity(const QByteArray &uid); +}; + +NfcConnection::NfcConnection() +: QObject(MobilityConnection::instance()) +{ + MobilityConnection *connection = MobilityConnection::instance(); + connection->addMessageHandler(this); + + RemoteMetacall<void>::call(connection->sendSocket(), NoSync, "setRequestsNfc"); +} + +NfcConnection::~NfcConnection() +{ +} + +} + +QNearFieldManagerPrivateImpl::QNearFieldManagerPrivateImpl() +: nfcConnection(new Simulator::NfcConnection) +{ + connect(nfcConnection, SIGNAL(targetEnteringProximity(QByteArray)), + this, SLOT(targetEnteringProximity(QByteArray))); + connect(nfcConnection, SIGNAL(targetLeavingProximity(QByteArray)), + this, SLOT(targetLeavingProximity(QByteArray))); +} + +QNearFieldManagerPrivateImpl::~QNearFieldManagerPrivateImpl() +{ + delete nfcConnection; +} + +bool QNearFieldManagerPrivateImpl::isAvailable() const +{ + return true; +} + +void QNearFieldManagerPrivateImpl::targetEnteringProximity(const QByteArray &uid) +{ + QNearFieldTarget *target = m_targets.value(uid).data(); + if (!target) { + target = new Simulator::TagType1(uid, this); + m_targets.insert(uid, target); + } + + targetActivated(target); +} + +void QNearFieldManagerPrivateImpl::targetLeavingProximity(const QByteArray &uid) +{ + QNearFieldTarget *target = m_targets.value(uid).data(); + if (!target) { + m_targets.remove(uid); + return; + } + + targetDeactivated(target); +} + +#include "qnearfieldmanager_simulator.moc" +#include "moc_qnearfieldmanager_simulator_p.cpp" diff --git a/src/nfc/qnearfieldmanager_simulator_p.h b/src/nfc/qnearfieldmanager_simulator_p.h new file mode 100644 index 00000000..a55f3e94 --- /dev/null +++ b/src/nfc/qnearfieldmanager_simulator_p.h @@ -0,0 +1,76 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QNEARFIELDMANAGER_SIMULATOR_P_H +#define QNEARFIELDMANAGER_SIMULATOR_P_H + +#include "qnearfieldmanagervirtualbase_p.h" + +#include <QtCore/QWeakPointer> + +QT_BEGIN_HEADER + +namespace Simulator { +class NfcConnection; +} + +class QNearFieldManagerPrivateImpl : public QNearFieldManagerPrivateVirtualBase +{ + Q_OBJECT + +public: + QNearFieldManagerPrivateImpl(); + ~QNearFieldManagerPrivateImpl(); + + bool isAvailable() const; + +private slots: + void targetEnteringProximity(const QByteArray &uid); + void targetLeavingProximity(const QByteArray &uid); + +private: + Simulator::NfcConnection *nfcConnection; + QMap<QByteArray, QWeakPointer<QNearFieldTarget> > m_targets; +}; + +QT_END_HEADER + +#endif // QNEARFIELDMANAGER_SIMULATOR_P_H diff --git a/src/nfc/qnearfieldmanager_symbian.cpp b/src/nfc/qnearfieldmanager_symbian.cpp new file mode 100644 index 00000000..8492d526 --- /dev/null +++ b/src/nfc/qnearfieldmanager_symbian.cpp @@ -0,0 +1,385 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <qservicefilter.h> +#include <qservicemanager.h> +#include <QCoreApplication> +#include <ndefmessage.h> + +#include "qnearfieldmanager_symbian_p.h" +#include "qndefmessage.h" +#include "symbian/nearfieldmanager_symbian.h" +#include "symbian/debug.h" +#include "symbian/nearfieldutility_symbian.h" + +Proxy contentHandlerProxy; + +Proxy::Proxy(QObject* parent) : QObject (parent) +{ +} + +ContentHandlerInterface::ContentHandlerInterface(QObject* parent) + : QObject(parent) +{ +} +void ContentHandlerInterface::handleMessage(const QByteArray& btArray) +{ + // incoming message from ECOM content handler loader eventually cause object & method registered via below + // registerNdefMessageHandler to be invoked with message as parameter. i.e. MyContentHandler::handleMessage(message) + // from above. + + + QNdefMessage msg = QNdefMessage::fromByteArray(btArray); + QMetaObject::invokeMethod(&contentHandlerProxy, "handleMessage", Q_ARG(QNdefMessage, msg)); + + +} +/* + \class QNearFieldManagerPrivateImpl + \brief The QNearFieldManagerPrivateImpl class provides symbian backend access to NFC service. + + \ingroup connectivity-nfc + \inmodule QtConnectivity + + A Qt-Symbian wrapper implementation class to support symbian NFC backend. +*/ + +/* + Constructs a new near field manager private implementation. +*/ +QNearFieldManagerPrivateImpl::QNearFieldManagerPrivateImpl(): m_symbianbackend(NULL),m_target(NULL),m_serviceRegister(NULL) +{ + BEGIN + TRAPD(err, m_symbianbackend = CNearFieldManager::NewL(*this)); + END +} + +/* + Destroys the near field manager private implementation. +*/ +QNearFieldManagerPrivateImpl::~QNearFieldManagerPrivateImpl() +{ + BEGIN + delete m_target; + qDeleteAll(m_targetList); + delete m_serviceRegister; + delete m_symbianbackend; + END +} + +bool QNearFieldManagerPrivateImpl::isAvailable() const +{ + return m_symbianbackend; +} + +/* + Helper function to get the free handler id. +*/ +int QNearFieldManagerPrivateImpl::getFreeId() +{ + BEGIN + if (!m_freeIds.isEmpty()) + return m_freeIds.takeFirst(); + + m_registeredHandlers.append(Callback()); + END + return m_registeredHandlers.count() - 1; +} + +/* + Registers \a object to receive notifications on \a method when a tag with a tag type of + \a targetType has been detected and has an NDEF message is detected. The + \a method on \a object should have the prototype + 'void targetDetected(const QNdefMessage &message, QNearFieldTarget *target)'. + + Returns an identifier, which can be used to unregister the handler, on success; otherwise + returns -1. +*/ +int QNearFieldManagerPrivateImpl::registerNdefMessageHandler(QObject *object, + const QMetaMethod &method) +{ + QServiceFilter filter("com.nokia.qt.nfc.NdefMessageHandler"); + QCoreApplication* app = QCoreApplication::instance(); + //The appfile path will return something like \sys\bin\nfcspserviceprovider.exe + //but we only need nfcspserviceprovider as service name + QString appfilepath = app->applicationFilePath(); + TInt lastseprator = appfilepath.lastIndexOf("\\"); + TInt lastdot = appfilepath.lastIndexOf("."); + QString servicename = appfilepath.mid(lastseprator+1, lastdot-lastseprator-1); + qDebug() << "application name: " << servicename << endl; + + filter.setServiceName(servicename); + QServiceManager sfManager; + + if (!sfManager.findInterfaces(filter).isEmpty()) + { + // This application has been registered as a content handler (via the xml at install time), start the service + m_chobject = object; + m_chmethod = method; + + connect(&contentHandlerProxy, SIGNAL(handleMessage(QNdefMessage)), + this, SLOT(_q_privateHandleMessageSlot(QNdefMessage))); + if ( !m_serviceRegister ) + { + m_serviceRegister = new QRemoteServiceRegister(); + QRemoteServiceRegister::Entry entry = + m_serviceRegister->createEntry<ContentHandlerInterface>(servicename, + "com.nokia.qt.nfc.NdefMessageHandler", + "1.0"); + entry.setInstantiationType(QRemoteServiceRegister::PrivateInstance); + m_serviceRegister->publishEntries(servicename); + } + return 0xffff; + + } else { + // not supported if not registered as a content handler using this API + return -1; + } +} + +/* + Registers \a object to receive notifications on \a method when a tag with a tag type of + \a targetType has been detected and has an NDEF message that matches \a filter is detected. The + \a method on \a object should have the prototype + 'void targetDetected(const QNdefMessage &message, QNearFieldTarget *target)'. + + Returns an identifier, which can be used to unregister the handler, on success; otherwise + returns -1. +*/ +int QNearFieldManagerPrivateImpl::registerNdefMessageHandler(const QNdefFilter &filter, + QObject *object, + const QMetaMethod &method) +{ + if (!m_symbianbackend) + return -1; + + BEGIN + int id = getFreeId(); + + Callback &callback = m_registeredHandlers[id]; + + callback.filter = filter; + callback.object = object; + callback.method = method; + + for( int i = 0; i < filter.recordCount(); ++i) + { + QNdefRecord::TypeNameFormat tnf = filter.recordAt(i).typeNameFormat; + QByteArray type = filter.recordAt(i).type; + if (m_symbianbackend->AddNdefSubscription( tnf, type ) < 0) + { + for (int j = 0; j < i; ++j)//rollback the previous subscriptions + { + QNdefRecord::TypeNameFormat n = filter.recordAt(j).typeNameFormat; + QByteArray t = filter.recordAt(j).type; + m_symbianbackend->RemoveNdefSubscription( n, t ); + } + m_freeIds.append(id);//push back the id to freeid list + END + return -1; + } + } + END + return id; +} + +/* + Unregisters the target detect handler identified by \a id. + + Returns true on success; otherwise returns false. +*/ +bool QNearFieldManagerPrivateImpl::unregisterNdefMessageHandler(int id) +{ + if (!m_symbianbackend) + return false; + + BEGIN + if ( 0xffff == id ) + { + disconnect(&contentHandlerProxy, SIGNAL(handleMessage(QNdefMessage)), + this, SLOT(_q_privateHandleMessageSlot(QNdefMessage))); + return true; + } + if (id < 0 || id >= m_registeredHandlers.count() || m_freeIds.contains(id)) + return false; + + m_freeIds.append(id); + + for ( int i = 0; i < m_registeredHandlers[id].filter.recordCount(); ++i) + { + QNdefRecord::TypeNameFormat tnf = m_registeredHandlers[id].filter.recordAt(i).typeNameFormat; + QByteArray type = m_registeredHandlers[id].filter.recordAt(i).type; + m_symbianbackend->RemoveNdefSubscription( tnf, type ); + } + + while (m_freeIds.contains(m_registeredHandlers.count() - 1)) { + m_freeIds.removeAll(m_registeredHandlers.count() - 1); + m_registeredHandlers.removeLast(); + } + END + return true; +} + +bool QNearFieldManagerPrivateImpl::startTargetDetection(const QList<QNearFieldTarget::Type> &targetTypes) +{ + if (!m_symbianbackend) + return false; + + BEGIN + TRAPD(err, m_symbianbackend->StartTargetDetectionL(targetTypes)); + END + return err == KErrNone; +} + +void QNearFieldManagerPrivateImpl::stopTargetDetection() +{ + BEGIN + if (m_symbianbackend) + m_symbianbackend->stopTargetDetection(); + END +} + +struct VerifyRecord +{ + QNdefFilter::Record filterRecord; + unsigned int count; +}; + +/* + Callback function when symbian NFC backend found the NFC \a target. +*/ +void QNearFieldManagerPrivateImpl::targetFound(QNearFieldTarget *target) +{ + BEGIN + if (!target){ + return; + } + if (m_target){ + m_targetList.append(m_target); + } + m_target = target; + emit targetDetected(target); + END +} + +/* + * Private slot to be invoked by QT content handler loader + */ +void QNearFieldManagerPrivateImpl::_q_privateHandleMessageSlot(QNdefMessage aMsg) + { + + m_chmethod.invoke(m_chobject, Q_ARG(QNdefMessage, aMsg), Q_ARG(QNearFieldTarget* , NULL)); + } + +/* + Helper function to invoke the filtered TargetDetectedHandler for a found \a target. +*/ + +void QNearFieldManagerPrivateImpl::invokeNdefMessageHandler(const QNdefMessage msg) +{ + BEGIN + for (int i = 0; i < m_registeredHandlers.count(); ++i) { + if (m_freeIds.contains(i)) + continue; + Callback &callback = m_registeredHandlers[i]; + bool matched = true; + QList<VerifyRecord> filterRecords; + for (int j = 0; j < callback.filter.recordCount(); ++j) { + VerifyRecord vr; + vr.count = 0; + vr.filterRecord = callback.filter.recordAt(j); + filterRecords.append(vr); + } + + foreach (const QNdefRecord &record, msg) { + for (int j = 0; matched && (j < filterRecords.count()); ++j) { + VerifyRecord &vr = filterRecords[j]; + + if (vr.filterRecord.typeNameFormat == record.typeNameFormat() && + vr.filterRecord.type == record.type()) { + ++vr.count; + break; + } else { + if (callback.filter.orderMatch()) { + if (vr.filterRecord.minimum <= vr.count && + vr.count <= vr.filterRecord.maximum) { + continue; + } else { + matched = false; + } + } + } + } + }//end of foreach (const QNdefRecord &record, msg) { + + for (int j = 0; matched && (j < filterRecords.count()); ++j) { + const VerifyRecord &vr = filterRecords.at(j); + + if (vr.filterRecord.minimum <= vr.count && vr.count <= vr.filterRecord.maximum) + continue; + else + matched = false; + } + + if (matched) { + callback.method.invoke(callback.object, Q_ARG(QNdefMessage, msg), + Q_ARG(QNearFieldTarget *, NULL)); + } + + } + END +} + +/* + Callback function when symbian NFC backend lost the NFC \a target. +*/ +void QNearFieldManagerPrivateImpl::targetDisconnected() +{ + BEGIN + if (m_target) + { + QMetaObject::invokeMethod(m_target, "disconnected"); + emit targetLost(m_target); + } + END +} + +#include "moc_qnearfieldmanager_symbian_p.cpp" diff --git a/src/nfc/qnearfieldmanager_symbian_p.h b/src/nfc/qnearfieldmanager_symbian_p.h new file mode 100644 index 00000000..d1df3397 --- /dev/null +++ b/src/nfc/qnearfieldmanager_symbian_p.h @@ -0,0 +1,135 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QNEARFIELDMANAGER_SYMBIAN_P_H_ +#define QNEARFIELDMANAGER_SYMBIAN_P_H_ + + +#include "qnearfieldmanager_p.h" +#include "qnearfieldtarget.h" +#include "qndeffilter.h" + +#include <QtCore/QObject> +#include <QtCore/QMetaMethod> +#include <QPointer> +#include <QList> +#include <qremoteserviceregister.h> + +class CNearFieldManager; +class CNdefMessage; + +QT_BEGIN_HEADER + +class Proxy : public QObject +{ + Q_OBJECT +public: + Proxy(QObject* parent = 0); + +Q_SIGNALS: + void handleMessage(const QNdefMessage& message); +}; + +class ContentHandlerInterface : public QObject +{ + Q_OBJECT +public: + ContentHandlerInterface(QObject* parent = 0); + +public slots: + void handleMessage(const QByteArray& message); +}; + +class QNearFieldManagerPrivateImpl : public QNearFieldManagerPrivate +{ + Q_OBJECT + +public: + QNearFieldManagerPrivateImpl(); + ~QNearFieldManagerPrivateImpl(); + + bool isAvailable() const; + + int registerNdefMessageHandler(QObject *object, const QMetaMethod &method); + int registerNdefMessageHandler(const QNdefFilter &filter, + QObject *object, const QMetaMethod &method); + + bool unregisterNdefMessageHandler(int id); + + bool startTargetDetection(const QList<QNearFieldTarget::Type> &targetTypes); + void stopTargetDetection(); + +public://call back function by symbian backend implementation + void targetFound(QNearFieldTarget* target); + void targetDisconnected(); + +public://call back function by symbian backend implementation + void invokeNdefMessageHandler(const QNdefMessage msg); + + +private slots: + void _q_privateHandleMessageSlot(QNdefMessage msg); + +private: + struct Callback { + QNdefFilter filter; + QObject *object; + QMetaMethod method; + }; + + int getFreeId(); + + QList<Callback> m_registeredHandlers; + QList<int> m_freeIds; + + CNearFieldManager* m_symbianbackend; + + QPointer<QNearFieldTarget> m_target; + QList<QPointer<QNearFieldTarget> > m_targetList; + //For content handler purpose; + QObject *m_chobject; + QMetaMethod m_chmethod; + + QRemoteServiceRegister* m_serviceRegister ; +}; + +QT_END_HEADER +#endif /* QNEARFIELDMANAGER_SYMBIAN_P_H_ */ diff --git a/src/nfc/qnearfieldmanagerimpl_p.cpp b/src/nfc/qnearfieldmanagerimpl_p.cpp new file mode 100644 index 00000000..24609b30 --- /dev/null +++ b/src/nfc/qnearfieldmanagerimpl_p.cpp @@ -0,0 +1,61 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QCoreApplication> + +#include "qnearfieldmanagerimpl_p.h" + + +/* + Constructs a new near field manager private implementation. +*/ +QNearFieldManagerPrivateImpl::QNearFieldManagerPrivateImpl() +{ +} + +/* + Destroys the near field manager private implementation. +*/ +QNearFieldManagerPrivateImpl::~QNearFieldManagerPrivateImpl() +{ +} +//#include "moc_qnearfieldmanagerimpl_p.cpp" + diff --git a/src/nfc/qnearfieldmanagerimpl_p.h b/src/nfc/qnearfieldmanagerimpl_p.h new file mode 100644 index 00000000..fffcebd2 --- /dev/null +++ b/src/nfc/qnearfieldmanagerimpl_p.h @@ -0,0 +1,54 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QNEARFIELDMANAGERIMPL_P_H +#define QNEARFIELDMANAGERIMPL_P_H + +#include "qnearfieldmanager_p.h" + +class QNearFieldManagerPrivateImpl : public QNearFieldManagerPrivate +{ +public: + QNearFieldManagerPrivateImpl(); + ~QNearFieldManagerPrivateImpl(); +}; + +#endif // QNEARFIELDMANAGERIMPL_P_H diff --git a/src/nfc/qnearfieldmanagervirtualbase.cpp b/src/nfc/qnearfieldmanagervirtualbase.cpp new file mode 100644 index 00000000..84b88f2f --- /dev/null +++ b/src/nfc/qnearfieldmanagervirtualbase.cpp @@ -0,0 +1,215 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qnearfieldmanagervirtualbase_p.h" +#include "qndefmessage.h" +#include "qtlv_p.h" + +static inline bool matchesTarget(QNearFieldTarget::Type type, + const QList<QNearFieldTarget::Type> &types) +{ + return types.contains(type) || types.contains(QNearFieldTarget::AnyTarget); +} + +QNearFieldManagerPrivateVirtualBase::QNearFieldManagerPrivateVirtualBase() +{ +} + +QNearFieldManagerPrivateVirtualBase::~QNearFieldManagerPrivateVirtualBase() +{ +} + +bool QNearFieldManagerPrivateVirtualBase::startTargetDetection(const QList<QNearFieldTarget::Type> &targetTypes) +{ + m_detectTargetTypes = targetTypes; + return true; +} + +void QNearFieldManagerPrivateVirtualBase::stopTargetDetection() +{ + m_detectTargetTypes.clear(); +} + +int QNearFieldManagerPrivateVirtualBase::getFreeId() +{ + if (!m_freeIds.isEmpty()) + return m_freeIds.takeFirst(); + + m_registeredHandlers.append(Callback()); + return m_registeredHandlers.count() - 1; +} + +int QNearFieldManagerPrivateVirtualBase::registerNdefMessageHandler(QObject *object, + const QMetaMethod &method) +{ + int id = getFreeId(); + + Callback &callback = m_registeredHandlers[id]; + + callback.filter = QNdefFilter(); + callback.object = object; + callback.method = method; + + return id; +} + +int QNearFieldManagerPrivateVirtualBase::registerNdefMessageHandler(const QNdefFilter &filter, + QObject *object, + const QMetaMethod &method) +{ + int id = getFreeId(); + + Callback &callback = m_registeredHandlers[id]; + + callback.filter = filter; + callback.object = object; + callback.method = method; + + return id; +} + +bool QNearFieldManagerPrivateVirtualBase::unregisterNdefMessageHandler(int id) +{ + if (id < 0 || id >= m_registeredHandlers.count()) + return false; + + m_freeIds.append(id); + + while (m_freeIds.contains(m_registeredHandlers.count() - 1)) { + m_freeIds.removeAll(m_registeredHandlers.count() - 1); + m_registeredHandlers.removeLast(); + } + + return true; +} + +void QNearFieldManagerPrivateVirtualBase::targetActivated(QNearFieldTarget *target) +{ + if (matchesTarget(target->type(), m_detectTargetTypes)) + emit targetDetected(target); + + if (target->hasNdefMessage()) { + QTlvReader reader(target); + while (!reader.atEnd()) { + if (!reader.readNext()) { + if (!target->waitForRequestCompleted(reader.requestId())) + break; + else + continue; + } + + // NDEF Message TLV + if (reader.tag() == 0x03) + ndefReceived(QNdefMessage::fromByteArray(reader.data()), target); + } + } +} + +void QNearFieldManagerPrivateVirtualBase::targetDeactivated(QNearFieldTarget *target) +{ + emit targetLost(target); + QMetaObject::invokeMethod(target, "disconnected"); +} + +struct VerifyRecord +{ + QNdefFilter::Record filterRecord; + unsigned int count; +}; + +void QNearFieldManagerPrivateVirtualBase::ndefReceived(const QNdefMessage &message, + QNearFieldTarget *target) +{ + for (int i = 0; i < m_registeredHandlers.count(); ++i) { + if (m_freeIds.contains(i)) + continue; + + Callback &callback = m_registeredHandlers[i]; + + bool matched = true; + + QList<VerifyRecord> filterRecords; + for (int j = 0; j < callback.filter.recordCount(); ++j) { + VerifyRecord vr; + vr.count = 0; + vr.filterRecord = callback.filter.recordAt(j); + + filterRecords.append(vr); + } + + foreach (const QNdefRecord &record, message) { + for (int j = 0; matched && (j < filterRecords.count()); ++j) { + VerifyRecord &vr = filterRecords[j]; + + if (vr.filterRecord.typeNameFormat == record.typeNameFormat() && + vr.filterRecord.type == record.type()) { + ++vr.count; + break; + } else { + if (callback.filter.orderMatch()) { + if (vr.filterRecord.minimum <= vr.count && + vr.count <= vr.filterRecord.maximum) { + continue; + } else { + matched = false; + } + } + } + } + } + + for (int j = 0; matched && (j < filterRecords.count()); ++j) { + const VerifyRecord &vr = filterRecords.at(j); + + if (vr.filterRecord.minimum <= vr.count && vr.count <= vr.filterRecord.maximum) + continue; + else + matched = false; + } + + if (matched) { + callback.method.invoke(callback.object, Q_ARG(QNdefMessage, message), + Q_ARG(QNearFieldTarget *, target)); + } + } +} + +#include "moc_qnearfieldmanagervirtualbase_p.cpp" diff --git a/src/nfc/qnearfieldmanagervirtualbase_p.h b/src/nfc/qnearfieldmanagervirtualbase_p.h new file mode 100644 index 00000000..6dac5657 --- /dev/null +++ b/src/nfc/qnearfieldmanagervirtualbase_p.h @@ -0,0 +1,90 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QNEARFIELDMANAGERVIRTUALBASE_P_H +#define QNEARFIELDMANAGERVIRTUALBASE_P_H + +#include "qnearfieldmanager_p.h" + +#include <QtCore/QMetaMethod> + +QT_BEGIN_HEADER + +class QNearFieldManagerPrivateVirtualBase : public QNearFieldManagerPrivate +{ + Q_OBJECT + +public: + QNearFieldManagerPrivateVirtualBase(); + ~QNearFieldManagerPrivateVirtualBase(); + + bool startTargetDetection(const QList<QNearFieldTarget::Type> &targetTypes); + void stopTargetDetection(); + + int registerNdefMessageHandler(QObject *object, const QMetaMethod &method); + int registerNdefMessageHandler(const QNdefFilter &filter, + QObject *object, const QMetaMethod &method); + + bool unregisterNdefMessageHandler(int id); + +protected: + struct Callback { + QNdefFilter filter; + + QObject *object; + QMetaMethod method; + }; + + void targetActivated(QNearFieldTarget *target); + void targetDeactivated(QNearFieldTarget *target); + +private: + int getFreeId(); + void ndefReceived(const QNdefMessage &message, QNearFieldTarget *target); + + QList<Callback> m_registeredHandlers; + QList<int> m_freeIds; + QList<QNearFieldTarget::Type> m_detectTargetTypes; +}; + +QT_END_HEADER + +#endif // QNEARFIELDMANAGERVIRTUALBASE_P_H diff --git a/src/nfc/qnearfieldtagmifare_symbian.cpp b/src/nfc/qnearfieldtagmifare_symbian.cpp new file mode 100644 index 00000000..14f13205 --- /dev/null +++ b/src/nfc/qnearfieldtagmifare_symbian.cpp @@ -0,0 +1,98 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <nfctag.h> +#include <QVariant> +#include "qnearfieldtagmifare_symbian_p.h" + +QNearFieldTagMifareSymbian::QNearFieldTagMifareSymbian(CNearFieldNdefTarget *tag, QObject *parent) + : QNearFieldTarget(parent), QNearFieldTagImpl(tag) +{ +} + +QNearFieldTagMifareSymbian::~QNearFieldTagMifareSymbian() +{ +} + +QByteArray QNearFieldTagMifareSymbian::uid() const +{ + return _uid(); +} + +bool QNearFieldTagMifareSymbian::hasNdefMessage() +{ + return _hasNdefMessage(); +} + +QNearFieldTarget::RequestId QNearFieldTagMifareSymbian::readNdefMessages() +{ + return _ndefMessages(); +} + +QNearFieldTarget::RequestId QNearFieldTagMifareSymbian::writeNdefMessages(const QList<QNdefMessage> &messages) +{ + return _setNdefMessages(messages); +} + +QNearFieldTarget::RequestId QNearFieldTagMifareSymbian::sendCommand(const QByteArray &command) +{ + return _sendCommand(command); +} + +QNearFieldTarget::RequestId QNearFieldTagMifareSymbian::sendCommands(const QList<QByteArray> &commands) +{ + return _sendCommands(commands); +} + +void QNearFieldTagMifareSymbian::handleTagOperationResponse(const RequestId &id, const QByteArray &command, const QByteArray &response, bool emitRequestCompleted) +{ + Q_UNUSED(command); + QVariant decodedResponse = decodeResponse(command, response); + setResponseForRequest(id, decodedResponse, emitRequestCompleted); +} + +bool QNearFieldTagMifareSymbian::waitForRequestCompleted(const RequestId &id, int msecs) +{ + BEGIN + END + return _waitForRequestCompleted(id, msecs); +} +#include "moc_qnearfieldtagmifare_symbian_p.cpp" diff --git a/src/nfc/qnearfieldtagmifare_symbian_p.h b/src/nfc/qnearfieldtagmifare_symbian_p.h new file mode 100644 index 00000000..f9714e38 --- /dev/null +++ b/src/nfc/qnearfieldtagmifare_symbian_p.h @@ -0,0 +1,97 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#ifndef QNEARFIELDTAGMIFARE_H +#define QNEARFIELDTAGMIFARE_H + +#include "qnearfieldtarget.h" +#include "symbian/nearfieldndeftarget_symbian.h" +#include "symbian/nearfieldtag_symbian.h" +#include "symbian/nearfieldtagimpl_symbian.h" + +QT_BEGIN_HEADER + +class QNdefMessage; + +class QNearFieldTagMifareSymbian : public QNearFieldTarget, private QNearFieldTagImpl<QNearFieldTagMifareSymbian> +{ + Q_OBJECT + +public: + explicit QNearFieldTagMifareSymbian(CNearFieldNdefTarget *tag, QObject *parent = 0); + + ~QNearFieldTagMifareSymbian(); + + QByteArray uid() const; + + QNearFieldTarget::Type type() const { return QNearFieldTarget::MifareTag; } + QNearFieldTarget::AccessMethods accessMethods() const + { + return _accessMethods(); + } + + void setAccessMethods(const QNearFieldTarget::AccessMethods& accessMethods) + { + _setAccessMethods(accessMethods); + } + // NdefAccess + bool hasNdefMessage(); + RequestId readNdefMessages(); + RequestId writeNdefMessages(const QList<QNdefMessage> &messages); + + // TagTypeSpecificAccess + RequestId sendCommand(const QByteArray &command); + RequestId sendCommands(const QList<QByteArray> &commands); + bool isProcessingCommand() const { return _isProcessingRequest(); } + bool waitForRequestCompleted(const RequestId &id, int msecs = 5000); + + void handleTagOperationResponse(const RequestId &id, const QByteArray &command, const QByteArray &response, bool emitRequestCompleted); + QVariant decodeResponse(const QByteArray &/*command*/, const QByteArray &response) { return response; } +signals: + void disconnected(); + + friend class QNearFieldTagImpl<QNearFieldTagMifareSymbian>; +}; + +QT_END_HEADER + +#endif // QNEARFIELDTAGMIFARE_H diff --git a/src/nfc/qnearfieldtagtype1.cpp b/src/nfc/qnearfieldtagtype1.cpp new file mode 100644 index 00000000..eb1d6c7e --- /dev/null +++ b/src/nfc/qnearfieldtagtype1.cpp @@ -0,0 +1,735 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qnearfieldtagtype1.h" +#include "qnearfieldtarget_p.h" +#include "qndefmessage.h" +#include "qtlv_p.h" + +#include <QtCore/QByteArray> +#include <QtCore/QVariant> + +#include <QtCore/QDebug> + +/*! + \class QNearFieldTagType1 + \brief The QNearFieldTagType1 class provides an interface for communicating with an NFC Tag + Type 1 tag. + \since 5.0 + + \ingroup connectivity-nfc + \inmodule QtConnectivity +*/ + +/*! + \enum QNearFieldTagType1::WriteMode + \brief This enum describes the write modes that are supported. + + \value EraseAndWrite The memory is erased before the new value is written. + \value WriteOnly The memory is not erased before the new value is written. The effect of + this mode is that the final value store is the bitwise or of the data + to be written and the original data value. +*/ + +/*! + \fn Type QNearFieldTagType1::type() const + \reimp +*/ + +class QNearFieldTagType1Private +{ + Q_DECLARE_PUBLIC(QNearFieldTagType1) + +public: + QNearFieldTagType1Private(QNearFieldTagType1 *q) + : q_ptr(q), m_readNdefMessageState(NotReadingNdefMessage), + m_tlvReader(0), + m_writeNdefMessageState(NotWritingNdefMessage) + { } + + QNearFieldTagType1 *q_ptr; + + QMap<QNearFieldTarget::RequestId, QByteArray> m_pendingInternalCommands; + + enum ReadNdefMessageState { + NotReadingNdefMessage, + NdefReadCheckingIdentification, + NdefReadCheckingNdefMagicNumber, + NdefReadReadingTlv + }; + + void progressToNextNdefReadMessageState(); + ReadNdefMessageState m_readNdefMessageState; + QNearFieldTarget::RequestId m_readNdefRequestId; + + QTlvReader *m_tlvReader; + QNearFieldTarget::RequestId m_nextExpectedRequestId; + + enum WriteNdefMessageState { + NotWritingNdefMessage, + NdefWriteCheckingIdentification, + NdefWriteCheckingNdefMagicNumber, + NdefWriteReadingTlv, + NdefWriteWritingTlv, + NdefWriteWritingTlvFlush + }; + + void progressToNextNdefWriteMessageState(); + WriteNdefMessageState m_writeNdefMessageState; + QNearFieldTarget::RequestId m_writeNdefRequestId; + QList<QNdefMessage> m_ndefWriteMessages; + + QTlvWriter *m_tlvWriter; + + typedef QPair<quint8, QByteArray> Tlv; + QList<Tlv> m_tlvs; +}; + +void QNearFieldTagType1Private::progressToNextNdefReadMessageState() +{ + Q_Q(QNearFieldTagType1); + + switch (m_readNdefMessageState) { + case NotReadingNdefMessage: + m_readNdefMessageState = NdefReadCheckingIdentification; + m_nextExpectedRequestId = q->readIdentification(); + break; + case NdefReadCheckingIdentification: { + const QByteArray data = q->requestResponse(m_nextExpectedRequestId).toByteArray(); + + if (data.isEmpty()) { + m_readNdefMessageState = NotReadingNdefMessage; + m_nextExpectedRequestId = QNearFieldTarget::RequestId(); + emit q->error(QNearFieldTarget::NdefReadError, m_readNdefRequestId); + m_readNdefRequestId = QNearFieldTarget::RequestId(); + break; + } + + quint8 hr0 = data.at(0); + + // Check if target is a NFC TagType1 tag + if (!(hr0 & 0x10)) { + m_readNdefMessageState = NotReadingNdefMessage; + m_nextExpectedRequestId = QNearFieldTarget::RequestId(); + emit q->error(QNearFieldTarget::NdefReadError, m_readNdefRequestId); + m_readNdefRequestId = QNearFieldTarget::RequestId(); + break; + } + + m_readNdefMessageState = NdefReadCheckingNdefMagicNumber; + m_nextExpectedRequestId = q->readByte(8); + break; + } + case NdefReadCheckingNdefMagicNumber: { + quint8 ndefMagicNumber = q->requestResponse(m_nextExpectedRequestId).toUInt(); + m_nextExpectedRequestId = QNearFieldTarget::RequestId(); + + if (ndefMagicNumber != 0xe1) { + m_readNdefMessageState = NotReadingNdefMessage; + emit q->error(QNearFieldTarget::NdefReadError, m_readNdefRequestId); + m_readNdefRequestId = QNearFieldTarget::RequestId(); + break; + } + + m_readNdefMessageState = NdefReadReadingTlv; + m_tlvReader = new QTlvReader(q); + + // fall through + } + case NdefReadReadingTlv: + while (!m_tlvReader->atEnd()) { + if (!m_tlvReader->readNext()) + break; + + // NDEF Message TLV + if (m_tlvReader->tag() == 0x03) { + Q_Q(QNearFieldTagType1); + + emit q->ndefMessageRead(QNdefMessage::fromByteArray(m_tlvReader->data())); + } + } + + m_nextExpectedRequestId = m_tlvReader->requestId(); + if (!m_nextExpectedRequestId.isValid()) { + delete m_tlvReader; + m_tlvReader = 0; + m_readNdefMessageState = NotReadingNdefMessage; + emit q->requestCompleted(m_readNdefRequestId); + m_readNdefRequestId = QNearFieldTarget::RequestId(); + } + break; + } +} + +void QNearFieldTagType1Private::progressToNextNdefWriteMessageState() +{ + Q_Q(QNearFieldTagType1); + + switch (m_writeNdefMessageState) { + case NotWritingNdefMessage: + m_writeNdefMessageState = NdefWriteCheckingIdentification; + m_nextExpectedRequestId = q->readIdentification(); + break; + case NdefWriteCheckingIdentification: { + const QByteArray data = q->requestResponse(m_nextExpectedRequestId).toByteArray(); + + if (data.isEmpty()) { + m_writeNdefMessageState = NotWritingNdefMessage; + m_nextExpectedRequestId = QNearFieldTarget::RequestId(); + emit q->error(QNearFieldTarget::NdefWriteError, m_writeNdefRequestId); + m_writeNdefRequestId = QNearFieldTarget::RequestId(); + break; + } + + quint8 hr0 = data.at(0); + + // Check if target is a NFC TagType1 tag + if (!(hr0 & 0x10)) { + m_writeNdefMessageState = NotWritingNdefMessage; + m_nextExpectedRequestId = QNearFieldTarget::RequestId(); + emit q->error(QNearFieldTarget::NdefWriteError, m_writeNdefRequestId); + m_writeNdefRequestId = QNearFieldTarget::RequestId(); + break; + } + + m_writeNdefMessageState = NdefWriteCheckingNdefMagicNumber; + m_nextExpectedRequestId = q->readByte(8); + break; + } + case NdefWriteCheckingNdefMagicNumber: { + quint8 ndefMagicNumber = q->requestResponse(m_nextExpectedRequestId).toUInt(); + m_nextExpectedRequestId = QNearFieldTarget::RequestId(); + + if (ndefMagicNumber != 0xe1) { + m_writeNdefMessageState = NotWritingNdefMessage; + emit q->error(QNearFieldTarget::NdefWriteError, m_writeNdefRequestId); + m_writeNdefRequestId = QNearFieldTarget::RequestId(); + break; + } + + m_writeNdefMessageState = NdefWriteReadingTlv; + m_tlvReader = new QTlvReader(q); + + // fall through + } + case NdefWriteReadingTlv: + while (!m_tlvReader->atEnd()) { + if (!m_tlvReader->readNext()) + break; + + quint8 tag = m_tlvReader->tag(); + if (tag == 0x01 || tag == 0x02 || tag == 0xfd) + m_tlvs.append(qMakePair(tag, m_tlvReader->data())); + } + + m_nextExpectedRequestId = m_tlvReader->requestId(); + if (m_nextExpectedRequestId.isValid()) + break; + + delete m_tlvReader; + m_tlvReader = 0; + m_writeNdefMessageState = NdefWriteWritingTlv; + + // fall through + case NdefWriteWritingTlv: + m_tlvWriter = new QTlvWriter(q); + + // write old TLVs + foreach (const Tlv &tlv, m_tlvs) + m_tlvWriter->writeTlv(tlv.first, tlv.second); + + // write new NDEF message TLVs + foreach (const QNdefMessage &message, m_ndefWriteMessages) + m_tlvWriter->writeTlv(0x03, message.toByteArray()); + + // write terminator TLV + m_tlvWriter->writeTlv(0xfe); + + m_writeNdefMessageState = NdefWriteWritingTlvFlush; + + // fall through + case NdefWriteWritingTlvFlush: + // flush the writer + if (m_tlvWriter->process(true)) { + m_nextExpectedRequestId = QNearFieldTarget::RequestId(); + m_writeNdefMessageState = NotWritingNdefMessage; + delete m_tlvWriter; + m_tlvWriter = 0; + emit q->ndefMessagesWritten(); + emit q->requestCompleted(m_writeNdefRequestId); + m_writeNdefRequestId = QNearFieldTarget::RequestId(); + } else { + m_nextExpectedRequestId = m_tlvWriter->requestId(); + if (!m_nextExpectedRequestId.isValid()) { + m_writeNdefMessageState = NotWritingNdefMessage; + delete m_tlvWriter; + m_tlvWriter = 0; + emit q->error(QNearFieldTarget::NdefWriteError, m_writeNdefRequestId); + m_writeNdefRequestId = QNearFieldTarget::RequestId(); + } + } + break; + } +} + +static QVariant decodeResponse(const QByteArray &command, const QByteArray &response) +{ + switch (command.at(0)) { + case 0x01: // READ + if (command.at(1) == response.at(0)) + return quint8(response.at(1)); + break; + case 0x53: { // WRITE-E + quint8 address = command.at(1); + quint8 data = command.at(2); + quint8 writeAddress = response.at(0); + quint8 writeData = response.at(1); + + return ((writeAddress == address) && (writeData == data)); + } + case 0x1a: { // WRITE-NE + quint8 address = command.at(1); + quint8 data = command.at(2); + quint8 writeAddress = response.at(0); + quint8 writeData = response.at(1); + + return ((writeAddress == address) && ((writeData & data) == data)); + } + case 0x10: { // RSEG + quint8 segmentAddress = quint8(command.at(1)) >> 4; + quint8 readSegmentAddress = quint8(response.at(0)) >> 4; + if (readSegmentAddress == segmentAddress) + return response.mid(1); + break; + } + case 0x02: { // READ8 + quint8 blockAddress = command.at(1); + quint8 readBlockAddress = response.at(0); + if (readBlockAddress == blockAddress) + return response.mid(1); + break; + } + case 0x54: { // WRITE-E8 + quint8 blockAddress = command.at(1); + QByteArray data = command.mid(2, 8); + quint8 writeBlockAddress = response.at(0); + QByteArray writeData = response.mid(1); + + return ((writeBlockAddress == blockAddress) && (writeData == data)); + } + case 0x1b: { // WRITE-NE8 + quint8 blockAddress = command.at(1); + QByteArray data = command.mid(2, 8); + quint8 writeBlockAddress = response.at(0); + QByteArray writeData = response.mid(1); + + if (writeBlockAddress != blockAddress) + return false; + + for (int i = 0; i < writeData.length(); ++i) { + if ((writeData.at(i) & data.at(i)) != data.at(i)) + return false; + } + + return true; + } + } + + return QVariant(); +} + +/*! + Constructs a new tag type 1 near field target with \a parent. +*/ +QNearFieldTagType1::QNearFieldTagType1(QObject *parent) +: QNearFieldTarget(parent), d_ptr(new QNearFieldTagType1Private(this)) +{ +} + +/*! + Destroys the tag type 1 near field target. +*/ +QNearFieldTagType1::~QNearFieldTagType1() +{ + delete d_ptr; +} + +/*! + \reimp +*/ +bool QNearFieldTagType1::hasNdefMessage() +{ + RequestId id = readAll(); + if (!waitForRequestCompleted(id)) + return false; + + const QByteArray data = requestResponse(id).toByteArray(); + + if (data.isEmpty()) + return false; + + quint8 hr0 = data.at(0); + + // Check if target is a NFC TagType1 tag + if (!(hr0 & 0x10)) + return false; + + // Check if NDEF Message Magic number is present + quint8 nmn = data.at(10); + if (nmn != 0xe1) + return false; + + // Check if TLV contains NDEF Message + return true; +} + +/*! + \reimp +*/ +QNearFieldTarget::RequestId QNearFieldTagType1::readNdefMessages() +{ + Q_D(QNearFieldTagType1); + + d->m_readNdefRequestId = RequestId(new RequestIdPrivate); + + if (d->m_readNdefMessageState == QNearFieldTagType1Private::NotReadingNdefMessage) { + d->progressToNextNdefReadMessageState(); + } else { + QMetaObject::invokeMethod(this, "error", Qt::QueuedConnection, + Q_ARG(QNearFieldTarget::Error, NdefReadError), + Q_ARG(QNearFieldTarget::RequestId, d->m_readNdefRequestId)); + } + + return d->m_readNdefRequestId; +} + +/*! + \reimp +*/ +QNearFieldTarget::RequestId QNearFieldTagType1::writeNdefMessages(const QList<QNdefMessage> &messages) +{ + Q_D(QNearFieldTagType1); + + d->m_writeNdefRequestId = RequestId(new RequestIdPrivate); + + if (d->m_readNdefMessageState == QNearFieldTagType1Private::NotReadingNdefMessage && + d->m_writeNdefMessageState == QNearFieldTagType1Private::NotWritingNdefMessage) { + d->m_ndefWriteMessages = messages; + d->progressToNextNdefWriteMessageState(); + } else { + QMetaObject::invokeMethod(this, "error", Qt::QueuedConnection, + Q_ARG(QNearFieldTarget::Error, NdefWriteError), + Q_ARG(QNearFieldTarget::RequestId, d->m_readNdefRequestId)); + } + + return d->m_writeNdefRequestId; +} + +/*! + Returns the NFC Tag Type 1 specification version number that the tag supports. +*/ +quint8 QNearFieldTagType1::version() +{ + RequestId id = readByte(9); + if (!waitForRequestCompleted(id)) + return 0; + + quint8 versionNumber = requestResponse(id).toUInt(); + return versionNumber; +} + +/*! + Returns the memory size in bytes of the tag. +*/ +int QNearFieldTagType1::memorySize() +{ + RequestId id = readByte(10); + if (!waitForRequestCompleted(id)) + return 0; + + quint8 tms = requestResponse(id).toUInt(); + + return 8 * (tms + 1); +} + +/*! + Requests the identification bytes from the target. Returns a request id which can be used to + track the completion status of the request. + + Once the request completes successfully the response can be retrieved from the + requestResponse() function. The response of this request will be a QByteArray containing: HR0, + HR1, UID0, UID1, UID2 and UID3 in order. + + \sa requestCompleted(), waitForRequestCompleted() +*/ +QNearFieldTarget::RequestId QNearFieldTagType1::readIdentification() +{ + QByteArray command; + command.append(char(0x78)); // RID + command.append(char(0x00)); // Address (unused) + command.append(char(0x00)); // Data (unused) + command.append(uid().left(4)); // 4 bytes of UID + + return sendCommand(command); +} + +/*! + Requests all data in the static memory area of the target. Returns a request id which can be + used to track the completion status of the request. + + Once the request completes successfully the response can be retrieved from the + requestResponse() function. The response of this request will be a QByteArray containing: HR0 + and HR1 followed by the 120 bytes of data stored in the static memory area of the target. + + \sa requestCompleted(), waitForRequestCompleted() +*/ +QNearFieldTarget::RequestId QNearFieldTagType1::readAll() +{ + QByteArray command; + command.append(char(0x00)); // RALL + command.append(char(0x00)); // Address (unused) + command.append(char(0x00)); // Data (unused) + command.append(uid().left(4));// 4 bytes of UID + + return sendCommand(command); +} + +/*! + Requests a single byte from the static memory area of the tag. The \a address parameter + specifices the linear byte address to read. Returns a request id which can be used to track + the completion status of the request. + + Once the request completes successfully the response can be retrieved from the + requestResponse() function. The response of this request will be a quint8. + + \sa requestCompleted(), waitForRequestCompleted() +*/ +QNearFieldTarget::RequestId QNearFieldTagType1::readByte(quint8 address) +{ + if (address & 0x80) + return RequestId(); + + QByteArray command; + command.append(char(0x01)); // READ + command.append(char(address)); // Address + command.append(char(0x00)); // Data (unused) + command.append(uid().left(4)); // 4 bytes of UID + + RequestId id = sendCommand(command); + + Q_D(QNearFieldTagType1); + + d->m_pendingInternalCommands.insert(id, command); + + return id; +} + +/*! + Writes a single \a data byte to the linear byte \a address on the tag. If \a mode is + EraseAndWrite the byte will be erased before writing. If \a mode is WriteOnly the contents will + not be erased before writing. This is equivelant to writing the result of the bitwise OR of + \a data and the original value. + + Returns a request id which can be used to track the completion status of the request. + + Once the request completes the response can be retrieved from the requestResponse() function. + The response of this request will be a boolean value, true for success; otherwise false. + + \sa requestCompleted(), waitForRequestCompleted() +*/ +QNearFieldTarget::RequestId QNearFieldTagType1::writeByte(quint8 address, quint8 data, + WriteMode mode) +{ + if (address & 0x80) + return RequestId(); + + QByteArray command; + + if (mode == EraseAndWrite) + command.append(char(0x53)); // WRITE-E + else if (mode == WriteOnly) + command.append(char(0x1a)); // WRITE-NE + else + return RequestId(); + + command.append(char(address)); // Address + command.append(char(data)); // Data + command.append(uid().left(4)); // 4 bytes of UID + + RequestId id = sendCommand(command); + + Q_D(QNearFieldTagType1); + + d->m_pendingInternalCommands.insert(id, command); + + return id; +} + +/*! + Requests 128 bytes of data from the segment specified by \a segmentAddress. Returns a request + id which can be used to track the completion status of the request. + + Once the request completes successfully the response can be retrieved from the + requestResponse() function. The response of this request will be a QByteArray. + + \sa requestCompleted(), waitForRequestCompleted() +*/ +QNearFieldTarget::RequestId QNearFieldTagType1::readSegment(quint8 segmentAddress) +{ + if (segmentAddress & 0xf0) + return RequestId(); + + QByteArray command; + command.append(char(0x10)); // RSEG + command.append(char(segmentAddress << 4)); // Segment address + command.append(QByteArray(8, char(0x00))); // Data (unused) + command.append(uid().left(4)); // 4 bytes of UID + + RequestId id = sendCommand(command); + + Q_D(QNearFieldTagType1); + + d->m_pendingInternalCommands.insert(id, command); + + return id; +} + +/*! + Requests 8 bytes of data from the block specified by \a blockAddress. Returns a request id + which can be used to track the completion status of the request. + + Once the request completes successfully the response can be retrieved from the + requestResponse() function. The response of this request will be a QByteArray. + + \sa requestCompleted(), waitForRequestCompleted() +*/ +QNearFieldTarget::RequestId QNearFieldTagType1::readBlock(quint8 blockAddress) +{ + QByteArray command; + command.append(char(0x02)); // READ8 + command.append(char(blockAddress)); // Block address + command.append(QByteArray(8, char(0x00))); // Data (unused) + command.append(uid().left(4)); // 4 bytes of UID + + RequestId id = sendCommand(command); + + Q_D(QNearFieldTagType1); + + d->m_pendingInternalCommands.insert(id, command); + + return id; +} + +/*! + Writes 8 bytes of \a data to the block specified by \a blockAddress. If \a mode is + EraseAndWrite the bytes will be erased before writing. If \a mode is WriteOnly the contents + will not be erased before writing. This is equivelant to writing the result of the bitwise OR + of \a data and the original value. + + Returns a request id which can be used to track the completion status of the request. + + Once the request completes the response can be retrieved from the requestResponse() function. + The response of this request will be a boolean value, true for success; otherwise false. + + \sa requestCompleted(), waitForRequestCompleted() +*/ +QNearFieldTarget::RequestId QNearFieldTagType1::writeBlock(quint8 blockAddress, + const QByteArray &data, + WriteMode mode) +{ + if (data.length() != 8) + return RequestId(); + + QByteArray command; + + if (mode == EraseAndWrite) + command.append(char(0x54)); // WRITE-E8 + else if (mode == WriteOnly) + command.append(char(0x1b)); // WRITE-NE8 + else + return RequestId(); + + command.append(char(blockAddress)); // Block address + command.append(data); // Data + command.append(uid().left(4)); // 4 bytes of UID + + RequestId id = sendCommand(command); + + Q_D(QNearFieldTagType1); + + d->m_pendingInternalCommands.insert(id, command); + + return id; +} + +/*! + \reimp +*/ +bool QNearFieldTagType1::handleResponse(const QNearFieldTarget::RequestId &id, + const QByteArray &response) +{ + Q_D(QNearFieldTagType1); + + bool handled; + + if (d->m_pendingInternalCommands.contains(id)) { + const QByteArray command = d->m_pendingInternalCommands.take(id); + + QVariant decodedResponse = decodeResponse(command, response); + setResponseForRequest(id, decodedResponse); + + handled = true; + } else { + handled = QNearFieldTarget::handleResponse(id, response); + } + + // continue reading / writing NDEF message + if (d->m_nextExpectedRequestId == id) { + if (d->m_readNdefMessageState != QNearFieldTagType1Private::NotReadingNdefMessage) + d->progressToNextNdefReadMessageState(); + else if (d->m_writeNdefMessageState != QNearFieldTagType1Private::NotWritingNdefMessage) + d->progressToNextNdefWriteMessageState(); + } + + return handled; +} + +#include "moc_qnearfieldtagtype1.cpp" diff --git a/src/nfc/qnearfieldtagtype1.h b/src/nfc/qnearfieldtagtype1.h new file mode 100644 index 00000000..f925fda3 --- /dev/null +++ b/src/nfc/qnearfieldtagtype1.h @@ -0,0 +1,98 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QNEARFIELDTAGTYPE1_H +#define QNEARFIELDTAGTYPE1_H + +#include <qnearfieldtarget.h> + +QT_BEGIN_HEADER + +class QNearFieldTagType1Private; + +class Q_CONNECTIVITY_EXPORT QNearFieldTagType1 : public QNearFieldTarget +{ + Q_OBJECT + + Q_DECLARE_PRIVATE(QNearFieldTagType1) + +public: + enum WriteMode { + EraseAndWrite, + WriteOnly + }; + + explicit QNearFieldTagType1(QObject *parent = 0); + ~QNearFieldTagType1(); + + Type type() const { return NfcTagType1; } + + bool hasNdefMessage(); + RequestId readNdefMessages(); + RequestId writeNdefMessages(const QList<QNdefMessage> &messages); + + quint8 version(); + virtual int memorySize(); + + // DIGPROTO + virtual RequestId readIdentification(); + + // static memory functions + virtual RequestId readAll(); + virtual RequestId readByte(quint8 address); + virtual RequestId writeByte(quint8 address, quint8 data, WriteMode mode = EraseAndWrite); + + // dynamic memory functions + virtual RequestId readSegment(quint8 segmentAddress); + virtual RequestId readBlock(quint8 blockAddress); + virtual RequestId writeBlock(quint8 blockAddress, const QByteArray &data, + WriteMode mode = EraseAndWrite); + +protected: + bool handleResponse(const QNearFieldTarget::RequestId &id, const QByteArray &response); + +private: + QNearFieldTagType1Private *d_ptr; +}; + +QT_END_HEADER + +#endif // QNEARFIELDTAGTYPE1_H diff --git a/src/nfc/qnearfieldtagtype1_symbian.cpp b/src/nfc/qnearfieldtagtype1_symbian.cpp new file mode 100644 index 00000000..fc7be21a --- /dev/null +++ b/src/nfc/qnearfieldtagtype1_symbian.cpp @@ -0,0 +1,402 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <nfctag.h> +#include <QVariant> +#include "symbian/nearfieldutility_symbian.h" +#include "qnearfieldtagtype1_symbian_p.h" +#include "debug.h" + +//#define SYMBIAN_BUG_NOT_FIX + +static void OutputByteArray(const QByteArray& data) +{ + for(int i = 0; i < data.count(); ++i) + { + LOG("data ["<<i<<"] = "<<((quint16)(data.at(i)))); + } +} + +QVariant QNearFieldTagType1Symbian::decodeResponse(const QByteArray &command, const QByteArray &response) +{ + BEGIN + OutputByteArray(response); + END + switch (command.at(0)) { + case 0x01: // READ +#ifndef SYMBIAN_BUG_NOT_FIX + if (command.at(1) == response.at(0)) + return quint8(response.at(1)); + break; +#else + return quint8(response.at(0)); +#endif + case 0x53: { // WRITE-E +#ifndef SYMBIAN_BUG_NOT_FIX + quint8 address = command.at(1); + quint8 data = command.at(2); + quint8 writeAddress = response.at(0); + quint8 writeData = response.at(1); + return ((writeAddress == address) && (writeData == data)); +#else + quint8 data = command.at(2); + + quint8 writeData = response.at(0); + return (writeData == data); +#endif + } + case 0x1a: { // WRITE-NE +#ifndef SYMBIAN_BUG_NOT_FIX + quint8 address = command.at(1); + quint8 data = command.at(2); + quint8 writeAddress = response.at(0); + quint8 writeData = response.at(1); + + return ((writeAddress == address) && ((writeData & data) == data)); +#else + quint8 data = command.at(2); + quint8 writeData = response.at(0); + return ((writeData & data) == data); +#endif + } + case 0x10: { // RSEG +#ifndef SYMBIAN_BUG_NOT_FIX + quint8 segmentAddress = quint8(command.at(1)) >> 4; + quint8 readSegmentAddress = quint8(response.at(0)) >> 4; + if (readSegmentAddress == segmentAddress) + return response.mid(1); + break; +#else + return response; +#endif + } + case 0x02: { // READ8 +#ifndef SYMBIAN_BUG_NOT_FIX + quint8 blockAddress = command.at(1); + quint8 readBlockAddress = response.at(0); + if (readBlockAddress == blockAddress) + return response.mid(1); + break; +#else + return response; +#endif + } + case 0x54: { // WRITE-E8 +#ifndef SYMBIAN_BUG_NOT_FIX + quint8 blockAddress = command.at(1); + QByteArray data = command.mid(2, 8); + quint8 writeBlockAddress = response.at(0); + QByteArray writeData = response.mid(1); + + return ((writeBlockAddress == blockAddress) && (writeData == data)); +#else + QByteArray data = command.mid(2, 8); + + return (response == data); +#endif + } + case 0x1b: { // WRITE-NE8 +#ifndef SYMBIAN_BUG_NOT_FIX + quint8 blockAddress = command.at(1); + QByteArray data = command.mid(2, 8); + quint8 writeBlockAddress = response.at(0); + QByteArray writeData = response.mid(1); + + if (writeBlockAddress != blockAddress) + return false; + + for (int i = 0; i < writeData.length(); ++i) { + if ((writeData.at(i) & data.at(i)) != data.at(i)) + return false; + } + return true; +#else + QByteArray data = command.mid(2, 8); + QByteArray writeData = response; + + for (int i = 0; i < writeData.length(); ++i) { + if ((writeData.at(i) & data.at(i)) != data.at(i)) + return false; + } + return true; +#endif + } + } + + return response; +} +/* + \class QNearFieldTagType1Symbian + \brief The QNearFieldTagType1Symbian class provides symbian backend implementation for communicating with an NFC Tag + Type 1 tag. + + \ingroup connectivity-nfc + \inmodule QtConnectivity +*/ + +/* + Constructs a new tag type 1 near field target with \a tag and \a parent. +*/ +QNearFieldTagType1Symbian::QNearFieldTagType1Symbian(CNearFieldNdefTarget *tag, QObject *parent) + : QNearFieldTagType1(parent), QNearFieldTagImpl(tag) +{ +} + +/* + Destructor +*/ +QNearFieldTagType1Symbian::~QNearFieldTagType1Symbian() +{ +} + +QByteArray QNearFieldTagType1Symbian::uid() const +{ + return _uid(); +} + +/* + \reimp +*/ +QNearFieldTarget::RequestId QNearFieldTagType1Symbian::readIdentification() +{ + BEGIN + QByteArray command; + command.append(char(0x78)); // RID + command.append(char(0x00)); // Address (unused) + command.append(char(0x00)); // Data (unused) + command.append(uid().left(4)); // 4 bytes of UID + END + return sendCommand(command); +} + +/* + \reimp +*/ +QNearFieldTarget::RequestId QNearFieldTagType1Symbian::readAll() +{ + BEGIN + QByteArray command; + command.append(char(0x00)); // RALL + command.append(char(0x00)); + command.append(char(0x00)); + command.append(uid().left(4)); // UID + END + return sendCommand(command); +} + +/* + \reimp +*/ +QNearFieldTarget::RequestId QNearFieldTagType1Symbian::readByte(quint8 address) +{ + BEGIN + // MSB must be 0 + if (address & 0x80) + return QNearFieldTarget::RequestId(); + + QByteArray command; + command.append(char(0x01)); // READ + command.append(char(address)); // Address + command.append(char(0x00)); // Data (unused) + command.append(uid().left(4)); // 4 bytes of UID + + END + return sendCommand(command); +} + +/* + \reimp +*/ +QNearFieldTarget::RequestId QNearFieldTagType1Symbian::writeByte(quint8 address, quint8 data, WriteMode mode) +{ + BEGIN + // MSB must be 0 + if (address & 0x80) + { + END + return QNearFieldTarget::RequestId(); + } + + QByteArray command; + + if (mode == EraseAndWrite) + command.append(char(0x53)); // WRITE-E + else + command.append(char(0x1a)); // WRITE-NE + + command.append(char(address)); // Address + command.append(char(data)); // Data + command.append(uid().left(4)); // 4 bytes of UID + + END + return sendCommand(command); +} + +/* + \reimp +*/ +QNearFieldTarget::RequestId QNearFieldTagType1Symbian::readSegment(quint8 segmentAddress) +{ + BEGIN + if (segmentAddress & 0xf0) + { + END + return QNearFieldTarget::RequestId(); + } + + QByteArray command; + command.append(char(0x10)); // RSEG + command.append(char(segmentAddress << 4)); // Segment address + command.append(QByteArray(8, char(0x00))); // Data (unused) + command.append(uid().left(4)); // 4 bytes of UIDD + + END + return sendCommand(command); +} + +/* + \reimp +*/ +QNearFieldTarget::RequestId QNearFieldTagType1Symbian::readBlock(quint8 blockAddress) +{ + BEGIN + QByteArray command; + command.append(char(0x02)); // READ8 + command.append(char(blockAddress)); // Block address + command.append(QByteArray(8, char(0x00))); // Data (unused) + command.append(uid().left(4)); // 4 bytes of UID + + END + return sendCommand(command); +} + +/* + \reimp +*/ +QNearFieldTarget::RequestId QNearFieldTagType1Symbian::writeBlock(quint8 blockAddress, const QByteArray &data, + WriteMode mode) +{ + BEGIN + if (data.length() != 8) + { + END + return QNearFieldTarget::RequestId(); + } + + QByteArray command; + + if (mode == EraseAndWrite) + command.append(char(0x54)); // WRITE-E8 + else + command.append(char(0x1b)); // WRITE-NE8 + + command.append(char(blockAddress)); // Block address + command.append(data); // Data + command.append(uid().left(4)); // 4 bytes of UID + + END + return sendCommand(command); +} + +bool QNearFieldTagType1Symbian::hasNdefMessage() +{ + return _hasNdefMessage(); +} + +QNearFieldTarget::RequestId QNearFieldTagType1Symbian::readNdefMessages() +{ + BEGIN + END + return _ndefMessages(); +} + +QNearFieldTarget::RequestId QNearFieldTagType1Symbian::writeNdefMessages(const QList<QNdefMessage> &messages) +{ + BEGIN + END + return _setNdefMessages(messages); +} + +/* + \reimp +*/ +QNearFieldTarget::RequestId QNearFieldTagType1Symbian::sendCommand(const QByteArray &command) +{ + BEGIN + END + return _sendCommand(command); +} + +/* + \reimp +*/ +QNearFieldTarget::RequestId QNearFieldTagType1Symbian::sendCommands(const QList<QByteArray> &commands) +{ + BEGIN + END + return _sendCommands(commands); +} + +bool QNearFieldTagType1Symbian::waitForRequestCompleted(const RequestId &id, int msecs) +{ + BEGIN + END + return _waitForRequestCompleted(id, msecs); +} + +void QNearFieldTagType1Symbian::handleTagOperationResponse(const RequestId &id, const QByteArray &command, const QByteArray &response, bool emitRequestCompleted) +{ + BEGIN + QVariant decodedResponse; + if (!response.isNull()) + { + decodedResponse = decodeResponse(command, response); + } + else + { + decodedResponse = response; + } + + setResponseForRequest(id, decodedResponse, emitRequestCompleted); + END +} + +#include "moc_qnearfieldtagtype1_symbian_p.cpp" diff --git a/src/nfc/qnearfieldtagtype1_symbian_p.h b/src/nfc/qnearfieldtagtype1_symbian_p.h new file mode 100644 index 00000000..cfcdbe70 --- /dev/null +++ b/src/nfc/qnearfieldtagtype1_symbian_p.h @@ -0,0 +1,104 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QNEARFIELDTAGTYPE1SYMBIAN_H +#define QNEARFIELDTAGTYPE1SYMBIAN_H + +#include <qnearfieldtagtype1.h> +#include "symbian/nearfieldndeftarget_symbian.h" +#include "symbian/nearfieldtag_symbian.h" +#include "symbian/nearfieldtagimpl_symbian.h" + +QT_BEGIN_HEADER + +class QNearFieldTagType1Symbian : public QNearFieldTagType1, private QNearFieldTagImpl<QNearFieldTagType1Symbian> +{ + Q_OBJECT + +public: + + explicit QNearFieldTagType1Symbian(CNearFieldNdefTarget *tag, QObject *parent = 0); + + ~QNearFieldTagType1Symbian(); + + virtual QByteArray uid() const; + + // DIGPROTO + RequestId readIdentification(); + + // static memory functions + RequestId readAll(); + RequestId readByte(quint8 address); + RequestId writeByte(quint8 address, quint8 data, WriteMode mode = EraseAndWrite); + + // dynamic memory functions + RequestId readSegment(quint8 segmentAddress); + RequestId readBlock(quint8 blockAddress); + RequestId writeBlock(quint8 blockAddress, const QByteArray &data, + WriteMode mode = EraseAndWrite); + + bool hasNdefMessage(); + RequestId readNdefMessages(); + RequestId writeNdefMessages(const QList<QNdefMessage> &messages); + + bool isProcessingCommand() const { return _isProcessingRequest(); } + RequestId sendCommand(const QByteArray &command); + RequestId sendCommands(const QList<QByteArray> &commands); + bool waitForRequestCompleted(const RequestId &id, int msecs = 5000); + + void setAccessMethods(const QNearFieldTarget::AccessMethods& accessMethods) + { + _setAccessMethods(accessMethods); + } + + QNearFieldTarget::AccessMethods accessMethods() const + { + return _accessMethods(); + } + + void handleTagOperationResponse(const RequestId &id, const QByteArray &command, const QByteArray &response, bool emitRequestCompleted); + QVariant decodeResponse(const QByteArray &command, const QByteArray &response); + friend class QNearFieldTagImpl<QNearFieldTagType1Symbian>; +}; + +QT_END_HEADER + +#endif // QNEARFIELDTAGTYPE1SYMBIAN_H diff --git a/src/nfc/qnearfieldtagtype2.cpp b/src/nfc/qnearfieldtagtype2.cpp new file mode 100644 index 00000000..f54567ec --- /dev/null +++ b/src/nfc/qnearfieldtagtype2.cpp @@ -0,0 +1,348 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qnearfieldtagtype2.h" +#include "qnearfieldtarget_p.h" + +#include <QtCore/QVariant> +#include <QtCore/QCoreApplication> +#include <QtCore/QTime> + +#include <QtCore/QDebug> + +/*! + \class QNearFieldTagType2 + \brief The QNearFieldTagType2 class provides an interface for communicating with an NFC Tag + Type 2 tag. + \since 5.0 + + \ingroup connectivity-nfc + \inmodule QtConnectivity +*/ + +/*! + \fn Type QNearFieldTagType2::type() const + \reimp +*/ + +struct SectorSelectState { + int timerId; // id of timer used for passive ack + quint8 sector; // sector being selected +}; + +class QNearFieldTagType2Private +{ +public: + QNearFieldTagType2Private() : m_currentSector(0) { } + + QMap<QNearFieldTarget::RequestId, QByteArray> m_pendingInternalCommands; + + quint8 m_currentSector; + + QMap<QNearFieldTarget::RequestId, SectorSelectState> m_pendingSectorSelectCommands; +}; + +static QVariant decodeResponse(const QByteArray &command, const QByteArray &response) +{ + quint8 opcode = command.at(0); + + switch (opcode) { + case 0xa2: // WRITE + return quint8(response.at(0)) == 0x0a; + case 0xc2: // SECTOR SELECT (Command Packet 1) + return quint8(response.at(0)) == 0x0a; + } + + return QVariant(); +} + +/*! + Constructs a new tag type 2 near field target with \a parent. +*/ +QNearFieldTagType2::QNearFieldTagType2(QObject *parent) +: QNearFieldTarget(parent), d_ptr(new QNearFieldTagType2Private) +{ +} + +/*! + Destroys the tag type 2 near field target. +*/ +QNearFieldTagType2::~QNearFieldTagType2() +{ + delete d_ptr; +} + +/*! + \reimp +*/ +bool QNearFieldTagType2::hasNdefMessage() +{ + qDebug() << Q_FUNC_INFO << "is unimplemeted"; + return false; +} + +/*! + \reimp +*/ +QNearFieldTarget::RequestId QNearFieldTagType2::readNdefMessages() +{ + return RequestId(); +} + +/*! + \reimp +*/ +QNearFieldTarget::RequestId QNearFieldTagType2::writeNdefMessages(const QList<QNdefMessage> &messages) +{ + Q_UNUSED(messages); + + return RequestId(); +} + +/*! + Returns the NFC Tag Type 2 specification version number that the tag supports. +*/ +quint8 QNearFieldTagType2::version() +{ + Q_D(QNearFieldTagType2); + if (d->m_currentSector != 0) { + RequestId id = selectSector(0); + if (!waitForRequestCompleted(id)) + return 0; + } + + RequestId id = readBlock(0); + if (!waitForRequestCompleted(id)) + return 0; + + const QByteArray data = requestResponse(id).toByteArray(); + return data.at(13); +} + +/*! + Returns the memory size in bytes of the tag. +*/ +int QNearFieldTagType2::memorySize() +{ + Q_D(QNearFieldTagType2); + if (d->m_currentSector != 0) { + RequestId id = selectSector(0); + if (!waitForRequestCompleted(id)) + return 0; + } + + RequestId id = readBlock(0); + if (!waitForRequestCompleted(id)) + return 0; + + const QByteArray data = requestResponse(id).toByteArray(); + return 8 * quint8(data.at(14)); +} + +/*! + Requests 16 bytes of data starting at \a blockAddress. Returns a request id which can be used + to track the completion status of the request. + + Once the request completes successfully the response can be retrieved from the + requestResponse() function. The response of this request will be a QByteArray. + + \sa requestCompleted(), waitForRequestCompleted() +*/ +QNearFieldTarget::RequestId QNearFieldTagType2::readBlock(quint8 blockAddress) +{ + QByteArray command; + command.append(char(0x30)); // READ + command.append(char(blockAddress)); // Block address + + return sendCommand(command); +} + +/*! + Writes 4 bytes of \a data to the block at \a blockAddress. Returns a request id which can be + used to track the completion status of the request. + + Once the request completes the response can be retrieved from the requestResponse() function. + The response of this request will be a boolean value, true for success; otherwise false. + + Returns true on success; otherwise returns false. +*/ +QNearFieldTarget::RequestId QNearFieldTagType2::writeBlock(quint8 blockAddress, + const QByteArray &data) +{ + if (data.length() != 4) + return RequestId(); + + QByteArray command; + command.append(char(0xa2)); // WRITE + command.append(char(blockAddress)); // Block address + command.append(data); // Data + + RequestId id = sendCommand(command); + + Q_D(QNearFieldTagType2); + + d->m_pendingInternalCommands.insert(id, command); + + return id; +} + +/*! + Selects the \a sector upon which subsequent readBlock() and writeBlock() operations will act. + + Returns a request id which can be used to track the completion status of the request. + + Once the request completes the response can be retrieved from the requestResponse() function. + The response of this request will be a boolean value, true for success; otherwise false. + + \note this request has a passive acknowledgement mechanism. The operation is deemed successful + if no response is received within 1ms. It will therefore take a minimum of 1 millisecond for + the requestCompleted() signal to be emitted and calling waitForRequestCompleted() on the + returned request id may cause the current thread to block for up to 1 millisecond. +*/ +QNearFieldTarget::RequestId QNearFieldTagType2::selectSector(quint8 sector) +{ + QByteArray command; + command.append(char(0xc2)); // SECTOR SELECT (Command Packet 1) + command.append(char(0xff)); + + RequestId id = sendCommand(command); + + Q_D(QNearFieldTagType2); + + d->m_pendingInternalCommands.insert(id, command); + + SectorSelectState state; + state.timerId = -1; + state.sector = sector; + + d->m_pendingSectorSelectCommands.insert(id, state); + + return id; +} + +/*! + \reimp +*/ +bool QNearFieldTagType2::waitForRequestCompleted(const RequestId &id, int msecs) +{ + Q_D(QNearFieldTagType2); + + QTime timer; + timer.start(); + while (d->m_pendingSectorSelectCommands.contains(id)) { + QCoreApplication::processEvents(QEventLoop::WaitForMoreEvents, 1); + + // detect passive ack + if (timer.elapsed() >= 1) + break; + } + + return QNearFieldTarget::waitForRequestCompleted(id, msecs); +} + +/*! + \reimp +*/ +bool QNearFieldTagType2::handleResponse(const QNearFieldTarget::RequestId &id, + const QByteArray &response) +{ + Q_D(QNearFieldTagType2); + + if (d->m_pendingInternalCommands.contains(id)) { + const QByteArray command = d->m_pendingInternalCommands.take(id); + + QVariant decodedResponse = decodeResponse(command, response); + if (quint8(command.at(0)) == 0xc2 && decodedResponse.toBool()) { + // SECTOR SELECT (Command Packet 2) + SectorSelectState &state = d->m_pendingSectorSelectCommands[id]; + + QByteArray packet2; + packet2.append(char(state.sector)); + packet2.append(QByteArray(3, 0x00)); + + sendCommand(packet2); + + state.timerId = startTimer(1); + } else { + setResponseForRequest(id, decodedResponse); + } + + return true; + } else if (d->m_pendingSectorSelectCommands.contains(id)) { + if (!response.isEmpty()) { + d->m_pendingSectorSelectCommands.remove(id); + setResponseForRequest(id, false); + + return true; + } + } + + return QNearFieldTarget::handleResponse(id, response); +} + +/*! + \internal +*/ +void QNearFieldTagType2::timerEvent(QTimerEvent *event) +{ + Q_D(QNearFieldTagType2); + + killTimer(event->timerId()); + + QMutableMapIterator<QNearFieldTarget::RequestId, SectorSelectState> i(d->m_pendingSectorSelectCommands); + while (i.hasNext()) { + i.next(); + + SectorSelectState &state = i.value(); + + if (state.timerId == event->timerId()) { + d->m_currentSector = state.sector; + + setResponseForRequest(i.key(), true); + + i.remove(); + + break; + } + } +} + +#include "moc_qnearfieldtagtype2.cpp" diff --git a/src/nfc/qnearfieldtagtype2.h b/src/nfc/qnearfieldtagtype2.h new file mode 100644 index 00000000..ad83fe8b --- /dev/null +++ b/src/nfc/qnearfieldtagtype2.h @@ -0,0 +1,87 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QNEARFIELDTAGTYPE2_H +#define QNEARFIELDTAGTYPE2_H + +#include <qnearfieldtarget.h> + +QT_BEGIN_HEADER + +class QNearFieldTagType2Private; + +class Q_CONNECTIVITY_EXPORT QNearFieldTagType2 : public QNearFieldTarget +{ + Q_OBJECT + + Q_DECLARE_PRIVATE(QNearFieldTagType2) + +public: + explicit QNearFieldTagType2(QObject *parent = 0); + ~QNearFieldTagType2(); + + Type type() const { return NfcTagType2; } + + bool hasNdefMessage(); + RequestId readNdefMessages(); + RequestId writeNdefMessages(const QList<QNdefMessage> &messages); + + quint8 version(); + int memorySize(); + + virtual RequestId readBlock(quint8 blockAddress); + virtual RequestId writeBlock(quint8 blockAddress, const QByteArray &data); + virtual RequestId selectSector(quint8 sector); + + bool waitForRequestCompleted(const RequestId &id, int msecs = 5000); + + void timerEvent(QTimerEvent *event); + +protected: + bool handleResponse(const QNearFieldTarget::RequestId &id, const QByteArray &response); + +private: + QNearFieldTagType2Private *d_ptr; +}; + +QT_END_HEADER + +#endif // QNEARFIELDTAGTYPE2_H diff --git a/src/nfc/qnearfieldtagtype2_symbian.cpp b/src/nfc/qnearfieldtagtype2_symbian.cpp new file mode 100644 index 00000000..adac6370 --- /dev/null +++ b/src/nfc/qnearfieldtagtype2_symbian.cpp @@ -0,0 +1,245 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <nfctag.h> +#include <QVariant> +#include "qnearfieldtagtype2_symbian_p.h" +#include <qnearfieldtarget_p.h> + +//#define SYMBIAN_NEED_CRC +//#define SYMBIAN_RETURN_CRC +//#define SYMBIAN_RETURN_NO_ACK + +static void OutputByteArray(const QByteArray& data) +{ + for(int i = 0; i < data.count(); ++i) + { + LOG("data ["<<i<<"] = "<<((quint16)(data.at(i)))); + } +} + +QNearFieldTagType2Symbian::QNearFieldTagType2Symbian(CNearFieldNdefTarget *tag, QObject *parent) + : QNearFieldTagType2(parent), QNearFieldTagImpl(tag), mCurrentSector(0) +{ +} + +QNearFieldTagType2Symbian::~QNearFieldTagType2Symbian() +{ + BEGIN + END +} + +QVariant QNearFieldTagType2Symbian::decodeResponse(const QByteArray& command, const QByteArray& response) +{ + BEGIN + OutputByteArray(response); + + QVariant result; + switch(command.at(0)) + { + case 0x30: + { + // read command +#ifdef SYMBIAN_RETURN_CRC + result = response.left(16); +#else + result = response; +#endif + break; + } + case 0xA2: + { +#ifdef SYMBIAN_RETURN_NO_ACK + result = true; +#else + // write command + result = (response.at(0) == 0x0A); +#endif + break; + } + default: + { +#ifdef SYMBIAN_RETURN_CRC + result = response.left(16); +#else + result = response; +#endif + } + } + END + return result; +} + +QNearFieldTarget::RequestId QNearFieldTagType2Symbian::readBlock(quint8 blockAddress) +{ + BEGIN + QByteArray command; + command.append(char(0x30)); // READ + command.append(char(blockAddress)); // Block address + +#ifdef SYMBIAN_NEED_CRC + // append CRC + quint16 crc = qNfcChecksum(command.constData(), command.count()); + command.append((unsigned char)(crc&0xFF)); + command.append((unsigned char)((crc>>8)&0xFF)); +#endif + END + return sendCommand(command); +} + +QNearFieldTarget::RequestId QNearFieldTagType2Symbian::writeBlock(quint8 blockAddress, const QByteArray &data) +{ + BEGIN + if (data.length() != 4) + { + END + return QNearFieldTarget::RequestId(); + } + QByteArray command; + command.append(char(0xa2)); // WRITE + command.append(char(blockAddress)); // Block address + command.append(data); // Data + +#ifdef SYMBIAN_NEED_CRC + // append CRC + quint16 crc = qNfcChecksum(command.constData(), command.count()); + command.append((unsigned char)(crc&0xFF)); + command.append((unsigned char)((crc>>8)&0xFF)); +#endif + + END + return sendCommand(command); +} + +QNearFieldTarget::RequestId QNearFieldTagType2Symbian::selectSector(quint8 sector) +{ + BEGIN + QByteArray command; + command.append(char(0xc2)); // SECTOR SELECT (Command Packet 1) + command.append(char(0xff)); + +#ifdef SYMBIAN_NEED_CRC + // append CRC + quint16 crc = qNfcChecksum(command.constData(), command.count()); + command.append((unsigned char)(crc&0xFF)); + command.append((unsigned char)((crc>>8)&0xFF)); +#endif + + RequestId id = sendCommand(command); + + if (!_waitForRequestCompletedNoSignal(id, 1)) + { + END + return QNearFieldTarget::RequestId(); + } + else + { + command.clear(); + command.append(char(sector)); // Sector number + command.append(QByteArray(3, char(0x00))); // RFU +#ifdef SYMBIAN_NEED_CRC + // append CRC + quint16 crc = qNfcChecksum(command.constData(), command.count()); + command.append((unsigned char)(crc&0xFF)); + command.append((unsigned char)((crc>>8)&0xFF)); +#endif + END + return sendCommand(command); + } +} + +QNearFieldTarget::RequestId QNearFieldTagType2Symbian::sendCommand(const QByteArray &command) +{ + BEGIN + END + return _sendCommand(command); +} + +QNearFieldTarget::RequestId QNearFieldTagType2Symbian::sendCommands(const QList<QByteArray> &commands) +{ + BEGIN + END + return _sendCommands(commands); +} + +bool QNearFieldTagType2Symbian::hasNdefMessage() +{ + return _hasNdefMessage(); +} + +QNearFieldTarget::RequestId QNearFieldTagType2Symbian::readNdefMessages() +{ + BEGIN + END + return _ndefMessages(); +} + +QNearFieldTarget::RequestId QNearFieldTagType2Symbian::writeNdefMessages(const QList<QNdefMessage> &messages) +{ + BEGIN + END + return _setNdefMessages(messages); +} + +QByteArray QNearFieldTagType2Symbian::uid() const +{ + BEGIN + END + return _uid(); +} + +void QNearFieldTagType2Symbian::handleTagOperationResponse(const RequestId &id, const QByteArray &command, const QByteArray &response, bool emitRequestCompleted) +{ + BEGIN + Q_UNUSED(command); + QVariant decodedResponse = decodeResponse(command, response); + setResponseForRequest(id, decodedResponse, emitRequestCompleted); + END +} + +bool QNearFieldTagType2Symbian::waitForRequestCompleted(const RequestId &id, int msecs) +{ + BEGIN + END + return _waitForRequestCompleted(id, msecs); +} + +#include "moc_qnearfieldtagtype2_symbian_p.cpp" diff --git a/src/nfc/qnearfieldtagtype2_symbian_p.h b/src/nfc/qnearfieldtagtype2_symbian_p.h new file mode 100644 index 00000000..10ac6066 --- /dev/null +++ b/src/nfc/qnearfieldtagtype2_symbian_p.h @@ -0,0 +1,96 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QNEARFIELDTAGTYPE2SYMBIAN_H +#define QNEARFIELDTAGTYPE2SYMBIAN_H + +#include <qnearfieldtagtype2.h> +#include "symbian/nearfieldndeftarget_symbian.h" +#include "symbian/nearfieldtag_symbian.h" +#include "symbian/nearfieldtagimpl_symbian.h" + +QT_BEGIN_HEADER + +class QNearFieldTagType2Symbian : public QNearFieldTagType2, private QNearFieldTagImpl<QNearFieldTagType2Symbian> +{ + Q_OBJECT +public: + explicit QNearFieldTagType2Symbian(CNearFieldNdefTarget * tag, QObject *parent = 0); + + ~QNearFieldTagType2Symbian(); + + QByteArray uid() const; + + RequestId readBlock(quint8 blockAddress); + RequestId writeBlock(quint8 blockAddress, const QByteArray &data); + RequestId selectSector(quint8 sector); + + RequestId sendCommand(const QByteArray &command); + RequestId sendCommands(const QList<QByteArray> &commands); + bool isProcessingCommand() const { return _isProcessingRequest(); } + + bool hasNdefMessage(); + RequestId readNdefMessages(); + RequestId writeNdefMessages(const QList<QNdefMessage> &messages); + + void setAccessMethods(const QNearFieldTarget::AccessMethods& accessMethods) + { + _setAccessMethods(accessMethods); + } + + QNearFieldTarget::AccessMethods accessMethods() const + { + return _accessMethods(); + } + + void handleTagOperationResponse(const RequestId &id, const QByteArray &command, const QByteArray &response, bool emitRequestCompleted); + QVariant decodeResponse(const QByteArray &command, const QByteArray &response); + + bool waitForRequestCompleted(const RequestId &id, int msecs = 5000); + friend class QNearFieldTagImpl<QNearFieldTagType2Symbian>; + +private: + quint8 mCurrentSector; +}; + +QT_END_HEADER + +#endif //QNEARFIELDTAGTYPE2SYMBIAN_H diff --git a/src/nfc/qnearfieldtagtype3.cpp b/src/nfc/qnearfieldtagtype3.cpp new file mode 100644 index 00000000..2c751b09 --- /dev/null +++ b/src/nfc/qnearfieldtagtype3.cpp @@ -0,0 +1,185 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qnearfieldtagtype3.h" + +/*! + \class QNearFieldTagType3 + \brief The QNearFieldTagType3 class provides an interface for communicating with an NFC Tag + Type 3 tag. + \since 5.0 + + \ingroup connectivity-nfc + \inmodule QtConnectivity +*/ + +/*! + \fn Type QNearFieldTagType3::type() const + \reimp +*/ + +/*! + Constructs a new tag type 3 near field target with \a parent. +*/ +QNearFieldTagType3::QNearFieldTagType3(QObject *parent) : + QNearFieldTarget(parent) +{ +} + +/*! + Returns the system code of the target. +*/ +quint16 QNearFieldTagType3::systemCode() +{ + return 0; +} + +/*! + Returns a list of available services. +*/ +QList<quint16> QNearFieldTagType3::services() +{ + return QList<quint16>(); +} + +/*! + Returns the memory size of the service specified by \a serviceCode. +*/ +int QNearFieldTagType3::serviceMemorySize(quint16 serviceCode) +{ + Q_UNUSED(serviceCode); + + return 0; +} + +/*! + Requests the data contents of the service specified by \a serviceCode. Returns a request id + which can be used to track the completion status of the request. + + Once the request completes successfully the service data can be retrieved from the + requestResponse() function. The response of this request will be a QByteArray. + + \sa requestCompleted(), waitForRequestCompleted() +*/ +QNearFieldTarget::RequestId QNearFieldTagType3::serviceData(quint16 serviceCode) +{ + Q_UNUSED(serviceCode); + + return RequestId(); +} + +/*! + Writes \a data to the the service specified by \a serviceCode. Returns a request id which can + be used to track the completion status of the request. + + Once the request completes the response can be retrieved from the requestResponse() function. + The response of this request will be a boolean value, true for success; otherwise false. + + \sa requestCompleted(), waitForRequestCompleted() +*/ +QNearFieldTarget::RequestId QNearFieldTagType3::writeServiceData(quint16 serviceCode, + const QByteArray &data) +{ + Q_UNUSED(serviceCode); + Q_UNUSED(data); + + return RequestId(); +} + +/*! + Sends the \i check request to the target. Requests the service data blocks specified by + \a serviceBlockList. Returns a request id which can be used to track the completion status of + the request. + + The \a serviceBlockList parameter is a map with the key being the service code and the value + being a list of block indexes to retrieve. + + Once the request completes the response can be retrieved from the requestResponse() function. + The response of this request will be a QMap<quint16, QByteArray>, with the key being the + service code and the value being the concatenated blocks retrieved for that service. + + This is a low level function, to retrieve the entire data contents of a service use + serviceData(). + + \sa requestCompleted(), waitForRequestCompleted() +*/ +QNearFieldTarget::RequestId QNearFieldTagType3::check(const QMap<quint16, QList<quint16> > &serviceBlockList) +{ + Q_UNUSED(serviceBlockList); + + return RequestId(); +} + +/*! + Sends the \i update request to the target. Writes \a data to the services and block indexes + sepecified by \a serviceBlockList. Returns a request id which can be used to track the + completion status of the request. + + The \a serviceBlockList parameter is a map with the key being the service code and the value + being a list of block indexes to write to. + + Once the request completes the response can be retried from the requestResponse() function. The + response of this request will be a boolean value, true for success; otherwise false. + + This is a low level function, to write the entire data contents of a service use + writeServiceData(). + + \sa requestCompleted(), waitForRequestCompleted() +*/ +QNearFieldTarget::RequestId QNearFieldTagType3::update(const QMap<quint16, QList<quint16> > &serviceBlockList, + const QByteArray &data) +{ + Q_UNUSED(serviceBlockList); + Q_UNUSED(data); + + return RequestId(); +} + +/*! + \reimp +*/ +bool QNearFieldTagType3::handleResponse(const QNearFieldTarget::RequestId &id, + const QByteArray &response) +{ + return QNearFieldTarget::handleResponse(id, response); +} + +#include "moc_qnearfieldtagtype3.cpp" diff --git a/src/nfc/qnearfieldtagtype3.h b/src/nfc/qnearfieldtagtype3.h new file mode 100644 index 00000000..7ab9721d --- /dev/null +++ b/src/nfc/qnearfieldtagtype3.h @@ -0,0 +1,78 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QNEARFIELDTAGTYPE3_H +#define QNEARFIELDTAGTYPE3_H + +#include <qnearfieldtarget.h> + +#include <QtCore/QList> +#include <QtCore/QMap> + +QT_BEGIN_HEADER + +class Q_CONNECTIVITY_EXPORT QNearFieldTagType3 : public QNearFieldTarget +{ + Q_OBJECT + +public: + explicit QNearFieldTagType3(QObject *parent = 0); + + Type type() const { return NfcTagType3; } + + quint16 systemCode(); + QList<quint16> services(); + int serviceMemorySize(quint16 serviceCode); + + virtual RequestId serviceData(quint16 serviceCode); + virtual RequestId writeServiceData(quint16 serviceCode, const QByteArray &data); + + virtual RequestId check(const QMap<quint16, QList<quint16> > &serviceBlockList); + virtual RequestId update(const QMap<quint16, QList<quint16> > &serviceBlockList, + const QByteArray &data); + +protected: + bool handleResponse(const QNearFieldTarget::RequestId &id, const QByteArray &response); +}; + +QT_END_HEADER + +#endif // QNEARFIELDTAGTYPE3_H diff --git a/src/nfc/qnearfieldtagtype3_symbian.cpp b/src/nfc/qnearfieldtagtype3_symbian.cpp new file mode 100644 index 00000000..b7c66a6a --- /dev/null +++ b/src/nfc/qnearfieldtagtype3_symbian.cpp @@ -0,0 +1,504 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <nfctag.h> +#include "qnearfieldtagtype3_symbian_p.h" +#include <nfctype3connection.h> +#include <QtEndian> +#include <QVariant> + +/* For all #if 0 blocks: this is due to symbian RawModeAccess API is not + * available yet. After the RawModeAccess API is stable, those blocks + * should be enabled. + */ + +#define SYMBIAN_RESP_INCLUDE_LEN + +static void OutputByteArray(const QByteArray& data) +{ + for(int i = 0; i < data.count(); ++i) + { + LOG("data ["<<i<<"] = "<<((quint16)(data.at(i)))); + } +} + +static void OutputCmdMap(const QMap<quint16, QList<quint16> >& data) +{ + QList<quint16> mapKeys = data.keys(); + for(int i = 0; i < mapKeys.count(); ++i) + { + LOG("cmd Map key "<<mapKeys.at(i)<<" value "<<data.value(mapKeys.at(i))); + } +} + +static void OutputRspMap(const QMap<quint16, QByteArray>& data) +{ + QList<quint16> mapKeys = data.keys(); + for(int i = 0; i < mapKeys.count(); ++i) + { + LOG("rsp Map key "<<mapKeys.at(i)); + OutputByteArray(data.value(mapKeys.at(i))); + } +} + +QNearFieldTagType3Symbian::QNearFieldTagType3Symbian(CNearFieldNdefTarget *tag, QObject *parent) + : QNearFieldTagType3(parent), QNearFieldTagImpl(tag) +{ + // It's silly, but easy. + getIDm(); +} + +QNearFieldTagType3Symbian::~QNearFieldTagType3Symbian() +{ +} + +QByteArray QNearFieldTagType3Symbian::uid() const +{ + return _uid(); +} + +QVariant QNearFieldTagType3Symbian::decodeResponse(const QByteArray & command, const QByteArray &response) +{ + BEGIN + OutputByteArray(response); +#ifndef SYMBIAN_RESP_INCLUDE_LEN + QVariant result; + if (command.count() < 0) + { + END; + return result; + } + + switch(command.at(0)) + { + case 0x06: + { + // check command + result.setValue(checkResponse2ServiceBlockList(cmd2ServiceBlockList(command), response)); + break; + } + case 0x08: + { + result = (response.at(9) == 0); + break; + } + default: + { + result = response; + } + + } + END +#else + QVariant result; + if (command.count() < 0) + { + END; + return result; + } + QByteArray newResponse = response.right(response.count() - 1); + switch(command.at(0)) + { + case 0x06: + { + // check command + result.setValue(checkResponse2ServiceBlockList(cmd2ServiceBlockList(command), newResponse)); + break; + } + case 0x08: + { + result = (newResponse.at(9) == 0); + break; + } + default: + { + result = newResponse; + } + } + END +#endif + return result; +} + +bool QNearFieldTagType3Symbian::hasNdefMessage() +{ +#if 0 + BEGIN + bool hasNdef = false; + QList<quint16> blockList; + // first block + blockList.append(0); + // NDEF service + quint16 serviceCode = 0x0B; + + QMap<quint16, QList<quint16> > serviceBlockList; + serviceBlockList.insert(serviceCode, blockList); + + QNearFieldTarget::RequestId id = check(serviceBlockList); + + if (_waitForRequestCompletedNoSignal(id)) + { + QMap<quint16, QByteArray> result = requestResponse(id).value<QMap<quint16, QByteArray> >(); + if (result.contains(serviceCode)) + { + const QByteArray& lens = result.value(serviceCode); + if (!lens.isEmpty()) + { + quint32 len = lens.at(11); + len<<=8; + len |= lens.at(12); + len<<=8; + len |= lens.at(13); + hasNdef = (len > 0); + } + } + } + END + return hasNdef; +#endif + return _hasNdefMessage(); +} + +QNearFieldTarget::RequestId QNearFieldTagType3Symbian::readNdefMessages() +{ + return _ndefMessages(); +} + +QNearFieldTarget::RequestId QNearFieldTagType3Symbian::writeNdefMessages(const QList<QNdefMessage> &messages) +{ + return _setNdefMessages(messages); +} + +QNearFieldTarget::RequestId QNearFieldTagType3Symbian::sendCommand(const QByteArray &command) +{ + return _sendCommand(command); +} + +QNearFieldTarget::RequestId QNearFieldTagType3Symbian::sendCommands(const QList<QByteArray> &commands) +{ + return _sendCommands(commands); +} + +#if 0 +quint16 QNearFieldTagType3Symbian::systemCode() +{ + return 0; +} + +QList<quint16> QNearFieldTagType3Symbian::services() +{ + return QList<quint16>(); +} + +int QNearFieldTagType3Symbian::serviceMemorySize(quint16 serviceCode) +{ + Q_UNUSED(serviceCode); + return 0; +} + +QNearFieldTarget::RequestId QNearFieldTagType3Symbian::serviceData(quint16 serviceCode) +{ + Q_UNUSED(serviceCode); + return QNearFieldTarget::RequestId(); +} + +QNearFieldTarget::RequestId QNearFieldTagType3Symbian::writeServiceData(quint16 serviceCode, const QByteArray &data) +{ + Q_UNUSED(serviceCode); + Q_UNUSED(data); + + return RequestId(); +} +#endif + +QNearFieldTarget::RequestId QNearFieldTagType3Symbian::check(const QMap<quint16, QList<quint16> > &serviceBlockList) +{ + BEGIN + quint8 numberOfBlocks; + QByteArray command; + command.append(0x06); // command code + command.append(serviceBlockList2CmdParam(serviceBlockList, numberOfBlocks, true)); + if (command.count() > 1) + { + END + return (_sendCommand(command)); + } + else + { + END + return QNearFieldTarget::RequestId(); + } +} + +QNearFieldTarget::RequestId QNearFieldTagType3Symbian::update(const QMap<quint16, QList<quint16> > &serviceBlockList, const QByteArray &data) +{ + BEGIN + quint8 numberOfBlocks; + QByteArray command; + command.append(0x08); // command code + command.append(serviceBlockList2CmdParam(serviceBlockList, numberOfBlocks, false)); + if (command.count() > 1) + { + command.append(data); + END + return (_sendCommand(command)); + } + else + { + END + return QNearFieldTarget::RequestId(); + } +} + +const QByteArray& QNearFieldTagType3Symbian::getIDm() +{ + BEGIN + if (mIDm.isEmpty()) + { + // this is the first time to get IDm + CNearFieldTag * tag = mTag->CastToTag(); + + if (tag) + { + CNfcType3Connection * connection = static_cast<CNfcType3Connection *>(tag->TagConnection()); + TBuf8<8> IDm; + TInt error = connection->GetIDm(IDm); + if (KErrNone == error) + { + mIDm = QNFCNdefUtility::TDesC2QByteArray(IDm); + } + } + } + OutputByteArray(mIDm); + END + return mIDm; +} + +QByteArray QNearFieldTagType3Symbian::serviceBlockList2CmdParam(const QMap<quint16, QList<quint16> > &serviceBlockList, quint8& numberOfBlocks, bool isCheckCommand) +{ + BEGIN + OutputCmdMap(serviceBlockList); + QByteArray command; + command.append(getIDm()); + numberOfBlocks = 0; + + if (command.isEmpty()) + { + // can't get IDm + END + return command; + } + + quint8 numberOfServices = serviceBlockList.keys().count(); + + if ((numberOfServices > 16) || (numberOfServices < 1)) + { + // out of range of services number + END + return QByteArray(); + } + else + { + command.append(numberOfServices); + } + + quint8 serviceCodeListOrder = 0; + QByteArray serviceCodeList; + QByteArray blockList; + foreach(const quint16 serviceCode, serviceBlockList.keys()) + { + serviceCodeList.append(reinterpret_cast<const char *>(&serviceCode), sizeof(quint16)); + + numberOfBlocks += serviceBlockList.value(serviceCode).count(); + LOG("numberOfBlocks "<<numberOfBlocks) + if ( (isCheckCommand && (numberOfBlocks > 12)) || + (!isCheckCommand && (numberOfBlocks > 8)) ) + { + // out of range of block number + LOG("out of range of block number"); + END + return QByteArray(); + } + + foreach(const quint16 blockNumber, serviceBlockList.value(serviceCode)) + { + if (blockNumber > 255) + { + // 3 bytes format + blockList.append(0x00 | (serviceCodeListOrder & 0x0F)); + quint16 blkNum = blockNumber; + blkNum = qToLittleEndian(blkNum); + blockList.append(reinterpret_cast<const char *>(&blkNum), sizeof(quint16)); + } + else // 2 bytes format + { + blockList.append(0x80 | (serviceCodeListOrder & 0x0F)); + quint8 blkNum = blockNumber; + blockList.append(blkNum); + } + } + } + + if (numberOfBlocks < 1) + { + // out of range of block number + LOG("out of range of block number, number of blocks < 1"); + END + return QByteArray(); + } + + command.append(serviceCodeList); + command.append(numberOfBlocks); + command.append(blockList); + OutputByteArray(command); + END + return command; +} + +QMap<quint16, QList<quint16> > QNearFieldTagType3Symbian::cmd2ServiceBlockList(const QByteArray& cmd) +{ + BEGIN + QMap<quint16, QList<quint16> > result; + // skip command code and IDm + QByteArray data = cmd.right(cmd.count() - 9); + + quint8 numberOfServices = data.at(0); + + QByteArray serviceCodeList = data.mid(1, 2 * numberOfServices); + + quint8 numberOfBlocks = data.at(2 * numberOfServices + 1); + + QByteArray blockList = data.right(data.count() - 1 - 2*numberOfServices - 1); + + QList<quint16> svcList; + for (int i = 0; i < numberOfServices; ++i) + { + unsigned char bytes[2]; + bytes[0] = serviceCodeList.at(i*2); + bytes[1] = serviceCodeList.at(i*2+1); + quint16 serviceCode = qFromLittleEndian<quint16>(bytes); + svcList.append(serviceCode); + } + + for (int j = 0, k = 0; j < numberOfBlocks; ++j, ++k) + { + quint8 byte0 = blockList.at(k); + quint8 serviceCodeListOrder = byte0 & 0x0F; + quint16 blockNumber = 0; + + if (byte0 & 0x80) + { + // two bytes format + blockNumber = blockList.at(++k); + } + else + { + // three bytes format + unsigned char bytes[2]; + bytes[0] = blockList.at(++k); + bytes[1] = blockList.at(++k); + blockNumber = qFromLittleEndian<quint16>(bytes); + } + + if (result.contains(svcList.at(serviceCodeListOrder))) + { + result[svcList.at(serviceCodeListOrder)].append(blockNumber); + } + else + { + QList<quint16> blocks; + blocks.append(blockNumber); + result.insert(svcList.at(serviceCodeListOrder), blocks); + } + } + + OutputCmdMap(result); + + END + return result; +} + +QMap<quint16, QByteArray> QNearFieldTagType3Symbian::checkResponse2ServiceBlockList(const QMap<quint16, QList<quint16> > &serviceBlockList, const QByteArray& response) +{ + BEGIN + OutputCmdMap(serviceBlockList); + QMap<quint16, QByteArray> result; + // at least, the response should contain resp code + IDM + status flags + if (response.count() < 11) + { + END + return result; + } + + if ((response.at(0) != 0x07) || (response.mid(1,8) != getIDm()) || (response.at(10) != 0)) + { + END + return result; + } + + quint32 index = 12; + foreach(const quint16 serviceCode, serviceBlockList.keys()) + { + quint8 blockCount = serviceBlockList.value(serviceCode).count(); + result.insert(serviceCode, response.mid(index, 16*blockCount)); + index+=16*blockCount; + } + OutputRspMap(result); + END + return result; +} + + +void QNearFieldTagType3Symbian::handleTagOperationResponse(const RequestId &id, const QByteArray &command, const QByteArray &response, bool emitRequestCompleted) +{ + Q_UNUSED(command); + QVariant decodedResponse = decodeResponse(command, response); + setResponseForRequest(id, decodedResponse, emitRequestCompleted); +} + +bool QNearFieldTagType3Symbian::waitForRequestCompleted(const RequestId &id, int msecs) +{ + BEGIN + END + return _waitForRequestCompleted(id, msecs); +} + +#include "moc_qnearfieldtagtype3_symbian_p.cpp" diff --git a/src/nfc/qnearfieldtagtype3_symbian_p.h b/src/nfc/qnearfieldtagtype3_symbian_p.h new file mode 100644 index 00000000..a726ae8b --- /dev/null +++ b/src/nfc/qnearfieldtagtype3_symbian_p.h @@ -0,0 +1,112 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QNEARFIELDTAGTYPE3SYMBIAN_H +#define QNEARFIELDTAGTYPE3SYMBIAN_H + +#include <qnearfieldtagtype3.h> +#include "symbian/nearfieldtagimpl_symbian.h" +#include "symbian/nearfieldndeftarget_symbian.h" + +QT_BEGIN_HEADER + +class QNearFieldTagType3Symbian : public QNearFieldTagType3, private QNearFieldTagImpl<QNearFieldTagType3Symbian> +{ + Q_OBJECT +public: + + explicit QNearFieldTagType3Symbian(CNearFieldNdefTarget *tag, QObject *parent = 0); + + ~QNearFieldTagType3Symbian(); + + virtual QByteArray uid() const; + + void setAccessMethods(const QNearFieldTarget::AccessMethods& accessMethods) + { + _setAccessMethods(accessMethods); + } + + QNearFieldTarget::AccessMethods accessMethods() const + { + return _accessMethods(); + } + + bool hasNdefMessage(); + RequestId readNdefMessages(); + RequestId writeNdefMessages(const QList<QNdefMessage> &messages); + +#if 0 + quint16 systemCode(); + QList<quint16> services(); + int serviceMemorySize(quint16 serviceCode); + + + RequestId serviceData(quint16 serviceCode); + RequestId writeServiceData(quint16 serviceCode, const QByteArray &data); +#endif + + RequestId check(const QMap<quint16, QList<quint16> > &serviceBlockList); + RequestId update(const QMap<quint16, QList<quint16> > &serviceBlockList, + const QByteArray &data); + + bool isProcessingCommand() const { return _isProcessingRequest(); } + RequestId sendCommand(const QByteArray &command); + RequestId sendCommands(const QList<QByteArray> &commands); + bool waitForRequestCompleted(const RequestId &id, int msecs = 5000); +private: + const QByteArray& getIDm(); + QByteArray serviceBlockList2CmdParam(const QMap<quint16, QList<quint16> > &serviceBlockList, quint8& numberOfBlocks, bool isCheckCommand); + QMap<quint16, QList<quint16> > cmd2ServiceBlockList(const QByteArray& cmd); + + QMap<quint16, QByteArray> checkResponse2ServiceBlockList(const QMap<quint16, QList<quint16> > &serviceBlockList, const QByteArray& response); + + void handleTagOperationResponse(const RequestId &id, const QByteArray &command, const QByteArray &response, bool emitRequestCompleted); + QVariant decodeResponse(const QByteArray & command, const QByteArray &response); +private: + QByteArray mIDm; + friend class QNearFieldTagImpl<QNearFieldTagType3Symbian>; +}; + +typedef QMap<quint16,QByteArray> checkResponseType; +Q_DECLARE_METATYPE(checkResponseType) +QT_END_HEADER +#endif // QNEARFIELDTAGTYPE3SYMBIAN_H + diff --git a/src/nfc/qnearfieldtagtype4.cpp b/src/nfc/qnearfieldtagtype4.cpp new file mode 100644 index 00000000..19cf8b80 --- /dev/null +++ b/src/nfc/qnearfieldtagtype4.cpp @@ -0,0 +1,161 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qnearfieldtagtype4.h" + +/*! + \class QNearFieldTagType4 + \brief The QNearFieldTagType4 class provides an interface for communicating with an NFC Tag + Type 4 tag. + \since 5.0 + + \ingroup connectivity-nfc + \inmodule QtConnectivity +*/ + +/*! + \fn Type QNearFieldTagType4::type() const + \reimp +*/ + +/*! + Constructs a new tag type 4 near field target with \a parent. +*/ +QNearFieldTagType4::QNearFieldTagType4(QObject *parent) +: QNearFieldTarget(parent) +{ +} + +/*! + Destroys the tag type 4 near field target. +*/ +QNearFieldTagType4::~QNearFieldTagType4() +{ +} + +/*! + Returns the NFC Tag Type 4 specification version number that the tag supports. +*/ +quint8 QNearFieldTagType4::version() +{ + return 0; +} + +/*! + Requests that the file specified by \a name be selected. Upon success calls to read() and + write() will act on the selected file. Returns a request id which can be used to track the + completion status of the request. + + Once the request completes the response can be retrieved from the requestResponse() function. + The response of this request will be a boolean value, true for success; otherwise false. + + \sa requestCompleted(), waitForRequestCompleted() +*/ +QNearFieldTarget::RequestId QNearFieldTagType4::select(const QByteArray &name) +{ + Q_UNUSED(name); + + return RequestId(); +} + +/*! + Requests that the file specified by \a fileIdentifier be selected. Upon success calls to read() + and write() will act on the selected file. Returns a request id which can be used to track the + completion status of the request. + + Once the request completes the response can be retrieved from the requestResponse() function. + The response of this request will be a boolean value, true for success; otherwise false. + + \sa requestCompleted(), waitForRequestCompleted() +*/ +QNearFieldTarget::RequestId QNearFieldTagType4::select(quint16 fileIdentifier) +{ + Q_UNUSED(fileIdentifier); + + return RequestId(); +} + +/*! + Requests that \a length bytes be read from the currently selected file starting from + \a startOffset. If \a length is 0 all data or the maximum read size bytes will be read, + whichever is smaller. Returns a request id which can be used to track the completion status of + the request. + + Once the request completes successfully the response can be retrieved from the + requestResponse() function. The response of this request will be a QByteArray. + + \sa requestCompleted(), waitForRequestCompleted() +*/ +QNearFieldTarget::RequestId QNearFieldTagType4::read(quint16 length, quint16 startOffset) +{ + Q_UNUSED(length); + Q_UNUSED(startOffset); + + return RequestId(); +} + +/*! + Writes \a data to the currently selected file starting at \a startOffset. Returns a request id + which can be used to track the completion status of the request. + + Once the request completes the response can be retrieved from the requestResponse() function. + The response of this request will be a boolean value, true for success; otherwise false. + + \sa requestCompleted(), waitForRequestCompleted() +*/ +QNearFieldTarget::RequestId QNearFieldTagType4::write(const QByteArray &data, quint16 startOffset) +{ + Q_UNUSED(data); + Q_UNUSED(startOffset); + + return RequestId(); +} + +/*! + \reimp +*/ +bool QNearFieldTagType4::handleResponse(const QNearFieldTarget::RequestId &id, + const QByteArray &response) +{ + return QNearFieldTarget::handleResponse(id, response); +} + +#include "moc_qnearfieldtagtype4.cpp" diff --git a/src/nfc/qnearfieldtagtype4.h b/src/nfc/qnearfieldtagtype4.h new file mode 100644 index 00000000..d280580c --- /dev/null +++ b/src/nfc/qnearfieldtagtype4.h @@ -0,0 +1,73 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QNEARFIELDTAGTYPE4_H +#define QNEARFIELDTAGTYPE4_H + +#include <qnearfieldtarget.h> + +QT_BEGIN_HEADER + +class Q_CONNECTIVITY_EXPORT QNearFieldTagType4 : public QNearFieldTarget +{ + Q_OBJECT + +public: + explicit QNearFieldTagType4(QObject *parent = 0); + ~QNearFieldTagType4(); + + Type type() const { return NfcTagType4; } + + quint8 version(); + + virtual RequestId select(const QByteArray &name); + virtual RequestId select(quint16 fileIdentifier); + + virtual RequestId read(quint16 length = 0, quint16 startOffset = 0); + virtual RequestId write(const QByteArray &data, quint16 startOffset = 0); + +protected: + bool handleResponse(const QNearFieldTarget::RequestId &id, const QByteArray &response); +}; + +QT_END_HEADER + +#endif // QNEARFIELDTAGTYPE4_H diff --git a/src/nfc/qnearfieldtagtype4_symbian.cpp b/src/nfc/qnearfieldtagtype4_symbian.cpp new file mode 100644 index 00000000..b1940b62 --- /dev/null +++ b/src/nfc/qnearfieldtagtype4_symbian.cpp @@ -0,0 +1,396 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <nfctag.h> +#include <QVariant> +#include <QtEndian> +#include "symbian/nearfieldutility_symbian.h" +#include "qnearfieldtagtype4_symbian_p.h" + +static void OutputByteArray(const QByteArray& data) +{ + for(int i = 0; i < data.count(); ++i) + { + LOG("data ["<<i<<"] = "<<((quint16)(data.at(i)))); + } +} + +QNearFieldTagType4Symbian::QNearFieldTagType4Symbian(CNearFieldNdefTarget *tag, QObject *parent) + : QNearFieldTagType4(parent), QNearFieldTagImpl(tag) +{ +} + +QNearFieldTagType4Symbian::~QNearFieldTagType4Symbian() +{ +} + +QByteArray QNearFieldTagType4Symbian::uid() const +{ + return _uid(); +} + +quint8 QNearFieldTagType4Symbian::version() +{ + BEGIN + quint8 result = 0; + QByteArray resp; + resp.append(char(0x90)); + resp.append(char(0x00)); + + QNearFieldTarget::RequestId id = selectNdefApplication(); + if (_waitForRequestCompletedNoSignal(id)) + { + if (requestResponse(id).toByteArray().right(2) == resp) + { + // response is ok + // select cc + LOG("select cc"); + QNearFieldTarget::RequestId id1 = selectCC(); + if (_waitForRequestCompletedNoSignal(id1)) + { + if (requestResponse(id1).toBool()) + { + // response is ok + // read cc + LOG("read cc"); + QNearFieldTarget::RequestId id2 = read(0x0001,0x0002); + if (_waitForRequestCompletedNoSignal(id2)) + { + if (requestResponse(id2).toByteArray().right(2) == resp) + { + // response is ok + result = requestResponse(id2).toByteArray().at(0); + } + } + } + } + } + } + LOG("version is "<<result); + END + return result; +} + +QVariant QNearFieldTagType4Symbian::decodeResponse(const QByteArray &command, const QByteArray &response) +{ + BEGIN + QVariant result; + + OutputByteArray(response); + if ((command.count() > 2) && (0x00 == command.at(0))) + { + if ( (0xA4 == command.at(1)) || (0xD6 == command.at(1)) ) + { + if (response.count() >= 2) + { + LOG("select or write command"); + QByteArray resp = response.right(2); + result = ((resp.at(0) == 0x90) && (resp.at(1) == 0x00)); + } + } + else + { + LOG("read command"); + result = response; + } + } + END + return result; +} + +bool QNearFieldTagType4Symbian::hasNdefMessage() +{ + BEGIN + QByteArray resp; + resp.append(char(0x90)); + resp.append(char(0x00)); + + QNearFieldTarget::RequestId id = selectNdefApplication(); + if (!_waitForRequestCompletedNoSignal(id)) + { + LOG("select NDEF application failed"); + END + return false; + } + + if (!requestResponse(id).toBool()) + { + LOG("select NDEF application response is not ok"); + END + return false; + } + + QNearFieldTarget::RequestId id1 = selectCC(); + if (!_waitForRequestCompletedNoSignal(id1)) + { + LOG("select CC failed"); + END + return false; + } + + if (!requestResponse(id1).toBool()) + { + LOG("select CC response is not ok"); + END + return false; + } + + QNearFieldTarget::RequestId id2 = read(0x000F,0x0000); + if (!_waitForRequestCompletedNoSignal(id2)) + { + LOG("read CC failed"); + END + return false; + } + + QByteArray ccContent = requestResponse(id2).toByteArray(); + if (ccContent.right(2) != resp) + { + LOG("read CC response is "<<ccContent.right(2)); + END + return false; + } + + if ((ccContent.count() != (15 + 2)) && (ccContent.at(1) != 0x0F)) + { + LOG("CC is invalid"<<ccContent); + END + return false; + } + + quint8 temp = ccContent.at(9); + quint16 fileId = 0; + fileId |= temp; + fileId<<=8; + + temp = ccContent.at(10); + fileId |= temp; + + temp = ccContent.at(11); + quint16 maxNdefLen = 0; + maxNdefLen |= temp; + maxNdefLen<<=8; + + temp = ccContent.at(12); + maxNdefLen |= temp; + + QNearFieldTarget::RequestId id3 = select(fileId); + if (!_waitForRequestCompletedNoSignal(id3)) + { + LOG("select NDEF failed"); + END + return false; + } + if (!requestResponse(id3).toBool()) + { + END + return false; + } + + QNearFieldTarget::RequestId id4 = read(0x0002, 0x0000); + if (!_waitForRequestCompletedNoSignal(id4)) + { + LOG("read NDEF failed"); + END + return false; + } + QByteArray ndefContent = requestResponse(id4).toByteArray(); + if (ndefContent.right(2) != resp) + { + LOG("read NDEF response is "<<ndefContent.right(2)); + END + return false; + } + + if (ndefContent.count() != (2 + 2)) + { + LOG("ndef content invalid"); + END + return false; + } + + temp = ndefContent.at(0); + quint16 nLen = 0; + nLen |= temp; + nLen<<=8; + + temp = ndefContent.at(1); + nLen |= temp; + + END + return ( (nLen > 0) && (nLen < maxNdefLen -2) ); +} + +QNearFieldTarget::RequestId QNearFieldTagType4Symbian::readNdefMessages() +{ + return _ndefMessages(); +} + +QNearFieldTarget::RequestId QNearFieldTagType4Symbian::writeNdefMessages(const QList<QNdefMessage> &messages) +{ + return _setNdefMessages(messages); +} + +QNearFieldTarget::RequestId QNearFieldTagType4Symbian::sendCommand(const QByteArray &command) +{ + return _sendCommand(command); +} + +QNearFieldTarget::RequestId QNearFieldTagType4Symbian::sendCommands(const QList<QByteArray> &commands) +{ + return _sendCommands(commands); +} + +QNearFieldTarget::RequestId QNearFieldTagType4Symbian::select(const QByteArray &name) +{ + BEGIN + QByteArray command; + command.append(char(0x00)); // CLA + command.append(char(0xA4)); // INS + command.append(char(0x04)); // P1, select by name + command.append(char(0x00)); // First or only occurrence + command.append(char(0x07)); // Lc + command.append(name); + END + return _sendCommand(command); +} + +QNearFieldTarget::RequestId QNearFieldTagType4Symbian::select(quint16 fileIdentifier) +{ + BEGIN + QByteArray command; + command.append(char(0x00)); // CLA + command.append(char(0xA4)); // INS + command.append(char(0x00)); // P1, select by file identifier + command.append(char(0x00)); // First or only occurrence + command.append(char(0x02)); // Lc + quint16 temp = qToBigEndian<quint16>(fileIdentifier); + command.append(reinterpret_cast<const char*>(&temp), + sizeof(quint16)); + + END + return _sendCommand(command); +} + +QNearFieldTarget::RequestId QNearFieldTagType4Symbian::read(quint16 length, quint16 startOffset) +{ + BEGIN + QByteArray command; + command.append(char(0x00)); // CLA + command.append(char(0xB0)); // INS + quint16 temp = qToBigEndian<quint16>(startOffset); + command.append(reinterpret_cast<const char*>(&temp), + sizeof(quint16)); // P1/P2 offset + /*temp = qToBigEndian<quint16>(length); + command.append(reinterpret_cast<const char*>(&temp), + sizeof(quint16)); // Le*/ + command.append((quint8)length); + + END + return _sendCommand(command); +} + +QNearFieldTarget::RequestId QNearFieldTagType4Symbian::write(const QByteArray &data, quint16 startOffset) +{ + BEGIN + QByteArray command; + command.append(char(0x00)); // CLA + command.append(char(0xD6)); // INS + quint16 temp = qToBigEndian<quint16>(startOffset); + command.append(reinterpret_cast<const char *>(&temp), sizeof(quint16)); + quint16 length = data.count(); + if ((length > 0xFF) || (length < 0x01)) + { + END + return QNearFieldTarget::RequestId(); + } + else + { + /*quint16 temp = qToBigEndian<quint16>(length); + command.append(reinterpret_cast<const char *>(&temp), + sizeof(quint16));*/ + command.append((quint8)length); + } + + command.append(data); + END + return _sendCommand(command); +} + +QNearFieldTarget::RequestId QNearFieldTagType4Symbian::selectNdefApplication() +{ + BEGIN + QByteArray command; + command.append(char(0xD2)); + command.append(char(0x76)); + command.append(char(0x00)); + command.append(char(0x00)); + command.append(char(0x85)); + command.append(char(0x01)); + command.append(char(0x00)); + QNearFieldTarget::RequestId id = select(command); + END + return id; +} + +QNearFieldTarget::RequestId QNearFieldTagType4Symbian::selectCC() +{ + BEGIN + END + return select(0xe103); +} + +void QNearFieldTagType4Symbian::handleTagOperationResponse(const RequestId &id, const QByteArray &command, const QByteArray &response, bool emitRequestCompleted) +{ + BEGIN + Q_UNUSED(command); + QVariant decodedResponse = decodeResponse(command, response); + setResponseForRequest(id, decodedResponse, emitRequestCompleted); + END +} + +bool QNearFieldTagType4Symbian::waitForRequestCompleted(const RequestId &id, int msecs) +{ + BEGIN + END + return _waitForRequestCompleted(id, msecs); +} +#include "moc_qnearfieldtagtype4_symbian_p.cpp" diff --git a/src/nfc/qnearfieldtagtype4_symbian_p.h b/src/nfc/qnearfieldtagtype4_symbian_p.h new file mode 100644 index 00000000..6bf8bf59 --- /dev/null +++ b/src/nfc/qnearfieldtagtype4_symbian_p.h @@ -0,0 +1,104 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QNEARFIELDTAGTYPE4SYMBIAN_H +#define QNEARFIELDTAGTYPE4SYMBIAN_H + +#include <qnearfieldtagtype4.h> +#include "symbian/nearfieldndeftarget_symbian.h" +#include "symbian/nearfieldtag_symbian.h" +#include "symbian/nearfieldtagimpl_symbian.h" +#include "symbian/debug.h" + +QT_BEGIN_HEADER + +class QNearFieldTagType4Symbian : public QNearFieldTagType4, private QNearFieldTagImpl<QNearFieldTagType4Symbian> +{ + Q_OBJECT + +public: + + explicit QNearFieldTagType4Symbian(CNearFieldNdefTarget *tag, QObject *parent = 0); + + ~QNearFieldTagType4Symbian(); + + virtual QByteArray uid() const; + Type type() const { return NfcTagType4; } + quint8 version(); + + bool hasNdefMessage(); + RequestId readNdefMessages(); + RequestId writeNdefMessages(const QList<QNdefMessage> &messages); + + RequestId sendCommand(const QByteArray &command); + RequestId sendCommands(const QList<QByteArray> &commands); + + RequestId select(const QByteArray &name); + RequestId select(quint16 fileIdentifier); + + RequestId read(quint16 length = 0, quint16 startOffset = 0); + RequestId write(const QByteArray &data, quint16 startOffset = 0); + bool isProcessingCommand() const { return _isProcessingRequest(); } + bool waitForRequestCompleted(const RequestId &id, int msecs = 5000); + + void setAccessMethods(const QNearFieldTarget::AccessMethods& accessMethods) + { + _setAccessMethods(accessMethods); + } + + QNearFieldTarget::AccessMethods accessMethods() const + { + return _accessMethods(); + } + + void handleTagOperationResponse(const RequestId &id, const QByteArray &command, const QByteArray &response, bool emitRequestCompleted); + QVariant decodeResponse(const QByteArray &command, const QByteArray &response); + +private: + RequestId selectNdefApplication(); + RequestId selectCC(); + + friend class QNearFieldTagImpl<QNearFieldTagType4Symbian>; +}; + +QT_END_HEADER + +#endif // QNEARFIELDTAGTYPE4SYMBIAN_H diff --git a/src/nfc/qnearfieldtarget.cpp b/src/nfc/qnearfieldtarget.cpp new file mode 100644 index 00000000..8a7d25bc --- /dev/null +++ b/src/nfc/qnearfieldtarget.cpp @@ -0,0 +1,464 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qnearfieldtarget.h" +#include "qnearfieldtarget_p.h" +#include "qndefmessage.h" + +#include <QtCore/QString> +#include <QtCore/QUrl> +#include <QtCore/QVariant> + +#include <QtCore/QDebug> + +/*! + \class QNearFieldTarget + \brief The QNearFieldTarget class provides an interface for communicating with a target + device. + + \ingroup connectivity-nfc + \inmodule QtConnectivity + \since 5.0 + + QNearFieldTarget provides a generic interface for communicating with an NFC target device. + Both NFC Forum devices and NFC Forum Tag targets are supported by this class. All target + specific classes subclass this class. + + The type() function can be used to get the type of the target device. The uid() function + returns the unique identifier of the target. The AccessMethods flags returns from the + accessMethods() function can be tested to determine which access methods are supported by the + target. + + If the target supports NdefAccess, hasNdefMessage() can be called to test if the target has a + stored NDEF message, readNdefMessages() and writeNdefMessages() functions can be used to get + and set the NDEF message. + + If the target supports TagTypeSpecificAccess, sendCommand() can be used to send a single + proprietary command to the target and retrieve the response. sendCommands() can be used to + send multiple proprietary commands to the target and retrieve all of the responses. + + If the target supports LlcpAccess, the QLlcpSocket class can be used to connected to a + service provided by the target. +*/ + +/*! + \enum QNearFieldTarget::Type + + This enum describes the type of tag the target is detected as. + + \value AnyTarget This value is only used when registering handlers to indicate that any + compatible target can be used. + \value ProprietaryTag An unidentified proprietary target tag. + \value NfcTagType1 An NFC tag type 1 target. + \value NfcTagType2 An NFC tag type 2 target. + \value NfcTagType3 An NFC tag type 3 target. + \value NfcTagType4 An NFC tag type 4 target. + \value MifareTag A Mifare target. + \value NfcForumDevice An NFC Forum device target. +*/ + +/*! + \enum QNearFieldTarget::AccessMethod + + This enum describes the access methods a near field target supports. + + \value NdefAccess The target supports reading and writing NDEF messages using + readNdefMessages() and writeNdefMessages(). + \value TagTypeSpecificAccess The target supports sending tag type specific commands using + sendCommand() and sendCommands(). + \value LlcpAccess The target supports peer-to-peer LLCP communication. +*/ + +/*! + \enum QNearFieldTarget::Error + + This enum describes the error codes that that a near field target reports. + + \value NoError No error has occurred. + \value UnknownError An unidentified error occurred. + \value UnsupportedError The requested operation is unsupported by this near field + target. + \value TargetOutOfRangeError The target is no longer within range. + \value NoResponseError The target did not respond. + \value ChecksumMismatchError The checksum has detected a corrupted response. + \value InvalidParametersError Invalid parameters were passed to a tag type specific function. + \value NdefReadError Failed to read NDEF messages from the target. + \value NdefWriteError Failed to write NDEF messages to the target. +*/ + +/*! + \fn qNfcChecksum(const char *data, uint len) + + \relates QNearFieldTarget + + Returns the NFC checksum of the first \a len bytes of \a data. +*/ +#include "checksum_p.h" + +/*! + \fn void QNearFieldTarget::disconnected() + + This signal is emitted when the near field target moves out of proximity. +*/ + +/*! + \fn void QNearFieldTarget::ndefMessageRead(const QNdefMessage &message) + + This signal is emitted when a complete NDEF \a message has been read from the target. + + \sa readNdefMessages() +*/ + +/*! + \fn void QNearFieldTarget::ndefMessagesWritten() + + This signal is emitted when NDEF messages have been successfully written to the target. + + \sa writeNdefMessages() +*/ + +/*! + \fn void QNearFieldTarget::requestCompleted(const QNearFieldTarget::RequestId &id) + + This signal is emitted when a request \a id completes. + + \sa sendCommand() +*/ + +/*! + \fn void QNearFieldTarget::error(QNearFieldTarget::Error error, const QNearFieldTarget::RequestId &id) + + This signal is emitted when an error occurs while processing request \a id. The \a error + parameter describes the error. +*/ + +/*! + Constructs a new invalid request id handle. +*/ +QNearFieldTarget::RequestId::RequestId() +{ +} + +/*! + Constructs a new request id handle that is a copy of \a other. +*/ +QNearFieldTarget::RequestId::RequestId(const RequestId &other) +: d(other.d) +{ +} + +/*! + \internal +*/ +QNearFieldTarget::RequestId::RequestId(RequestIdPrivate *p) +: d(p) +{ +} + +/*! + Destroys the request id handle. +*/ +QNearFieldTarget::RequestId::~RequestId() +{ +} + +/*! + Returns true if this is a valid request id; otherwise returns false. +*/ +bool QNearFieldTarget::RequestId::isValid() const +{ + return d; +} + +/*! + Returns the current reference count of the request id. +*/ +int QNearFieldTarget::RequestId::refCount() const +{ + if (d) + return d->ref; + + return 0; +} + +/*! + \internal +*/ +bool QNearFieldTarget::RequestId::operator<(const RequestId &other) const +{ + return d < other.d; +} + +/*! + \internal +*/ +bool QNearFieldTarget::RequestId::operator==(const RequestId &other) const +{ + return d == other.d; +} + +/*! + \internal +*/ +bool QNearFieldTarget::RequestId::operator!=(const RequestId &other) const +{ + return d != other.d; +} + +/*! + Assigns a copy of \a other to this request id and returns a reference to this request id. +*/ +QNearFieldTarget::RequestId &QNearFieldTarget::RequestId::operator=(const RequestId &other) +{ + d = other.d; + return *this; +} + +/*! + Constructs a new near field target with \a parent. +*/ +QNearFieldTarget::QNearFieldTarget(QObject *parent) +: QObject(parent), d_ptr(new QNearFieldTargetPrivate) +{ + qRegisterMetaType<RequestId>("QNearFieldTarget::RequestId"); + qRegisterMetaType<Error>("QNearFieldTarget::Error"); +} + +/*! + Destroys the near field target. +*/ +QNearFieldTarget::~QNearFieldTarget() +{ + delete d_ptr; +} + +/*! + \fn QByteArray QNearFieldTarget::uid() const = 0 + + Returns the UID of the near field target. +*/ + +/*! + Returns the URL of the near field target. +*/ +QUrl QNearFieldTarget::url() const +{ + return QUrl(); +} + +/*! + \fn QNearFieldTarget::Type QNearFieldTarget::type() const = 0 + + Returns the type of tag type of this near field target. +*/ + +/*! + \fn QNearFieldTarget::AccessMethods QNearFieldTarget::accessMethods() const = 0 + + Returns the access methods support by this near field target. +*/ + +/*! + Returns true if the target is processing commands; otherwise returns false. +*/ +bool QNearFieldTarget::isProcessingCommand() const +{ + return false; +} + +/*! + Returns true if at least one NDEF message is stored on the near field target; otherwise returns + false. +*/ +bool QNearFieldTarget::hasNdefMessage() +{ + return false; +} + +/*! + Starts reading NDEF messages stored on the near field target. Returns a request id which can + be used to track the completion status of the request. An invalid request id will be returned + if the target does not support reading NDEF messages. + + An ndefMessageRead() signal will be emitted for each NDEF message. The requestCompleted() + signal will be emitted was all NDEF messages have been read. The error() signal is emitted if + an error occurs. + + \note Symbian^3 and Maemo 6 only support read one NDEF message. +*/ +QNearFieldTarget::RequestId QNearFieldTarget::readNdefMessages() +{ + return RequestId(); +} + +/*! + Writes the NDEF messages in \a messages to the target. Returns a request id which can be used + to track the completion status of the request. An invalid request id will be returned if the + target does not support reading NDEF messages. + + The ndefMessagesWritten() signal will be emitted when the write operation completes + successfully; otherwise the error() signal is emitted. + + \note Symbian^3 and Maemo 6 only support writing one NDEF message. Only the first NDEF message + in the list will be written, others are silently dropped. +*/ +QNearFieldTarget::RequestId QNearFieldTarget::writeNdefMessages(const QList<QNdefMessage> &messages) +{ + Q_UNUSED(messages); + + return RequestId(); +} + +/*! + Sends \a command to the near field target. Returns a request id which can be used to track the + completion status of the request. An invalid request id will be returned if the target does not + support sending tag type specific commands. + + The requestCompleted() signal will be emitted on successful completion of the request; + otherwise the error() signal will be emitted. + + Once the request completes successfully the response can be retrieved from the + requestResponse() function. The response of this request will be a QByteArray. + + \sa requestCompleted(), waitForRequestCompleted() +*/ +QNearFieldTarget::RequestId QNearFieldTarget::sendCommand(const QByteArray &command) +{ + Q_UNUSED(command); + + emit error(UnsupportedError, RequestId()); + + return RequestId(); +} + +/*! + Sends multiple \a commands to the near field target. Returns a request id which can be used to + track the completion status of the request. An invalid request id will be returned if the + target does not support sending tag type specific commands. + + If all commands complete successfully the requestCompleted() signal will be emitted; otherwise + the error() signal will be emitted. If a command fails succeeding commands from this call will + not be processed. + + Once the request completes the response for successfully completed requests can be retrieved + from the requestResponse() function. The response of this request will be a QList<QByteArray>. + + \sa requestCompleted(), waitForRequestCompleted() +*/ +QNearFieldTarget::RequestId QNearFieldTarget::sendCommands(const QList<QByteArray> &commands) +{ + Q_UNUSED(commands); + + emit error(UnsupportedError, RequestId()); + + return RequestId(); +} + +/*! + Waits up to \a msecs milliseconds for the request \a id to complete. Returns true if the + request completes successfully and the requestCompeted() signal is emitted; otherwise returns + false. +*/ +bool QNearFieldTarget::waitForRequestCompleted(const RequestId &id, int msecs) +{ + Q_UNUSED(msecs); + + Q_D(QNearFieldTarget); + + return d->m_decodedResponses.contains(id); +} + +/*! + Returns the decoded response for request \a id. If the request is unknown or has not yet been + completed an invalid QVariant is returned. +*/ +QVariant QNearFieldTarget::requestResponse(const RequestId &id) +{ + Q_D(QNearFieldTarget); + + return d->m_decodedResponses.value(id); +} + +/*! + Sets the decoded response for request \a id to \a response. If \a emitRequestCompleted is true + the requestCompleted() signal will be emitted for \a id; otherwise no signal will be emitted. + + \sa requestResponse() +*/ +void QNearFieldTarget::setResponseForRequest(const QNearFieldTarget::RequestId &id, + const QVariant &response, bool emitRequestCompleted) +{ + Q_D(QNearFieldTarget); + + QMutableMapIterator<RequestId, QVariant> i(d->m_decodedResponses); + while (i.hasNext()) { + i.next(); + + // no more external references + if (i.key().refCount() == 1) + i.remove(); + } + + d->m_decodedResponses.insert(id, response); + + if (emitRequestCompleted) + emit requestCompleted(id); +} + +/*! + Handles the \a response received for the request \a id. Returns true if the response is + handled; otherwise returns false. + + Classes reimplementing this virtual function should call the base class implementation to + ensure that requests initiated by those classes are handled correctly. + + The default implementation stores the response such that it can be retrieved by + requestResponse(). +*/ +bool QNearFieldTarget::handleResponse(const QNearFieldTarget::RequestId &id, + const QByteArray &response) +{ + setResponseForRequest(id, response); + + return true; +} + +#include "moc_qnearfieldtarget.cpp" diff --git a/src/nfc/qnearfieldtarget.h b/src/nfc/qnearfieldtarget.h new file mode 100644 index 00000000..7e081660 --- /dev/null +++ b/src/nfc/qnearfieldtarget.h @@ -0,0 +1,172 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#ifndef QNEARFIELDTARGET_H +#define QNEARFIELDTARGET_H + +#include "../qtconnectivityglobal.h" + +#include <QtCore/QObject> +#include <QtCore/QList> +#include <QtCore/QMetaType> +#include <QtCore/QSharedDataPointer> + +class QString; +class QUrl; + +QT_BEGIN_HEADER + +class QNdefMessage; +class QNearFieldTargetPrivate; + +class Q_CONNECTIVITY_EXPORT QNearFieldTarget : public QObject +{ + Q_OBJECT + + Q_DECLARE_PRIVATE(QNearFieldTarget) + +public: + enum Type { + AnyTarget, + ProprietaryTag, + NfcTagType1, + NfcTagType2, + NfcTagType3, + NfcTagType4, + MifareTag, + NfcForumDevice + }; + + enum AccessMethod { + NdefAccess, + TagTypeSpecificAccess, + LlcpAccess + }; + Q_DECLARE_FLAGS(AccessMethods, AccessMethod) + + enum Error { + NoError, + UnknownError, + UnsupportedError, + TargetOutOfRangeError, + NoResponseError, + ChecksumMismatchError, + InvalidParametersError, + NdefReadError, + NdefWriteError + }; + + class RequestIdPrivate; + class Q_CONNECTIVITY_EXPORT RequestId + { + public: + RequestId(); + RequestId(const RequestId &other); + RequestId(RequestIdPrivate *p); + ~RequestId(); + + bool isValid() const; + + int refCount() const; + + bool operator<(const RequestId &other) const; + bool operator==(const RequestId &other) const; + bool operator!=(const RequestId &other) const; + RequestId &operator=(const RequestId &other); + + QSharedDataPointer<RequestIdPrivate> d; + }; + + explicit QNearFieldTarget(QObject *parent = 0); + virtual ~QNearFieldTarget(); + + virtual QByteArray uid() const = 0; + virtual QUrl url() const; + + virtual Type type() const = 0; + virtual AccessMethods accessMethods() const = 0; + + bool isProcessingCommand() const; + + // NdefAccess + virtual bool hasNdefMessage(); + virtual RequestId readNdefMessages(); + virtual RequestId writeNdefMessages(const QList<QNdefMessage> &messages); + + // TagTypeSpecificAccess + virtual RequestId sendCommand(const QByteArray &command); + virtual RequestId sendCommands(const QList<QByteArray> &commands); + + virtual bool waitForRequestCompleted(const RequestId &id, int msecs = 5000); + + QVariant requestResponse(const RequestId &id); + void setResponseForRequest(const QNearFieldTarget::RequestId &id, const QVariant &response, + bool emitRequestCompleted = true); + +protected: + Q_INVOKABLE virtual bool handleResponse(const QNearFieldTarget::RequestId &id, + const QByteArray &response); + +Q_SIGNALS: + void disconnected(); + + void ndefMessageRead(const QNdefMessage &message); + void ndefMessagesWritten(); + + void requestCompleted(const QNearFieldTarget::RequestId &id); + + void error(QNearFieldTarget::Error error, const QNearFieldTarget::RequestId &id); + +private: + QNearFieldTargetPrivate *d_ptr; +}; + +Q_CONNECTIVITY_EXPORT quint16 qNfcChecksum(const char * data, uint len); + +Q_DECLARE_OPERATORS_FOR_FLAGS(QNearFieldTarget::AccessMethods) + +Q_DECLARE_METATYPE(QNearFieldTarget::RequestId) +Q_DECLARE_METATYPE(QNearFieldTarget::Error) + +QT_END_HEADER + +#endif // QNEARFIELDTARGET_H diff --git a/src/nfc/qnearfieldtarget_emulator.cpp b/src/nfc/qnearfieldtarget_emulator.cpp new file mode 100644 index 00000000..2a05a6e3 --- /dev/null +++ b/src/nfc/qnearfieldtarget_emulator.cpp @@ -0,0 +1,300 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qnearfieldtarget_emulator_p.h" +#include "qnearfieldtarget_p.h" + +#include <QtCore/QDirIterator> +#include <QtCore/QSettings> +#include <QtCore/QMutex> +#include <QtCore/QCoreApplication> +#include <QtCore/QDateTime> + +#include <QtCore/QDebug> + +static QMutex tagMutex; +static QMap<TagBase *, bool> tagMap; +static TagActivator tagActivator; + + +TagType1::TagType1(TagBase *tag, QObject *parent) +: QNearFieldTagType1(parent), m_tag(tag) +{ +} + +TagType1::~TagType1() +{ +} + +QByteArray TagType1::uid() const +{ + QMutexLocker locker(&tagMutex); + + return m_tag->uid(); +} + +QNearFieldTarget::AccessMethods TagType1::accessMethods() const +{ + return NdefAccess | TagTypeSpecificAccess; +} + +QNearFieldTarget::RequestId TagType1::sendCommand(const QByteArray &command) +{ + QMutexLocker locker(&tagMutex); + + RequestId id(new RequestIdPrivate); + + // tag not in proximity + if (!tagMap.value(m_tag)) { + QMetaObject::invokeMethod(this, "error", Qt::QueuedConnection, + Q_ARG(QNearFieldTarget::Error, TargetOutOfRangeError), + Q_ARG(QNearFieldTarget::RequestId, id)); + return id; + } + + quint16 crc = qNfcChecksum(command.constData(), command.length()); + + QByteArray response = m_tag->processCommand(command + char(crc & 0xff) + char(crc >> 8)); + + if (response.isEmpty()) { + QMetaObject::invokeMethod(this, "error", Qt::QueuedConnection, + Q_ARG(QNearFieldTarget::Error, NoResponseError), + Q_ARG(QNearFieldTarget::RequestId, id)); + return id; + } + + // check crc + if (qNfcChecksum(response.constData(), response.length()) != 0) { + QMetaObject::invokeMethod(this, "error", Qt::QueuedConnection, + Q_ARG(QNearFieldTarget::Error, ChecksumMismatchError), + Q_ARG(QNearFieldTarget::RequestId, id)); + return id; + } + + response.chop(2); + + QMetaObject::invokeMethod(this, "handleResponse", Qt::QueuedConnection, + Q_ARG(QNearFieldTarget::RequestId, id), Q_ARG(QByteArray, response)); + + return id; +} + +bool TagType1::waitForRequestCompleted(const RequestId &id, int msecs) +{ + QCoreApplication::sendPostedEvents(this, QEvent::MetaCall); + + return QNearFieldTagType1::waitForRequestCompleted(id, msecs); +} + + +TagType2::TagType2(TagBase *tag, QObject *parent) +: QNearFieldTagType2(parent), m_tag(tag) +{ +} + +TagType2::~TagType2() +{ +} + +QByteArray TagType2::uid() const +{ + QMutexLocker locker(&tagMutex); + + return m_tag->uid(); +} + +QNearFieldTarget::AccessMethods TagType2::accessMethods() const +{ + return NdefAccess | TagTypeSpecificAccess; +} + +QNearFieldTarget::RequestId TagType2::sendCommand(const QByteArray &command) +{ + QMutexLocker locker(&tagMutex); + + RequestId id(new RequestIdPrivate); + + // tag not in proximity + if (!tagMap.value(m_tag)) { + QMetaObject::invokeMethod(this, "error", Qt::QueuedConnection, + Q_ARG(QNearFieldTarget::Error, TargetOutOfRangeError), + Q_ARG(QNearFieldTarget::RequestId, id)); + return id; + } + + quint16 crc = qNfcChecksum(command.constData(), command.length()); + + QByteArray response = m_tag->processCommand(command + char(crc & 0xff) + char(crc >> 8)); + + if (response.isEmpty()) + return id; + + if (response.length() > 1) { + // check crc + if (qNfcChecksum(response.constData(), response.length()) != 0) { + QMetaObject::invokeMethod(this, "error", Qt::QueuedConnection, + Q_ARG(QNearFieldTarget::Error, ChecksumMismatchError), + Q_ARG(QNearFieldTarget::RequestId, id)); + return id; + } + + response.chop(2); + } + + QMetaObject::invokeMethod(this, "handleResponse", Qt::QueuedConnection, + Q_ARG(QNearFieldTarget::RequestId, id), Q_ARG(QByteArray, response)); + + return id; +} + +bool TagType2::waitForRequestCompleted(const RequestId &id, int msecs) +{ + QCoreApplication::sendPostedEvents(this, QEvent::MetaCall); + + return QNearFieldTagType2::waitForRequestCompleted(id, msecs); +} + + +TagActivator::TagActivator() +: timerId(-1) +{ + qRegisterMetaType<QNearFieldTarget::Error>("QNearFieldTarget::Error"); +} + +TagActivator::~TagActivator() +{ + QMutexLocker locker(&tagMutex); + qDeleteAll(tagMap.keys()); + tagMap.clear(); +} + +void TagActivator::initialize() +{ + QMutexLocker locker(&tagMutex); + + if (!tagMap.isEmpty()) + return; + + QDirIterator nfcTargets(QDir::currentPath(), QStringList(QLatin1String("*.nfc")), QDir::Files); + while (nfcTargets.hasNext()) { + const QString targetFilename = nfcTargets.next(); + + QSettings target(targetFilename, QSettings::IniFormat); + + target.beginGroup(QLatin1String("Target")); + + const QString tagType = target.value(QLatin1String("Type")).toString(); + + target.endGroup(); + + if (tagType == QLatin1String("TagType1")) { + qDebug() << "loading" << targetFilename << "as NfcTagType1"; + NfcTagType1 *tag = new NfcTagType1; + tag->load(&target); + + tagMap.insert(tag, false); + } else if (tagType == QLatin1String("TagType2")) { + qDebug() << "loading" << targetFilename << "as NfcTagType2"; + NfcTagType2 *tag = new NfcTagType2; + tag->load(&target); + + tagMap.insert(tag, false); + } else { + qWarning("Unknown tag type %s\n", qPrintable(tagType)); + } + } + + m_current = tagMap.end(); + + timerId = startTimer(1000); +} + +void TagActivator::reset() +{ + QMutexLocker locker(&tagMutex); + + killTimer(timerId); + timerId = -1; + + qDeleteAll(tagMap.keys()); + tagMap.clear(); +} + +TagActivator *TagActivator::instance() +{ + return &tagActivator; +} + +void TagActivator::timerEvent(QTimerEvent *e) +{ + Q_UNUSED(e); + + tagMutex.lock(); + + if (m_current != tagMap.end()) { + if (m_current.key()->lastAccessTime() + 1500 > QDateTime::currentMSecsSinceEpoch()) { + tagMutex.unlock(); + return; + } + + *m_current = false; + + tagMutex.unlock(); + emit tagDeactivated(m_current.key()); + tagMutex.lock(); + } + + ++m_current; + if (m_current == tagMap.end()) + m_current = tagMap.begin(); + + if (m_current != tagMap.end()) { + *m_current = true; + + tagMutex.unlock(); + + emit tagActivated(m_current.key()); + tagMutex.lock(); + } + + tagMutex.unlock(); +} + diff --git a/src/nfc/qnearfieldtarget_emulator_p.h b/src/nfc/qnearfieldtarget_emulator_p.h new file mode 100644 index 00000000..1867df89 --- /dev/null +++ b/src/nfc/qnearfieldtarget_emulator_p.h @@ -0,0 +1,114 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QNEARFIELDTARGET_EMULATOR_P_H +#define QNEARFIELDTARGET_EMULATOR_P_H + +#include "qnearfieldtagtype1.h" +#include "qnearfieldtagtype2.h" +#include "targetemulator_p.h" + +#include <QtCore/QMap> + +class TagType1 : public QNearFieldTagType1 +{ + Q_OBJECT + +public: + TagType1(TagBase *tag, QObject *parent); + ~TagType1(); + + QByteArray uid() const; + + AccessMethods accessMethods() const; + + RequestId sendCommand(const QByteArray &command); + bool waitForRequestCompleted(const RequestId &id, int msecs = 5000); + +private: + TagBase *m_tag; +}; + +class TagType2 : public QNearFieldTagType2 +{ + Q_OBJECT + +public: + TagType2(TagBase *tag, QObject *parent); + ~TagType2(); + + QByteArray uid() const; + + AccessMethods accessMethods() const; + + RequestId sendCommand(const QByteArray &command); + bool waitForRequestCompleted(const RequestId &id, int msecs = 5000); + +private: + TagBase *m_tag; +}; + +class TagActivator : public QObject +{ + Q_OBJECT + +public: + TagActivator(); + ~TagActivator(); + + void initialize(); + void reset(); + + static TagActivator *instance(); + +protected: + void timerEvent(QTimerEvent *e); + +signals: + void tagActivated(TagBase *tag); + void tagDeactivated(TagBase *tag); + +private: + QMap<TagBase *, bool>::Iterator m_current; + int timerId; +}; + +#endif // QNEARFIELDTARGET_EMULATOR_P_H diff --git a/src/nfc/qnearfieldtarget_maemo6.cpp b/src/nfc/qnearfieldtarget_maemo6.cpp new file mode 100644 index 00000000..dddf8776d --- /dev/null +++ b/src/nfc/qnearfieldtarget_maemo6.cpp @@ -0,0 +1,176 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qnearfieldtarget_maemo6_p.h" + +void PendingCallWatcher::addSendCommand(const QDBusPendingReply<QByteArray> &reply, + const QNearFieldTarget::RequestId &id) +{ + QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(reply, this); + connect(watcher, SIGNAL(finished(QDBusPendingCallWatcher*)), + this, SLOT(sendCommandFinished(QDBusPendingCallWatcher*))); + + m_pendingCommands.insert(watcher, id); +} + +void PendingCallWatcher::addReadNdefMessages(const QDBusPendingReply<QList<QByteArray> > &reply, + const QNearFieldTarget::RequestId &id) +{ + QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(reply, this); + connect(watcher, SIGNAL(finished(QDBusPendingCallWatcher*)), + this, SLOT(readNdefMessagesFinished(QDBusPendingCallWatcher*))); + + m_pendingNdefReads.insert(watcher, id); +} + +void PendingCallWatcher::addWriteNdefMessages(const QDBusPendingReply<> &reply, + const QNearFieldTarget::RequestId &id) +{ + QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(reply, this); + connect(watcher, SIGNAL(finished(QDBusPendingCallWatcher*)), + this, SLOT(writeNdefMessages(QDBusPendingCallWatcher*))); + + m_pendingNdefWrites.insert(watcher, id); +} + +void PendingCallWatcher::sendCommandFinished(QDBusPendingCallWatcher *watcher) +{ + QNearFieldTarget::RequestId id = m_pendingCommands.take(watcher); + + if (!id.isValid()) { + watcher->deleteLater(); + return; + } + + QDBusPendingReply<QByteArray> reply = *watcher; + if (reply.isError()) { + QMetaObject::invokeMethod(parent(), "error", + Q_ARG(QNearFieldTarget::Error, QNearFieldTarget::UnknownError), + Q_ARG(QNearFieldTarget::RequestId, id)); + } else { + const QByteArray data = reply.argumentAt<0>(); + QMetaObject::invokeMethod(parent(), "handleResponse", + Q_ARG(QNearFieldTarget::RequestId, id), + Q_ARG(QByteArray, data)); + } + + watcher->deleteLater(); +} + +void PendingCallWatcher::readNdefMessagesFinished(QDBusPendingCallWatcher *watcher) +{ + QNearFieldTarget::RequestId id = m_pendingNdefReads.take(watcher); + + if (!id.isValid()) { + watcher->deleteLater(); + return; + } + + QDBusPendingReply<QList<QByteArray> > reply = *watcher; + if (reply.isError()) { + QMetaObject::invokeMethod(parent(), "error", + Q_ARG(QNearFieldTarget::Error, QNearFieldTarget::NdefReadError), + Q_ARG(QNearFieldTarget::RequestId, id)); + } else { + const QList<QByteArray> data = reply.argumentAt<0>(); + foreach (const QByteArray &m, data) { + qDebug() << Q_FUNC_INFO << m.toHex(); + const QNdefMessage message = QNdefMessage::fromByteArray(m); + + qDebug() << "record count:" << message.count(); + foreach (const QNdefRecord &record, message) + qDebug() << record.typeNameFormat() << record.type() << record.payload().toHex(); + + QMetaObject::invokeMethod(parent(), "ndefMessageRead", Q_ARG(QNdefMessage, message)); + } + + QMetaObject::invokeMethod(parent(), "requestCompleted", + Q_ARG(QNearFieldTarget::RequestId, id)); + } + + watcher->deleteLater(); +} + +void PendingCallWatcher::writeNdefMessages(QDBusPendingCallWatcher *watcher) +{ + QNearFieldTarget::RequestId id = m_pendingNdefWrites.take(watcher); + + if (!id.isValid()) { + watcher->deleteLater(); + return; + } + + QDBusPendingReply<> reply = *watcher; + if (reply.isError()) { + QMetaObject::invokeMethod(parent(), "error", + Q_ARG(QNearFieldTarget::Error, QNearFieldTarget::NdefWriteError), + Q_ARG(QNearFieldTarget::RequestId, id)); + } else { + QMetaObject::invokeMethod(parent(), "ndefMessagesWritten"); + QMetaObject::invokeMethod(parent(), "requestCompleted", + Q_ARG(QNearFieldTarget::RequestId, id)); + } + + watcher->deleteLater(); +} + +int TagType1::memorySize() const +{ + return m_tag->size(); +} + +int TagType2::memorySize() const +{ + return m_tag->size(); +} + +int TagType3::memorySize() const +{ + return m_tag->size(); +} + +int TagType4::memorySize() const +{ + return m_tag->size(); +} + +#include <moc_qnearfieldtarget_maemo6_p.cpp> + diff --git a/src/nfc/qnearfieldtarget_maemo6_p.h b/src/nfc/qnearfieldtarget_maemo6_p.h new file mode 100644 index 00000000..5002a08e --- /dev/null +++ b/src/nfc/qnearfieldtarget_maemo6_p.h @@ -0,0 +1,309 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QNEARFIELDTARGET_MAEMO6_P_H +#define QNEARFIELDTARGET_MAEMO6_P_H + +#include <qconnectivityglobal.h> + +#include "qnearfieldmanager_maemo6_p.h" + +#include <qnearfieldtarget.h> +#include <qnearfieldtarget_p.h> +#include <qnearfieldtagtype1.h> +#include <qnearfieldtagtype2.h> +#include <qnearfieldtagtype3.h> +#include <qnearfieldtagtype4.h> +#include <qndefmessage.h> + +#include "maemo6/adapter_interface_p.h" +#include "maemo6/target_interface_p.h" +#include "maemo6/tag_interface_p.h" +#include "maemo6/device_interface_p.h" + +#include <QtDBus/QDBusPendingReply> + +using namespace com::nokia::nfc; + +class PendingCallWatcher : public QObject +{ + Q_OBJECT + +public: + PendingCallWatcher(QObject *parent) : QObject(parent) { } + + void addSendCommand(const QDBusPendingReply<QByteArray> &reply, + const QNearFieldTarget::RequestId &id); + void addReadNdefMessages(const QDBusPendingReply<QList<QByteArray> > &reply, + const QNearFieldTarget::RequestId &id); + void addWriteNdefMessages(const QDBusPendingReply<> &reply, + const QNearFieldTarget::RequestId &id); + +private slots: + void sendCommandFinished(QDBusPendingCallWatcher *watcher); + void readNdefMessagesFinished(QDBusPendingCallWatcher *watcher); + void writeNdefMessages(QDBusPendingCallWatcher *watcher); + +private: + QMap<QDBusPendingCallWatcher *, QNearFieldTarget::RequestId> m_pendingCommands; + QMap<QDBusPendingCallWatcher *, QNearFieldTarget::RequestId> m_pendingNdefReads; + QMap<QDBusPendingCallWatcher *, QNearFieldTarget::RequestId> m_pendingNdefWrites; +}; + +template <typename T> +class NearFieldTarget : public T +{ +public: + NearFieldTarget(QNearFieldManagerPrivateImpl *manager, Target *target, Tag *tag) + : T(manager), m_manager(manager), m_target(target), m_tag(tag), m_device(0), + m_callWatcher(new PendingCallWatcher(this)) + { + } + + NearFieldTarget(QNearFieldManagerPrivateImpl *manager, Target *target, Device *device) + : T(manager), m_manager(manager), m_target(target), m_tag(0), m_device(device), + m_callWatcher(new PendingCallWatcher(this)) + { + } + + ~NearFieldTarget() + { + delete m_device; + delete m_tag; + delete m_target; + } + + QByteArray uid() const + { + QStringList fields; + + if (m_tag) + fields = m_tag->uID().split(QLatin1Char(':')); + else if (m_device) + fields = m_device->uID().split(QLatin1Char(':')); + + QByteArray id; + foreach (const QString &f, fields) + id.append(char(f.toUInt(0, 16))); + + return id; + } + + QNearFieldTarget::Type type() const + { + if (m_device) + return QNearFieldTarget::NfcForumDevice; + + if (m_tag) { + const QString tagType = m_tag->technology(); + if (tagType == QLatin1String("jewel")) + return QNearFieldTarget::NfcTagType1; + else if (tagType == QLatin1String("mifare-ul")) + return QNearFieldTarget::NfcTagType2; + else if (tagType == QLatin1String("felica")) + return QNearFieldTarget::NfcTagType3; + else if (tagType == QLatin1String("iso-4a")) + return QNearFieldTarget::NfcTagType4; + else if (tagType == QLatin1String("mifare-1k")) + return QNearFieldTarget::MifareTag; + else + return QNearFieldTarget::ProprietaryTag; + } + + return QNearFieldTarget::ProprietaryTag; + } + + QNearFieldTarget::AccessMethods accessMethods() const + { + QNearFieldTarget::AccessMethods result = QNearFieldTarget::NdefAccess; +#ifdef MAEMO6_TAG_TYPE_SEPECIFIC_ACCESS_SUPPORTED + if (m_tag) + result |= QNearFieldTarget::TagTypeSpecificAccess; +#endif + if (!m_tag) + result |= QNearFieldTarget::LlcpAccess; + + return result; + } + + bool hasNdefMessage() + { + return true; + } + + QNearFieldTarget::RequestId readNdefMessages() + { + if (!m_tag) + return QNearFieldTarget::RequestId(); + + QNearFieldTarget::RequestId id(new QNearFieldTarget::RequestIdPrivate); + + QDBusPendingReply<QList<QByteArray> > reply = m_tag->ReadNDEFData(); + m_callWatcher->addReadNdefMessages(reply, id); + + return id; + } + + QNearFieldTarget::RequestId writeNdefMessages(const QList<QNdefMessage> &messages) + { + if (!m_tag) + return QNearFieldTarget::RequestId(); + + QNearFieldTarget::RequestId id(new QNearFieldTarget::RequestIdPrivate); + QList<QByteArray> rawMessages; + + foreach (const QNdefMessage &message, messages) + rawMessages.append(message.toByteArray()); + + QDBusPendingReply<> reply = m_tag->WriteNDEFData(rawMessages); + m_callWatcher->addWriteNdefMessages(reply, id); + + return id; + } + + QNearFieldTarget::RequestId sendCommand(const QByteArray &command) + { +#if 0 + quint16 crc = qNfcChecksum(command.constData(), command.length()); + + QNearFieldTarget::RequestId id(new QNearFieldTarget::RequestIdPrivate); + + QDBusPendingReply<QByteArray> reply = + m_tag->RawRequest(command + char(crc & 0xff) + char(crc >> 8)); + + m_callWatcher->addSendCommand(reply, id); + + return id; +#else + Q_UNUSED(command); + return QNearFieldTarget::RequestId(); +#endif + } + + QNearFieldTarget::RequestId sendCommands(const QList<QByteArray> &commands) + { +#if 0 + for (int i = 0; i < commandCount; ++i) { + reply[i] = m_tag->RawRequest(commands.at(i)); + } + + QList<QByteArray> results; + for (int i = 0; i < commandCount; ++i) { + reply[i].waitForFinished(); + results.append(reply[i].isError() ? QByteArray() : reply->value()); + } + + return results; +#else + Q_UNUSED(commands); + return QNearFieldTarget::RequestId(); +#endif + } + +protected: + QNearFieldManagerPrivateImpl *m_manager; + Target *m_target; + Tag *m_tag; + Device *m_device; + PendingCallWatcher *m_callWatcher; +}; + +class TagType1 : public NearFieldTarget<QNearFieldTagType1> +{ +public: + TagType1(QNearFieldManagerPrivateImpl *manager, Target *target, Tag *tag) + : NearFieldTarget<QNearFieldTagType1>(manager, target, tag) + { + } + + ~TagType1() + { + } + + int memorySize() const; +}; + +class TagType2 : public NearFieldTarget<QNearFieldTagType2> +{ +public: + TagType2(QNearFieldManagerPrivateImpl *manager, Target *target, Tag *tag) + : NearFieldTarget<QNearFieldTagType2>(manager, target, tag) + { + } + + ~TagType2() + { + } + + int memorySize() const; +}; + +class TagType3 : public NearFieldTarget<QNearFieldTagType3> +{ +public: + TagType3(QNearFieldManagerPrivateImpl *manager, Target *target, Tag *tag) + : NearFieldTarget<QNearFieldTagType3>(manager, target, tag) + { + } + + ~TagType3() + { + } + + int memorySize() const; +}; + +class TagType4 : public NearFieldTarget<QNearFieldTagType4> +{ +public: + TagType4(QNearFieldManagerPrivateImpl *manager, Target *target, Tag *tag) + : NearFieldTarget<QNearFieldTagType4>(manager, target, tag) + { + } + + ~TagType4() + { + } + + int memorySize() const; +}; + +#endif // QNEARFIELDTARGET_MAEMO6_P_H diff --git a/src/nfc/qnearfieldtarget_p.h b/src/nfc/qnearfieldtarget_p.h new file mode 100644 index 00000000..d3d98c9b --- /dev/null +++ b/src/nfc/qnearfieldtarget_p.h @@ -0,0 +1,62 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QNEARFIELDTARGET_P_H +#define QNEARFIELDTARGET_P_H + +#include "../qtconnectivityglobal.h" + +#include "qnearfieldtarget.h" + +#include <QtCore/QMap> +#include <QtCore/QSharedData> + +class QNearFieldTarget::RequestIdPrivate : public QSharedData +{ +}; + +class QNearFieldTargetPrivate +{ +public: + QMap<QNearFieldTarget::RequestId, QVariant> m_decodedResponses; +}; + +#endif // QNEARFIELDTARGET_P_H diff --git a/src/nfc/qtlv.cpp b/src/nfc/qtlv.cpp new file mode 100644 index 00000000..83c5d585 --- /dev/null +++ b/src/nfc/qtlv.cpp @@ -0,0 +1,528 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qtlv_p.h" + +#include "qnearfieldtagtype1.h" + +#include <QtCore/QVariant> + +#include <QtCore/QDebug> + +QPair<int, int> qParseReservedMemoryControlTlv(const QByteArray &tlvData) +{ + quint8 position = tlvData.at(0); + int pageAddr = position >> 4; + int byteOffset = position & 0x0f; + + int size = quint8(tlvData.at(1)); + if (size == 0) + size = 256; + + quint8 pageControl = tlvData.at(2); + int bytesPerPage = pageControl & 0x0f; + + if (!bytesPerPage) + return qMakePair(0, 0); + + int byteAddress = pageAddr * (1 << bytesPerPage) + byteOffset; + return qMakePair(byteAddress, size); +} + +QPair<int, int> qParseLockControlTlv(const QByteArray &tlvData) +{ + quint8 position = tlvData.at(0); + int pageAddr = position >> 4; + int byteOffset = position & 0x0f; + + int size = quint8(tlvData.at(1)); + if (size == 0) + size = 256; + size = size / 8; + + quint8 pageControl = tlvData.at(2); + int bytesPerPage = pageControl & 0x0f; + + if (!bytesPerPage) + return qMakePair(0, 0); + + int byteAddress = pageAddr * (1 << bytesPerPage) + byteOffset; + return qMakePair(byteAddress, size); +} + +QTlvReader::QTlvReader(QNearFieldTarget *target) +: m_target(target), m_index(-1) +{ + if (qobject_cast<QNearFieldTagType1 *>(m_target)) { + addReservedMemory(0, 12); // skip uid, cc + addReservedMemory(104, 16); // skip reserved block D, lock block E + + addReservedMemory(120, 8); // skip reserved block F + } +} + +QTlvReader::QTlvReader(const QByteArray &data) +: m_target(0), m_rawData(data), m_index(-1) +{ +} + +void QTlvReader::addReservedMemory(int offset, int length) +{ + m_reservedMemory.insert(offset, length); +} + +/*! + Returns the number of bytes of reserved memory found so far. The actual number of reserved + bytes will not be known until atEnd() returns true. +*/ +int QTlvReader::reservedMemorySize() const +{ + int total = 0; + + QMap<int, int>::ConstIterator i; + for (i = m_reservedMemory.constBegin(); i != m_reservedMemory.constEnd(); ++i) + total += i.value(); + + return total; +} + +/*! + Returns the request id that the TLV reader is currently waiting on. +*/ +QNearFieldTarget::RequestId QTlvReader::requestId() const +{ + return m_requestId; +} + +bool QTlvReader::atEnd() const +{ + if (m_index == -1) + return false; + + if (m_requestId.isValid()) + return false; + + return (m_index == m_tlvData.length()) || (tag() == 0xfe); +} + +/*! + Moves to the next TLV. Returns true on success; otherwise returns false. +*/ +bool QTlvReader::readNext() +{ + if (atEnd()) + return false; + + // Move to next TLV + if (m_index == -1) { + m_index = 0; + } else if (m_requestId.isValid()) { + // do nothing + } else if (tag() == 0x00 || tag() == 0xfe) { + ++m_index; + } else { + int tlvLength = length(); + m_index += (tlvLength < 0xff) ? tlvLength + 2 : tlvLength + 4; + } + + // Ensure that tag byte is available + if (!readMoreData(m_index)) + return false; + + // Ensure that length byte(s) are available + if (length() == -1) + return false; + + // Ensure that data bytes are available + int tlvLength = length(); + + int dataOffset = (tlvLength < 0xff) ? m_index + 2 : m_index + 4; + + if (!readMoreData(dataOffset + tlvLength - 1)) + return false; + + switch (tag()) { + case 0x01: { // Lock Control TLV + QPair<int, int> locked = qParseLockControlTlv(data()); + addReservedMemory(locked.first, locked.second); + break; + } + case 0x02: { // Reserved Memory Control TLV + QPair<int, int> reserved = qParseReservedMemoryControlTlv(data()); + addReservedMemory(reserved.first, reserved.second); + break; + } + } + + return true; +} + +quint8 QTlvReader::tag() const +{ + return m_tlvData.at(m_index); +} + +int QTlvReader::length() +{ + if (tag() == 0x00 || tag() == 0xfe) + return 0; + + if (!readMoreData(m_index + 1)) + return -1; + + quint8 shortLength = m_tlvData.at(m_index + 1); + if (shortLength != 0xff) + return shortLength; + + if (!readMoreData(m_index + 3)) + return -1; + + quint16 longLength = (quint8(m_tlvData.at(m_index + 2)) << 8) | + quint8(m_tlvData.at(m_index + 3)); + + if (longLength < 0xff || longLength == 0xffff) { + qWarning("Invalid 3 byte length"); + return 0; + } + + return longLength; +} + +QByteArray QTlvReader::data() +{ + int tlvLength = length(); + + int dataOffset = (tlvLength < 0xff) ? m_index + 2 : m_index + 4; + + if (!readMoreData(dataOffset + tlvLength - 1)) + return QByteArray(); + + return m_tlvData.mid(dataOffset, tlvLength); +} + +bool QTlvReader::readMoreData(int sparseOffset) +{ + while (sparseOffset >= m_tlvData.length()) { + int absOffset = absoluteOffset(m_tlvData.length()); + + QByteArray data; + + if (!m_rawData.isEmpty()) { + data = m_rawData.mid(absOffset, dataLength(absOffset)); + } else if (QNearFieldTagType1 *tag = qobject_cast<QNearFieldTagType1 *>(m_target)) { + quint8 segment = absOffset / 128; + + if (m_requestId.isValid()) { + QVariant v = m_target->requestResponse(m_requestId); + if (!v.isValid()) + return false; + + m_requestId = QNearFieldTarget::RequestId(); + + data = v.toByteArray(); + + if (absOffset < 120) + data = data.mid(2); + + int length = dataLength(absOffset); + + data = data.mid(absOffset - (segment * 128), length); + } else { + m_requestId = (absOffset < 120) ? tag->readAll() : tag->readSegment(segment); + + return false; + } + } + + if (data.isEmpty() && sparseOffset >= m_tlvData.length()) + return false; + + m_tlvData.append(data); + } + + return true; +} + +int QTlvReader::absoluteOffset(int sparseOffset) const +{ + int absoluteOffset = sparseOffset; + foreach (int offset, m_reservedMemory.keys()) { + if (offset <= absoluteOffset) + absoluteOffset += m_reservedMemory.value(offset); + } + + return absoluteOffset; +} + +/*! + Returns the length of the contiguous non-reserved data block starting from absolute offset + \a startOffset. -1 is return as the length of the last contiguous data block. +*/ +int QTlvReader::dataLength(int startOffset) const +{ + foreach (int offset, m_reservedMemory.keys()) { + if (offset <= startOffset) + continue; + + return offset - startOffset; + } + + return -1; +} + + +QTlvWriter::QTlvWriter(QNearFieldTarget *target) +: m_target(target), m_rawData(0), m_index(0), m_tagMemorySize(-1) +{ + if (qobject_cast<QNearFieldTagType1 *>(m_target)) { + addReservedMemory(0, 12); // skip uid, cc + addReservedMemory(104, 16); // skip reserved block D, lock block E + + addReservedMemory(120, 8); // skip reserved block F + } +} + +QTlvWriter::QTlvWriter(QByteArray *data) +: m_target(0), m_rawData(data), m_index(0), m_tagMemorySize(-1) +{ +} + +QTlvWriter::~QTlvWriter() +{ + if (m_rawData) + process(true); +} + +void QTlvWriter::addReservedMemory(int offset, int length) +{ + m_reservedMemory.insert(offset, length); +} + +void QTlvWriter::writeTlv(quint8 tagType, const QByteArray &data) +{ + m_buffer.append(tagType); + + if (tagType != 0x00 && tagType != 0xfe) { + int length = data.length(); + if (length < 0xff) { + m_buffer.append(quint8(length)); + } else { + m_buffer.append(0xff); + m_buffer.append(quint16(length) >> 8); + m_buffer.append(quint16(length) & 0x00ff); + } + + m_buffer.append(data); + } + + process(); + + switch (tagType) { + case 0x01: { // Lock Control TLV + QPair<int, int> locked = qParseLockControlTlv(data); + addReservedMemory(locked.first, locked.second); + break; + } + case 0x02: { // Reserved Memory Control TLV + QPair<int, int> reserved = qParseReservedMemoryControlTlv(data); + addReservedMemory(reserved.first, reserved.second); + break; + } + } +} + +/*! + Processes more of the TLV writer process. Returns true if the TLVs have been successfully + written to the target or buffer; otherwise returns false. + + A false return value indicates that an NFC request is pending (if requestId() returns a valid + request identifier) or the write process has failed (requestId() returns an invalid request + identifier). +*/ +bool QTlvWriter::process(bool all) +{ + if (m_requestId.isValid()) { + QVariant v = m_target->requestResponse(m_requestId); + if (!v.isValid()) + return false; + } + + if (m_tagMemorySize == -1) { + if (m_rawData) + m_tagMemorySize = m_rawData->length(); + else if (QNearFieldTagType1 *tag = qobject_cast<QNearFieldTagType1 *>(m_target)) { + if (m_requestId.isValid()) { + m_tagMemorySize = 8 * (tag->requestResponse(m_requestId).toUInt() + 1); + m_requestId = QNearFieldTarget::RequestId(); + } else { + m_requestId = tag->readByte(10); + return false; + } + } + } + + while (!m_buffer.isEmpty()) { + int spaceRemaining = moveToNextAvailable(); + if (spaceRemaining < 1) + return false; + + int length = qMin(spaceRemaining, m_buffer.length()); + + if (m_rawData) { + m_rawData->replace(m_index, length, m_buffer); + m_index += length; + m_buffer = m_buffer.mid(length); + } else if (QNearFieldTagType1 *tag = qobject_cast<QNearFieldTagType1 *>(m_target)) { + int bufferIndex = 0; + + // static memory - can only use writeByte() + while (m_index < 120 && bufferIndex < length) { + if (m_requestId.isValid()) { + if (!m_target->requestResponse(m_requestId).toBool()) + return false; + + m_requestId = QNearFieldTarget::RequestId(); + + ++m_index; + ++bufferIndex; + } else { + m_requestId = tag->writeByte(m_index, m_buffer.at(bufferIndex)); + m_buffer = m_buffer.mid(bufferIndex); + return false; + } + } + + + // dynamic memory - writeBlock() full + while (m_index >= 120 && (m_index % 8 == 0) && bufferIndex + 8 < length) { + if (m_requestId.isValid()) { + if (!m_target->requestResponse(m_requestId).toBool()) + return false; + + m_requestId = QNearFieldTarget::RequestId(); + + m_index += 8; + bufferIndex += 8; + } else { + m_requestId = tag->writeBlock(m_index / 8, m_buffer.mid(bufferIndex, 8)); + m_buffer = m_buffer.mid(bufferIndex); + return false; + } + } + + // partial block + int currentBlock = m_index / 8; + int nextBlock = currentBlock + 1; + int currentBlockStart = currentBlock * 8; + int nextBlockStart = nextBlock * 8; + + int fillLength = qMin(nextBlockStart - m_index, spaceRemaining - bufferIndex); + + if (fillLength && (all || m_buffer.length() - bufferIndex >= fillLength) && + (m_buffer.length() != bufferIndex)) { + // sufficient data available + if (m_requestId.isValid()) { + const QVariant v = tag->requestResponse(m_requestId); + if (v.type() == QVariant::ByteArray) { + // read in block + QByteArray block = v.toByteArray(); + + int fill = qMin(fillLength, m_buffer.length() - bufferIndex); + + for (int i = m_index - currentBlockStart; i < fill; ++i) + block[i] = m_buffer.at(bufferIndex++); + + // now write block + m_requestId = tag->writeBlock(currentBlock, block); + return false; + } else if (v.type() == QVariant::Bool) { + m_requestId = QNearFieldTarget::RequestId(); + int fill = qMin(fillLength, m_buffer.length() - bufferIndex); + bufferIndex = fill - (m_index - currentBlockStart); + + // write complete + if (!v.toBool()) + return false; + } + } else { + // read in block + m_requestId = tag->readBlock(currentBlock); + m_buffer = m_buffer.mid(bufferIndex); + return false; + } + } + + m_buffer = m_buffer.mid(bufferIndex); + } + } + + return true; +} + +QNearFieldTarget::RequestId QTlvWriter::requestId() const +{ + return m_requestId; +} + +int QTlvWriter::moveToNextAvailable() +{ + int length = -1; + + // move index to next available byte + QMap<int, int>::ConstIterator i; + for (i = m_reservedMemory.constBegin(); i != m_reservedMemory.constEnd(); ++i) { + if (m_index < i.key()) { + length = i.key() - m_index; + break; + } else if (m_index == i.key()) { + m_index += i.value(); + } else if (m_index > i.key() && m_index < (i.key() + i.value())) { + m_index = i.key() + i.value(); + } + } + + if (length == -1) + return m_tagMemorySize - m_index; + + Q_ASSERT(length != -1); + + return length; +} diff --git a/src/nfc/qtlv_p.h b/src/nfc/qtlv_p.h new file mode 100644 index 00000000..a47d1a93 --- /dev/null +++ b/src/nfc/qtlv_p.h @@ -0,0 +1,124 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QTLV_P_H +#define QTLV_P_H + +#include "../qtconnectivityglobal.h" + +#include "qnearfieldtarget.h" + +#include <QtCore/QByteArray> +#include <QtCore/QMap> +#include <QtCore/QPair> + +QT_BEGIN_HEADER + +class QNearFieldTarget; +class QM_AUTOTEST_EXPORT QTlvReader +{ +public: + explicit QTlvReader(QNearFieldTarget *target); + explicit QTlvReader(const QByteArray &data); + + void addReservedMemory(int offset, int length); + int reservedMemorySize() const; + + QNearFieldTarget::RequestId requestId() const; + + bool atEnd() const; + + bool readNext(); + + quint8 tag() const; + int length(); + QByteArray data(); + +private: + bool readMoreData(int sparseOffset); + int absoluteOffset(int sparseOffset) const; + int dataLength(int startOffset) const; + + QNearFieldTarget *m_target; + QByteArray m_rawData; + QNearFieldTarget::RequestId m_requestId; + + QByteArray m_tlvData; + int m_index; + QMap<int, int> m_reservedMemory; +}; + +class QTlvWriter +{ +public: + explicit QTlvWriter(QNearFieldTarget *target); + explicit QTlvWriter(QByteArray *data); + ~QTlvWriter(); + + void addReservedMemory(int offset, int length); + + void writeTlv(quint8 tag, const QByteArray &data = QByteArray()); + + bool process(bool all = false); + + QNearFieldTarget::RequestId requestId() const; + +private: + int moveToNextAvailable(); + + QNearFieldTarget *m_target; + QByteArray *m_rawData; + + int m_index; + int m_tagMemorySize; + QMap<int, int> m_reservedMemory; + + QByteArray m_buffer; + + QNearFieldTarget::RequestId m_requestId; +}; + +QPair<int, int> qParseReservedMemoryControlTlv(const QByteArray &tlvData); +QPair<int, int> qParseLockControlTlv(const QByteArray &tlvData); + +QT_END_HEADER + +#endif // QTLV_P_H diff --git a/src/nfc/qtnfcversion.h b/src/nfc/qtnfcversion.h new file mode 100644 index 00000000..e182a3f9 --- /dev/null +++ b/src/nfc/qtnfcversion.h @@ -0,0 +1,9 @@ +/* This file was generated by syncqt with the info from sync.profile. */ +#ifndef QT_QTNFC_VERSION_H +#define QT_QTNFC_VERSION_H + +#define QTNFC_VERSION_STR "5.0.0" + +#define QTNFC_VERSION 0x050000 + +#endif // QT_QTNFC_VERSION_H diff --git a/src/nfc/symbian/debug.h b/src/nfc/symbian/debug.h new file mode 100644 index 00000000..06a4de9b --- /dev/null +++ b/src/nfc/symbian/debug.h @@ -0,0 +1,60 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef DEBUG_H_ +#define DEBUG_H_ +#include <QDebug> + +//#define SYMBIAN_NFC_DEBUG + +#ifdef SYMBIAN_NFC_DEBUG +# define BEGIN qDebug()<<__PRETTY_FUNCTION__<<" Line: "<<__LINE__ <<" Begin"; +# define END qDebug()<<__PRETTY_FUNCTION__<<" Line: "<<__LINE__ <<" End"; +# define BEGIN_END qDebug()<<__PRETTY_FUNCTION__<<" Line: "<<__LINE__ <<" BEGIN_End"; +# define LOG(a) qDebug()<<__PRETTY_FUNCTION__<<" Line: "<<__LINE__ <<a; +#else +# define BEGIN +# define END +# define BEGIN_END +# define LOG(a) +#endif + +#endif /* DEBUG_H_ */ diff --git a/src/nfc/symbian/llcpserver_symbian.cpp b/src/nfc/symbian/llcpserver_symbian.cpp new file mode 100644 index 00000000..26f97874 --- /dev/null +++ b/src/nfc/symbian/llcpserver_symbian.cpp @@ -0,0 +1,210 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "llcpserver_symbian.h" +#include "llcpsockettype2_symbian.h" +#include "../qllcpserver_symbian_p.h" +#include "nearfieldutility_symbian.h" + +#include "debug.h" + +/* + CLlcpServer::NewL() +*/ +CLlcpServer* CLlcpServer::NewL(QLlcpServerPrivate& aCallback) + { + BEGIN + CLlcpServer* self = new (ELeave) CLlcpServer(aCallback); + CleanupStack::PushL( self ); + self->ConstructL(); + CleanupStack::Pop( self ); + END + return self; + } + +/* + CLlcpServer::CLlcpServer() +*/ +CLlcpServer::CLlcpServer(QLlcpServerPrivate& aCallback) + :iLlcp( NULL ), + iSocketListening(EFalse), + iCallback(aCallback) + { + } + +/* + CLlcpServer::ContructL() +*/ +void CLlcpServer::ConstructL() + { + BEGIN + User::LeaveIfError(iNfcServer.Open()); + iLlcp = CLlcpProvider::NewL( iNfcServer ); + END + } + +/* + Destroys the LLCP socket. +*/ +CLlcpServer::~CLlcpServer() + { + BEGIN + StopListening(); + iLlcpSocketArray.ResetAndDestroy();//this should destroy before iLlcp + iLlcpSocketArray.Close(); + iServiceName.Close(); + + delete iLlcp; + iNfcServer.Close(); + END + } + +/* + Returns the next pending connection as a connected CLlcpSocketType2 + object. + + The socket is created as a child of the server, which means that + it is automatically deleted when the CLlcpServer object is + destroyed. It is still a good idea to delete the object + explicitly when you are done with it, to avoid wasting memory. +*/ +CLlcpSocketType2* CLlcpServer::nextPendingConnection() + { + // take first element + BEGIN + CLlcpSocketType2 *llcpSocket = NULL; + if (iLlcpSocketArray.Count() > 0) + { + llcpSocket = iLlcpSocketArray[0]; + iLlcpSocketArray.Remove(0); + } + END + return llcpSocket; + } + +TBool CLlcpServer::hasPendingConnections() const + { + BEGIN + END + return iLlcpSocketArray.Count() > 0 ? ETrue: EFalse; + } + +const TDesC8& CLlcpServer::serviceUri() const + { + BEGIN + END + return iServiceName; + } + +/* + Listen to the LLCP Socket by the URI \a serviceUri . +*/ +TBool CLlcpServer::Listen( const TDesC8& aServiceName) + { + BEGIN + TInt error = KErrNone; + + iServiceName.Zero(); + if (iServiceName.Create(aServiceName.Size()) < 0) + { + END + return EFalse; + } + iServiceName.Append(aServiceName); + + TRAP(error,iLlcp->StartListeningConnOrientedRequestL( *this, iServiceName )); + + error == KErrNone ? iSocketListening = ETrue : iSocketListening = EFalse; + END + return iSocketListening; + } + +void CLlcpServer::StopListening( ) + { + BEGIN + if (iSocketListening) + { + iLlcp->StopListeningConnOrientedRequest( iServiceName ); + iSocketListening = EFalse; + iLlcpSocketArray.ResetAndDestroy(); + } + END + } + + +TBool CLlcpServer::isListening() const + { + BEGIN + END + return iSocketListening; + } + +/* + Call back from MLlcpConnOrientedListener +*/ +void CLlcpServer::RemoteConnectRequest( MLlcpConnOrientedTransporter* aConnection ) + { + BEGIN + if (aConnection == NULL) + { + END + return; + } + + TInt error = KErrNone; + + // create remote connection for the iLlcpsocket + aConnection->AcceptConnectRequest(); + + CLlcpSocketType2 *llcpSocket = NULL; + TRAP(error,llcpSocket = CLlcpSocketType2::NewL(aConnection)); + // Creating wrapper for connection. + if (KErrNone == error) + { + iLlcpSocketArray.Append(llcpSocket); + //The newConnection() signal is then emitted each time a client connects to the server. + TInt error = KErrNone; + QT_TRYCATCH_ERROR(error, iCallback.invokeNewConnection()); + Q_UNUSED(error);//just skip the error + } + END + } +//EOF diff --git a/src/nfc/symbian/llcpserver_symbian.h b/src/nfc/symbian/llcpserver_symbian.h new file mode 100644 index 00000000..10e0771f --- /dev/null +++ b/src/nfc/symbian/llcpserver_symbian.h @@ -0,0 +1,110 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef LLCPSERVER_SYMBIAN_H_ +#define LLCPSERVER_SYMBIAN_H_ + +#include <e32base.h> +#include <nfcserver.h> // RNfcServer +#include <llcpprovider.h> // CLlcpProvider +#include <llcpconnorientedlistener.h> // MLlcpConnOrientedListener +#include <qconnectivityglobal.h> +#include "../qllcpserver_symbian_p.h" + + +class CLlcpSocketType2; + +class CLlcpServer : public CBase, + public MLlcpConnOrientedListener + { +public: + /* + * Creates a new CLlcpServer object. + */ + static CLlcpServer* NewL(QLlcpServerPrivate&); + + /* + * Destructor + */ + ~CLlcpServer(); + +public: + TBool Listen( const TDesC8& aServiceName); + void StopListening(); + TBool isListening() const; + CLlcpSocketType2 *nextPendingConnection(); + TBool hasPendingConnections() const; + const TDesC8& serviceUri() const; + +private: // From MLlcpConnOrientedListener + void RemoteConnectRequest( MLlcpConnOrientedTransporter* aConnection ); + +private: + // Constructor + CLlcpServer(QLlcpServerPrivate&); + + // Second phase constructor + void ConstructL(); + +private: + + RPointerArray<CLlcpSocketType2> iLlcpSocketArray; + + /* + * Handle to NFC-server. + * Own. + */ + RNfcServer iNfcServer; + + /* + * Pointer to CLlcpProvider object. + * Own. + */ + CLlcpProvider* iLlcp; + + TBool iSocketListening; + + RBuf8 iServiceName; + + QLlcpServerPrivate& iCallback; + }; + +#endif /* LLCPSERVER_SYMBIAN_H_ */ diff --git a/src/nfc/symbian/llcpsockettype1_symbian.cpp b/src/nfc/symbian/llcpsockettype1_symbian.cpp new file mode 100644 index 00000000..3baf39fd --- /dev/null +++ b/src/nfc/symbian/llcpsockettype1_symbian.cpp @@ -0,0 +1,857 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <llcpprovider.h> // CLlcpProvider +#include <llcpconnlesstransporter.h> // MLlcpConnLessTransporter + +#include "nearfieldutility_symbian.h" +#include "llcpsockettype1_symbian.h" +#include "debug.h" + + +/* + CLlcpSocketType1::NewL() +*/ +CLlcpSocketType1* CLlcpSocketType1::NewL(QLlcpSocketPrivate& aCallback) + { + CLlcpSocketType1* self = CLlcpSocketType1::NewLC(aCallback); + CleanupStack::Pop(self); + return self; + } + +/* + CLlcpSocketType1::NewLC() +*/ +CLlcpSocketType1* CLlcpSocketType1::NewLC(QLlcpSocketPrivate& aCallback) + { + CLlcpSocketType1* self = new (ELeave) CLlcpSocketType1(aCallback); + CleanupStack::PushL(self); + self->ConstructL(); + return self; + } + +/* + CLlcpSocketType1::CLlcpSocketType1() +*/ +CLlcpSocketType1::CLlcpSocketType1(QLlcpSocketPrivate& aCallback) + : iWaitStatus(ENone), + iPortBinded(EFalse), + iCallback(aCallback) + { + } + +/* + CLlcpSocketPrivate::ContructL() +*/ +void CLlcpSocketType1::ConstructL() + { + User::LeaveIfError(iNfcServer.Open()); + iLlcp = CLlcpProvider::NewL(iNfcServer); + iWait = new (ELeave) CActiveSchedulerWait; + } + +/* + Destroys the LLCP socket. +*/ +CLlcpSocketType1::~CLlcpSocketType1() + { + BEGIN + // Destroy connection + Cleanup(); + + if (iLlcp) + { + iLlcp->StopListeningConnLessRequest(iLocalPort); + delete iLlcp; + } + iNfcServer.Close(); + delete iTimer; + delete iWait; + + END + } + +/* + Cancel the Receive/Transfer and destroy the local/remote connection. +*/ +void CLlcpSocketType1::Cleanup() + { + BEGIN + // Deleting connection + if (iConnectionWrapper) + { + iConnectionWrapper->TransferCancel(); + iConnectionWrapper->ReceiveCancel(); + delete iConnectionWrapper; + iConnectionWrapper = NULL; + } + END + } + +/* + Start to listen the port as given, set as local port which is used to read datagram +*/ +TBool CLlcpSocketType1::Bind(TUint8 aPortNum) + { + BEGIN + TBool bindOK = EFalse; + if (!iPortBinded) + { + TInt error = KErrNone; + TRAP(error, iLlcp->StartListeningConnLessRequestL(*this,aPortNum)); + if (KErrNone == error) + { + iPortBinded = ETrue; + iLocalPort = aPortNum; + bindOK = ETrue; + } + } + END + return bindOK; + } + +/* + Sends the datagram at aData to the service that this socket is connected to. + Returns the number of bytes sent on success; otherwise return -1; +*/ +TInt CLlcpSocketType1::StartWriteDatagram(const TDesC8& aData,TUint8 aPortNum) + { + BEGIN + TInt val = -1; + + if (iConnectionWrapper != NULL && iRemotePort != aPortNum) + { + return val; + } + + if (KErrNone == CreateConnection(aPortNum)) + { + TInt error = KErrNone; + QT_TRYCATCH_ERROR(error , iConnectionWrapper->TransferL(aData)); + + if (KErrNone == error) + { + iCallback.m_writeDatagramRefCount++; + val = 0; + } + } + END + return val; + } + + +TInt CLlcpSocketType1::ReadDatagram(TDes8& aData, TUint8& aRemotePortNum) + { + BEGIN + aRemotePortNum = iRemotePort; + TInt val = ReadDatagram(aData); + END + return val; + } + +TInt CLlcpSocketType1::ReadDatagram(TDes8& aData) + { + BEGIN + TInt readSize = -1; + if (NULL != iConnectionWrapper) + { + readSize = iConnectionWrapper->ReceiveDataFromBuf(aData); + + // Start receiving data again + TInt error = KErrNone; + error = iConnectionWrapper->Receive(); + if (KErrNone != error) + { + readSize = -1; + } + } + END + return readSize; + } + +TBool CLlcpSocketType1::HasPendingDatagrams() const + { + BEGIN + TBool val = EFalse; + if (NULL != iConnectionWrapper) + { + val = iConnectionWrapper->HasPendingDatagrams(); + } + END + return val; + } + +TInt64 CLlcpSocketType1::PendingDatagramSize() const + { + BEGIN + TInt64 val = -1; + if (NULL != iConnectionWrapper) + { + val = iConnectionWrapper->PendingDatagramSize(); + } + END + return val; + } + +/* + Call back from MLlcpConnLessListener +*/ +void CLlcpSocketType1::FrameReceived(MLlcpConnLessTransporter* aConnection) + { + BEGIN + iRemotePort = aConnection->SsapL(); +// StartTransportAndReceive(aConnection); + // Only accepting one incoming remote connection + TInt error = KErrNone; + if (iConnectionWrapper) + { + delete iConnectionWrapper; + iConnectionWrapper = NULL; + } + // Creating wrapper for connection. + TRAP(error, iConnectionWrapper = COwnLlcpConnectionWrapper::NewL(aConnection, *this)); + + if (error == KErrNone && iConnectionWrapper != NULL) + { + error = iConnectionWrapper->Receive(); + } + if (error != KErrNone) + { + QT_TRYCATCH_ERROR(error,iCallback.invokeError()); + } + END + } + +/* + Call back from MLlcpReadWriteCb +*/ +void CLlcpSocketType1::ReceiveComplete(TInt aError) + { + BEGIN + TInt err = KErrNone; + if (KErrNone == aError) + { + QT_TRYCATCH_ERROR(err,iCallback.invokeReadyRead()); + } + else + { + LOG("err = "<<err); + QT_TRYCATCH_ERROR(err,iCallback.invokeError()); + } + Q_UNUSED(err); + END + } + +/* + Call back from MLlcpReadWriteCb +*/ +void CLlcpSocketType1::WriteComplete(TInt aError, TInt aSize) + { + BEGIN + if (iWaitStatus == EWaitForBytesWritten) + { + StopWaitNow(EWaitForBytesWritten); + } + + TInt err = KErrNone; + if (KErrNone == aError) + { + iCallback.m_writeDatagramRefCount--; + QT_TRYCATCH_ERROR(err,iCallback.invokeBytesWritten(aSize)); + } + else + { + QT_TRYCATCH_ERROR(err,iCallback.invokeError()); + } + + if (err == aError && iConnectionWrapper != NULL + && iConnectionWrapper->HasQueuedWrittenDatagram()) + { + iConnectionWrapper->TransferQueued(); + } + END + } + +void CLlcpSocketType1::StopWaitNow(TWaitStatus aWaitStatus) + { + BEGIN + if (iWaitStatus == aWaitStatus) + { + if (iWait->IsStarted()) + { + iWait->AsyncStop(); + } + if (iTimer)//stop the timer + { + delete iTimer; + iTimer = NULL; + } + } + END + } + +/* + Creating MLlcpConnLessTransporter object if connection type connectionless, + Creating Creating wrapper for local peer connection. +*/ +TInt CLlcpSocketType1::CreateConnection(TUint8 portNum) + { + BEGIN + TInt error = KErrNone; + MLlcpConnLessTransporter* llcpConnection = NULL; + + if (iConnectionWrapper) + { + return error; + } + + TRAP(error, llcpConnection = iLlcp->CreateConnLessTransporterL(portNum)); + + if (error == KErrNone) + { + iRemotePort = portNum; + error = StartTransportAndReceive(llcpConnection); + } + END + return error; + } + +TInt CLlcpSocketType1::StartTransportAndReceive(MLlcpConnLessTransporter* aConnection) + { + BEGIN + TInt error = KErrNone; + + // Only accepting one incoming remote connection + if (!iConnectionWrapper) + { + // Creating wrapper for connection. + TRAP(error, iConnectionWrapper = COwnLlcpConnectionWrapper::NewL(aConnection, *this)); + } + + if (error == KErrNone && iConnectionWrapper != NULL) + { + error = iConnectionWrapper->Receive(); + } + END + return error; + } + + +TBool CLlcpSocketType1::WaitForBytesWritten(TInt aMilliSeconds) + { + BEGIN_END + return WaitForOperationReady(EWaitForBytesWritten, aMilliSeconds); + } + +TBool CLlcpSocketType1::WaitForOperationReady(TWaitStatus aWaitStatus,TInt aMilliSeconds) + { + BEGIN + TBool ret = EFalse; + if (iWaitStatus != ENone || iWait->IsStarted()) + { + return ret; + } + iWaitStatus = aWaitStatus; + + if (iTimer) + { + delete iTimer; + iTimer = NULL; + } + if (aMilliSeconds > 0) + { + TRAPD(err, iTimer = CLlcpTimer::NewL(*iWait)); + if (err != KErrNone) + { + return ret; + } + iTimer->Start(aMilliSeconds); + } + iWait->Start(); + + //control is back here when iWait->AsyncStop() is called by the timer or the callback function + iWaitStatus = ENone; + + if (!iTimer) + { + //iTimer == NULL means this CActiveSchedulerWait + //AsyncStop is fired by the call back of ReadyRead + ret = ETrue; + } + else + { + delete iTimer; + iTimer = NULL; + } + + END + return ret; + } + + +/* + Construct the wrapper for connectionLess transport. +*/ +COwnLlcpConnectionWrapper* COwnLlcpConnectionWrapper::NewL(MLlcpConnLessTransporter* aConnection + , MLlcpReadWriteCb& aCallBack) + { + COwnLlcpConnectionWrapper* self = COwnLlcpConnectionWrapper::NewLC(aConnection, aCallBack); + CleanupStack::Pop(self); + return self; + } + +/* + Construct the new wrapper for connectionLess transport. +*/ +COwnLlcpConnectionWrapper* COwnLlcpConnectionWrapper::NewLC(MLlcpConnLessTransporter* aConnection + , MLlcpReadWriteCb& aCallBack) + { + COwnLlcpConnectionWrapper* self = new (ELeave) COwnLlcpConnectionWrapper(aConnection); + CleanupStack::PushL(self); + self->ConstructL(aCallBack); + return self; + } + +/* + Constructor +*/ +COwnLlcpConnectionWrapper::COwnLlcpConnectionWrapper(MLlcpConnLessTransporter* aConnection) + : iConnection(aConnection) + { + } + +/* + ConstructL +*/ +void COwnLlcpConnectionWrapper::ConstructL(MLlcpReadWriteCb& aCallBack) + { + if (NULL == iConnection) + { + User::Leave(KErrArgument); + } + // Create the transmitter AO + iSenderAO = CLlcpSenderType1::NewL(*iConnection, aCallBack); + // Create the receiver AO + iReceiverAO = CLlcpReceiverType1::NewL(*iConnection, aCallBack); + } + +/* + Destroy the new wrapper for connectionLess transport. +*/ +COwnLlcpConnectionWrapper::~COwnLlcpConnectionWrapper() + { + BEGIN + iSendBufArray.ResetAndDestroy(); + iSendBufArray.Close(); + + delete iSenderAO; + delete iReceiverAO; + + if (iConnection) + { + delete iConnection; + iConnection = NULL; + } + END + } + +/* + Send data from queued buffer +*/ +bool COwnLlcpConnectionWrapper::TransferQueued() + { + BEGIN + bool ret = false; + if (iSendBufArray.Count() == 0 || iSenderAO->IsActive()) + return ret; + + HBufC8* bufRef = iSendBufArray[0]; + if (NULL == bufRef) + return ret; + + TPtrC8 ptr(bufRef->Ptr(), bufRef->Length()); + if(!iSenderAO->IsActive() && iSenderAO->Transfer(ptr) == KErrNone) + { + ret = true; + } + iSendBufArray.Remove(0); + delete bufRef; + bufRef = NULL; + + END + return ret; + } + +/* + Send data from local peer to remote peer via connectionLess transport +*/ +TInt COwnLlcpConnectionWrapper::TransferL(const TDesC8& aData) + { + BEGIN + TInt error = KErrNone; + // Pass message into transmitter AO + if (!iSenderAO->IsActive()) + { + error = iSenderAO->Transfer(aData); + } + else if (aData.Length() > 0) + { + HBufC8* buf = HBufC8::NewLC(aData.Length()); + buf->Des().Copy(aData); + error = iSendBufArray.Append(buf); + CleanupStack::Pop(buf); + } + END + return error; + } + + +/* + * Trigger the receiver AO to start receive datagram + Receive data from remote peer to local peer via connectionLess transport +*/ +TInt COwnLlcpConnectionWrapper::Receive() + { + BEGIN + TInt error = KErrInUse; + // Pass message on to transmit AO + if (!iReceiverAO->IsActive()) + { + error = iReceiverAO->Receive(); + } + + END + return error; + } + +/* + Retrieve data from the buffer of the connection less socket +*/ +TInt COwnLlcpConnectionWrapper::ReceiveDataFromBuf(TDes8& aData) + { + return iReceiverAO->ReceiveDataFromBuf(aData); + } + +bool COwnLlcpConnectionWrapper::HasPendingDatagrams() const + { + return iReceiverAO->HasPendingDatagrams(); + } + +bool COwnLlcpConnectionWrapper::HasQueuedWrittenDatagram() const + { + bool hasData = iSendBufArray.Count() > 0 ? true : false; + return hasData; + } + +TInt64 COwnLlcpConnectionWrapper::PendingDatagramSize() const + { + return iReceiverAO->PendingDatagramSize(); + } + +/* + Cancel data transfer from local peer to remote peer via connectionLess transport +*/ +void COwnLlcpConnectionWrapper::TransferCancel() + { + BEGIN + if (iSenderAO->IsActive()) + { + iSenderAO->Cancel(); + } + END + } + +/* + Cancel data receive from local peer to remote peer via connectionLess transport +*/ +void COwnLlcpConnectionWrapper::ReceiveCancel() + { + BEGIN + if (iReceiverAO->IsActive()) + { + iReceiverAO->Cancel(); + } + END + } + +/* + Start of implementation of Sender AO & Receiver AO for connection less mode (type1) +*/ + +/* + Constructor +*/ +CLlcpSenderType1::CLlcpSenderType1(MLlcpConnLessTransporter& aConnection, MLlcpReadWriteCb& aCallBack) + : CActive(CActive::EPriorityStandard) + , iConnection(aConnection) + , iSendObserver(aCallBack) + { + } + +/* + Constructor +*/ +CLlcpSenderType1* CLlcpSenderType1::NewL(MLlcpConnLessTransporter& iConnection, MLlcpReadWriteCb& aCallBack) + { + CLlcpSenderType1* self = new(ELeave) CLlcpSenderType1(iConnection, aCallBack); + CActiveScheduler::Add(self); + return self; + } + +/* + Destructor +*/ +CLlcpSenderType1::~CLlcpSenderType1() + { + BEGIN + Cancel(); // Cancel ANY outstanding request at time of destruction + iTransmitBuf.Close(); + iTempSendBuf.Close(); + END + } + +TInt CLlcpSenderType1::Transfer(const TDesC8& aData) + { + BEGIN + + if (aData.Length() == 0) + { + return KErrArgument; + } + + TInt supportedDataLength = iConnection.SupportedDataLength(); + if (supportedDataLength <= 0) + { + return KErrNotReady; + } + // Reset pos to start + iCurrentSendBufPos = 0; + TInt error = KErrNone; + // Copying data to internal buffer. + iTransmitBuf.Zero(); + error = iTransmitBuf.ReAlloc(aData.Length()); + + if (error == KErrNone) + { + iTransmitBuf.Append(aData); + + if (iTransmitBuf.Length() > supportedDataLength) + { + iCurrentSendBufPtr.Set(iTransmitBuf.Ptr(), supportedDataLength); + } + else + { + iCurrentSendBufPtr.Set(iTransmitBuf.Ptr(), iTransmitBuf.Length()); + } + iCurrentSendBufPos = iCurrentSendBufPtr.Length(); + // Sending data, don't need check active, external func has checked it + iTempSendBuf.Close(); + iTempSendBuf.Create(iCurrentSendBufPtr); + iConnection.Transmit(iStatus, iTempSendBuf); + SetActive(); + } + else + { + error = KErrNoMemory; + } + END + return error; + } + +void CLlcpSenderType1::RunL(void) + { + BEGIN + TInt error = iStatus.Int(); + // Sending error, notify user + if (KErrNone != error) + { + // Return buffer's length which has been sent successfully. + iSendObserver.WriteComplete(error, iCurrentSendBufPos - iCurrentSendBufPtr.Length()); + return; + } + + TInt bytesWritten = iCurrentSendBufPtr.Length(); + + // Still have some buffer need send, don't stop + if (iCurrentSendBufPos < iTransmitBuf.Length()) + { + TInt supportedDataLength = iConnection.SupportedDataLength(); + if (supportedDataLength <= 0) + { + iSendObserver.WriteComplete(KErrGeneral, iCurrentSendBufPtr.Length()); + return; + } + + if (iTransmitBuf.Length() > iCurrentSendBufPos + supportedDataLength) + { + // Still left some buffer + iCurrentSendBufPtr.Set(iTransmitBuf.Ptr() + iCurrentSendBufPos, supportedDataLength); + iCurrentSendBufPos += supportedDataLength; + } + else + { + // All buffer will be sent in this time + iCurrentSendBufPtr.Set(iTransmitBuf.Ptr() + iCurrentSendBufPos + , iTransmitBuf.Length() - iCurrentSendBufPos); + iCurrentSendBufPos = iTransmitBuf.Length(); + } + // Sending data + iTempSendBuf.Close(); + iTempSendBuf.Create(iCurrentSendBufPtr); + iConnection.Transmit(iStatus, iTempSendBuf); + SetActive(); + } + // Sent signal for each successful sending + iSendObserver.WriteComplete(error, bytesWritten); + END + } + +void CLlcpSenderType1::DoCancel(void) + { + BEGIN + // Cancel any outstanding write request on iSocket at this time. + iConnection.TransmitCancel(); + END + } + +/* + Start of implementation of Receiver AO for connection less mode (type1) - CLlcpReceiverType1 +*/ + +/* + Constructor +*/ +CLlcpReceiverType1::CLlcpReceiverType1(MLlcpConnLessTransporter& aConnection, MLlcpReadWriteCb& aCallBack) + : CActive(CActive::EPriorityStandard) + , iConnection(aConnection) + , iReceiveObserver(aCallBack) + { + } + +/* + Constructor +*/ +CLlcpReceiverType1* CLlcpReceiverType1::NewL(MLlcpConnLessTransporter& aConnection, MLlcpReadWriteCb& aCallBack) + { + CLlcpReceiverType1* self = new (ELeave) CLlcpReceiverType1(aConnection, aCallBack); + CActiveScheduler::Add(self); + return self; + } + + +/* + Set active for the receiver AO + Receive complete callback function "cb" registered +*/ +TInt CLlcpReceiverType1::Receive() + { + BEGIN + TInt error = KErrNotReady; + TInt length = 0; + length = iConnection.SupportedDataLength(); + iReceiveBuf.Zero(); + if (length > 0) + error = iReceiveBuf.ReAlloc(length); + + if (error == KErrNone) + { + iConnection.Receive(iStatus, iReceiveBuf); + SetActive(); + } + + END + return error; + } + +void CLlcpReceiverType1::RunL(void) + { + BEGIN + TInt error = iStatus.Int(); + // Call back functions of notifying the llcp receiver completed. + iReceiveObserver.ReceiveComplete(error); + END + } + +CLlcpReceiverType1::~CLlcpReceiverType1() + { + BEGIN + // cancel ANY outstanding request at time of destruction + Cancel(); + iReceiveBuf.Close(); + END + } + +TInt CLlcpReceiverType1::ReceiveDataFromBuf(TDes8& aData) + { + BEGIN + if (iReceiveBuf.Size() == 0) + return 0; + + TInt requiredLength = aData.MaxLength() - aData.Length(); + TInt bufLength = iReceiveBuf.Length(); + TInt readLength = requiredLength < bufLength ? requiredLength : bufLength; + + TPtrC8 ptr(iReceiveBuf.Ptr(),readLength); + aData.Append(ptr); + + //Empty the buffer as long as receive data request issued. + iReceiveBuf.Zero(); + END + return readLength; + } + +bool CLlcpReceiverType1::HasPendingDatagrams() const + { + return iReceiveBuf.Size() > 0 ? true : false; + } + +TInt64 CLlcpReceiverType1::PendingDatagramSize() const + { + return iReceiveBuf.Size(); + } + +void CLlcpReceiverType1::DoCancel(void) + { + BEGIN + // Cancel any outstanding write request on iSocket at this time. + iConnection.ReceiveCancel(); + END + } diff --git a/src/nfc/symbian/llcpsockettype1_symbian.h b/src/nfc/symbian/llcpsockettype1_symbian.h new file mode 100644 index 00000000..d45e20e9 --- /dev/null +++ b/src/nfc/symbian/llcpsockettype1_symbian.h @@ -0,0 +1,305 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef LLCPSOCKETTYPE1_SYMBIAN_H_ +#define LLCPSOCKETTYPE1_SYMBIAN_H_ + +#include <e32base.h> +#include <nfcserver.h> // RNfcServer +#include <llcpconnlesslistener.h> // MLlcpConnLessListener + +/* + * FORWARD DECLARATIONS + */ +class COwnLlcpConnectionWrapper; +class CLlcpSenderType1; +class CLlcpReceiverType1; +class CLlcpTimer; +class CLlcpProvider; +class MLlcpConnLessTransporter; + +#include <qconnectivityglobal.h> +#include "../qllcpsocket_symbian_p.h" + +class MLlcpReadWriteCb + { +public: + + /* + * Empty Destructor. + */ + virtual ~MLlcpReadWriteCb() {}; + + /* + * Called + */ + virtual void ReceiveComplete(TInt aError) = 0; + virtual void WriteComplete(TInt aError, TInt aSize) = 0; + }; + +/* + * CLASS DECLARATION for CLlcpSocketType1 (ConnectLess Tran). + */ +class CLlcpSocketType1 : public CBase, + public MLlcpConnLessListener, + public MLlcpReadWriteCb + { +public: + /* + * Creates a new CLlcpSocketType1 object. + */ + static CLlcpSocketType1* NewL(QLlcpSocketPrivate&); + + /* + * Creates a new CLlcpSocketType1 object. + */ + static CLlcpSocketType1* NewLC(QLlcpSocketPrivate&); + + /* + * Destructor + */ + ~CLlcpSocketType1(); + +public: + TInt StartWriteDatagram(const TDesC8& aData,TUint8 portNum); + TInt ReadDatagram(TDes8& aData); + TInt ReadDatagram(TDes8& aData, TUint8& aRemotePortNum); + TBool Bind(TUint8 portNum); + + /* + Returns true if at least one datagram is waiting to be read; + otherwise returns false. + */ + TBool HasPendingDatagrams() const; + TInt64 PendingDatagramSize() const; + TBool WaitForBytesWritten(TInt aMilliSeconds); + +private: + enum TWaitStatus + { + ENone, + EWaitForBytesWritten + }; + +private: + TBool WaitForOperationReady(TWaitStatus aWaitStatus,TInt aMilliSeconds); + void StopWaitNow(TWaitStatus aWaitStatus); + +private: // from MLlcpReadWriteCb + void ReceiveComplete(TInt aError); + void WriteComplete(TInt aError, TInt aSize); + +private: // From MLlcpConnLessListener + void FrameReceived(MLlcpConnLessTransporter* aConnection); + +private: + // Constructor + CLlcpSocketType1(QLlcpSocketPrivate&); + + // Second phase constructor + void ConstructL(); + void Cleanup(); + + TInt CreateConnection(TUint8 portNum); + TInt StartTransportAndReceive(MLlcpConnLessTransporter* aConnection); + +private: + /* + * Handle to NFC-server. + * Own. + */ + RNfcServer iNfcServer; + + /* + * Pointer to CLlcpProvider object. + * Own. + */ + CLlcpProvider* iLlcp; // Own + + /* + * Pointer to MLlcpConnLessTransporter object. + * Own. + * + * This is used to send data to local device. + */ + COwnLlcpConnectionWrapper* iConnectionWrapper; // Own + + CActiveSchedulerWait * iWait; //Own + CLlcpTimer * iTimer; // Own + TWaitStatus iWaitStatus; + + bool iPortBinded; + TUint8 iLocalPort; + TUint8 iRemotePort; + + QLlcpSocketPrivate& iCallback; + }; + +/* + * CLASS DECLARATION for COwnLlcpConnectionWrapper. + * + */ +class COwnLlcpConnectionWrapper : public CBase + { +public: + + /* + * Creates a new COwnLlcpConnection object. + */ + static COwnLlcpConnectionWrapper* NewL(MLlcpConnLessTransporter* aTransporter + , MLlcpReadWriteCb& aCallBack); + + /* + * Creates a new COwnLlcpConnection object. + */ + static COwnLlcpConnectionWrapper* NewLC(MLlcpConnLessTransporter* aTransporter + , MLlcpReadWriteCb& aCallBack); + + /* + * Destructor. + */ + ~COwnLlcpConnectionWrapper(); + +public: + /* + * Transfer given data to remote device. + */ + TInt TransferL(const TDesC8& aData); + bool TransferQueued(); + void TransferCancel(); + TInt Receive(); + + /* + * Cancels COwnLlcpConnection::Receive() request. + */ + void ReceiveCancel(); + + TInt ReceiveDataFromBuf(TDes8& aData); + bool HasPendingDatagrams() const; + TInt64 PendingDatagramSize() const; + bool HasQueuedWrittenDatagram() const; + +private: + + // Constructor + COwnLlcpConnectionWrapper(MLlcpConnLessTransporter* aConnection); + // Second phase constructor + void ConstructL(MLlcpReadWriteCb& aCallBack); + +private: + MLlcpConnLessTransporter* iConnection; + CLlcpSenderType1* iSenderAO; + CLlcpReceiverType1* iReceiverAO; + RPointerArray<HBufC8> iSendBufArray; + }; + + +class CLlcpSenderType1 : public CActive + { +public: + static CLlcpSenderType1* NewL(MLlcpConnLessTransporter& aConnection, MLlcpReadWriteCb& aCallBack); + ~CLlcpSenderType1(); + +public: + /* + * Transfer given data to remote device. + */ + TInt Transfer(const TDesC8& aData); + + /* + * Cancels COwnLlcpConnection::Transfer() request. + */ + void TransferCancel(); + +public: // From CActive + void RunL(); + void DoCancel(); + +private: + CLlcpSenderType1(MLlcpConnLessTransporter& aConnection, MLlcpReadWriteCb& aCallBack); +private: + /* + Buffered data for transmitting data. + */ + MLlcpConnLessTransporter& iConnection; + MLlcpReadWriteCb& iSendObserver; + RBuf8 iTransmitBuf; + // Symbian have limitaion for sending buffer in one send, + // The variable used to record how many buffer have been sent so far + TInt iCurrentSendBufPos; + TPtrC8 iCurrentSendBufPtr; + RBuf8 iTempSendBuf; // Temp workround to avoid NFC server's bug, if use ptr, it will crash + }; + +class CLlcpReceiverType1 : public CActive + { +public: + static CLlcpReceiverType1* NewL(MLlcpConnLessTransporter& aConnection, MLlcpReadWriteCb& aCallBack); + ~CLlcpReceiverType1(); + +public: + /* + * Starts receive data from ConnLess. + */ + TInt Receive(); + + /* + * Cancels COwnLlcpConnection::Receive() request. + */ + void ReceiveCancel(); + TInt ReceiveDataFromBuf(TDes8& aData); + + bool HasPendingDatagrams() const; + TInt64 PendingDatagramSize() const; + +public: // From CActive + void RunL(); + void DoCancel(); + +private: + CLlcpReceiverType1(MLlcpConnLessTransporter& aConnection, MLlcpReadWriteCb& aCallBack); + +private: + RBuf8 iReceiveBuf; + MLlcpConnLessTransporter& iConnection; + MLlcpReadWriteCb& iReceiveObserver; + }; +#endif /* LLCPSOCKETTYPE1_SYMBIAN_H_ */ diff --git a/src/nfc/symbian/llcpsockettype2_symbian.cpp b/src/nfc/symbian/llcpsockettype2_symbian.cpp new file mode 100644 index 00000000..0cc92d2b --- /dev/null +++ b/src/nfc/symbian/llcpsockettype2_symbian.cpp @@ -0,0 +1,986 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "nearfieldutility_symbian.h" +#include "llcpsockettype2_symbian.h" + +#include "debug.h" + +/* + CLlcpSocketType2::ContructL() +*/ +void CLlcpSocketType2::ConstructL() + { + BEGIN + User::LeaveIfError(iNfcServer.Open()); + iLlcp = CLlcpProvider::NewL( iNfcServer ); + iWait = new (ELeave) CActiveSchedulerWait; + END + } + +/* + CLlcpSocketType2::CLlcpSocketType2() +*/ +CLlcpSocketType2::CLlcpSocketType2(MLlcpConnOrientedTransporter* aTransporter, QLlcpSocketPrivate* aCallback) + : iLlcp( NULL ), + iTransporter(aTransporter), + iWaitStatus(ENone), + iCallback(aCallback) + { + } + +CLlcpSocketType2* CLlcpSocketType2::NewL(QLlcpSocketPrivate* aCallback) + { + BEGIN + CLlcpSocketType2* self = new (ELeave) CLlcpSocketType2(NULL,aCallback); + CleanupStack::PushL(self); + self->ConstructL(); + CleanupStack::Pop(self); + END + return self; + } + +CLlcpSocketType2* CLlcpSocketType2::NewL(MLlcpConnOrientedTransporter* aTransporter, QLlcpSocketPrivate* aCallback) + { + BEGIN + CLlcpSocketType2* self = new (ELeave) CLlcpSocketType2(aTransporter,aCallback); + CleanupStack::PushL(self); + self->ConstructL(); + CleanupStack::Pop(self); + END + return self; + } + +/* + Destroys the LLCP socket. +*/ +CLlcpSocketType2::~CLlcpSocketType2() + { + BEGIN + delete iConnecter; + delete iSender; + delete iReceiver; + delete iTransporter; + delete iLlcp; + delete iWait; + delete iTimer; + iReceiveBufArray.ResetAndDestroy(); + iReceiveBufArray.Close(); + iNfcServer.Close(); + END + } + +/* + Connects to the service identified by the URI \a serviceUri (on \a target). +*/ +void CLlcpSocketType2::ConnectToServiceL( const QString &serviceUri) + { + BEGIN + HBufC8* serviceName = QNFCNdefUtility::QString2HBufC8L(serviceUri); + + CleanupStack::PushL(serviceName); + ConnectToServiceL(serviceName->Des()) ; + CleanupStack::PopAndDestroy(serviceName); + END + } + +void CLlcpSocketType2::ConnectToServiceL( const TDesC8& aServiceName) + { + BEGIN + if ( !iConnecter && !iTransporter) + { + iTransporter = iLlcp->CreateConnOrientedTransporterL( aServiceName ); + iConnecter = CLlcpConnecterAO::NewL( *iTransporter, *this ); + } + iConnecter->ConnectL( aServiceName ); + END + } + +/* + Disconnects the socket. +*/ + +TInt CLlcpSocketType2::DisconnectFromService() + { + BEGIN + if (iSender && iSender->IsActive()) + { + WaitForBytesWritten(3000);//wait 3 seconds + } + if (iSender) + { + delete iSender; + iSender = NULL; + } + if (iReceiver) + { + delete iReceiver; + iReceiver = NULL; + } + + if (iConnecter) + { + iConnecter->Disconnect(); + delete iConnecter; + iConnecter = NULL; + } + if (iTransporter) + { + LOG("delete iTransporter;"); + delete iTransporter; + iTransporter = NULL; + } + END + return KErrNone; + } + +/* + Sends the datagram at aData to the service that this socket is connected to. + Returns the number of bytes sent on success; otherwise return -1; +*/ +TInt CLlcpSocketType2::StartWriteDatagram(const TDesC8& aData) + { + BEGIN + TInt val = -1; + if (!iTransporter) + { + END + return val; + } + + if (!iSender) + { + TRAPD(err,iSender = CLlcpSenderAO::NewL(*iTransporter, *this)); + if (err != KErrNone) + { + END + return val; + } + } + TInt error = KErrNone; + //asynchronous transfer + error = iSender->Send( aData); + if (KErrNone == error) + { + val = 0; + } + END + return val; + } + +TBool CLlcpSocketType2::ReceiveData(TDes8& aData) + { + //fetch data from internal buffer + BEGIN + TBool ret = EFalse; + HBufC8* buf = NULL; + TInt extBufferLength = aData.Length(); + TInt extBufferMaxLength = aData.MaxLength(); + while ( iReceiveBufArray.Count() > 0 ) + { + buf = iReceiveBufArray[ 0 ]; + if (buf->Length() - iBufferOffset <= extBufferMaxLength - extBufferLength ) + {//internal buffer's size <= available space of the user specified buffer + TPtrC8 ptr(buf->Ptr() + iBufferOffset, buf->Length() - iBufferOffset); + aData.Append( ptr ); + iReceiveBufArray.Remove( 0 ); + extBufferLength += buf->Length() - iBufferOffset; + delete buf; + buf = NULL; + iBufferOffset = 0; + } + else + { + TPtrC8 ptr(buf->Ptr() + iBufferOffset, extBufferMaxLength - extBufferLength); + aData.Append( ptr ); + iBufferOffset += extBufferMaxLength - extBufferLength; + ret = ETrue; + break; + } + ret = ETrue; + } + END + return ret; + } + +TInt64 CLlcpSocketType2::BytesAvailable() + { + BEGIN + TInt64 ret = 0; + for (TInt i = 0; i < iReceiveBufArray.Count(); ++i) + { + HBufC8* buf = iReceiveBufArray[ i ]; + if (!buf) + { + continue; + } + if ( i == 0) + { + ret += buf->Length() - iBufferOffset; + } + else + { + ret += buf->Length(); + } + } + END + return ret; + } + +TBool CLlcpSocketType2::WaitForOperationReady(TWaitStatus aWaitStatus,TInt aMilliSeconds) + { + BEGIN + TBool ret = EFalse; + if (iWaitStatus != ENone || iWait->IsStarted()) + { + END + return ret; + } + iWaitStatus = aWaitStatus; + + if (iTimer) + { + delete iTimer; + iTimer = NULL; + } + if (aMilliSeconds > 0) + { + TRAPD(err, iTimer = CLlcpTimer::NewL(*iWait)); + if (err != KErrNone) + { + END + return ret; + } + iTimer->Start(aMilliSeconds); + } + iWait->Start(); + //control is back here when iWait->AsyncStop() is called by the timer or the callback function + iWaitStatus = ENone; + + if (!iTimer) + { + //iTimer == NULL means this CActiveSchedulerWait + //AsyncStop is fired by the call back of ReadyRead + ret = ETrue; + } + else + { + delete iTimer; + iTimer = NULL; + } + END + return ret; + } + +/** + * Blocks until data is available for reading and the readyRead() + * signal has been emitted, or until msecs milliseconds have + * passed. If msecs is -1, this function will not time out. + * Returns true if data is available for reading; otherwise + * returns false (if the operation timed out or if an error + * occurred). + */ +TBool CLlcpSocketType2::WaitForReadyRead(TInt aMilliSeconds) + { + BEGIN + END + return WaitForOperationReady(EWaitForReadyRead, aMilliSeconds); + } + +TBool CLlcpSocketType2::WaitForBytesWritten(TInt aMilliSeconds) + { + BEGIN + END + return WaitForOperationReady(EWaitForBytesWritten, aMilliSeconds); + } +TBool CLlcpSocketType2::WaitForConnected(TInt aMilliSeconds) + { + BEGIN + END + return WaitForOperationReady(EWaitForConnected, aMilliSeconds); + } + +void CLlcpSocketType2::AttachCallbackHandler(QLlcpSocketPrivate* aCallback) + { + BEGIN + iCallback = aCallback; + if (iTransporter && iTransporter->IsConnected())//has connected llcp transporter + { + LOG("A server llcp type2 socket"); + if (!iReceiver) + { + TRAPD(err,iReceiver = CLlcpReceiverAO::NewL( *iTransporter, *this )); + if (err != KErrNone) + { + END + return; + } + } + if (!iConnecter) + { + TRAP_IGNORE(iConnecter = CLlcpConnecterAO::NewL( *iTransporter, *this )); + } + if (iReceiver->StartReceiveDatagram() != KErrNone) + { + Error(QLlcpSocket::UnknownSocketError); + } + } + END + } + +void CLlcpSocketType2::Error(QLlcpSocket::SocketError /*aSocketError*/) + { + BEGIN + //emit error + if ( iCallback ) + { + TInt error = KErrNone; + QT_TRYCATCH_ERROR(error,iCallback->invokeError()); + //can do nothing if there is an error,so just ignore it + Q_UNUSED(error); + } + END + } +void CLlcpSocketType2::StateChanged(QLlcpSocket::SocketState aSocketState) + { + BEGIN + if (aSocketState == QLlcpSocket::ConnectedState && iWaitStatus == EWaitForConnected) + { + StopWaitNow(EWaitForConnected); + } + TInt error = KErrNone; + if (aSocketState == QLlcpSocket::ConnectedState) + { + if ( iCallback) + { + QT_TRYCATCH_ERROR(error, iCallback->invokeConnected()); + Q_UNUSED(error); + } + if (!iReceiver) + { + TRAPD(err,iReceiver = CLlcpReceiverAO::NewL( *iTransporter, *this )); + if (err != KErrNone) + { + Error(QLlcpSocket::UnknownSocketError); + return; + } + } + if(iReceiver->StartReceiveDatagram() != KErrNone) + { + Error(QLlcpSocket::UnknownSocketError); + } + } + + if (aSocketState == QLlcpSocket::ClosingState && iCallback) + { + QT_TRYCATCH_ERROR(error, iCallback->invokeDisconnected()); + Q_UNUSED(error); + } + + END + } + +void CLlcpSocketType2::StopWaitNow(TWaitStatus aWaitStatus) + { + BEGIN + if ( iWaitStatus == aWaitStatus ) + { + if (iTimer)//stop the timer + { + delete iTimer; + iTimer = NULL; + } + if (iWait->IsStarted()) + { + iWait->AsyncStop(); + } + } + END + } +void CLlcpSocketType2::ReadyRead() + { + BEGIN + if (iWaitStatus == EWaitForReadyRead) + { + StopWaitNow(EWaitForReadyRead); + } + //emit readyRead() + if ( iCallback ) + { + TInt error = KErrNone; + QT_TRYCATCH_ERROR(error,iCallback->invokeReadyRead()); + //can do nothing if there is an error,so just ignore it + Q_UNUSED(error); + } + END + } +void CLlcpSocketType2::BytesWritten(qint64 aBytes) + { + BEGIN + if (iWaitStatus == EWaitForBytesWritten) + { + StopWaitNow(EWaitForBytesWritten); + } + //emit bytesWritten signal; + if ( iCallback ) + { + TInt error = KErrNone; + QT_TRYCATCH_ERROR(error,iCallback->invokeBytesWritten(aBytes)); + //can do nothing if there is an error,so just ignore it + Q_UNUSED(error); + } + END + } + +// connecter implementation +CLlcpConnecterAO* CLlcpConnecterAO::NewL( MLlcpConnOrientedTransporter& aConnection, CLlcpSocketType2& aSocket ) + { + BEGIN + CLlcpConnecterAO* self = new (ELeave) CLlcpConnecterAO( aConnection, aSocket ); + CleanupStack::PushL(self); + self->ConstructL(); + CleanupStack::Pop(self); + END + return self; + } + +CLlcpConnecterAO::CLlcpConnecterAO( MLlcpConnOrientedTransporter& aConnection, CLlcpSocketType2& aSocket ) + : CActive( EPriorityStandard ), + iConnection( aConnection ), + iSocket( aSocket ), + iConnState( ENotConnected ) + { + } +/* + ConstructL +*/ +void CLlcpConnecterAO::ConstructL() + { + BEGIN + CActiveScheduler::Add( this ); + if ( iConnection.IsConnected() ) + { + LOG("a LLCP server side socket"); + iConnState = EConnected; + // Starting listening disconnect event + iConnection.WaitForDisconnection( iStatus ); + SetActive(); + } + END + } + +/* + * Destructor. + */ +CLlcpConnecterAO::~CLlcpConnecterAO() + { + BEGIN + Cancel(); + if ( iConnState == EConnected ) + { + iConnection.Disconnect(); + } + END + } +/* + * Connect to remote peer as given service uri. + */ +void CLlcpConnecterAO::ConnectL(const TDesC8& /*aServiceName*/) + { + BEGIN + if ( iConnState == ENotConnected ) + { + // Starting connecting if is in idle state + iConnection.Connect( iStatus ); + SetActive(); + iConnState = EConnecting; + //emit connecting signal + iSocket.StateChanged(QLlcpSocket::ConnectingState); + } + END + } + +/* + * Disconnect with remote peer. + */ +void CLlcpConnecterAO::Disconnect() + { + BEGIN + if ( iConnState == ENotConnected ) + { + END + return; + } + Cancel(); + if ( iConnState == EConnected ) + { + iConnection.Disconnect(); + } + iConnState = ENotConnected; + + //emit QAbstractSocket::ClosingState; + iSocket.StateChanged(QLlcpSocket::ClosingState); + END + } +void CLlcpConnecterAO::RunL() + { + BEGIN + TInt error = iStatus.Int(); + + switch ( iConnState ) + { + // Handling connecting request + case EConnecting: + { + if ( error == KErrNone ) + { + LOG("Connected to LLCP server"); + // Updating state + iConnState = EConnected; + //emit connected signal + iSocket.StateChanged(QLlcpSocket::ConnectedState); + // Starting listening disconnect event + iConnection.WaitForDisconnection( iStatus ); + SetActive(); + } + else + { + LOG("!!Failed to Connected to LLCP server"); + //KErrNotSupported when remote peer has lost from the near field. + iConnState = ENotConnected; + //emit error signal + iSocket.Error(QLlcpSocket::UnknownSocketError); + } + } + break; + case EConnected: + { + //handling disconnect event + if ( error == KErrNone ) + { + LOG("Disconnected event received"); + // Updating state + iConnState = ENotConnected; + //emit disconnected signal + iSocket.StateChanged(QLlcpSocket::ClosingState); + } + else + { + iConnState = ENotConnected; + //emit error signal + iSocket.Error(QLlcpSocket::UnknownSocketError); + } + } + break; + default: + { + // Do nothing + } + break; + } + END + } +void CLlcpConnecterAO::DoCancel() + { + BEGIN + switch ( iConnState ) + { + case EConnecting: + { + iConnection.ConnectCancel(); + } + break; + + case EConnected: + { + iConnection.WaitForDisconnectionCancel(); + } + break; + + default: + { + // Do nothing + } + break; + } + END + } +//sender AO implementation + +CLlcpSenderAO* CLlcpSenderAO::NewL( MLlcpConnOrientedTransporter& aConnection, CLlcpSocketType2& aSocket ) + { + BEGIN + CLlcpSenderAO* self = new (ELeave) CLlcpSenderAO( aConnection, aSocket ); + CleanupStack::PushL(self); + self->ConstructL(); + CleanupStack::Pop(self); + END + return self; + } + +CLlcpSenderAO::CLlcpSenderAO( MLlcpConnOrientedTransporter& aConnection, CLlcpSocketType2& aSocket ) + : CActive( EPriorityStandard ), + iConnection( aConnection ), + iSocket( aSocket ) + { + } +/* + ConstructL +*/ +void CLlcpSenderAO::ConstructL() + { + BEGIN + CActiveScheduler::Add( this ); + END + } + +/* + * Destructor. + */ +CLlcpSenderAO::~CLlcpSenderAO() + { + BEGIN + Cancel(); + iSendBuf0.Close(); + iSendBuf1.Close(); + //todo + iCurrentSendBuf.Close(); + END + } +/* + * Transfer given data to remote device. + */ +TInt CLlcpSenderAO::Send( const TDesC8& aData ) + { + BEGIN + TInt error = KErrNone; + if (aData.Length() == 0) + { + END + return KErrArgument; + } + TInt supportedDataLength = iConnection.SupportedDataLength(); + if (supportedDataLength <= 0) + { + END + return KErrNotReady; + } + if ( !IsActive() ) + { + // Copying data to internal buffer. + iSendBuf0.Zero(); + iCurrentPos = 0; + error = iSendBuf0.ReAlloc( aData.Length() ); + + if ( error == KErrNone ) + { + iSendBuf0.Append( aData ); + + if (iSendBuf0.Length() > supportedDataLength) + { + iCurrentSendPtr.Set(iSendBuf0.Ptr(), supportedDataLength); + } + else + { + iCurrentSendPtr.Set(iSendBuf0.Ptr(), iSendBuf0.Length()); + } + // Sending data + //TODO defect in NFC server + iCurrentSendBuf.Close(); + iCurrentSendBuf.Create(iCurrentSendPtr); + iConnection.Transmit( iStatus, iCurrentSendBuf ); +// iConnection.Transmit( iStatus, iCurrentSendPtr ); + SetActive(); + iCurrentBuffer = EBuffer0; + } + } + else + { + if (iCurrentBuffer == EBuffer0) + { + error = iSendBuf1.ReAlloc( iSendBuf1.Length() + aData.Length() ); + if (error == KErrNone) + { + iSendBuf1.Append(aData); + } + } + else + { + error = iSendBuf0.ReAlloc( iSendBuf0.Length() + aData.Length() ); + if (error == KErrNone) + { + iSendBuf0.Append(aData); + } + } + } + END + return error; + } + +void CLlcpSenderAO::SendRestDataAndSwitchBuffer(RBuf8& aWorkingBuffer, RBuf8& aNextBuffer) + { + BEGIN + TInt supportedDataLength = iConnection.SupportedDataLength(); + if (iCurrentPos == aWorkingBuffer.Length()) + { + LOG("Current working buffer write finished"); + + aWorkingBuffer.Zero(); + if(aNextBuffer.Length() > 0) + { + + if (&aNextBuffer == &iSendBuf0) + { + iCurrentBuffer = EBuffer0; + LOG("Start switch to buffer 0"); + } + else + { + iCurrentBuffer = EBuffer1; + LOG("Start switch to buffer 1"); + } + + iCurrentPos = 0; + + if (supportedDataLength > 0) + { + if (aNextBuffer.Length() > supportedDataLength) + { + iCurrentSendPtr.Set(aNextBuffer.Ptr(), supportedDataLength); + } + else + { + iCurrentSendPtr.Set(aNextBuffer.Ptr(), aNextBuffer.Length()); + } + //TODO + iCurrentSendBuf.Close(); + iCurrentSendBuf.Create(iCurrentSendPtr); + iConnection.Transmit( iStatus, iCurrentSendBuf ); +// iConnection.Transmit( iStatus, iCurrentSendPtr ); + SetActive(); + } + else + { + LOG("SupportedDataLength is invalid, value="<<supportedDataLength); + iSendBuf0.Zero(); + iSendBuf1.Zero(); + iCurrentBuffer = EBuffer0; + iSocket.Error(QLlcpSocket::UnknownSocketError); + } + } + } + else //means current working buffer still have data need to be sent + { + LOG("Current working buffer still has data need to be sent"); + if (supportedDataLength > 0) + { + if (aWorkingBuffer.Length() - iCurrentPos > supportedDataLength) + { + iCurrentSendPtr.Set(aWorkingBuffer.Ptr() + iCurrentPos, supportedDataLength); + } + else + { + iCurrentSendPtr.Set(aWorkingBuffer.Ptr() + iCurrentPos, aWorkingBuffer.Length() - iCurrentPos); + } + // Sending data + //TODO + iCurrentSendBuf.Close(); + iCurrentSendBuf.Create(iCurrentSendPtr); + iConnection.Transmit( iStatus, iCurrentSendBuf ); + +// iConnection.Transmit( iStatus, iCurrentSendPtr ); + SetActive(); + } + else + { + LOG("SupportedDataLength is invalid, value="<<supportedDataLength); + iSendBuf0.Zero(); + iSendBuf1.Zero(); + iCurrentBuffer = EBuffer0; + iSocket.Error(QLlcpSocket::UnknownSocketError); + } + } + END + } +void CLlcpSenderAO::RunL() + { + BEGIN + TInt error = iStatus.Int(); + if ( error == KErrNone ) + { + TInt bytesWritten = iCurrentSendPtr.Length(); + + iCurrentPos += iCurrentSendPtr.Length(); + if (iCurrentBuffer == EBuffer0) + { + SendRestDataAndSwitchBuffer(iSendBuf0, iSendBuf1); + }//if (iCurrentBuffer == EBuffer0) + else //current working buffer is buffer1 + { + SendRestDataAndSwitchBuffer(iSendBuf1, iSendBuf0); + } + //emit BytesWritten signal + iSocket.BytesWritten(bytesWritten); + }//if ( error == KErrNone ) + else + { + LOG("iStatus.Int() = "<<error); + iSendBuf0.Zero(); + iSendBuf1.Zero(); + iCurrentBuffer = EBuffer0; + //emit error() signal + iSocket.Error(QLlcpSocket::UnknownSocketError); + } + END + } +void CLlcpSenderAO::DoCancel() + { + BEGIN + iConnection.TransmitCancel(); + END + } +//receiver implementation +CLlcpReceiverAO* CLlcpReceiverAO::NewL( MLlcpConnOrientedTransporter& aConnection, CLlcpSocketType2& aSocket ) + { + BEGIN + CLlcpReceiverAO* self = new (ELeave) CLlcpReceiverAO( aConnection, aSocket ); + CleanupStack::PushL(self); + self->ConstructL(); + CleanupStack::Pop(self); + END + return self; + } + +CLlcpReceiverAO::CLlcpReceiverAO( MLlcpConnOrientedTransporter& aConnection, CLlcpSocketType2& aSocket ) + : CActive( EPriorityStandard ), + iConnection( aConnection ), + iSocket( aSocket ) + { + } +/* + ConstructL +*/ +void CLlcpReceiverAO::ConstructL() + { + BEGIN + CActiveScheduler::Add( this ); + END + } + +/* + * Destructor. + */ +CLlcpReceiverAO::~CLlcpReceiverAO() + { + BEGIN + Cancel(); + iReceiveBuf.Close(); + END + } + +TInt CLlcpReceiverAO::StartReceiveDatagram() + { + BEGIN + TInt length = 0; + TInt error = KErrNone; + length = iConnection.SupportedDataLength(); + + if ( length > 0 ) + { + iReceiveBuf.Zero(); + error = iReceiveBuf.ReAlloc( length ); + + if ( error == KErrNone ) + { + iConnection.Receive( iStatus, iReceiveBuf ); + SetActive(); + } + } + else + { + // if length is 0 or negative, LLCP link is destroyed. + LOG("Error: length is"<<length); + error = KErrNotReady; + } + END + return error; + } + +void CLlcpReceiverAO::RunL() + { + BEGIN + TInt error = iStatus.Int(); + if ( error == KErrNone ) + { + //append to buffer + HBufC8* buf = NULL; + buf = HBufC8::NewLC( iReceiveBuf.Length() ); + buf->Des().Copy( iReceiveBuf ); + iSocket.iReceiveBufArray.AppendL( buf ); + CleanupStack::Pop( buf ); + + //emit readyRead() signal + iSocket.ReadyRead(); + //resend the Receive request to NFC server + if (StartReceiveDatagram() != KErrNone) + { + iSocket.Error(QLlcpSocket::UnknownSocketError); + } + } + else if ( error == KErrCancel ) + { + //just omit the KErrCancel + LOG(" iStatus = KErrCancel"); + } + else + { + //emit error() signal + iSocket.Error(QLlcpSocket::UnknownSocketError); + } + END + } +void CLlcpReceiverAO::DoCancel() + { + BEGIN + iConnection.ReceiveCancel(); + END + } +//EOF diff --git a/src/nfc/symbian/llcpsockettype2_symbian.h b/src/nfc/symbian/llcpsockettype2_symbian.h new file mode 100644 index 00000000..e67ea2b9 --- /dev/null +++ b/src/nfc/symbian/llcpsockettype2_symbian.h @@ -0,0 +1,266 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#ifndef LLCPSOCKETTYPE2_SYMBIAN_H_ +#define LLCPSOCKETTYPE2_SYMBIAN_H_ + +#include <e32base.h> +#include <nfcserver.h> // RNfcServer +#include <llcpprovider.h> // CLlcpProvider +#include <llcpconnorientedtransporter.h> // MLlcpConnOrientedTransporter +#include <llcpconnorientedlistener.h> // MLlcpConnOrientedListener +#include <llcplinklistener.h> // MLlcpLinkListener +#include <qconnectivityglobal.h> +#include "../qllcpsocket_symbian_p.h" +#include "../qllcpsocket.h" + +/* + * FORWARD DECLARATIONS + */ +class CLlcpConnecterAO; +class CLlcpSenderAO; +class CLlcpReceiverAO; +class CLlcpTimer; +/* + * CLASS DECLARATION for CLlcpSocketType2 (ConnectOriented Transportation). + */ +class CLlcpSocketType2 : public CBase +{ +public: + static CLlcpSocketType2* NewL(QLlcpSocketPrivate* aCallback = NULL); + + static CLlcpSocketType2* NewL(MLlcpConnOrientedTransporter* aTransporter, QLlcpSocketPrivate* aCallback = NULL); + ~CLlcpSocketType2(); + +public: + void ConnectToServiceL( const QString &serviceUri); + TInt DisconnectFromService(); + + TInt StartWriteDatagram(const TDesC8& aData); + TBool ReceiveData(TDes8& aData); + + TInt64 BytesAvailable(); + + //for qt signals + void Error(QLlcpSocket::SocketError aSocketError); + void StateChanged(QLlcpSocket::SocketState aSocketState); + void ReadyRead(); + void BytesWritten(qint64 aBytes); + + TBool WaitForReadyRead(TInt aMilliSeconds); + TBool WaitForBytesWritten(TInt aMilliSeconds); + TBool WaitForConnected(TInt aMilliSeconds); + + void AttachCallbackHandler(QLlcpSocketPrivate* aCallback); +private: + // Constructor + explicit CLlcpSocketType2(MLlcpConnOrientedTransporter* aTransporter = NULL,QLlcpSocketPrivate* aCallback = NULL); + // Second phase constructor + void ConstructL(); + void ConnectToServiceL( const TDesC8& aServiceName); + enum TWaitStatus + { + ENone, + EWaitForReadyRead, + EWaitForBytesWritten, + EWaitForConnected, + EWaitForDisconnected + }; + TBool WaitForOperationReady(TWaitStatus aWaitStatus,TInt aSeconds); + void StopWaitNow(TWaitStatus aWaitStatus); +private: + friend class CLlcpReceiverAO; + /* + * Handle to NFC-server. + * Own. + */ + RNfcServer iNfcServer; + + /* + * Pointer to CLlcpProvider object. + * Own. + */ + CLlcpProvider* iLlcp; + + MLlcpConnOrientedTransporter* iTransporter; + + CLlcpConnecterAO* iConnecter; + CLlcpSenderAO* iSender; + CLlcpReceiverAO* iReceiver; + + RPointerArray<HBufC8> iReceiveBufArray; + TInt iBufferOffset; + + CActiveSchedulerWait * iWait; + TWaitStatus iWaitStatus; + CLlcpTimer * iTimer; + + QLlcpSocketPrivate* iCallback; // not own + +}; + +class CLlcpConnecterAO : public CActive +{ +public: + static CLlcpConnecterAO* NewL( MLlcpConnOrientedTransporter& aConnection, CLlcpSocketType2& aSocket ); + ~CLlcpConnecterAO(); + +public: + /* + * Disonnect with remote peer . + */ + void Disconnect(); + + /* + * Connect to remote peer as given service uri. + */ + void ConnectL(const TDesC8& aServiceName); + +private: // From CActive + void RunL(); + void DoCancel(); + +private: + // Constructor + CLlcpConnecterAO( MLlcpConnOrientedTransporter& aConnection, CLlcpSocketType2& aSocket ); + // Second phase constructor + void ConstructL(); + +private: + enum TConnectionState + { + ENotConnected, + EConnecting, + EConnected + }; + /* + Pointer to MLlcpConnOrientedTransporter object. + */ + MLlcpConnOrientedTransporter& iConnection;//Not Own + CLlcpSocketType2& iSocket; + /* + State of LLCP connection object. + */ + TConnectionState iConnState; +}; +class CLlcpSenderAO : public CActive +{ +public: + static CLlcpSenderAO* NewL( MLlcpConnOrientedTransporter& aConnection, CLlcpSocketType2& aSocket ); + ~CLlcpSenderAO(); + +public: + /* + Transfer given data to remote device. + */ + TInt Send( const TDesC8& aData ); + +private: // From CActive + void RunL(); + void DoCancel(); + +private: + // Constructor + CLlcpSenderAO( MLlcpConnOrientedTransporter& aConnection, CLlcpSocketType2& aSocket ); + // Second phase constructor + void ConstructL(); +private: + void SendRestDataAndSwitchBuffer(RBuf8& aWorkingBuffer, RBuf8& aNextBuffer); + +private: + /* + Pointer to MLlcpConnOrientedTransporter object. + */ + MLlcpConnOrientedTransporter& iConnection; //Not Own + + CLlcpSocketType2& iSocket; + enum TSendBuffer + { + EBuffer0, + EBuffer1 + }; + /* + * Buffered data for sending data. + */ + RBuf8 iSendBuf0; + RBuf8 iSendBuf1; + TSendBuffer iCurrentBuffer; + TPtrC8 iCurrentSendPtr; + TInt iCurrentPos; + RBuf8 iCurrentSendBuf; +}; +class CLlcpReceiverAO : public CActive +{ +public: + static CLlcpReceiverAO* NewL( MLlcpConnOrientedTransporter& aConnection, CLlcpSocketType2& aSocket ); + ~CLlcpReceiverAO(); + +public: + /* + Receive data from remote device. + */ + TInt StartReceiveDatagram(); + +private: // From CActive + void RunL(); + void DoCancel(); + +private: + // Constructor + CLlcpReceiverAO( MLlcpConnOrientedTransporter& aConnection, CLlcpSocketType2& aSocket ); + // Second phase constructor + void ConstructL(); +private: + + /* + * Pointer to MLlcpConnOrientedTransporter object. + */ + MLlcpConnOrientedTransporter& iConnection; //Not Own + + CLlcpSocketType2& iSocket; + /* + * Buffered data for receiving data. + */ + RBuf8 iReceiveBuf; +}; + +#endif /* LLCPSOCKETTYPE2_SYMBIAN_H_ */ diff --git a/src/nfc/symbian/nearfieldmanager_symbian.cpp b/src/nfc/symbian/nearfieldmanager_symbian.cpp new file mode 100644 index 00000000..c0d485b3 --- /dev/null +++ b/src/nfc/symbian/nearfieldmanager_symbian.cpp @@ -0,0 +1,388 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "nearfieldmanager_symbian.h" +#include "nearfieldtargetfactory_symbian.h" +#include "../qnearfieldmanager_symbian_p.h" +#include "nearfieldutility_symbian.h" + +#include <ndefmessage.h> +#include "debug.h" + +/* + \class CNearFieldManager + \brief The CNearFieldManager class provides symbian backend implementation to access NFC service. + + \ingroup connectivity-nfc + \inmodule QtConnectivity + \since 5.0 + \internal + + A Symbian implementation class to support symbian NFC backend. +*/ + +/* + Constructs a CNearFieldManager. +*/ +void CNearFieldManager::ConstructL() + { + BEGIN + User::LeaveIfError(iServer.Open()); + END + } + +/* + Start listening all type tags. +*/ +void CNearFieldManager::StartTargetDetectionL(const QList<QNearFieldTarget::Type> &aTargetTypes) + { + BEGIN + if (aTargetTypes.size() > 0) + { + if (!iNfcTagDiscovery) + { + iNfcTagDiscovery = CNfcTagDiscovery::NewL( iServer ); + User::LeaveIfError(iNfcTagDiscovery->AddTagConnectionListener( *this )); + } + else + { + iNfcTagDiscovery->RemoveTagSubscription(); + } + + if (!iTagSubscription) + { + iTagSubscription = CNfcTagSubscription::NewL(); + } + else + { + iTagSubscription->RemoveAllConnectionModes(); + } + for (int i = 0; i < aTargetTypes.size(); ++i) + { + switch(aTargetTypes[i]) + { + case QNearFieldTarget::NfcTagType1: + iTagSubscription->RemoveConnectionMode(TNfcConnectionInfo::ENfcType1); + iTagSubscription->AddConnectionModeL( TNfcConnectionInfo::ENfcType1 ); + break; + case QNearFieldTarget::NfcTagType2: + iTagSubscription->RemoveConnectionMode(TNfcConnectionInfo::ENfcType2); + iTagSubscription->AddConnectionModeL( TNfcConnectionInfo::ENfcType2 ); + break; + case QNearFieldTarget::NfcTagType3: + iTagSubscription->RemoveConnectionMode(TNfcConnectionInfo::ENfcType3); + iTagSubscription->AddConnectionModeL( TNfcConnectionInfo::ENfcType3 ); + break; + case QNearFieldTarget::NfcTagType4: + iTagSubscription->RemoveConnectionMode(TNfcConnectionInfo::ENfc14443P4); + iTagSubscription->AddConnectionModeL( TNfcConnectionInfo::ENfc14443P4 ); + break; + case QNearFieldTarget::MifareTag: + iTagSubscription->RemoveConnectionMode(TNfcConnectionInfo::ENfcMifareStd); + iTagSubscription->AddConnectionModeL( TNfcConnectionInfo::ENfcMifareStd ); + break; + case QNearFieldTarget::AnyTarget: + iTagSubscription->RemoveAllConnectionModes(); + iTagSubscription->AddConnectionModeL( TNfcConnectionInfo::ENfcType1 ); + iTagSubscription->AddConnectionModeL( TNfcConnectionInfo::ENfcType2 ); + iTagSubscription->AddConnectionModeL( TNfcConnectionInfo::ENfcType3 ); + iTagSubscription->AddConnectionModeL( TNfcConnectionInfo::ENfc14443P4 ); + iTagSubscription->AddConnectionModeL( TNfcConnectionInfo::ENfcMifareStd ); + if (!iLlcpProvider) + { + //create LLCP provider api + iLlcpProvider = CLlcpProvider::NewL( iServer ); + iLlcpProvider->AddLlcpLinkListenerL( *this ); + } + break; + case QNearFieldTarget::ProprietaryTag: + //No conterpart in symbian api + break; + case QNearFieldTarget::NfcForumDevice: + if (!iLlcpProvider) + { + //create LLCP provider api + iLlcpProvider = CLlcpProvider::NewL( iServer ); + iLlcpProvider->AddLlcpLinkListenerL( *this ); + } + break; + default: + break; + } + } + } + iNfcTagDiscovery->AddTagSubscriptionL( *iTagSubscription ); + END + } + +/* + Stop listening all type tags. +*/ +void CNearFieldManager::stopTargetDetection() + { + BEGIN + if (iNfcTagDiscovery) + { + iNfcTagDiscovery->RemoveTagConnectionListener(); + iNfcTagDiscovery->RemoveTagSubscription(); + + if (iTagSubscription) + { + delete iTagSubscription; + iTagSubscription = NULL; + } + delete iNfcTagDiscovery; + iNfcTagDiscovery = NULL; + } + if (iLlcpProvider) + { + iLlcpProvider->RemoveLlcpLinkListener(); + delete iLlcpProvider; + iLlcpProvider = NULL; + } + + END + } + +CNdefRecord::TNdefRecordTnf CNearFieldManager::QTnf2CTnf(const QNdefRecord::TypeNameFormat aQTnf) + { + CNdefRecord::TNdefRecordTnf ret = CNdefRecord::EEmpty; + switch(aQTnf) + { + case QNdefRecord::Empty: + break; + case QNdefRecord::NfcRtd: + ret = CNdefRecord::ENfcWellKnown; + break; + case QNdefRecord::Mime: + ret = CNdefRecord::EMime; + break; + case QNdefRecord::Uri: + ret = CNdefRecord::EUri; + break; + case QNdefRecord::ExternalRtd: + ret = CNdefRecord::ENfcExternal; + break; + case QNdefRecord::Unknown: + ret = CNdefRecord::EUnknown; + break; + default: + break; + } + return ret; + } + +/* + Register interested TNF NDEF message to NFC server. +*/ +TInt CNearFieldManager::AddNdefSubscription( const QNdefRecord::TypeNameFormat aTnf, + const QByteArray& aType ) + { + BEGIN + TInt err = KErrNone; + if ( !iNdefDiscovery ) + { + TRAP(err, iNdefDiscovery = CNdefDiscovery::NewL( iServer )); + if (err != KErrNone) + { + END + return err; + } + err = iNdefDiscovery->AddNdefMessageListener( *this ); + if (err != KErrNone) + { + END + return err; + } + + } + TPtrC8 type(QNFCNdefUtility::QByteArray2TPtrC8(aType)); + err = iNdefDiscovery->AddNdefSubscription( QTnf2CTnf(aTnf), type ); + END + return err; + } + +/* + Unregister interested TNF NDEF message to NFC server. +*/ +void CNearFieldManager::RemoveNdefSubscription( const QNdefRecord::TypeNameFormat aTnf, + const QByteArray& aType ) + { + BEGIN + if ( iNdefDiscovery ) + { + TPtrC8 type(QNFCNdefUtility::QByteArray2TPtrC8(aType)); + iNdefDiscovery->RemoveNdefSubscription( QTnf2CTnf(aTnf), type ); + } + END + } + +/* + Callback function when the tag found by NFC symbain services. +*/ +void CNearFieldManager::TagDetected( MNfcTag* aNfcTag ) + { + BEGIN + if (aNfcTag) + { + QNearFieldTarget* tag = TNearFieldTargetFactory::CreateTargetL(aNfcTag, iServer, &iCallback); + TInt error = KErrNone; + QT_TRYCATCH_ERROR(error, iCallback.targetFound(tag)); + Q_UNUSED(error);//just skip the error + } + END + } + +/* + Callback function when the tag lost event found by NFC symbain services. +*/ +void CNearFieldManager::TagLost() + { + BEGIN + TInt error = KErrNone; + QT_TRYCATCH_ERROR(error, iCallback.targetDisconnected());//just skip the error + Q_UNUSED(error);//just skip the error + END + } + +/* + Callback function when the LLCP peer found by NFC symbain services. +*/ +void CNearFieldManager::LlcpRemoteFound() + { + BEGIN + TInt error = KErrNone; + QNearFieldTarget* tag = NULL; + TRAP(error, tag = TNearFieldTargetFactory::CreateTargetL(NULL, iServer, &iCallback)); + if (error == KErrNone) + { + QT_TRYCATCH_ERROR(error, iCallback.targetFound(tag) ); + Q_UNUSED(error);//just skip the error + } + END + } + +/* + Callback function when the LLCP peer lost event found by NFC symbain services. +*/ +void CNearFieldManager::LlcpRemoteLost() + { + BEGIN + TInt error = KErrNone; + QT_TRYCATCH_ERROR(error, iCallback.targetDisconnected()); + Q_UNUSED(error);//just skip the error + END + } + +/* + Callback function when the registerd NDEF message found by NFC symbain services. +*/ +void CNearFieldManager::MessageDetected( CNdefMessage* aMessage ) + { + BEGIN + if ( aMessage ) + { + TInt error = KErrNone; + QNdefMessage msg; + TRAP(error, msg = QNFCNdefUtility::CNdefMsg2QNdefMsgL( *aMessage)); + if (error == KErrNone) + { + QT_TRYCATCH_ERROR(error, iCallback.invokeNdefMessageHandler(msg)); + Q_UNUSED(error);//just skip the error + } + delete aMessage; + } + END + } + +/* + New a CNearFieldManager instance. +*/ +CNearFieldManager::CNearFieldManager( QNearFieldManagerPrivateImpl& aCallback) + : iCallback(aCallback) + { + } + +/* + Create a new instance of this class. +*/ +CNearFieldManager* CNearFieldManager::NewL( QNearFieldManagerPrivateImpl& aCallback) + { + BEGIN + CNearFieldManager* self = new (ELeave) CNearFieldManager(aCallback); + CleanupStack::PushL( self ); + self->ConstructL(); + CleanupStack::Pop( self ); + END + return self; + } + +/* + Destructor. +*/ +CNearFieldManager::~CNearFieldManager() + { + BEGIN + if ( iNfcTagDiscovery ) + { + iNfcTagDiscovery->RemoveTagConnectionListener(); + iNfcTagDiscovery->RemoveTagSubscription(); + } + + delete iTagSubscription; + delete iNfcTagDiscovery; + + if (iLlcpProvider) + { + iLlcpProvider->RemoveLlcpLinkListener(); + } + delete iLlcpProvider; + + if (iNdefDiscovery) + { + iNdefDiscovery->RemoveAllNdefSubscription(); + } + delete iNdefDiscovery; + + iServer.Close(); + END + } +//EOF diff --git a/src/nfc/symbian/nearfieldmanager_symbian.h b/src/nfc/symbian/nearfieldmanager_symbian.h new file mode 100644 index 00000000..82e05436 --- /dev/null +++ b/src/nfc/symbian/nearfieldmanager_symbian.h @@ -0,0 +1,115 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QNEARFIELDMANAGER_SYMBIAN_H_ +#define QNEARFIELDMANAGER_SYMBIAN_H_ + +#include <nfcserver.h> +#include <nfctag.h> +#include <nfctagsubscription.h> +#include <nfcconnection.h> +#include <nfctype2connection.h> + +#include <nfctagdiscovery.h> +#include <nfctagconnectionlistener.h> +#include <nfcconnectioninfo.h> +#include <llcpprovider.h> // CLlcpProvider +#include <llcplinklistener.h> // MLlcpLinkListener + +#include <ndefmessagelistener.h> +#include <ndefdiscovery.h> + +#include "../qndefrecord.h" +#include <QList> +#include "../qnearfieldtarget.h" + +class QNearFieldManagerPrivateImpl; + +class CNearFieldManager : public CBase, + public MNfcTagConnectionListener, + public MLlcpLinkListener, + public MNdefMessageListener + { +public: + + static CNearFieldManager* NewL( QNearFieldManagerPrivateImpl& aCallback); + virtual ~CNearFieldManager(); + + void StartTargetDetectionL(const QList<QNearFieldTarget::Type> &aTargetTypes); + void stopTargetDetection(); + //for registerNdefMessageHandler ... api + TInt AddNdefSubscription( const QNdefRecord::TypeNameFormat aTnf, + const QByteArray& aType ); + void RemoveNdefSubscription( const QNdefRecord::TypeNameFormat aTnf, + const QByteArray& aType ); + +public: // From MNfcTagConnectionListener + + void TagDetected( MNfcTag* aNfcTag ); + void TagLost(); + +public: // From MLlcpLinkListener + + void LlcpRemoteFound(); + void LlcpRemoteLost(); + +public: // From MNdefMessageListener + + void MessageDetected( CNdefMessage* aMessage ); + +private: + + CNearFieldManager( QNearFieldManagerPrivateImpl& aCallback); + void ConstructL(); + CNdefRecord::TNdefRecordTnf QTnf2CTnf(const QNdefRecord::TypeNameFormat aQTnf); + //own + RNfcServer iServer; + //for Tag discovery + CNfcTagDiscovery* iNfcTagDiscovery; + CNfcTagSubscription* iTagSubscription; + //for LLCP discovery + CLlcpProvider* iLlcpProvider; + //for NDEF discovery + CNdefDiscovery* iNdefDiscovery; + //not own + QNearFieldManagerPrivateImpl& iCallback; + }; +#endif /* QNEARFIELDMANAGER_SYMBIAN_H_ */ diff --git a/src/nfc/symbian/nearfieldndeftarget_symbian.cpp b/src/nfc/symbian/nearfieldndeftarget_symbian.cpp new file mode 100644 index 00000000..0167462a --- /dev/null +++ b/src/nfc/symbian/nearfieldndeftarget_symbian.cpp @@ -0,0 +1,315 @@ +/**************************************************************************** + ** + ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). + ** All rights reserved. + ** Contact: Nokia Corporation (qt-info@nokia.com) + ** + ** This file is part of the Qt Mobility Components. + ** + ** $QT_BEGIN_LICENSE:LGPL$ + ** GNU Lesser General Public License Usage + ** This file may be used under the terms of the GNU Lesser General Public + ** License version 2.1 as published by the Free Software Foundation and + ** appearing in the file LICENSE.LGPL included in the packaging of this + ** file. Please review the following information to ensure the GNU Lesser + ** General Public License version 2.1 requirements will be met: + ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. + ** + ** In addition, as a special exception, Nokia gives you certain additional + ** rights. These rights are described in the Nokia Qt LGPL Exception + ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. + ** + ** GNU General Public License Usage + ** Alternatively, this file may be used under the terms of the GNU General + ** Public License version 3.0 as published by the Free Software Foundation + ** and appearing in the file LICENSE.GPL included in the packaging of this + ** file. Please review the following information to ensure the GNU General + ** Public License version 3.0 requirements will be met: + ** http://www.gnu.org/copyleft/gpl.html. + ** + ** Other Usage + ** Alternatively, this file may be used in accordance with the terms and + ** conditions contained in a signed written agreement between you and Nokia. + ** + ** + ** + ** + ** + ** $QT_END_LICENSE$ + ** + ****************************************************************************/ +#include <nfctype1connection.h> +#include <nfctype2connection.h> +#include <nfctype3connection.h> +#include <iso14443connection.h> +#include <ndefconnection.h> +#include <nfctag.h> +#include <qglobal.h> +#include "nearfieldtag_symbian.h" +#include "nearfieldndeftarget_symbian.h" +#include "nearfieldtagndefoperationcallback_symbian.h" +#include "debug.h" + +CNearFieldNdefTarget::CNearFieldNdefTarget(MNfcTag * aNfcTag, RNfcServer& aNfcServer) : iNfcTag(aNfcTag), + iNfcServer(aNfcServer), + iCurrentOperation(ENull) + { + } + +CNearFieldNdefTarget* CNearFieldNdefTarget::NewLC(MNfcTag * aNfcTag, RNfcServer& aNfcServer) + { + CNearFieldNdefTarget* self = new (ELeave) CNearFieldNdefTarget(aNfcTag, aNfcServer); + CleanupStack::PushL(self); + self->ConstructL(); + return self; + } + +void CNearFieldNdefTarget::ConstructL() + { + iNdefConnection = CNdefConnection::NewL(iNfcServer, *this); + } + +void CNearFieldNdefTarget::SetRealTarget(CNearFieldTag * aRealTarget) + { + iTagConnection = aRealTarget; + } + +CNearFieldNdefTarget::~CNearFieldNdefTarget() + { + BEGIN + // when connection is closed, cancel for each specific connection will be done. + if (iNdefConnection) + { + if (iNdefConnection->IsActivated()) + { + CloseConnection(); + } + delete iNdefConnection; + } + + // when Ndef target has a tag connection, iNfcTag ownership + // will transfer to tag connection. + if (iTagConnection) + { + delete iTagConnection; + } + else + { + delete iNfcTag; + } + END + } + +void CNearFieldNdefTarget::Cancel() + { + BEGIN + if (ERead == iCurrentOperation) + { + iNdefConnection->CancelRead(); + } + else if (EWrite == iCurrentOperation) + { + iNdefConnection->CancelWrite(); + } + + iCurrentOperation = ENull; + END + } + +CNearFieldTag * CNearFieldNdefTarget::CastToTag() + { + BEGIN + if (IsConnectionOpened()) + { + LOG("Ndef connection will be closed"); + CloseConnection(); + } + END + return iTagConnection ? iTagConnection->CastToTag() : reinterpret_cast<CNearFieldTag *>(0); + } + +CNearFieldNdefTarget * CNearFieldNdefTarget::CastToNdefTarget() + { + BEGIN + TInt error = KErrNone; + if (iTagConnection) + { + LOG("Check if Tag Connection is opened"); + if (iTagConnection->IsConnectionOpened()) + { + LOG("Close tag connection"); + iTagConnection->CloseConnection(); + } + } + + if (!IsConnectionOpened()) + { + LOG("Open ndef connection") + error = OpenConnection(); + LOG("error code is"<<error); + } + END + return (error == KErrNone) ? const_cast<CNearFieldNdefTarget *>(this) + : reinterpret_cast<CNearFieldNdefTarget *>(0); + } + +TInt CNearFieldNdefTarget::OpenConnection() + { + BEGIN + END + return iNfcTag->OpenConnection(*iNdefConnection); + } + +void CNearFieldNdefTarget::CloseConnection() + { + BEGIN + END + return iNfcTag->CloseConnection(*iNdefConnection); + } + +TBool CNearFieldNdefTarget::IsConnectionOpened() + { + BEGIN + TBool result = iNdefConnection->IsActivated(); + LOG(result); + END + return result; + } + +const TDesC8& CNearFieldNdefTarget::Uid() const + { + BEGIN + END + return iNfcTag->Uid(); + } + +void CNearFieldNdefTarget::ReadComplete( CNdefMessage* aMessage ) + { + BEGIN + if (iCallback) + { + TInt err = KErrNone; + if (iMessages) + { + err = iMessages->Append(aMessage); + LOG("append message, err = "<<err); + } + + TInt errIgnore = KErrNone; + QT_TRYCATCH_ERROR(errIgnore, iCallback->ReadComplete(err, iMessages)); + //TODO: consider it carefully + //iMessages = 0; + LOG("callback error is "<<errIgnore); + } + iCurrentOperation = ENull; + LOG(iCurrentOperation); + END + } + +void CNearFieldNdefTarget::WriteComplete() + { + BEGIN + if (iCallback) + { + TInt errIgnore = KErrNone; + QT_TRYCATCH_ERROR(errIgnore, iCallback->WriteComplete(KErrNone)); + LOG("callback error is "<<errIgnore); + } + iCurrentOperation = ENull; + LOG(iCurrentOperation); + END + } + +void CNearFieldNdefTarget::HandleError( TInt aError ) + { + BEGIN + if (iCallback) + { + LOG(iCurrentOperation); + + if (ERead == iCurrentOperation) + { + iCallback->ReadComplete(aError, iMessages); + } + else if (EWrite == iCurrentOperation) + { + iCallback->WriteComplete(aError); + } + //TODO: consider it carefully + //iMessages = 0; + } + iCurrentOperation = ENull; + END + } + +TInt CNearFieldNdefTarget::ndefMessages(RPointerArray<CNdefMessage>& aMessages) + { + BEGIN + TInt error = KErrNone; + LOG("iCurrentOperation = "<<iCurrentOperation); + if (iCurrentOperation != ENull) + { + error = KErrInUse; + } + else + { + if (!IsConnectionOpened()) + { + error = OpenConnection(); + LOG("Open connection, err = "<<error); + } + if (KErrNone == error) + { + LOG("begin to read message"); + iMessages = &aMessages; + error = iNdefConnection->ReadMessage(); + LOG("read message err = "<<error); + iCurrentOperation = (KErrNone == error) ? ERead : ENull; + } + } + END + return error; + } + +TInt CNearFieldNdefTarget::setNdefMessages(const RPointerArray<CNdefMessage>& aMessages) + { + BEGIN + TInt error = KErrNone; + CNdefMessage * message; + LOG("iCurrentOperation = "<<iCurrentOperation); + if (iCurrentOperation != ENull) + { + error = KErrInUse; + } + else + { + if (aMessages.Count() > 0) + { + LOG("message count > 0"); + // current only support single ndef message + message = aMessages[0]; + if (!IsConnectionOpened()) + { + error = OpenConnection(); + LOG("Open connection, err = "<<error); + } + if (KErrNone == error) + { + LOG("begin to write message"); + error = iNdefConnection->WriteMessage(*message); + LOG("write message err = "<<error); + iCurrentOperation = (KErrNone == error) ? EWrite : ENull; + } + } + } + END + return error; + } + +void CNearFieldNdefTarget::SetNdefOperationCallback(MNearFieldNdefOperationCallback * const aCallback) + { + BEGIN + iCallback = aCallback; + END + } + diff --git a/src/nfc/symbian/nearfieldndeftarget_symbian.h b/src/nfc/symbian/nearfieldndeftarget_symbian.h new file mode 100644 index 00000000..485e2516 --- /dev/null +++ b/src/nfc/symbian/nearfieldndeftarget_symbian.h @@ -0,0 +1,124 @@ +/**************************************************************************** + ** + ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). + ** All rights reserved. + ** Contact: Nokia Corporation (qt-info@nokia.com) + ** + ** This file is part of the Qt Mobility Components. + ** + ** $QT_BEGIN_LICENSE:LGPL$ + ** GNU Lesser General Public License Usage + ** This file may be used under the terms of the GNU Lesser General Public + ** License version 2.1 as published by the Free Software Foundation and + ** appearing in the file LICENSE.LGPL included in the packaging of this + ** file. Please review the following information to ensure the GNU Lesser + ** General Public License version 2.1 requirements will be met: + ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. + ** + ** In addition, as a special exception, Nokia gives you certain additional + ** rights. These rights are described in the Nokia Qt LGPL Exception + ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. + ** + ** GNU General Public License Usage + ** Alternatively, this file may be used under the terms of the GNU General + ** Public License version 3.0 as published by the Free Software Foundation + ** and appearing in the file LICENSE.GPL included in the packaging of this + ** file. Please review the following information to ensure the GNU General + ** Public License version 3.0 requirements will be met: + ** http://www.gnu.org/copyleft/gpl.html. + ** + ** Other Usage + ** Alternatively, this file may be used in accordance with the terms and + ** conditions contained in a signed written agreement between you and Nokia. + ** + ** + ** + ** + ** + ** $QT_END_LICENSE$ + ** + ****************************************************************************/ + +#ifndef NEARFIELDNDEFTARGET_H +#define NEARFIELDNDEFTARGET_H + +#include <e32base.h> +#include <nfcserver.h> +#include <ndefconnection.h> +#include <e32cmn.h> +#include <ndefhandler.h> + +#include "debug.h" + +class CNearFieldTag; +class CNdefMessage; + +class CNdefConnection; +class MNfcTag; + +class MNearFieldNdefOperationCallback; + +class CNearFieldNdefTarget : public CBase, + public MNdefHandler + { + enum TOperation + { + ENull, + ERead, + EWrite + }; +public: + // Cancel and destroy + ~CNearFieldNdefTarget(); + + // Two-phased constructor. + static CNearFieldNdefTarget* NewLC(MNfcTag * aNfcTag, RNfcServer& aNfcServer); +public: // New functions + void SetRealTarget(CNearFieldTag * aRealTarget); + + // NdefAccess + TInt ndefMessages(RPointerArray<CNdefMessage>& aMessages); + TInt setNdefMessages(const RPointerArray<CNdefMessage>& aMessages); + void Cancel(); + +public: + CNearFieldTag * CastToTag(); + CNearFieldNdefTarget * CastToNdefTarget(); + + TInt OpenConnection(); + void CloseConnection(); + TBool IsConnectionOpened(); + const TDesC8& Uid() const; + void SetNdefOperationCallback(MNearFieldNdefOperationCallback * const aCallback); + +private: + // C++ constructor + CNearFieldNdefTarget(MNfcTag * aNfcTag, RNfcServer& aNfcServer); + + // Second-phase constructor + void ConstructL(); + +private: // From MNdefHandler + void ReadComplete( CNdefRecord* /*aRecord*/, CNdefRecord::TNdefMessagePart /*aPart*/ ){} + void ReadComplete( CNdefMessage* aMessage ); + void ReadComplete( const RPointerArray<CNdefMessage>& /*aMessages*/ ){} + void WriteComplete(); + void HandleError( TInt aError ); + +private: + // own + CNearFieldTag * iTagConnection; + CNdefConnection * iNdefConnection; + // own + MNfcTag * iNfcTag; + + RNfcServer& iNfcServer; + + TOperation iCurrentOperation; + + // Not own + MNearFieldNdefOperationCallback * iCallback; + RPointerArray<CNdefMessage> * iMessages; + }; + +#endif // NEARFIELDNDEFTARGET_H diff --git a/src/nfc/symbian/nearfieldtag_symbian.cpp b/src/nfc/symbian/nearfieldtag_symbian.cpp new file mode 100644 index 00000000..e6f9dbbe --- /dev/null +++ b/src/nfc/symbian/nearfieldtag_symbian.cpp @@ -0,0 +1,181 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <nfctag.h> +#include <qglobal.h> +#include <nfcconnection.h> +#include "nearfieldtag_symbian.h" +#include "nearfieldtagoperationcallback_symbian.h" +#include "debug.h" +/* + \class CNearFieldTag + \brief The CNearFieldTag class provides ways to access tag + + \ingroup connectivity-nfc + \inmodule QtConnectivity + \internal + \since 5.0 +*/ + +CNearFieldTag::CNearFieldTag(MNfcTag * aNfcTag, RNfcServer& aNfcServer) : CActive(EPriorityStandard), + iNfcTag(aNfcTag), + iNfcServer(aNfcServer) + { + CActiveScheduler::Add(this); + } + +CNearFieldTag* CNearFieldTag::NewLC(MNfcTag * aNfcTag, RNfcServer& aNfcServer) + { + CNearFieldTag* self = new (ELeave) CNearFieldTag(aNfcTag, aNfcServer); + CleanupStack::PushL(self); + return self; + } + +CNearFieldTag::~CNearFieldTag() + { + Cancel(); + if (iTagConnection) + { + if(iTagConnection->IsActivated()) + { + CloseConnection(); + } + delete iTagConnection; + } + + delete iNfcTag; + } + +CNearFieldTag * CNearFieldTag::CastToTag() + { + BEGIN + TInt error = KErrNone; + + if (!IsConnectionOpened()) + { + error = OpenConnection(); + LOG("open connection, error is "<<error); + } + END + return (error == KErrNone) ? const_cast<CNearFieldTag *>(this) + : reinterpret_cast<CNearFieldTag *>(0); + } + +TInt CNearFieldTag::OpenConnection() + { + BEGIN + TInt error = iNfcTag->OpenConnection(*iTagConnection); + LOG(error); + END + return error; + } + +void CNearFieldTag::CloseConnection() + { + BEGIN + iNfcTag->CloseConnection(*iTagConnection); + END + } + +TBool CNearFieldTag::IsConnectionOpened() + { + BEGIN + LOG((int)iTagConnection); + LOG("check if connection is opened"); + TBool result = iTagConnection->IsActivated(); + LOG("result is "<<result); + END + return result; + } + +TInt CNearFieldTag::RawModeAccess(const TDesC8& aCommand, TDes8& aResponse, TTimeIntervalMicroSeconds32& aTimeout) + { + BEGIN + TInt error = KErrInUse; + if (!IsActive()) + { + LOG("AO is not active"); + // No ongoing request + if (IsConnectionOpened()) + { + LOG("Connection is open"); + error = KErrNone; + iTagConnection->RawModeAccess(iStatus, aCommand, aResponse, aTimeout); + SetActive(); + } + } + END + return error; + } + +void CNearFieldTag::DoCancel() + { + BEGIN + iTagConnection->CancelRawModeAccess(); + if (iCallback) + { + LOG("call back command complete with KErrCancel"); + TInt err; + QT_TRYCATCH_ERROR(err, iCallback->CommandComplete(KErrCancel)); + Q_UNUSED(err); + } + END + } + +void CNearFieldTag::RunL() + { + BEGIN + if (iCallback) + { + LOG("call back command complete with error"<<iStatus.Int()); + TInt err; + QT_TRYCATCH_ERROR(err, iCallback->CommandComplete(iStatus.Int())); + Q_UNUSED(err); + } + END + } + +void CNearFieldTag::SetTagOperationCallback(MNearFieldTagOperationCallback * const aCallback) + { + BEGIN + iCallback = aCallback; + END + } diff --git a/src/nfc/symbian/nearfieldtag_symbian.h b/src/nfc/symbian/nearfieldtag_symbian.h new file mode 100644 index 00000000..5b59f05a --- /dev/null +++ b/src/nfc/symbian/nearfieldtag_symbian.h @@ -0,0 +1,94 @@ +/**************************************************************************** + ** + ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). + ** All rights reserved. + ** Contact: Nokia Corporation (qt-info@nokia.com) + ** + ** This file is part of the Qt Mobility Components. + ** + ** $QT_BEGIN_LICENSE:LGPL$ + ** GNU Lesser General Public License Usage + ** This file may be used under the terms of the GNU Lesser General Public + ** License version 2.1 as published by the Free Software Foundation and + ** appearing in the file LICENSE.LGPL included in the packaging of this + ** file. Please review the following information to ensure the GNU Lesser + ** General Public License version 2.1 requirements will be met: + ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. + ** + ** In addition, as a special exception, Nokia gives you certain additional + ** rights. These rights are described in the Nokia Qt LGPL Exception + ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. + ** + ** GNU General Public License Usage + ** Alternatively, this file may be used under the terms of the GNU General + ** Public License version 3.0 as published by the Free Software Foundation + ** and appearing in the file LICENSE.GPL included in the packaging of this + ** file. Please review the following information to ensure the GNU General + ** Public License version 3.0 requirements will be met: + ** http://www.gnu.org/copyleft/gpl.html. + ** + ** Other Usage + ** Alternatively, this file may be used in accordance with the terms and + ** conditions contained in a signed written agreement between you and Nokia. + ** + ** + ** + ** + ** + ** $QT_END_LICENSE$ + ** + ****************************************************************************/ + +#ifndef NEARFIELDTAG_SYMBIAN_H +#define NEARFIELDTAG_SYMBIAN_H +#include <nfcserver.h> +#include <e32base.h> +#include <iso14443connection.h> + +class MNfcTag; +class MNfcConnection; +class MNearFieldTagOperationCallback; + + +class CNearFieldTag : public CActive + { +public: + // Cancel and destroy + ~CNearFieldTag(); + + // Two-phased constructor. + static CNearFieldTag* NewLC(MNfcTag * aNfcTag, RNfcServer& aNfcServer); + +public: + CNearFieldTag * CastToTag(); + void SetConnection(MNfcConnection * aTagConnection) { iTagConnection = aTagConnection; } + + TInt OpenConnection(); + void CloseConnection(); + TBool IsConnectionOpened(); + + TInt RawModeAccess(const TDesC8& aCommand, TDes8& aResponse, TTimeIntervalMicroSeconds32& aTimeout); + + MNfcConnection * TagConnection() { return iTagConnection;} + + void SetTagOperationCallback(MNearFieldTagOperationCallback * const aCallback); + +private: + // C++ constructor + CNearFieldTag(MNfcTag * aNfcTag, RNfcServer& aNfcServer); + +private: + void RunL(); + void DoCancel(); + +private: + // own + MNfcConnection * iTagConnection; + MNfcTag * iNfcTag; + RNfcServer& iNfcServer; + // Not own + MNearFieldTagOperationCallback * iCallback; + TBool iIsTag4; + }; + +#endif // NEARFIELDTAG_SYMBIAN_H diff --git a/src/nfc/symbian/nearfieldtagasyncrequest_symbian.cpp b/src/nfc/symbian/nearfieldtagasyncrequest_symbian.cpp new file mode 100644 index 00000000..48dde301 --- /dev/null +++ b/src/nfc/symbian/nearfieldtagasyncrequest_symbian.cpp @@ -0,0 +1,277 @@ +/**************************************************************************** + ** + ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). + ** All rights reserved. + ** Contact: Nokia Corporation (qt-info@nokia.com) + ** + ** This file is part of the Qt Mobility Components. + ** + ** $QT_BEGIN_LICENSE:LGPL$ + ** GNU Lesser General Public License Usage + ** This file may be used under the terms of the GNU Lesser General Public + ** License version 2.1 as published by the Free Software Foundation and + ** appearing in the file LICENSE.LGPL included in the packaging of this + ** file. Please review the following information to ensure the GNU Lesser + ** General Public License version 2.1 requirements will be met: + ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. + ** + ** In addition, as a special exception, Nokia gives you certain additional + ** rights. These rights are described in the Nokia Qt LGPL Exception + ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. + ** + ** GNU General Public License Usage + ** Alternatively, this file may be used under the terms of the GNU General + ** Public License version 3.0 as published by the Free Software Foundation + ** and appearing in the file LICENSE.GPL included in the packaging of this + ** file. Please review the following information to ensure the GNU General + ** Public License version 3.0 requirements will be met: + ** http://www.gnu.org/copyleft/gpl.html. + ** + ** Other Usage + ** Alternatively, this file may be used in accordance with the terms and + ** conditions contained in a signed written agreement between you and Nokia. + ** + ** + ** + ** + ** + ** $QT_END_LICENSE$ + ** + ****************************************************************************/ +#include "nearfieldtagasyncrequest_symbian.h" +#include "nearfieldutility_symbian.h" +#include "nearfieldtagimplcommon_symbian.h" +#include <e32std.h> +#include "debug.h" + +TInt MNearFieldTagAsyncRequest::TimeoutCallback(TAny * aObj) +{ + BEGIN + MNearFieldTagAsyncRequest * obj = static_cast<MNearFieldTagAsyncRequest *>(aObj); + obj->ProcessTimeout(); + END + return KErrNone; +} + +MNearFieldTagAsyncRequest::MNearFieldTagAsyncRequest(QNearFieldTagImplCommon& aOperator) : iOperator(aOperator) +{ + iWait = 0; + iTimer = 0; + iRequestIssued = EFalse; + iCurrentRequestResult = 0; + iSendSignal = true; + iRequestResult = 0; +} + +MNearFieldTagAsyncRequest::~MNearFieldTagAsyncRequest() +{ + BEGIN + if (iTimer) + { + LOG("delete timer"); + delete iTimer; + iTimer = 0; + } + + if (iWait) + { + if (iWait->IsStarted()) + { + iWait->AsyncStop(); + } + LOG("delete waiter"); + delete iWait; + } + END +} + +void MNearFieldTagAsyncRequest::SetRequestId(QNearFieldTarget::RequestId aId) +{ + BEGIN + iId = aId; + END +} + +QNearFieldTarget::RequestId MNearFieldTagAsyncRequest::RequestID() +{ + BEGIN + END + return iId; +} + +bool MNearFieldTagAsyncRequest::WaitRequestCompleted(int aMsecs) +{ + BEGIN + volatile bool result = false; + if (iWait) + { + if (iWait->IsStarted()) + { + LOG("waiter has already started"); + // the request is already waited, return false. + return false; + } + } + else + { + LOG("new a new waiter"); + iWait = new(ELeave) CActiveSchedulerWait(); + iCurrentRequestResult = &result; + } + + if (iTimer) + { + LOG("cancel previous timer"); + iTimer->Cancel(); + } + else + { + LOG("create a new timer"); + iTimer = CPeriodic::NewL(CActive::EPriorityStandard); + } + + iMsecs = aMsecs * 1000; + if (iRequestIssued) + { + // timer should be started when request is issued. + LOG("Start timer"); + TCallBack callback(MNearFieldTagAsyncRequest::TimeoutCallback, this); + iTimer->Start(iMsecs, iMsecs, callback); + } + LOG("Start waiter"); + iWait->Start(); + LOG("Waiting completed, "<<result); + END + return result; +} + +int MNearFieldTagAsyncRequest::WaitRequestCompletedNoSignal(int aMsecs) +{ + BEGIN + volatile int result = KErrNone; + iSendSignal = false; + iRequestResult = &result; + if (iWait) + { + if (iWait->IsStarted()) + { + LOG("waiter has already started"); + // the request is already waited, return false. + return KErrInUse; + } + } + else + { + LOG("new a new waiter"); + iWait = new(ELeave) CActiveSchedulerWait(); + iRequestResult = &result; + } + + if (iTimer) + { + LOG("cancel previous timer"); + iTimer->Cancel(); + } + else + { + LOG("create a new timer"); + iTimer = CPeriodic::NewL(CActive::EPriorityStandard); + } + + iMsecs = aMsecs * 1000; + if (iRequestIssued) + { + // timer should be started when request is issued. + LOG("Start timer"); + TCallBack callback(MNearFieldTagAsyncRequest::TimeoutCallback, this); + iTimer->Start(iMsecs, iMsecs, callback); + } + LOG("Start waiter"); + iWait->Start(); + LOG("Waiting completed, "<<result); + END + return result; +} + + +void MNearFieldTagAsyncRequest::ProcessResponse(TInt aError) +{ + BEGIN + LOG("Error is "<<aError); + + iOperator.IssueNextRequest(iId); + + HandleResponse(aError); + + if (iWait) + { + ProcessWaitRequestCompleted(aError); + } + else + { + ProcessEmitSignal(aError); + } + + LOG("remove the request from queue"); + iOperator.RemoveRequestFromQueue(iId); + LOG("delete the request"); + iRequestIssued = EFalse; + delete this; + END +} + +void MNearFieldTagAsyncRequest::ProcessWaitRequestCompleted(TInt aError) +{ + BEGIN + if (iSendSignal) + { + if (iCurrentRequestResult) + { + (*iCurrentRequestResult) = (KErrNone == aError); + } + + iCurrentRequestResult = 0; + if (iTimer) + { + LOG("cancel timer"); + delete iTimer; + iTimer = 0; + } + if (iWait) + { + if (iWait->IsStarted()) + { + LOG("async stop waiter"); + iWait->AsyncStop(); + } + } + ProcessEmitSignal(aError); + } + else + { + // just for internal waiting operation. + if (iRequestResult) + { + (*iRequestResult) = aError; + } + + iRequestResult = 0; + if (iTimer) + { + LOG("cancel timer"); + delete iTimer; + iTimer = 0; + } + if (iWait) + { + if (iWait->IsStarted()) + { + LOG("async stop waiter"); + iWait->AsyncStop(); + } + } + } + + END +} + diff --git a/src/nfc/symbian/nearfieldtagasyncrequest_symbian.h b/src/nfc/symbian/nearfieldtagasyncrequest_symbian.h new file mode 100644 index 00000000..cf5aa96b --- /dev/null +++ b/src/nfc/symbian/nearfieldtagasyncrequest_symbian.h @@ -0,0 +1,107 @@ +/**************************************************************************** + ** + ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). + ** All rights reserved. + ** Contact: Nokia Corporation (qt-info@nokia.com) + ** + ** This file is part of the Qt Mobility Components. + ** + ** $QT_BEGIN_LICENSE:LGPL$ + ** GNU Lesser General Public License Usage + ** This file may be used under the terms of the GNU Lesser General Public + ** License version 2.1 as published by the Free Software Foundation and + ** appearing in the file LICENSE.LGPL included in the packaging of this + ** file. Please review the following information to ensure the GNU Lesser + ** General Public License version 2.1 requirements will be met: + ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. + ** + ** In addition, as a special exception, Nokia gives you certain additional + ** rights. These rights are described in the Nokia Qt LGPL Exception + ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. + ** + ** GNU General Public License Usage + ** Alternatively, this file may be used under the terms of the GNU General + ** Public License version 3.0 as published by the Free Software Foundation + ** and appearing in the file LICENSE.GPL included in the packaging of this + ** file. Please review the following information to ensure the GNU General + ** Public License version 3.0 requirements will be met: + ** http://www.gnu.org/copyleft/gpl.html. + ** + ** Other Usage + ** Alternatively, this file may be used in accordance with the terms and + ** conditions contained in a signed written agreement between you and Nokia. + ** + ** + ** + ** + ** + ** $QT_END_LICENSE$ + ** + ****************************************************************************/ + +#ifndef NEARFIELDTAGASYNCREQUEST_SYMBIAN_H +#define NEARFIELDTAGASYNCREQUEST_SYMBIAN_H + +#include <qnearfieldtarget.h> +#include <e32base.h> + +class QNearFieldTagImplCommon; + +class MNearFieldTagAsyncRequest + { +public: + enum TRequestType + { + ENdefRequest, + ETagCommandRequest, + ETagCommandsRequest, + ENull + }; + +public: + MNearFieldTagAsyncRequest(QNearFieldTagImplCommon& aOperator); + + virtual ~MNearFieldTagAsyncRequest(); + virtual void IssueRequest() = 0; + virtual void ProcessResponse(TInt aError); + + // inline to get fast speed since this function is used internally + // to convert async ndef request to sync. + virtual void ProcessTimeout() = 0; + + virtual void ProcessWaitRequestCompleted(TInt aError); + + // emit signal defined in QNearFieldTarget + virtual void ProcessEmitSignal(TInt aError) = 0; + + // should call iOperator->handleResponse(id, response) + virtual void HandleResponse(TInt aError) = 0; + + virtual TRequestType Type() = 0; + + virtual bool WaitRequestCompleted(int aMsec); + virtual int WaitRequestCompletedNoSignal(int aMsec); + + void SetRequestId(QNearFieldTarget::RequestId aId); + QNearFieldTarget::RequestId RequestID(); + static TInt TimeoutCallback(TAny * aObj); +protected: + // Current async request ID. + QNearFieldTarget::RequestId iId; + // Not own. + QNearFieldTagImplCommon& iOperator; + + // Own. + CActiveSchedulerWait * iWait; + // Own. + CPeriodic * iTimer; + TBool iRequestIssued; + + int iMsecs; + bool iSendSignal; + volatile int * iRequestResult; + + volatile bool * iCurrentRequestResult; + }; + +#endif // NEARFIELDTAGASYNCREQUEST_SYMBIAN_H diff --git a/src/nfc/symbian/nearfieldtagcommandrequest_symbian.cpp b/src/nfc/symbian/nearfieldtagcommandrequest_symbian.cpp new file mode 100644 index 00000000..79a9f0a8 --- /dev/null +++ b/src/nfc/symbian/nearfieldtagcommandrequest_symbian.cpp @@ -0,0 +1,158 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +#include "nearfieldtagcommandrequest_symbian.h" +#include "nearfieldutility_symbian.h" +#include "nearfieldtagimplcommon_symbian.h" +#include "debug.h" + +NearFieldTagCommandRequest::NearFieldTagCommandRequest(QNearFieldTagImplCommon& aOperator) : MNearFieldTagAsyncRequest(aOperator) +{ +} + +NearFieldTagCommandRequest::~NearFieldTagCommandRequest() +{ + BEGIN + if (iRequestIssued) + { + iOperator.DoCancelSendCommand(); + } + END +} + +void NearFieldTagCommandRequest::IssueRequest() +{ + BEGIN + + iOperator.DoSendCommand(iCommand, this); + iRequestIssued = ETrue; + if (iWait) + { + if (iWait->IsStarted()) + { + // start timer here + LOG("Start timer"); + TCallBack callback(MNearFieldTagAsyncRequest::TimeoutCallback, this); + iTimer->Start(iMsecs, iMsecs, callback); + } + } + + END +} + +bool NearFieldTagCommandRequest::IssueRequestNoDefer() +{ + BEGIN + iRequestIssued = iOperator.DoSendCommand(iCommand, this, false); + return iRequestIssued; +} + +void NearFieldTagCommandRequest::CommandComplete(TInt aError) +{ + BEGIN + iRequestIssued = EFalse; + ProcessResponse(HandlePassiveCommand(aError)); + END +} + + +void NearFieldTagCommandRequest::ProcessEmitSignal(TInt aError) +{ + BEGIN + LOG(aError); + if (aError != KErrNone) + { + iOperator.EmitError(aError, iId); + } + END +} + +void NearFieldTagCommandRequest::ProcessTimeout() +{ + if (iWait) + { + if (iWait->IsStarted()) + { + if (iRequestIssued) + { + iOperator.DoCancelSendCommand(); + iRequestIssued = EFalse; + } + ProcessResponse(HandlePassiveCommand(KErrTimedOut)); + } + } +} + +void NearFieldTagCommandRequest::HandleResponse(TInt aError) +{ + BEGIN + LOG(aError); + if (aError == KErrNone) + { + iOperator.HandleResponse(iId, iCommand, iRequestResponse, iSendSignal); + } + END +} + +TInt NearFieldTagCommandRequest::HandlePassiveCommand(TInt aError) +{ + BEGIN + TInt result = aError; + // check if the command is passive ack + if (iCommand.count() == 6) + { + // it may be the select sector packet 2 command for tag type 2 + if ((iCommand.at(1) == 0) && (iCommand.at(2) == 0) && (iCommand.at(3) == 0)) + { + result = KErrNone; + if (KErrTimedOut == aError) + { + iResponse->Append(0x0A); + } + else + { + iResponse->Append(0x05); + } + } + } + iRequestResponse = QNFCNdefUtility::TDesC2QByteArray(*iResponse); + END + return result; +} diff --git a/src/nfc/symbian/nearfieldtagcommandrequest_symbian.h b/src/nfc/symbian/nearfieldtagcommandrequest_symbian.h new file mode 100644 index 00000000..6ff06243 --- /dev/null +++ b/src/nfc/symbian/nearfieldtagcommandrequest_symbian.h @@ -0,0 +1,72 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef NEARFIELDTAGCOMMANDREQUEST_SYMBIAN_H +#define NEARFIELDTAGCOMMANDREQUEST_SYMBIAN_H + +#include "nearfieldtagasyncrequest_symbian.h" +#include "nearfieldtagoperationcallback_symbian.h" + +class NearFieldTagCommandRequest : public MNearFieldTagAsyncRequest, + public MNearFieldTagOperationCallback + { +public: + NearFieldTagCommandRequest(QNearFieldTagImplCommon& aOperator); + ~NearFieldTagCommandRequest(); + void IssueRequest(); + bool IssueRequestNoDefer(); + void ProcessTimeout(); + void ProcessEmitSignal(TInt aError); + void HandleResponse(TInt aError); + void SetInputCommand(QByteArray aCommand) { iCommand = aCommand; } + void SetResponseBuffer(RBuf8 * aResponse) { iResponse = aResponse; } + QString GetRequestCommand() { return iCommand; } + TRequestType Type() { return ETagCommandRequest; } +private: + void CommandComplete(TInt aError); + TInt HandlePassiveCommand(TInt aError); + QByteArray iCommand; + // Not own + RBuf8 * iResponse; + QByteArray iRequestResponse; + }; + +#endif diff --git a/src/nfc/symbian/nearfieldtagcommandsrequest_symbian.cpp b/src/nfc/symbian/nearfieldtagcommandsrequest_symbian.cpp new file mode 100644 index 00000000..5d3a3816 --- /dev/null +++ b/src/nfc/symbian/nearfieldtagcommandsrequest_symbian.cpp @@ -0,0 +1,207 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +#include "nearfieldtagcommandsrequest_symbian.h" +#include "nearfieldutility_symbian.h" +#include "nearfieldtagimplcommon_symbian.h" +#include "debug.h" + +NearFieldTagCommandsRequest::NearFieldTagCommandsRequest(QNearFieldTagImplCommon& aOperator) : MNearFieldTagAsyncRequest(aOperator) +{ + iCurrentCommand = 0; + iRequestCancelled = EFalse; +} + +NearFieldTagCommandsRequest::~NearFieldTagCommandsRequest() +{ + BEGIN + iRequestCancelled = ETrue; + if (iRequestIssued) + { + iOperator.DoCancelSendCommand(); + } + END +} + +void NearFieldTagCommandsRequest::IssueRequest() +{ + BEGIN + LOG("current command index = "<<iCurrentCommand); + LOG("commands count = "<<iCommands.count()); + iRequestIssued = ETrue; + if (iCurrentCommand < iCommands.count()) + { + if (iWait && (iCurrentCommand == 0)) + { + if (iWait->IsStarted() && !iTimer->IsActive()) + { + // start timer here + LOG("Start timer"); + TCallBack callback(MNearFieldTagAsyncRequest::TimeoutCallback, this); + iTimer->Start(iMsecs, iMsecs, callback); + } + } + iOperator.DoSendCommand(iCommands.at(iCurrentCommand), this); + ++iCurrentCommand; + } + END +} + +bool NearFieldTagCommandsRequest::IssueRequestNoDefer() +{ + BEGIN + if (iCommands.count() > 0) + { + iRequestIssued = iOperator.DoSendCommand(iCommands.at(0), this, false); + ++iCurrentCommand; + } + END + return iRequestIssued; +} + +void NearFieldTagCommandsRequest::ProcessResponse(TInt aError) +{ + BEGIN + LOG("error is "<<aError); + QByteArray result; + if (KErrNone == aError) + { + result = QNFCNdefUtility::TDesC2QByteArray(*iResponse); + LOG("result is "<<result); + LOG("clear the buffer"); + iResponse->Zero(); + iDecodedResponses.append(iOperator.decodeResponse(iCommands.at(iCurrentCommand - 1), result)); + } + else + { + // error occurs + LOG("error occurs, append QVariant() to rest list"); + for (--iCurrentCommand; iCurrentCommand < iCommands.count(); ++iCurrentCommand) + { + iDecodedResponses.append(QVariant()); + } + } + iRequestIssued = EFalse; + if (!iRequestCancelled && (iCurrentCommand < iCommands.count())) + { + LOG("issue another command in command list"); + IssueRequest(); + } + else + { + // all commands finished + LOG("all commands completed"); + MNearFieldTagAsyncRequest::ProcessResponse(aError); + } + END +} + +void NearFieldTagCommandsRequest::HandleResponse(TInt aError) +{ + BEGIN + iOperator.HandleResponse(iId, iDecodedResponses, aError); + END +} + +void NearFieldTagCommandsRequest::CommandComplete(TInt aError) +{ + BEGIN + ProcessResponse(HandlePassiveCommand(aError)); + END +} + +void NearFieldTagCommandsRequest::ProcessEmitSignal(TInt aError) +{ + BEGIN + LOG(aError); + if (aError != KErrNone) + { + iOperator.EmitError(aError, iId); + } + END +} + +void NearFieldTagCommandsRequest::ProcessTimeout() +{ + BEGIN + if (iWait) + { + if (iWait->IsStarted()) + { + if (iRequestIssued) + { + iOperator.DoCancelSendCommand(); + iRequestCancelled = ETrue; + iRequestIssued = EFalse; + } + LOG("wait timeout"); + ProcessResponse(HandlePassiveCommand(KErrTimedOut)); + } + } + END +} + +TInt NearFieldTagCommandsRequest::HandlePassiveCommand(TInt aError) +{ + BEGIN + TInt result = aError; + TInt index = (iCurrentCommand == 0) ? iCurrentCommand : (iCurrentCommand - 1); + QByteArray command = iCommands.at(index); + // check if the command is passive ack + if (command.count() == 6) + { + // it may be the select sector packet 2 command for tag type 2 + if ((command.at(1) == 0) && (command.at(2) == 0) && (command.at(3) == 0)) + { + iResponse->Zero(); + if (KErrTimedOut == aError) + { + result = KErrNone; + iResponse->Append(0x0A); + } + else + { + iResponse->Append(0x05); + } + } + } + END + return result; +} diff --git a/src/nfc/symbian/nearfieldtagcommandsrequest_symbian.h b/src/nfc/symbian/nearfieldtagcommandsrequest_symbian.h new file mode 100644 index 00000000..605d691f --- /dev/null +++ b/src/nfc/symbian/nearfieldtagcommandsrequest_symbian.h @@ -0,0 +1,74 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +#ifndef NEARFIELDTAGCOMMANDSREQUEST_SYMBIAN_H +#define NEARFIELDTAGCOMMANDSREQUEST_SYMBIAN_H + +#include "nearfieldtagasyncrequest_symbian.h" +#include "nearfieldtagoperationcallback_symbian.h" +#include <QVariantList> + +class NearFieldTagCommandsRequest : public MNearFieldTagAsyncRequest, + public MNearFieldTagOperationCallback + { +public: + NearFieldTagCommandsRequest(QNearFieldTagImplCommon& aOperator); + ~NearFieldTagCommandsRequest(); + void IssueRequest(); + bool IssueRequestNoDefer(); + void ProcessResponse(TInt aError); + void ProcessEmitSignal(TInt aError); + void HandleResponse(TInt aError); + void ProcessTimeout(); + void SetInputCommands(QList<QByteArray> aCommands) { iCommands = aCommands; } + void SetResponseBuffer(RBuf8 * aResponse) { iResponse = aResponse; } + TRequestType Type() { return ETagCommandsRequest; } +private: + void CommandComplete(TInt aError); + TInt HandlePassiveCommand(TInt aError); + + QList<QByteArray> iCommands; + QVariantList iDecodedResponses; + // Not own + RBuf8 * iResponse; + int iCurrentCommand; + TBool iRequestCancelled; + }; +#endif diff --git a/src/nfc/symbian/nearfieldtagimpl_symbian.h b/src/nfc/symbian/nearfieldtagimpl_symbian.h new file mode 100644 index 00000000..00d2ec03 --- /dev/null +++ b/src/nfc/symbian/nearfieldtagimpl_symbian.h @@ -0,0 +1,181 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QNEARFIELDTAGIMPL_H +#define QNEARFIELDTAGIMPL_H + +#include "nearfieldtagimplcommon_symbian.h" +#include "debug.h" + +class QNearFieldTagType1Symbian; +class QNearFieldTagType2Symbian; +class QNearFieldTagType3Symbian; +class QNearFieldTagType4Symbian; + +template<typename TAGTYPE> +struct TagConstValue +{ + enum { MaxResponseSize = 4096, Timeout = 100 * 1000 }; +}; + +template<> +struct TagConstValue<QNearFieldTagType1Symbian> +{ + enum { MaxResponseSize = 131, Timeout = 5 * 1000 }; +}; + +template<> +struct TagConstValue<QNearFieldTagType2Symbian> +{ + enum { MaxResponseSize = 18, Timeout = 5 * 1000 }; +}; + +template<> +struct TagConstValue<QNearFieldTagType3Symbian> +{ + enum { MaxResponseSize = 256, Timeout = 500 * 1000 }; +}; + +template <typename TAGTYPE> +class QNearFieldTagImpl : public QNearFieldTagImplCommon +{ +public: // From MNearFieldTargetOperation + + void HandleResponse(const QNearFieldTarget::RequestId &id, const QByteArray &command, const QByteArray &response, bool emitRequestCompleted); + void HandleResponse(const QNearFieldTarget::RequestId &id, const QVariantList& response, int error); + QVariant decodeResponse(const QByteArray& command, const QByteArray& response); + + void EmitNdefMessageRead(const QNdefMessage &message); + void EmitNdefMessagesWritten(); + void EmitRequestCompleted(const QNearFieldTarget::RequestId &id); + void EmitError(int error, const QNearFieldTarget::RequestId &id); + +public: + QNearFieldTagImpl(CNearFieldNdefTarget *tag); +}; + +template<typename TAGTYPE> +QNearFieldTagImpl<TAGTYPE>::QNearFieldTagImpl(CNearFieldNdefTarget *tag) : QNearFieldTagImplCommon(tag) +{ + TRAP_IGNORE(mResponse.CreateL(TagConstValue<TAGTYPE>::MaxResponseSize)); + mTimeout = TagConstValue<TAGTYPE>::Timeout; +} + +template<typename TAGTYPE> +void QNearFieldTagImpl<TAGTYPE>::HandleResponse(const QNearFieldTarget::RequestId &id, const QByteArray &command, const QByteArray &response, bool emitRequestCompleted) +{ + BEGIN + TAGTYPE * tag = static_cast<TAGTYPE *>(this); + tag->handleTagOperationResponse(id, command, response, emitRequestCompleted); + END +} + +template<typename TAGTYPE> +void QNearFieldTagImpl<TAGTYPE>::HandleResponse(const QNearFieldTarget::RequestId &id, const QVariantList& response, int error) +{ + BEGIN + TAGTYPE * tag = static_cast<TAGTYPE *>(this); + tag->setResponseForRequest(id, response, (error == KErrNone)); + END +} + +template<typename TAGTYPE> +QVariant QNearFieldTagImpl<TAGTYPE>::decodeResponse(const QByteArray& command, const QByteArray& response) +{ + BEGIN + TAGTYPE * tag = static_cast<TAGTYPE *>(this); + END + return tag->decodeResponse(command, response); +} + +template<typename TAGTYPE> +void QNearFieldTagImpl<TAGTYPE>::EmitNdefMessageRead(const QNdefMessage &message) +{ + BEGIN + TAGTYPE * tag = static_cast<TAGTYPE *>(this); + int err; + QT_TRYCATCH_ERROR(err, emit tag->ndefMessageRead(message)); + Q_UNUSED(err); + END +} + +template<typename TAGTYPE> +void QNearFieldTagImpl<TAGTYPE>::EmitNdefMessagesWritten() +{ + BEGIN + TAGTYPE * tag = static_cast<TAGTYPE *>(this); + int err; + QT_TRYCATCH_ERROR(err, emit tag->ndefMessagesWritten()); + Q_UNUSED(err); + END +} + +template<typename TAGTYPE> +void QNearFieldTagImpl<TAGTYPE>::EmitRequestCompleted(const QNearFieldTarget::RequestId &id) +{ + BEGIN + TAGTYPE * tag = static_cast<TAGTYPE *>(this); + int err; + QT_TRYCATCH_ERROR(err, emit tag->requestCompleted(id)); + Q_UNUSED(err); + END +} + +template<typename TAGTYPE> +void QNearFieldTagImpl<TAGTYPE>::EmitError(int error, const QNearFieldTarget::RequestId &id) +{ + BEGIN + TAGTYPE * tag = static_cast<TAGTYPE *>(this); + + int err = KErrNone; + try { + QMetaObject::invokeMethod(tag, "error", Qt::QueuedConnection, + Q_ARG(QNearFieldTarget::Error, SymbianError2QtError(error)), + Q_ARG(QNearFieldTarget::RequestId, id)); + } catch (const std::exception &ex) { + err = qt_symbian_exception2Error(ex); + } + + Q_UNUSED(err); + END +} + +#endif // QNEARFIELDTAGIMPL_H diff --git a/src/nfc/symbian/nearfieldtagimplcommon_symbian.cpp b/src/nfc/symbian/nearfieldtagimplcommon_symbian.cpp new file mode 100644 index 00000000..bbfba7fc --- /dev/null +++ b/src/nfc/symbian/nearfieldtagimplcommon_symbian.cpp @@ -0,0 +1,596 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "nearfieldtagimplcommon_symbian.h" + + +bool QNearFieldTagImplCommon::DoReadNdefMessages(MNearFieldNdefOperationCallback * const aCallback) +{ + BEGIN + int error = KErrGeneral; + CNearFieldNdefTarget * ndefTarget = mTag->CastToNdefTarget(); + if (ndefTarget) + { + LOG("switched to ndef connection"); + ndefTarget->SetNdefOperationCallback(aCallback); + mMessageList.Reset(); + error = ndefTarget->ndefMessages(mMessageList); + LOG("error code is"<<error); + } + + if (error != KErrNone) + { + aCallback->ReadComplete(error, 0); + } + END + return (error == KErrNone); +} + + +bool QNearFieldTagImplCommon::DoSetNdefMessages(const QList<QNdefMessage> &messages, MNearFieldNdefOperationCallback * const aCallback) +{ + BEGIN + int error = KErrGeneral; + CNearFieldNdefTarget * ndefTarget = mTag->CastToNdefTarget(); + + if (ndefTarget) + { + ndefTarget->SetNdefOperationCallback(aCallback); + if (ndefTarget) + { + mInputMessageList.ResetAndDestroy(); + TRAP( error, + for (int i = 0; i < messages.count(); ++i) + { + mInputMessageList.Append(QNFCNdefUtility::QNdefMsg2CNdefMsgL(messages.at(i))); + } + ) + + if (error == KErrNone) + { + ndefTarget->setNdefMessages(mInputMessageList); + } + } + } + if (error != KErrNone) + { + aCallback->WriteComplete(error); + } + END + return (error == KErrNone); +} + + +bool QNearFieldTagImplCommon::DoHasNdefMessages() +{ + BEGIN + + LOG("use async request to check ndef message"); + NearFieldTagNdefRequest * readNdefRequest = new NearFieldTagNdefRequest(*this); + + QNearFieldTarget::RequestId requestId; + + if (readNdefRequest) + { + readNdefRequest->SetRequestId(requestId); + readNdefRequest->SetNdefRequestType(NearFieldTagNdefRequest::EReadRequest); + + if (!_isProcessingRequest()) + { + // issue the request + LOG("the request will be issued at once"); + mCurrentRequest = readNdefRequest; + + mPendingRequestList.append(readNdefRequest); + readNdefRequest->IssueRequest(); + } + else + { + mPendingRequestList.append(readNdefRequest); + } + + readNdefRequest->WaitRequestCompletedNoSignal(5000); + if (mMessageList.Count() == 0) + { + END + return false; + } + else + { + mMessageList.Reset(); + END + return true; + } + } + else + { + LOG("unexpect error to create async request"); + END + return false; + } +} + + +bool QNearFieldTagImplCommon::DoSendCommand(const QByteArray& command, MNearFieldTagOperationCallback * const aCallback, bool deferred) +{ + BEGIN + int error = (mResponse.MaxLength() == 0) ? KErrGeneral : KErrNone; + + if ((KErrNone == error) && (command.count() > 0)) + { + CNearFieldTag * tag = mTag->CastToTag(); + + if (tag) + { + tag->SetTagOperationCallback(aCallback); + TPtrC8 cmd = QNFCNdefUtility::QByteArray2TPtrC8(command); + mResponse.Zero(); + error = tag->RawModeAccess(cmd, mResponse, mTimeout); + } + else + { + error = KErrGeneral; + } + } + else + { + if (deferred) + { + aCallback->CommandComplete(error); + } + } + END + return (error == KErrNone); +} + + +bool QNearFieldTagImplCommon::IssueNextRequest(QNearFieldTarget::RequestId aId) +{ + BEGIN + // find the request after current request + int index = mPendingRequestList.indexOf(mCurrentRequest); + LOG("index = "<<index); + if ((index < 0) || (index == mPendingRequestList.count() - 1)) + { + // no next request + mCurrentRequest = 0; + END + return false; + } + else + { + if (aId == mCurrentRequest->RequestID()) + { + mCurrentRequest = mPendingRequestList.at(index + 1); + mCurrentRequest->IssueRequest(); + } + else + { + LOG("re-entry happened"); + } + + END + return true; + } +} + + +void QNearFieldTagImplCommon::RemoveRequestFromQueue(QNearFieldTarget::RequestId aId) +{ + BEGIN + for(int i = 0; i < mPendingRequestList.count(); ++i) + { + MNearFieldTagAsyncRequest * request = mPendingRequestList.at(i); + if (request->RequestID() == aId) + { + LOG("remove request id"); + mPendingRequestList.removeAt(i); + break; + } + } + END +} + + +QNearFieldTarget::RequestId QNearFieldTagImplCommon::AllocateRequestId() +{ + BEGIN + QNearFieldTarget::RequestIdPrivate * p = new QNearFieldTarget::RequestIdPrivate; + QNearFieldTarget::RequestId id(p); + END + return id; +} + +QNearFieldTagImplCommon::QNearFieldTagImplCommon(CNearFieldNdefTarget *tag) : mTag(tag) +{ + mCurrentRequest = 0; +} + + +QNearFieldTagImplCommon::~QNearFieldTagImplCommon() +{ + BEGIN + LOG("pending request count is "<<mPendingRequestList.count()); + for (int i = 0; i < mPendingRequestList.count(); ++i) + { + delete mPendingRequestList[i]; + } + + mPendingRequestList.clear(); + mCurrentRequest = 0; + + delete mTag; + + mMessageList.Close(); + mInputMessageList.ResetAndDestroy(); + mInputMessageList.Close(); + + mResponse.Close(); + END +} + + +bool QNearFieldTagImplCommon::_hasNdefMessage() +{ + return DoHasNdefMessages(); +} + + +QNearFieldTarget::RequestId QNearFieldTagImplCommon::_ndefMessages() +{ + BEGIN + NearFieldTagNdefRequest * readNdefRequest = new NearFieldTagNdefRequest(*this); + QNearFieldTarget::RequestId requestId = AllocateRequestId(); + + if (readNdefRequest) + { + LOG("read ndef request created"); + readNdefRequest->SetRequestId(requestId); + readNdefRequest->SetNdefRequestType(NearFieldTagNdefRequest::EReadRequest); + + if (!_isProcessingRequest()) + { + LOG("the request will be issued at once"); + // issue the request + mCurrentRequest = readNdefRequest; + mPendingRequestList.append(readNdefRequest); + readNdefRequest->IssueRequest(); + } + else + { + mPendingRequestList.append(readNdefRequest); + } + } + else + { + EmitError(KErrNoMemory, requestId); + } + END + + return requestId; +} + + +QNearFieldTarget::RequestId QNearFieldTagImplCommon::_setNdefMessages(const QList<QNdefMessage> &messages) +{ + BEGIN + NearFieldTagNdefRequest * writeNdefRequest = new NearFieldTagNdefRequest(*this); + QNearFieldTarget::RequestId requestId = AllocateRequestId(); + + if (writeNdefRequest) + { + LOG("write ndef request created"); + writeNdefRequest->SetRequestId(requestId); + writeNdefRequest->SetNdefRequestType(NearFieldTagNdefRequest::EWriteRequest); + writeNdefRequest->SetInputNdefMessages(messages); + + if (!_isProcessingRequest()) + { + // issue the request + LOG("the request will be issued at once"); + mCurrentRequest = writeNdefRequest; + mPendingRequestList.append(writeNdefRequest); + writeNdefRequest->IssueRequest(); + } + else + { + mPendingRequestList.append(writeNdefRequest); + } + } + else + { + EmitError(KErrNoMemory, requestId); + } + END + + return requestId; +} + + +QNearFieldTarget::RequestId QNearFieldTagImplCommon::_sendCommand(const QByteArray &command) +{ + BEGIN + NearFieldTagCommandRequest * rawCommandRequest = new NearFieldTagCommandRequest(*this); + QNearFieldTarget::RequestId requestId = AllocateRequestId(); + + if (rawCommandRequest) + { + LOG("send command request created"); + rawCommandRequest->SetInputCommand(command); + rawCommandRequest->SetRequestId(requestId); + rawCommandRequest->SetResponseBuffer(&mResponse); + + if (!_isProcessingRequest()) + { + // issue the request + LOG("the request will be issued at once"); + mCurrentRequest = rawCommandRequest; + + if (rawCommandRequest->IssueRequestNoDefer()) + { + mPendingRequestList.append(rawCommandRequest); + } + else + { + END + return QNearFieldTarget::RequestId(); + } + } + else + { + mPendingRequestList.append(rawCommandRequest); + } + } + else + { + END + return QNearFieldTarget::RequestId(); + } + END + return requestId; +} + + +QNearFieldTarget::RequestId QNearFieldTagImplCommon::_sendCommands(const QList<QByteArray> &commands) +{ + BEGIN + NearFieldTagCommandsRequest * rawCommandsRequest = new NearFieldTagCommandsRequest(*this); + QNearFieldTarget::RequestId requestId = AllocateRequestId(); + + if (rawCommandsRequest) + { + LOG("send commands request created"); + rawCommandsRequest->SetInputCommands(commands); + rawCommandsRequest->SetRequestId(requestId); + rawCommandsRequest->SetResponseBuffer(&mResponse); + + if (!_isProcessingRequest()) + { + // issue the request + LOG("the request will be issued at once"); + mCurrentRequest = rawCommandsRequest; + + if (rawCommandsRequest->IssueRequestNoDefer()) + { + mPendingRequestList.append(rawCommandsRequest); + } + else + { + END + return QNearFieldTarget::RequestId(); + } + } + else + { + mPendingRequestList.append(rawCommandsRequest); + } + } + else + { + END + return QNearFieldTarget::RequestId(); + } + END + return requestId; +} + + +QByteArray QNearFieldTagImplCommon::_uid() const +{ + BEGIN + if (mUid.isEmpty()) + { + mUid = QNFCNdefUtility::TDesC2QByteArray(mTag->Uid()); + LOG(mUid); + } + END + return mUid; +} + + +bool QNearFieldTagImplCommon::_isProcessingRequest() const +{ + BEGIN + bool result = mPendingRequestList.count() > 0; + LOG(result); + END + return result; + +} + + +bool QNearFieldTagImplCommon::_waitForRequestCompleted(const QNearFieldTarget::RequestId &id, int msecs) +{ + BEGIN + int index = -1; + for (int i = 0; i < mPendingRequestList.count(); ++i) + { + if (id == mPendingRequestList.at(i)->RequestID()) + { + index = i; + break; + } + } + + if (index < 0) + { + // request ID is not in pending list. So maybe it is already completed. + END + return false; + } + + MNearFieldTagAsyncRequest * request = mPendingRequestList.at(index); + LOG("get the request from pending request list"); + END + return request->WaitRequestCompleted(msecs); +} + + +bool QNearFieldTagImplCommon::_waitForRequestCompletedNoSignal(const QNearFieldTarget::RequestId &id, int msecs) +{ + BEGIN + int index = -1; + for (int i = 0; i < mPendingRequestList.count(); ++i) + { + if (id == mPendingRequestList.at(i)->RequestID()) + { + index = i; + break; + } + } + + if (index < 0) + { + // request ID is not in pending list. So either it may not be issued, or has already completed + END + return false; + } + + MNearFieldTagAsyncRequest * request = mPendingRequestList.at(index); + LOG("get the request from pending request list"); + END + return (KErrNone == request->WaitRequestCompletedNoSignal(msecs)); +} + +void QNearFieldTagImplCommon::DoCancelSendCommand() +{ + BEGIN + CNearFieldTag * tag = mTag->CastToTag(); + if (tag) + { + LOG("Cancel raw command operation"); + tag->SetTagOperationCallback(0); + tag->Cancel(); + } + END +} + + +void QNearFieldTagImplCommon::DoCancelNdefAccess() +{ + BEGIN + CNearFieldNdefTarget * ndefTarget = mTag->CastToNdefTarget(); + if(ndefTarget) + { + LOG("Cancel ndef operation"); + ndefTarget->SetNdefOperationCallback(0); + ndefTarget->Cancel(); + } + END +} + + +QNearFieldTarget::Error QNearFieldTagImplCommon::SymbianError2QtError(int error) +{ + BEGIN + QNearFieldTarget::Error qtError = QNearFieldTarget::InvalidParametersError; + switch(error) + { + case KErrNone: + { + qtError = QNearFieldTarget::NoError; + break; + } + case KErrNotSupported: + { + qtError = QNearFieldTarget::UnsupportedError; + break; + } + case KErrTimedOut: + { + qtError = QNearFieldTarget::NoResponseError; + break; + } + case KErrAccessDenied: + case KErrEof: + case KErrServerTerminated: + { + if (mCurrentRequest) + { + if(mCurrentRequest->Type() == MNearFieldTagAsyncRequest::ENdefRequest) + { + NearFieldTagNdefRequest * req = static_cast<NearFieldTagNdefRequest *>(mCurrentRequest); + if (req->GetNdefRequestType() == NearFieldTagNdefRequest::EReadRequest) + { + qtError = QNearFieldTarget::NdefReadError; + } + else if (req->GetNdefRequestType() == NearFieldTagNdefRequest::EWriteRequest) + { + qtError = QNearFieldTarget::NdefWriteError; + } + } + } + break; + } + case KErrTooBig: + { + qtError = QNearFieldTarget::TargetOutOfRangeError; + break; + } + default: + { + break; + } + } + LOG(qtError); + END + return qtError; +} diff --git a/src/nfc/symbian/nearfieldtagimplcommon_symbian.h b/src/nfc/symbian/nearfieldtagimplcommon_symbian.h new file mode 100644 index 00000000..0d769863 --- /dev/null +++ b/src/nfc/symbian/nearfieldtagimplcommon_symbian.h @@ -0,0 +1,123 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef NEARFIELDTAGIMPLCOMMON_SYMBIAN_H +#define NEARFIELDTAGIMPLCOMMON_SYMBIAN_H + +#include <qnearfieldtarget.h> +#include <qnearfieldtarget_p.h> +#include "nearfieldtag_symbian.h" +#include "nearfieldndeftarget_symbian.h" +#include "nearfieldutility_symbian.h" +#include "nearfieldtagasyncrequest_symbian.h" + +#include "nearfieldtagoperationcallback_symbian.h" +#include "nearfieldtagndefoperationcallback_symbian.h" + +#include "nearfieldtagndefrequest_symbian.h" +#include "nearfieldtagcommandrequest_symbian.h" +#include "nearfieldtagcommandsrequest_symbian.h" + +class QNearFieldTagImplCommon +{ +public: + bool DoReadNdefMessages(MNearFieldNdefOperationCallback * const aCallback); + bool DoSetNdefMessages(const QList<QNdefMessage> &messages, MNearFieldNdefOperationCallback * const aCallback); + bool DoHasNdefMessages(); + bool DoSendCommand(const QByteArray& command, MNearFieldTagOperationCallback * const aCallback, bool deferred = true); + bool IssueNextRequest(QNearFieldTarget::RequestId aId); + void RemoveRequestFromQueue(QNearFieldTarget::RequestId aId); + QNearFieldTarget::RequestId AllocateRequestId(); + void DoCancelSendCommand(); + void DoCancelNdefAccess(); + QNearFieldTarget::Error SymbianError2QtError(int error); + + virtual void EmitNdefMessageRead(const QNdefMessage &message) = 0; + virtual void EmitNdefMessagesWritten() = 0; + virtual void EmitRequestCompleted(const QNearFieldTarget::RequestId &id) = 0; + virtual void EmitError(int error, const QNearFieldTarget::RequestId &id) = 0; + virtual void HandleResponse(const QNearFieldTarget::RequestId &id, const QByteArray &command, const QByteArray &response, bool emitRequestCompleted) = 0; + virtual void HandleResponse(const QNearFieldTarget::RequestId &id, const QVariantList& response, int error) = 0; + virtual QVariant decodeResponse(const QByteArray& command, const QByteArray& response) = 0; + +public: + QNearFieldTagImplCommon(CNearFieldNdefTarget *tag); + virtual ~QNearFieldTagImplCommon(); + +protected: + bool _hasNdefMessage(); + QNearFieldTarget::RequestId _ndefMessages(); + QNearFieldTarget::RequestId _setNdefMessages(const QList<QNdefMessage> &messages); + + void _setAccessMethods(const QNearFieldTarget::AccessMethods& accessMethods) + { + mAccessMethods = accessMethods; + } + + QNearFieldTarget::AccessMethods _accessMethods() const + { + return mAccessMethods; + } + + QNearFieldTarget::RequestId _sendCommand(const QByteArray &command); + QNearFieldTarget::RequestId _sendCommands(const QList<QByteArray> &command); + bool _waitForRequestCompleted(const QNearFieldTarget::RequestId &id, int msecs = 5000); + bool _waitForRequestCompletedNoSignal(const QNearFieldTarget::RequestId &id, int msecs = 5000); + + QByteArray _uid() const; + + bool _isProcessingRequest() const; + +protected: + CNearFieldNdefTarget * mTag; + QNearFieldTarget::AccessMethods mAccessMethods; + mutable QByteArray mUid; + RPointerArray<CNdefMessage> mMessageList; + RBuf8 mResponse; + + QList<MNearFieldTagAsyncRequest *> mPendingRequestList; + MNearFieldTagAsyncRequest * mCurrentRequest; + + TTimeIntervalMicroSeconds32 mTimeout; + RPointerArray<CNdefMessage> mInputMessageList; +}; + +#endif diff --git a/src/nfc/symbian/nearfieldtagndefoperationcallback_symbian.h b/src/nfc/symbian/nearfieldtagndefoperationcallback_symbian.h new file mode 100644 index 00000000..594d4396 --- /dev/null +++ b/src/nfc/symbian/nearfieldtagndefoperationcallback_symbian.h @@ -0,0 +1,54 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef NEARFIELDNDEFOPERATIONCALLBACK_H +#define NEARFIELDNDEFOPERATIONCALLBACK_H + +#include <e32cmn.h> +#include <ndefmessage.h> +class MNearFieldNdefOperationCallback + { +public: + virtual void ReadComplete(TInt aError, RPointerArray<CNdefMessage> * aMessages) = 0; + virtual void WriteComplete(TInt aError) = 0; + }; + +#endif diff --git a/src/nfc/symbian/nearfieldtagndefrequest_symbian.cpp b/src/nfc/symbian/nearfieldtagndefrequest_symbian.cpp new file mode 100644 index 00000000..5ac41b2c --- /dev/null +++ b/src/nfc/symbian/nearfieldtagndefrequest_symbian.cpp @@ -0,0 +1,171 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "nearfieldtagndefrequest_symbian.h" +#include "nearfieldutility_symbian.h" +#include "nearfieldtagimplcommon_symbian.h" +#include "debug.h" + +NearFieldTagNdefRequest::NearFieldTagNdefRequest(QNearFieldTagImplCommon& aOperator) : MNearFieldTagAsyncRequest(aOperator) +{ +} + +NearFieldTagNdefRequest::~NearFieldTagNdefRequest() +{ + BEGIN + if (iRequestIssued) + { + iOperator.DoCancelNdefAccess(); + } + END +} + +void NearFieldTagNdefRequest::IssueRequest() +{ + BEGIN + + iRequestIssued = ETrue; + LOG(iType); + switch(iType) + { + case EReadRequest: + { + iOperator.DoReadNdefMessages(this); + break; + } + case EWriteRequest: + { + iOperator.DoSetNdefMessages(iMessages, this); + break; + } + default: + { + iRequestIssued = EFalse; + break; + } + } + + END +} + +void NearFieldTagNdefRequest::ReadComplete(TInt aError, RPointerArray<CNdefMessage> * aMessage) +{ + BEGIN + LOG(aError); + iRequestIssued = EFalse; + TRAP_IGNORE( + if (aMessage != 0) + { + for(int i = 0; i < aMessage->Count(); ++i) + { + QNdefMessage message = QNFCNdefUtility::CNdefMsg2QNdefMsgL(*(*aMessage)[i]); + iReadMessages.append(message); + } + } + else + { + iReadMessages.clear(); + } + ) // TRAP end + ProcessResponse(aError); + END +} + +void NearFieldTagNdefRequest::WriteComplete(TInt aError) +{ + BEGIN + iRequestIssued = EFalse; + ProcessResponse(aError); + END +} + +void NearFieldTagNdefRequest::ProcessEmitSignal(TInt aError) +{ + BEGIN + LOG("error code is "<<aError<<" request type is "<<iType); + if (aError != KErrNone) + { + iOperator.EmitError(aError, iId); + } + else + { + if (EReadRequest == iType) + { + // since there is no error, iReadMessages can't be NULL. + + LOG("message count is "<<iReadMessages.count()); + for(int i = 0; i < iReadMessages.count(); ++i) + { + LOG("emit signal ndef message read"); + iOperator.EmitNdefMessageRead(iReadMessages.at(i)); + } + iOperator.EmitRequestCompleted(iId); + } + else if (EWriteRequest == iType) + { + iOperator.EmitNdefMessagesWritten(); + //iOperator.EmitRequestCompleted(iId); + } + } + END +} + +void NearFieldTagNdefRequest::ProcessTimeout() +{ + if (iWait) + { + if (iWait->IsStarted()) + { + if (iRequestIssued) + { + iOperator.DoCancelNdefAccess(); + iRequestIssued = EFalse; + } + ProcessResponse(KErrTimedOut); + } + } +} + +void NearFieldTagNdefRequest::HandleResponse(TInt /*aError*/) +{ + BEGIN + END +} diff --git a/src/nfc/symbian/nearfieldtagndefrequest_symbian.h b/src/nfc/symbian/nearfieldtagndefrequest_symbian.h new file mode 100644 index 00000000..f55829e5 --- /dev/null +++ b/src/nfc/symbian/nearfieldtagndefrequest_symbian.h @@ -0,0 +1,79 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +#ifndef NEARFIELDTAGNDEFREQUEST_SYMBIAN_H +#define NEARFIELDTAGNDEFREQUEST_SYMBIAN_H + +#include "nearfieldtagasyncrequest_symbian.h" +#include "nearfieldtagndefoperationcallback_symbian.h" + +class NearFieldTagNdefRequest : public MNearFieldTagAsyncRequest, + public MNearFieldNdefOperationCallback + { +public: + enum TNdefRequestType + { + EReadRequest, + EWriteRequest, + ECheckRequest + }; +public: + NearFieldTagNdefRequest(QNearFieldTagImplCommon& aOperator); + ~NearFieldTagNdefRequest(); + void IssueRequest(); + void ProcessEmitSignal(TInt aError); + void ProcessTimeout(); + void HandleResponse(TInt aError); + void SetNdefRequestType(TNdefRequestType aType) { iType = aType; } + void SetInputNdefMessages(QList<QNdefMessage> aMessages) { iMessages = aMessages; } + TNdefRequestType GetNdefRequestType() { return iType; } + TRequestType Type() { return ENdefRequest; } + +private: + void ReadComplete(TInt aError, RPointerArray<CNdefMessage> * aMessages); + void WriteComplete(TInt aError); + +private: + TNdefRequestType iType; + QList<QNdefMessage> iMessages; + + QList<QNdefMessage> iReadMessages; + }; +#endif diff --git a/src/nfc/symbian/nearfieldtagoperationcallback_symbian.h b/src/nfc/symbian/nearfieldtagoperationcallback_symbian.h new file mode 100644 index 00000000..f80da9c5 --- /dev/null +++ b/src/nfc/symbian/nearfieldtagoperationcallback_symbian.h @@ -0,0 +1,51 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef NEARFIELDTAGOPERATIONCALLBACK_H +#define NEARFIELDTAGOPERATIONCALLBACK_H + +class MNearFieldTagOperationCallback + { +public: + virtual void CommandComplete(TInt aError) = 0; + }; + +#endif diff --git a/src/nfc/symbian/nearfieldtargetfactory_symbian.cpp b/src/nfc/symbian/nearfieldtargetfactory_symbian.cpp new file mode 100644 index 00000000..03a032a9 --- /dev/null +++ b/src/nfc/symbian/nearfieldtargetfactory_symbian.cpp @@ -0,0 +1,160 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "nearfieldtargetfactory_symbian.h" +#include <nfcserver.h> +#include <nfctag.h> +#include <nfctype1connection.h> +#include <nfctype2connection.h> +#include <nfctype3connection.h> +#include <iso14443connection.h> +#include <mifareclassicconnection.h> +#include "qnearfieldtagtype1_symbian_p.h" +#include "qnearfieldtagtype2_symbian_p.h" +#include "qnearfieldtagtype3_symbian_p.h" +#include "qnearfieldtagtype4_symbian_p.h" +#include "qnearfieldtagmifare_symbian_p.h" +#include "qnearfieldllcpdevice_symbian_p.h" +/* + \class TNearFieldTargetFactory + \brief The TNearFieldTargetFactory class creates detected target instance according + to the input tag information + + \ingroup connectivity-nfc + \inmodule QtConnectivity + \since 5.0 +*/ + +/* + Create tag type instance according to the tag information in \a aNfcTag and assign + the \a aParent as target's parent. +*/ +template <typename CTAGCONNECTION, typename QTAGTYPE> +QNearFieldTarget * TNearFieldTargetFactory::CreateTagTypeL(MNfcTag * aNfcTag, RNfcServer& aNfcServer, QObject * aParent) +{ + BEGIN + // ownership of aNfcTag transferred. + CTAGCONNECTION * connection = CTAGCONNECTION::NewLC(aNfcServer); + CNearFieldTag * tagType = CNearFieldTag::NewLC(aNfcTag, aNfcServer); + tagType->SetConnection(connection); + QTAGTYPE * tag= new(ELeave)QTAGTYPE(WrapNdefAccessL(aNfcTag, aNfcServer, tagType), aParent); + // walk around, symbian discovery API can't know if tag has Ndef Connection mode when detected + tag->setAccessMethods(ConnectionMode2AccessMethods(aNfcTag)|QNearFieldTarget::NdefAccess); + CleanupStack::Pop(tagType); + CleanupStack::Pop(connection); + END + return tag; +} + +/* + Create target instance according to the tag information in \a aNfcTag and assign + the \a aParent as target's parent. +*/ + +QNearFieldTarget * TNearFieldTargetFactory::CreateTargetL(MNfcTag * aNfcTag, RNfcServer& aNfcServer, QObject * aParent) + { + BEGIN + QNearFieldTarget * target = 0; + if (!aNfcTag) + { + LOG("llcp device created"); + target = new (ELeave)QNearFieldLlcpDeviceSymbian(aNfcServer, aParent); + } + else if(aNfcTag->HasConnectionMode(TNfcConnectionInfo::ENfcType1)) + { + LOG("tag type 1 created"); + target = CreateTagTypeL<CNfcType1Connection, QNearFieldTagType1Symbian>(aNfcTag, aNfcServer, aParent); + } + else if (aNfcTag->HasConnectionMode(TNfcConnectionInfo::ENfcType2)) + { + LOG("tag type 2 created"); + target = CreateTagTypeL<CNfcType2Connection, QNearFieldTagType2Symbian>(aNfcTag, aNfcServer, aParent); + } + else if (aNfcTag->HasConnectionMode(TNfcConnectionInfo::ENfcType3)) + { + LOG("tag type 3 created"); + target = CreateTagTypeL<CNfcType3Connection, QNearFieldTagType3Symbian>(aNfcTag, aNfcServer, aParent); + } + else if (aNfcTag->HasConnectionMode(TNfcConnectionInfo::ENfc14443P4)) + { + LOG("tag type 4 created"); + target = CreateTagTypeL<CIso14443Connection, QNearFieldTagType4Symbian>(aNfcTag, aNfcServer, aParent); + } + else if (aNfcTag->HasConnectionMode(TNfcConnectionInfo::ENfcMifareStd)) + { + LOG("tag type mifare created"); + target = CreateTagTypeL<CMifareClassicConnection, QNearFieldTagMifareSymbian>(aNfcTag, aNfcServer, aParent); + } + END + return target; + } + +CNearFieldNdefTarget * TNearFieldTargetFactory::WrapNdefAccessL(MNfcTag * aNfcTag, RNfcServer& aNfcServer, CNearFieldTag * aTarget) + { + BEGIN + // walk around, symbian discovery API can't know if tag has Ndef Connection mode when detected + + LOG("Wrap NDEF Access to the tag"); + + CNearFieldNdefTarget * ndefTarget = CNearFieldNdefTarget::NewLC(aNfcTag, aNfcServer); + ndefTarget->SetRealTarget(aTarget); + CleanupStack::Pop(ndefTarget); + END + return ndefTarget; + } + +QNearFieldTarget::AccessMethods TNearFieldTargetFactory::ConnectionMode2AccessMethods(MNfcTag * aNfcTag) + { + BEGIN + QNearFieldTarget::AccessMethods accessMethod; + if (aNfcTag->HasConnectionMode(TNfcConnectionInfo::ENdefConnection)) + { + LOG("the tag has NDefConnection"); + accessMethod |= QNearFieldTarget::NdefAccess; + } + if (!aNfcTag->HasConnectionMode(TNfcConnectionInfo::ENfcUnknownConnectionMode)) + { + LOG("the tag has tag specified access"); + accessMethod |= QNearFieldTarget::TagTypeSpecificAccess; + } + END + return accessMethod; + } diff --git a/src/nfc/symbian/nearfieldtargetfactory_symbian.h b/src/nfc/symbian/nearfieldtargetfactory_symbian.h new file mode 100644 index 00000000..2795d9c7 --- /dev/null +++ b/src/nfc/symbian/nearfieldtargetfactory_symbian.h @@ -0,0 +1,66 @@ +/**************************************************************************** + ** + ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). + ** All rights reserved. + ** Contact: Nokia Corporation (qt-info@nokia.com) + ** + ** This file is part of the Qt Mobility Components. + ** + ** $QT_BEGIN_LICENSE:LGPL$ + ** GNU Lesser General Public License Usage + ** This file may be used under the terms of the GNU Lesser General Public + ** License version 2.1 as published by the Free Software Foundation and + ** appearing in the file LICENSE.LGPL included in the packaging of this + ** file. Please review the following information to ensure the GNU Lesser + ** General Public License version 2.1 requirements will be met: + ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. + ** + ** In addition, as a special exception, Nokia gives you certain additional + ** rights. These rights are described in the Nokia Qt LGPL Exception + ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. + ** + ** GNU General Public License Usage + ** Alternatively, this file may be used under the terms of the GNU General + ** Public License version 3.0 as published by the Free Software Foundation + ** and appearing in the file LICENSE.GPL included in the packaging of this + ** file. Please review the following information to ensure the GNU General + ** Public License version 3.0 requirements will be met: + ** http://www.gnu.org/copyleft/gpl.html. + ** + ** Other Usage + ** Alternatively, this file may be used in accordance with the terms and + ** conditions contained in a signed written agreement between you and Nokia. + ** + ** + ** + ** + ** + ** $QT_END_LICENSE$ + ** + ****************************************************************************/ + +#ifndef NEARFIELDTARGETFACTORY_H_ +#define NEARFIELDTARGETFACTORY_H_ + +#include <qnearfieldtarget.h> +#include "nearfieldndeftarget_symbian.h" +#include "nearfieldtag_symbian.h" +#include "debug.h" + +class MNfcTag; +class RNfcServer; + +class TNearFieldTargetFactory + { +public: + static QNearFieldTarget * CreateTargetL(MNfcTag * aNfcTag, RNfcServer& aNfcServer, QObject * aParent); +private: + static CNearFieldNdefTarget * WrapNdefAccessL(MNfcTag * aNfcTag, RNfcServer& aNfcServer, CNearFieldTag * aTarget); + static QNearFieldTarget::AccessMethods ConnectionMode2AccessMethods(MNfcTag * aNfcTag); + + template <typename CTAGCONNECTION, typename QTAGTYPE> + static QNearFieldTarget * CreateTagTypeL(MNfcTag * aNfcTag, RNfcServer& aNfcServer, QObject * aParent); + }; + + +#endif /* NEARFIELDTARGETFACTORY_H */ diff --git a/src/nfc/symbian/nearfieldutility_symbian.cpp b/src/nfc/symbian/nearfieldutility_symbian.cpp new file mode 100644 index 00000000..44a0554d --- /dev/null +++ b/src/nfc/symbian/nearfieldutility_symbian.cpp @@ -0,0 +1,178 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +#include <ndefmessage.h> +#include <QtCore/QList> +#include <e32base.h> +#include "../qndefmessage.h" +#include "nearfieldutility_symbian.h" +#include "debug.h" + +CNdefMessage* QNFCNdefUtility::QNdefMsg2CNdefMsgL( const QNdefMessage& msg ) + { + QByteArray payload = msg.toByteArray(); + CNdefMessage* cmsg = CNdefMessage::NewL(); + TPtrC8 rawData(reinterpret_cast<const TUint8*>(payload.constData()), payload.size()); + cmsg->ImportRawDataL(rawData, 0); + return cmsg; + } + + +QNdefMessage QNFCNdefUtility::CNdefMsg2QNdefMsgL( const CNdefMessage& msg ) + { + BEGIN + QNdefMessage result; + LOG("CNdefMessage size is "<<msg.SizeL()); + HBufC8* newBuf = HBufC8::NewL(msg.SizeL()); + RBuf8 buf; + buf.Assign(newBuf); + buf.CleanupClosePushL(); + LOG("export msg to raw data"); + msg.ExportRawDataL(buf,0); + LOG("import raw data to msg"); + QByteArray qtArray; + qtArray.append(reinterpret_cast<const char*>(newBuf->Ptr()),newBuf->Size()); + result = QNdefMessage::fromByteArray(qtArray); + CleanupStack::PopAndDestroy(&buf); + END + return result; + } + +TPtrC8 QNFCNdefUtility::QByteArray2TPtrC8(const QByteArray& qbytearray) + { + TPtrC8 ptr(reinterpret_cast<const TUint8*>(qbytearray.constData()), qbytearray.size()); + return ptr; + } + +QByteArray QNFCNdefUtility::TDesC2QByteArray( const TDesC8& des) + { + QByteArray result; + for(int i = 0; i < des.Length(); ++i) + { + result.append(des[i]); + } + return result; + } + + +HBufC8* QNFCNdefUtility::QString2HBufC8L(const QString& qstring) + { + TPtrC wide(static_cast<const TUint16*>(qstring.utf16()),qstring.length()); + HBufC8* newBuf = HBufC8::NewL(wide.Length()); + TPtr8 des = newBuf->Des(); + des.Copy(wide); + return newBuf; + } + +QString QNFCNdefUtility::TDesC82QStringL(const TDesC8& aDescriptor) + { + HBufC* newBuf = NULL; + QT_TRAP_THROWING(newBuf = HBufC::NewL(aDescriptor.Length())); + TPtr des = newBuf->Des(); + des.Copy(aDescriptor); + QString ret = QString::fromUtf16(newBuf->Ptr(),newBuf->Length()); + delete newBuf; + return ret; + } + +// timer implementation +CLlcpTimer* CLlcpTimer::NewL(CActiveSchedulerWait & aWait) + { + BEGIN + CLlcpTimer* self = new (ELeave) CLlcpTimer(aWait); + CleanupStack::PushL(self); + self->ConstructL(); + CleanupStack::Pop(self); + END + return self; + } + +/** +Destructor. +*/ +CLlcpTimer::~CLlcpTimer() + { + BEGIN + Cancel(); + END + } + +/** +Starts the shutdown timer. +*/ +void CLlcpTimer::Start(TInt aMSecs) + { + BEGIN + const TUint KDelay = (1000 * aMSecs); + After(KDelay); + END + } + +void CLlcpTimer::RunL() + { + BEGIN + if (iWait.IsStarted()) + { + iWait.AsyncStop(); + } + END + } + +/** +Constructor +*/ +CLlcpTimer::CLlcpTimer(CActiveSchedulerWait & aWait) : + CTimer(EPriorityNormal), + iWait(aWait) + { + } + +/** +Second phase constructor. +*/ +void CLlcpTimer::ConstructL() + { + BEGIN + CTimer::ConstructL(); + CActiveScheduler::Add(this); + END + } + + diff --git a/src/nfc/symbian/nearfieldutility_symbian.h b/src/nfc/symbian/nearfieldutility_symbian.h new file mode 100644 index 00000000..de526f03 --- /dev/null +++ b/src/nfc/symbian/nearfieldutility_symbian.h @@ -0,0 +1,92 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QNFCNDEFUTILITY_SYMBIAN_H_ +#define QNFCNDEFUTILITY_SYMBIAN_H_ +#include <qndefmessage.h> +#include <e32base.h> + +class CNdefMessage; + +class CLlcpTimer : public CTimer + { +public: + + static CLlcpTimer* NewL(CActiveSchedulerWait & aWait); + virtual ~CLlcpTimer(); + + void Start(TInt aMSecs); + +private: // From CTimer + + void RunL(); + +private: + + CLlcpTimer(CActiveSchedulerWait & aWait); + void ConstructL(); + +private: + + CActiveSchedulerWait& iWait; //not own + }; + +class QNdefMessage; +class QNFCNdefUtility +{ +public: + + /** + * Maps between CNdefMessage and QNdefMessage + * + */ + static CNdefMessage* QNdefMsg2CNdefMsgL( const QNdefMessage& msg ); + static QNdefMessage CNdefMsg2QNdefMsgL( const CNdefMessage& msg ); + + static TPtrC8 QByteArray2TPtrC8(const QByteArray& qbytearray); + static QByteArray TDesC2QByteArray( const TDesC8& des); + + static HBufC8* QString2HBufC8L(const QString& qstring); + static QString TDesC82QStringL(const TDesC8&); + +}; + +#endif /* QNFCNDEFUTILITY_SYMBIAN_H_ */ diff --git a/src/nfc/targetemulator.cpp b/src/nfc/targetemulator.cpp new file mode 100644 index 00000000..7d77aa17 --- /dev/null +++ b/src/nfc/targetemulator.cpp @@ -0,0 +1,382 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "targetemulator_p.h" + +#include <QtCore/QSettings> +#include <QtCore/QDateTime> + +#include <QtCore/QDebug> + +// Implementation of qNfcChecksum +#include "checksum_p.h" + +TagBase::TagBase() +: lastAccess(0) +{ +} + +TagBase::~TagBase() +{ +} + +static inline quint8 blockByteToAddress(quint8 block, quint8 byte) +{ + return ((block & 0x0f) << 3) | (byte & 0x07); +} + +NfcTagType1::NfcTagType1() +: hr0(0x11), hr1(0x00), memory(120, '\0') +{ + // Locked blocks + memory[(0x0e << 3) | 0x00] = 0x01; + memory[(0x0e << 3) | 0x01] = 0x60; +} + +void NfcTagType1::load(QSettings *settings) +{ + settings->beginGroup(QLatin1String("TagType1")); + + hr0 = settings->value(QLatin1String("HR0"), 0x11).toUInt(); + + if (!(hr0 & 0x10)) { + settings->endGroup(); + return; + } + + hr1 = settings->value(QLatin1String("HR1"), 0x00).toUInt(); + + memory = settings->value(QLatin1String("Data")).toByteArray(); + + //quint8 nmn = memory.at(8); + + quint8 vno = memory.at(9); + if (vno != 0x10) + qWarning("Only NFC TagType1 v1.0 behavior is supported."); + + quint8 tms = memory.at(10); + if (memory.length() != 8 * (tms + 1)) + qWarning("Static memory size does not match TMS value."); + + quint8 rwa = memory.at(11); + switch (rwa >> 4) { + case 0: + // Unrestricted read access tag + break; + default: + // tag with unknown read attributes + ; + } + + switch (rwa & 0x0f) { + case 0: + // Unrestricted write access tag + break; + case 0x0f: + // Read only tag + break; + default: + // tag with unknown write attributes + ; + } + + //quint16 lock = (quint8(memory[blockByteToAddress(0x0e, 1)]) << 8) | + // quint8(memory[blockByteToAddress(0x0e, 0)]); + + settings->endGroup(); +} + +QByteArray NfcTagType1::uid() const +{ + lastAccess = QDateTime::currentMSecsSinceEpoch(); + + return memory.left(7); +} + +quint8 NfcTagType1::readData(quint8 block, quint8 byte) +{ + return memory.at((block << 3) | byte); +} + +QByteArray NfcTagType1::processCommand(const QByteArray &command) +{ + lastAccess = QDateTime::currentMSecsSinceEpoch(); + + QByteArray response; + + bool tagType1 = (hr0 & 0xf0) == 0x10; + bool dynamic = (hr0 & 0x0f) != 0x01; + + if (command.length() == 9) { + // static memory model command + quint8 opcode = command.at(0); + quint8 address = command.at(1); + quint8 data = command.at(2); + QByteArray uid = command.mid(3, 4); + + // check checksum + if (qNfcChecksum(command.constData(), command.length()) != 0) + return QByteArray(); + + // check UID + if (uid != memory.left(4)) + return QByteArray(); + + switch (opcode) { + case 0x00: // RALL + response.append(hr0); + response.append(hr1); + response.append(memory.left(120)); + break; + case 0x01: // READ + response.append(address); + if (address & 0x80) + response.append(char(0x00)); + else + response.append(memory.at(address)); + break; + case 0x53: { // WRITE-E + quint8 block = address >> 3; + if (block == 0x00 || block == 0x0d || block == 0x0e) // locked blocks + break; + + quint16 lock = (readData(0x0e, 0x01) << 8) | readData(0x0e, 0x00); + if ((0x01 << block) & lock) // locked blocks + break; + + // FIXME: Test dynamic lock bytes + + memory[address] = data; + + response.append(address); + response.append(data); + break; + } + case 0x1a: { // WRITE-NE + quint8 block = address >> 3; + if (block == 0x00 || block == 0x0d) // locked blocks + break; + + quint16 lock = (readData(0x0e, 0x01) << 8) | readData(0x0e, 0x00); + if ((0x01 << block) & lock) // locked blocks + break; + + + // FIXME: Test dynamic lock bytes + + memory[address] = memory.at(address) | data; + + response.append(address); + response.append(memory.at(address)); + break; + } + case 0x78: // RID + response.append(hr0); + response.append(hr1); + response.append(memory.left(4)); + break; + } + } else if (tagType1 && dynamic && command.length() == 16) { + // dynamic memory model command + quint8 opcode = command.at(0); + quint8 address = command.at(1); + QByteArray data = command.mid(2, 8); + QByteArray uid = command.mid(10, 4); + + // check checksum + if (qNfcChecksum(command.constData(), command.length()) != 0) + return QByteArray(); + + // check UID + if (uid != memory.left(4)) + return QByteArray(); + + switch (opcode) { + case 0x10: // RSEG + response.append(address); + response.append(memory.mid(128 * (address >> 4), 128)); + break; + case 0x02: // READ8 + response.append(address); + response.append(memory.mid(8 * address, 8)); + break; + case 0x54: { // WRITE-E8 + // locked blocks + if (address == 0x00 || address == 0x0d || address == 0x0e || address == 0x0f) + break; + + quint16 lock = (readData(0x0e, 0x01) << 8) | readData(0x0e, 0x00); + if (address <= 0x0e && ((0x01 << address) & lock)) // locked blocks + break; + + // FIXME: Test dynamic lock bytes + + memory.replace(address * 8, 8, data); + + response.append(address); + response.append(memory.mid(address * 8, 8)); + break; + } + case 0x1b: // WRITE-NE8 + // locked blocks + if (address == 0x00 || address == 0x0d || address == 0x0e || address == 0x0f) + break; + + quint16 lock = (readData(0x0e, 0x01) << 8) | readData(0x0e, 0x00); + if (address <= 0x0e && ((0x01 << address) & lock)) // locked blocks + break; + + // FIXME: Test dynamic lock bytes + + for (int i = 0; i < 8; ++i) + memory[address * 8 + i] = memory.at(address * 8 + i) | data.at(i); + + response.append(address); + response.append(memory.mid(address * 8, 8)); + break; + } + } + + if (!response.isEmpty()) { + quint16 crc = qNfcChecksum(response.constData(), response.length()); + response.append(quint8(crc & 0xff)); + response.append(quint8(crc >> 8)); + } + + return response; +} + + +NfcTagType2::NfcTagType2() +: memory(64, 0x00), currentSector(0), expectPacket2(false) +{ +} + +void NfcTagType2::load(QSettings *settings) +{ + settings->beginGroup(QLatin1String("TagType2")); + + memory = settings->value(QLatin1String("Data")).toByteArray(); + + settings->endGroup(); +} + +QByteArray NfcTagType2::uid() const +{ + lastAccess = QDateTime::currentMSecsSinceEpoch(); + + return memory.left(3) + memory.mid(4, 4); +} + +#define NACK QByteArray("\x05") +#define ACK QByteArray("\x0a") + +QByteArray NfcTagType2::processCommand(const QByteArray &command) +{ + lastAccess = QDateTime::currentMSecsSinceEpoch(); + + QByteArray response; + + // check checksum + if (qNfcChecksum(command.constData(), command.length()) != 0) + return QByteArray(); + + if (expectPacket2) { + expectPacket2 = false; + quint8 sector = command.at(0); + if (sector * 1024 > memory.length()) + return NACK; + else { + currentSector = sector; + return QByteArray(); + } + } + + quint8 opcode = command.at(0); + + switch (opcode) { + case 0x30: { // READ BLOCK + quint8 block = command.at(1); + int absoluteBlock = currentSector * 256 + block; + + response.append(memory.mid(absoluteBlock * 4, 16)); + if (response.length() != 16) + response.append(QByteArray(16 - response.length(), '\0')); + + break; + } + case 0xa2: { // WRITE BLOCK + quint8 block = command.at(1); + int absoluteBlock = currentSector * 256 + block; + + // locked blocks + if (absoluteBlock == 0 || absoluteBlock == 1) + return NACK; + + const QByteArray data = command.mid(2, 4); + + memory.replace(absoluteBlock * 4, 4, data); + + return ACK; + } + case 0xc2: // SECTOR SELECT - Packet 1 + if (memory.length() > 1024) { + expectPacket2 = true; + return ACK; + } + + return NACK; + default: + qDebug() << "Unknown opcode for Tag Type 2" << hex << opcode; + qDebug() << "command:" << command.toHex(); + + return NACK; + ; + } + + if (!response.isEmpty()) { + quint16 crc = qNfcChecksum(response.constData(), response.length()); + response.append(quint8(crc & 0xff)); + response.append(quint8(crc >> 8)); + } + + return response; +} diff --git a/src/nfc/targetemulator_p.h b/src/nfc/targetemulator_p.h new file mode 100644 index 00000000..a19dd17d --- /dev/null +++ b/src/nfc/targetemulator_p.h @@ -0,0 +1,107 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef TARGETEMULATOR_P_H +#define TARGETEMULATOR_P_H + +#include <QtCore/QtGlobal> +#include <QtCore/QByteArray> + +QT_FORWARD_DECLARE_CLASS(QSettings) + +class TagBase +{ +public: + TagBase(); + ~TagBase(); + + virtual void load(QSettings *settings) = 0; + + virtual QByteArray processCommand(const QByteArray &command) = 0; + + virtual QByteArray uid() const = 0; + + qint64 lastAccessTime() const { return lastAccess; } + +protected: + mutable qint64 lastAccess; +}; + +class NfcTagType1 : public TagBase +{ +public: + NfcTagType1(); + ~NfcTagType1(); + + void load(QSettings *settings); + + QByteArray processCommand(const QByteArray &command); + + QByteArray uid() const; + +private: + quint8 readData(quint8 block, quint8 byte); + + quint8 hr0; + quint8 hr1; + + QByteArray memory; +}; + +class NfcTagType2 : public TagBase +{ +public: + NfcTagType2(); + ~NfcTagType2(); + + void load(QSettings *settings); + + QByteArray processCommand(const QByteArray &command); + + QByteArray uid() const; + +private: + QByteArray memory; + quint8 currentSector; + bool expectPacket2; +}; + +#endif // TARGETEMULATOR_P_H |