nfcnppexample.cpp 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217
  1. /*
  2. * Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies).
  3. * All rights reserved.
  4. * This component and the accompanying materials are made available
  5. * under the terms of "Eclipse Public License v1.0"
  6. * which accompanies this distribution, and is available
  7. * at the URL "http://www.eclipse.org/legal/epl-v10.html".
  8. *
  9. * Initial Contributors:
  10. * Nokia Corporation - initial contribution.
  11. *
  12. * Contributors:
  13. *
  14. * Description: NfcNppExample.
  15. */
  16. #include "nfcnppexample.h"
  17. #include <QUrl>
  18. #include <qllcpserver.h>
  19. #include <qndefrecord.h>
  20. #include <qndefnfctextrecord.h>
  21. #include <qndefnfcurirecord.h>
  22. #include <qnearfieldmanager.h>
  23. // Constants
  24. const quint8 NPPVersion = 1;
  25. const quint8 NPPActionCode = 1;
  26. const QLatin1String NPPServiceName("com.android.npp");
  27. NfcNppExample::NfcNppExample(QObject *parent) :
  28. QObject(parent)
  29. {
  30. nfcManager = new QNearFieldManager(this);
  31. connect(nfcManager, SIGNAL(targetDetected(QNearFieldTarget*)),
  32. this, SLOT(handleTargetDetected(QNearFieldTarget*)));
  33. connect(nfcManager, SIGNAL(targetLost(QNearFieldTarget*)),
  34. this, SLOT(handleTargetLost(QNearFieldTarget*)));
  35. // Only detect other NFC devices. Leave the phone to handle NFC tags.
  36. nfcManager->setTargetAccessModes(QNearFieldManager::NdefReadTargetAccess | QNearFieldManager::NdefWriteTargetAccess);
  37. nfcManager->startTargetDetection(QNearFieldTarget::NfcForumDevice);
  38. nfcServer = new QLlcpServer(this);
  39. connect(nfcServer, SIGNAL(newConnection()), this, SLOT(handleNewConnection()));
  40. nfcServer->listen(NPPServiceName);
  41. nfcClientSocket = new QLlcpSocket(this);
  42. connect(nfcClientSocket, SIGNAL(stateChanged(QLlcpSocket::SocketState)), this, SLOT(handleSocketStateChanged(QLlcpSocket::SocketState)));
  43. // QueuedConnection is used to close the connection on the next event loop event.
  44. connect(this, SIGNAL(closeConnection()), this, SLOT(handleCloseConnection()), Qt::QueuedConnection);
  45. }
  46. NfcNppExample::~NfcNppExample()
  47. {
  48. // empty implementation.
  49. }
  50. void NfcNppExample::handleTargetDetected(QNearFieldTarget *target)
  51. {
  52. // Check if the target supports LLCP access
  53. QNearFieldTarget::AccessMethods accessMethods = target->accessMethods();
  54. if (accessMethods.testFlag(QNearFieldTarget::LlcpAccess)) {
  55. nfcClientSocket->connectToService(target, NPPServiceName);
  56. }
  57. }
  58. void NfcNppExample::handleTargetLost(QNearFieldTarget *target)
  59. {
  60. nfcClientSocket->disconnectFromService();
  61. target->deleteLater();
  62. }
  63. void NfcNppExample::handleNewConnection()
  64. {
  65. if (nfcServerSocket) {
  66. nfcServerSocket->deleteLater();
  67. }
  68. // The socket is a child of the server and will therefore be deleted automatically
  69. nfcServerSocket = nfcServer->nextPendingConnection();
  70. connect(nfcServerSocket, SIGNAL(readyRead()), this, SLOT(readMessage()));
  71. }
  72. void NfcNppExample::handleSocketStateChanged(QLlcpSocket::SocketState socketState)
  73. {
  74. switch ( socketState )
  75. {
  76. case QLlcpSocket::ConnectedState:
  77. // Connection opened.
  78. emit targetConnected();
  79. //Try to send the message.
  80. if (nfcClientSocket && nfcClientSocket->isOpen()) {
  81. nfcClientSocket->write(ndefMessage);
  82. emit closeConnection();
  83. }
  84. break;
  85. default:
  86. break;
  87. }
  88. }
  89. void NfcNppExample::readMessage()
  90. {
  91. QByteArray rawData = nfcServerSocket->readAll();
  92. QList<QNdefMessage> messages;
  93. messages = parseNppMessage(rawData);
  94. QNdefMessage message = messages[0];
  95. foreach (const QNdefRecord &record, message) {
  96. if (record.isRecordType<QNdefNfcUriRecord>()) {
  97. QNdefNfcUriRecord uriRecord(record);
  98. emit messageReceived(record.type(), uriRecord.uri().toString());
  99. } else if (record.isRecordType<QNdefNfcTextRecord>()) {
  100. QNdefNfcTextRecord textRecord(record);
  101. emit messageReceived(record.type(), textRecord.text());
  102. }
  103. }
  104. }
  105. void NfcNppExample::sendMessage(const QString &type, const QString &text)
  106. {
  107. // Buffers the message.
  108. QNdefMessage message;
  109. if (type.compare("U") == 0) {
  110. QNdefNfcUriRecord uriRecord;
  111. uriRecord.setUri(QUrl(text));
  112. message.append(uriRecord);
  113. } else {
  114. QNdefNfcTextRecord textRecord;
  115. textRecord.setText(text);
  116. message.append(textRecord);
  117. }
  118. QList<QNdefMessage> messageArray;
  119. messageArray.append(message);
  120. ndefMessage = createNppMessage(messageArray);
  121. }
  122. QList<QNdefMessage> NfcNppExample::parseNppMessage(const QByteArray &array) const
  123. {
  124. QList<QNdefMessage> messages;
  125. QByteArray::const_iterator i = array.begin();
  126. while (i < array.constEnd()) {
  127. quint8 version = *i;
  128. if (version != NPPVersion) {
  129. return messages;
  130. }
  131. quint32 messageCount = 0;
  132. messageCount = quint8(*(++i)) << 24;
  133. messageCount |= quint8(*(++i)) << 16;
  134. messageCount |= quint8(*(++i)) << 8;
  135. messageCount |= quint8(*(++i)) << 0;
  136. if (messageCount == 1) {
  137. quint8 actionCode = *(++i);
  138. quint32 ndefLength = quint8(*(++i)) << 24;
  139. ndefLength |= quint8(*(++i)) << 16;
  140. ndefLength |= quint8(*(++i)) << 8;
  141. ndefLength |= quint8(*(++i)) << 0;
  142. QByteArray ndef(++i, ndefLength);
  143. QNdefMessage message = QNdefMessage::fromByteArray(ndef);
  144. messages.append(message);
  145. i += ndefLength;
  146. }
  147. }
  148. return messages;
  149. }
  150. QByteArray NfcNppExample::createNppMessage(const QList<QNdefMessage> &messages) const
  151. {
  152. QByteArray message;
  153. if (messages.count() != 1) {
  154. return message;
  155. }
  156. message.append(NPPVersion);
  157. quint32 messageCount = messages.count();
  158. message.append(messageCount >> 24);
  159. message.append(messageCount >> 16);
  160. message.append(messageCount >> 8);
  161. message.append(messageCount);
  162. // Only supported action code is 0x01 and only one NDEF entry
  163. // with the action code 0x01 is allowed.
  164. message.append(NPPActionCode);
  165. QByteArray entry = messages[0].toByteArray();
  166. quint32 ndefLength = entry.length();
  167. message.append(ndefLength >> 24);
  168. message.append(ndefLength >> 16);
  169. message.append(ndefLength >> 8);
  170. message.append(ndefLength);
  171. message.append(entry);
  172. return message;
  173. }
  174. void NfcNppExample::handleCloseConnection()
  175. {
  176. // Disconnect the open connection.
  177. if (nfcClientSocket && nfcClientSocket->isOpen()) {
  178. nfcClientSocket->disconnectFromService();
  179. }
  180. }