/**************************************************************************** ** ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). ** All rights reserved. ** Contact: http://www.qt-project.org/ ** ** This file is part of the QtNfc module of the Qt Toolkit. ** ** $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 #include "qnearfieldtagtype3_symbian_p.h" #include #include #include QTNFC_BEGIN_NAMESPACE /* 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 ["< >& data) { QList mapKeys = data.keys(); for(int i = 0; i < mapKeys.count(); ++i) { LOG("cmd Map key "<& data) { QList mapKeys = data.keys(); for(int i = 0; i < mapKeys.count(); ++i) { LOG("rsp Map key "< blockList; // first block blockList.append(0); // NDEF service quint16 serviceCode = 0x0B; QMap > serviceBlockList; serviceBlockList.insert(serviceCode, blockList); QNearFieldTarget::RequestId id = check(serviceBlockList); if (_waitForRequestCompletedNoSignal(id)) { QMap result = requestResponse(id).value >(); 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 &messages) { return _setNdefMessages(messages); } QNearFieldTarget::RequestId QNearFieldTagType3Symbian::sendCommand(const QByteArray &command) { return _sendCommand(command); } QNearFieldTarget::RequestId QNearFieldTagType3Symbian::sendCommands(const QList &commands) { return _sendCommands(commands); } #if 0 quint16 QNearFieldTagType3Symbian::systemCode() { return 0; } QList QNearFieldTagType3Symbian::services() { return QList(); } 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 > &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 > &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(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 > &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(&serviceCode), sizeof(quint16)); numberOfBlocks += serviceBlockList.value(serviceCode).count(); LOG("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(&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 > QNearFieldTagType3Symbian::cmd2ServiceBlockList(const QByteArray& cmd) { BEGIN QMap > 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 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(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(bytes); } if (result.contains(svcList.at(serviceCodeListOrder))) { result[svcList.at(serviceCodeListOrder)].append(blockNumber); } else { QList blocks; blocks.append(blockNumber); result.insert(svcList.at(serviceCodeListOrder), blocks); } } OutputCmdMap(result); END return result; } QMap QNearFieldTagType3Symbian::checkResponse2ServiceBlockList(const QMap > &serviceBlockList, const QByteArray& response) { BEGIN OutputCmdMap(serviceBlockList); QMap 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" QTNFC_END_NAMESPACE