diff --git a/libguh/coap/coap.cpp b/libguh/coap/coap.cpp index eb95c0ea..79b4c6db 100644 --- a/libguh/coap/coap.cpp +++ b/libguh/coap/coap.cpp @@ -62,6 +62,11 @@ This signal is emitted when a \a reply is finished. */ +/*! \fn void Coap::notificationReceived(const CoapObserveResource &resource, const int ¬ificationNumber, const QByteArray &payload); + This signal is emitted when a value of an observed \a resource changed. The \a notificationNumber specifies the the count of the notification + to keep the correct order. The value can be parsed from the \a payload. +*/ + #include "coap.h" #include "coappdu.h" #include "coapoption.h" @@ -216,6 +221,67 @@ CoapReply *Coap::deleteResource(const CoapRequest &request) return reply; } +/*! Enables notifications (observing) on the CoAP server for the resource specified in the + * given \a request. + * Returns a \l{CoapReply} to match the response with the request. */ +CoapReply *Coap::enableResourceNotifications(const CoapRequest &request) +{ + CoapReply *reply = new CoapReply(request, this); + reply->setRequestMethod(CoapPdu::Get); + reply->setObservation(true); + reply->setObservationEnable(true); + + connect(reply, &CoapReply::timeout, this, &Coap::onReplyTimeout); + connect(reply, &CoapReply::finished, this, &Coap::onReplyFinished); + + if (request.url().scheme() != "coap") { + reply->setError(CoapReply::InvalidUrlSchemeError); + reply->m_isFinished = true; + return reply; + } + + // check if there is a request running + if (m_reply == 0) { + m_reply = reply; + lookupHost(); + } else { + m_replyQueue.enqueue(reply); + } + + return reply; +} + +/*! Disables notifications (observing) on the CoAP server for the resource specified in the + * given \a request. + * Returns a \l{CoapReply} to match the response with the request. */ +CoapReply *Coap::disableNotifications(const CoapRequest &request) +{ + CoapReply *reply = new CoapReply(request, this); + reply->setRequestMethod(CoapPdu::Get); + reply->setMessageType(CoapPdu::Reset); + reply->setObservation(true); + reply->setObservationEnable(false); + + connect(reply, &CoapReply::timeout, this, &Coap::onReplyTimeout); + connect(reply, &CoapReply::finished, this, &Coap::onReplyFinished); + + if (request.url().scheme() != "coap") { + reply->setError(CoapReply::InvalidUrlSchemeError); + reply->m_isFinished = true; + return reply; + } + + // check if there is a request running + if (m_reply == 0) { + m_reply = reply; + lookupHost(); + } else { + m_replyQueue.enqueue(reply); + } + + return reply; +} + void Coap::lookupHost() { int lookupId = QHostInfo::lookupHost(m_reply->request().url().host(), this, SLOT(hostLookupFinished(QHostInfo))); @@ -230,21 +296,42 @@ void Coap::sendRequest(CoapReply *reply, const bool &lookedUp) pdu.createMessageId(); pdu.createToken(); + // Add the options in correct order + // Option number 3 if (lookedUp) pdu.addOption(CoapOption::UriHost, reply->request().url().host().toUtf8()); + if (reply->observation() && reply->requestMethod() == CoapPdu::Get) { + if (reply->observationEnable()) { + // Option number 6 + pdu.addOption(CoapOption::Observe, QByteArray::number(0)); + m_observeResources.insert(pdu.token(), CoapObserveResource(reply->request().url(), pdu.token())); + } else { + // if disable, we should use the sam token as the notifications + foreach (const CoapObserveResource &resource, m_observeResources.values()) { + if (resource.url() == reply->request().url()) { + pdu.setToken(resource.token()); + } + } + // Option number 6 + pdu.addOption(CoapOption::Observe, QByteArray::number(1)); + if (m_observeResources.contains(pdu.token())) + m_observeResources.remove(pdu.token()); + } + } + + // Option number 7 + if (reply->port() != 5683) + pdu.addOption(CoapOption::UriPort, QByteArray::number(reply->request().url().port())); + QStringList urlTokens = reply->request().url().path().split("/"); urlTokens.removeAll(QString()); + // Option number 11 foreach (const QString &token, urlTokens) pdu.addOption(CoapOption::UriPath, token.toUtf8()); - if (reply->request().url().hasQuery()) - pdu.addOption(CoapOption::UriQuery, reply->request().url().query().toUtf8()); - - if (reply->requestMethod() == CoapPdu::Get) - pdu.addOption(CoapOption::Block2, CoapPduBlock::createBlock(0)); - + // Option number 12 if (reply->requestMethod() == CoapPdu::Post || reply->requestMethod() == CoapPdu::Put) { pdu.addOption(CoapOption::ContentFormat, QByteArray(1, ((quint8)reply->request().contentType()))); @@ -257,6 +344,14 @@ void Coap::sendRequest(CoapReply *reply, const bool &lookedUp) } } + // Option number 15 + if (reply->request().url().hasQuery()) + pdu.addOption(CoapOption::UriQuery, reply->request().url().query().toUtf8()); + + // Option number 23 + if (reply->requestMethod() == CoapPdu::Get) + pdu.addOption(CoapOption::Block2, CoapPduBlock::createBlock(0)); + QByteArray pduData = pdu.pack(); reply->setRequestData(pduData); reply->setMessageId(pdu.messageId()); @@ -264,8 +359,6 @@ void Coap::sendRequest(CoapReply *reply, const bool &lookedUp) reply->m_lockedUp = lookedUp; reply->m_timer->start(); - qDebug() << "--->" << pdu; - // send the data if (reply->request().messageType() == CoapPdu::NonConfirmable) { sendData(reply->hostAddress(), reply->port(), pduData); @@ -286,30 +379,43 @@ void Coap::sendCoapPdu(const QHostAddress &hostAddress, const quint16 &port, con m_socket->writeDatagram(pdu.pack(), hostAddress, port); } -void Coap::processResponse(const CoapPdu &pdu) +void Coap::processResponse(const CoapPdu &pdu, const QHostAddress &address, const quint16 &port) { - qDebug() << "<---" << pdu; + // if we are waiting for a response + if (m_reply) { + qDebug() << "<---" << QString("%1:%2").arg(address.toString()).arg(QString::number(port)) << pdu; + if (!pdu.isValid()) { + qWarning() << "Got invalid PDU"; + m_reply->setError(CoapReply::InvalidPduError); + m_reply->setFinished(); + return; + } - if (!pdu.isValid()) { - qWarning() << "Got invalid PDU"; - m_reply->setError(CoapReply::InvalidPduError); - m_reply->setFinished(); + // check if the message is a response to a reply (message id based check) + if (m_reply->messageId() == pdu.messageId()) { + processIdBasedResponse(m_reply, pdu); + return; + } + + // check if we know the message by token (message token based check) + if (m_reply->messageToken() == pdu.token()) { + processTokenBasedResponse(m_reply, pdu); + return; + } + } + // check if this is a notification from a known observed resource + if (m_observeResources.keys().contains(pdu.token())) { + processNotification(pdu, address, port); return; } - // check if the message is a response to a reply (message id based check) - if (m_reply->messageId() == pdu.messageId()) { - processIdBasedResponse(m_reply, pdu); - return; - } + qWarning() << "Got message without request or registered observe resource."; + CoapPdu responsePdu; + responsePdu.setMessageType(CoapPdu::Reset); + responsePdu.setMessageId(pdu.messageId()); + responsePdu.setToken(pdu.token()); + sendCoapPdu(address, port, responsePdu); - // check if we know the message by token (message token based check) - if (m_reply->messageToken() == pdu.token()) { - processTokenBasedResponse(m_reply, pdu); - return; - } - - qDebug() << "Got message without request"; } void Coap::processIdBasedResponse(CoapReply *reply, const CoapPdu &pdu) @@ -355,6 +461,27 @@ void Coap::processTokenBasedResponse(CoapReply *reply, const CoapPdu &pdu) reply->setFinished(); } +void Coap::processNotification(const CoapPdu &pdu, const QHostAddress &address, const quint16 &port) +{ + // respond with ACK + CoapPdu responsePdu; + responsePdu.setMessageType(CoapPdu::Acknowledgement); + responsePdu.setStatusCode(CoapPdu::Empty); + responsePdu.setMessageId(pdu.messageId()); + responsePdu.setToken(pdu.token()); + sendCoapPdu(address, port, responsePdu); + + int notificationNumber = 0; + foreach (const CoapOption &option, pdu.options()) { + if (option.option() == CoapOption::Observe) { + notificationNumber = option.data().toHex().toInt(0, 16); + } + } + + CoapObserveResource resource = m_observeResources.value(pdu.token()); + emit notificationReceived(resource, notificationNumber, pdu.payload()); +} + void Coap::processBlock1Response(CoapReply *reply, const CoapPdu &pdu) { qDebug() << "sent successfully block #" << pdu.block().blockNumber(); @@ -383,21 +510,27 @@ void Coap::processBlock1Response(CoapReply *reply, const CoapPdu &pdu) nextBlockRequest.setMessageId(pdu.messageId() + 1); nextBlockRequest.setToken(pdu.token()); + // Add the options in correct order + // Option number 3 if (reply->m_lockedUp) nextBlockRequest.addOption(CoapOption::UriHost, reply->request().url().host().toUtf8()); + // Option number 7 if (reply->port() != 5683) nextBlockRequest.addOption(CoapOption::UriPort, QByteArray::number(reply->request().url().port())); QStringList urlTokens = reply->request().url().path().split("/"); urlTokens.removeAll(QString()); + // Option number 11 foreach (const QString &token, urlTokens) nextBlockRequest.addOption(CoapOption::UriPath, token.toUtf8()); + // Option number 15 if (reply->request().url().hasQuery()) nextBlockRequest.addOption(CoapOption::UriQuery, reply->request().url().query().toUtf8()); + // Option number 27 nextBlockRequest.addOption(CoapOption::Block1, CoapPduBlock::createBlock(pdu.block().blockNumber() + 1, 2, moreFlag)); nextBlockRequest.setPayload(newBlockData); @@ -432,22 +565,27 @@ void Coap::processBlock2Response(CoapReply *reply, const CoapPdu &pdu) nextBlockRequest.setMessageId(pdu.messageId() + 1); nextBlockRequest.setToken(pdu.token()); + // Add the options in correct order + // Option number 3 if (reply->m_lockedUp) nextBlockRequest.addOption(CoapOption::UriHost, reply->request().url().host().toUtf8()); + // Option number 7 if (reply->port() != 5683) nextBlockRequest.addOption(CoapOption::UriPort, QByteArray::number(reply->request().url().port())); - QStringList urlTokens = reply->request().url().path().split("/"); urlTokens.removeAll(QString()); + // Option number 11 foreach (const QString &token, urlTokens) nextBlockRequest.addOption(CoapOption::UriPath, token.toUtf8()); + // Option number 15 if (reply->request().url().hasQuery()) nextBlockRequest.addOption(CoapOption::UriQuery, reply->request().url().query().toUtf8()); + // Option number 23 nextBlockRequest.addOption(CoapOption::Block2, CoapPduBlock::createBlock(pdu.block().blockNumber() + 1, 2, false)); QByteArray pduData = nextBlockRequest.pack(); @@ -496,7 +634,7 @@ void Coap::onReadyRead() } CoapPdu pdu(data); - processResponse(pdu); + processResponse(pdu, hostAddress, port); } void Coap::onReplyTimeout() diff --git a/libguh/coap/coap.h b/libguh/coap/coap.h index eae731df..e4b60004 100644 --- a/libguh/coap/coap.h +++ b/libguh/coap/coap.h @@ -30,6 +30,7 @@ #include "libguh.h" #include "coaprequest.h" #include "coapreply.h" +#include "coapobserveresource.h" /* Information about CoAP * @@ -37,6 +38,7 @@ * Blockwise transfers in CoAP : https://tools.ietf.org/html/draft-ietf-core-block-18 * Constrained RESTful Environments (CoRE) Link Format : http://tools.ietf.org/html/rfc6690 * Observing Resources in CoAP : https://tools.ietf.org/html/rfc7641 + * */ class LIBGUH_EXPORT Coap : public QObject @@ -52,28 +54,36 @@ public: CoapReply *post(const CoapRequest &request, const QByteArray &data = QByteArray()); CoapReply *deleteResource(const CoapRequest &request); + // Notifications for observable resources + CoapReply *enableResourceNotifications(const CoapRequest &request); + CoapReply *disableNotifications(const CoapRequest &request); + private: QUdpSocket *m_socket; CoapReply *m_reply; QHash m_runningHostLookups; + QHash m_observeResources; QQueue m_replyQueue; void lookupHost(); void sendRequest(CoapReply *reply, const bool &lookedUp = false); void sendData(const QHostAddress &hostAddress, const quint16 &port, const QByteArray &data); - void sendCoapPdu(const QHostAddress &hostAddress, const quint16 &port, const CoapPdu &pdu); + void sendCoapPdu(const QHostAddress &address, const quint16 &port, const CoapPdu &pdu); - void processResponse(const CoapPdu &pdu); + void processResponse(const CoapPdu &pdu, const QHostAddress &address, const quint16 &port); void processIdBasedResponse(CoapReply *reply, const CoapPdu &pdu); void processTokenBasedResponse(CoapReply *reply, const CoapPdu &pdu); + void processNotification(const CoapPdu &pdu, const QHostAddress &address, const quint16 &port); + void processBlock1Response(CoapReply *reply, const CoapPdu &pdu); void processBlock2Response(CoapReply *reply, const CoapPdu &pdu); signals: void replyFinished(CoapReply *reply); + void notificationReceived(const CoapObserveResource &resource, const int ¬ificationNumber, const QByteArray &payload); private slots: void hostLookupFinished(const QHostInfo &hostInfo); @@ -82,4 +92,5 @@ private slots: void onReplyFinished(); }; + #endif // COAP_H diff --git a/libguh/coap/coapobserveresource.cpp b/libguh/coap/coapobserveresource.cpp new file mode 100644 index 00000000..e7a6aed9 --- /dev/null +++ b/libguh/coap/coapobserveresource.cpp @@ -0,0 +1,65 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * * + * Copyright (C) 2015 Simon Stuerz * + * * + * This file is part of QtCoap. * + * * + * QtCoap is free software: you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation, version 3 of the License. * + * * + * QtCoap is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with QtCoap. If not, see . * + * * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +/*! + \class CoapObserveResource + \brief Holds information about an observed resource. + + \ingroup coap + \inmodule libguh + + The CoapObserveResource class holds information about an observed resource. + + \sa Coap::notificationReceived() + +*/ + +#include "coapobserveresource.h" + +/*! Constructs a CoapObserveResource. */ +CoapObserveResource::CoapObserveResource() +{ +} + +/*! Constructs a CoapObserveResource with the given \a url and \a token. */ +CoapObserveResource::CoapObserveResource(const QUrl &url, const QByteArray &token): + m_url(url), + m_token(token) +{ +} + +/*! Constructs a copy of the given \a other \l{CoapObserveResource}. */ +CoapObserveResource::CoapObserveResource(const CoapObserveResource &other) +{ + m_url = other.url(); + m_token = other.token(); +} + +/*! Returns the url of this \l{CoapObserveResource}. */ +QUrl CoapObserveResource::url() const +{ + return m_url; +} + +/*! Returns the token of this \l{CoapObserveResource}. */ +QByteArray CoapObserveResource::token() const +{ + return m_token; +} diff --git a/libguh/coap/coapobserveresource.h b/libguh/coap/coapobserveresource.h new file mode 100644 index 00000000..19d09b0d --- /dev/null +++ b/libguh/coap/coapobserveresource.h @@ -0,0 +1,46 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * * + * Copyright (C) 2015 Simon Stuerz * + * * + * This file is part of QtCoap. * + * * + * QtCoap is free software: you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation, version 3 of the License. * + * * + * QtCoap is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with QtCoap. If not, see . * + * * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#ifndef COAPOBSERVERESOURCE_H +#define COAPOBSERVERESOURCE_H + +#include +#include + +#include "libguh.h" + +class LIBGUH_EXPORT CoapObserveResource +{ + +public: + CoapObserveResource(); + CoapObserveResource(const QUrl &url, const QByteArray &token); + CoapObserveResource(const CoapObserveResource &other); + + QUrl url() const; + QByteArray token() const; + +private: + QUrl m_url; + QByteArray m_token; + +}; + +#endif // COAPOBSERVERESOURCE_H diff --git a/libguh/coap/coapoption.cpp b/libguh/coap/coapoption.cpp index 73b0e99e..735320ee 100644 --- a/libguh/coap/coapoption.cpp +++ b/libguh/coap/coapoption.cpp @@ -41,6 +41,8 @@ \value IfNoneMatch + \value Observe + \l{https://tools.ietf.org/html/rfc7641} \value UriPort \value LocationPath @@ -58,8 +60,10 @@ \value LocationQuery \value Block2 + \l{https://tools.ietf.org/html/draft-ietf-core-block-18} \value Block1 + \l{https://tools.ietf.org/html/draft-ietf-core-block-18} \value ProxyUri @@ -73,19 +77,21 @@ #include -/*! Constructs a \l{CoapOption} . */ +/*! Constructs a CoapOption. */ CoapOption::CoapOption() { + } -/*! Constructs a \l{CoapOption} with the given \a option and option \a data. */ +/*! Constructs a CoapOption with the given \a option and option \a data. */ CoapOption::CoapOption(const CoapOption::Option &option, const QByteArray &data) : m_option(option), m_data(data) { + } -/*! Sets the option value of this CoapOption to the given \a option . */ +/*! Sets the \l{CoapOption::Option} of this CoapOption to the given \a option. */ void CoapOption::setOption(const CoapOption::Option &option) { m_option = option; @@ -111,6 +117,10 @@ QByteArray CoapOption::data() const #include "coappdu.h" +/*! Writes the data of the given \a coapOption to \a dbg. + + \sa CoapOption +*/ QDebug operator<<(QDebug debug, const CoapOption &coapOption) { const QMetaObject &metaObject = CoapOption::staticMetaObject; @@ -147,7 +157,10 @@ QDebug operator<<(QDebug debug, const CoapOption &coapOption) debug.nospace() << "CoapOption(" << optionEnum.valueToKey(coapOption.option()) << "): " << coapOption.data().toHex() << " Block #" << block.blockNumber() << ", More flag = " << block.moreFlag() << ", SZX:" << block.blockSize() << endl; break; } - + case CoapOption::Observe: { + debug.nospace() << "CoapOption(" << optionEnum.valueToKey(coapOption.option()) << "): " << coapOption.data().toHex().toInt(0, 16) << endl; + break; + } default: QString optionName = optionEnum.valueToKey(coapOption.option()); if (optionName.isNull()) { diff --git a/libguh/coap/coapoption.h b/libguh/coap/coapoption.h index 62760db9..53ace930 100644 --- a/libguh/coap/coapoption.h +++ b/libguh/coap/coapoption.h @@ -39,6 +39,7 @@ public: UriHost = 3, ETag = 4, IfNoneMatch = 5, + Observe = 6, // (Observe) https://tools.ietf.org/html/rfc7641 UriPort = 7, LocationPath = 8, UriPath = 11, @@ -47,7 +48,7 @@ public: UriQuery = 15, Accept = 17, LocationQuery = 20, - Block2 = 23, // (Block) + Block2 = 23, // (Block) https://tools.ietf.org/html/draft-ietf-core-block-18 Block1 = 27, // (Block) ProxyUri = 35, ProxyScheme = 39, diff --git a/libguh/coap/coappdu.cpp b/libguh/coap/coappdu.cpp index a7e846f2..7930552b 100644 --- a/libguh/coap/coappdu.cpp +++ b/libguh/coap/coappdu.cpp @@ -132,6 +132,7 @@ #include #include +/*! Constructs a CoapPdu with the given \a parent. */ CoapPdu::CoapPdu(QObject *parent) : QObject(parent), m_version(1), @@ -145,6 +146,7 @@ CoapPdu::CoapPdu(QObject *parent) : qsrand(QDateTime::currentMSecsSinceEpoch()); } +/*! Constructs a CoapPdu from the given \a data with the given \a parent. */ CoapPdu::CoapPdu(const QByteArray &data, QObject *parent) : QObject(parent), m_version(1), @@ -159,6 +161,7 @@ CoapPdu::CoapPdu(const QByteArray &data, QObject *parent) : unpack(data); } +/*! Returns the human readable status code for the given \a statusCode. */ QString CoapPdu::getStatusCodeString(const CoapPdu::StatusCode &statusCode) { QString statusCodeString; @@ -175,68 +178,89 @@ QString CoapPdu::getStatusCodeString(const CoapPdu::StatusCode &statusCode) return statusCodeString; } +/*! Returns the version of this \l{CoapPdu}. */ quint8 CoapPdu::version() const { return m_version; } +/*! Sets the version of this \l{CoapPdu} to the given \a version. */ void CoapPdu::setVersion(const quint8 &version) { m_version = version; } +/*! Returns the \l{CoapPdu::MessageType} of this \l{CoapPdu}. */ CoapPdu::MessageType CoapPdu::messageType() const { return m_messageType; } +/*! Sets the \l{CoapPdu::MessageType} of this \l{CoapPdu} to the given \a messageType. */ void CoapPdu::setMessageType(const CoapPdu::MessageType &messageType) { m_messageType = messageType; } +/*! Returns the \l{CoapPdu::StatusCode} of this \l{CoapPdu}. */ CoapPdu::StatusCode CoapPdu::statusCode() const { return m_statusCode; } +/*! Sets the \l{CoapPdu::StatusCode} of this \l{CoapPdu} to the given \a statusCode. */ void CoapPdu::setStatusCode(const CoapPdu::StatusCode &statusCode) { m_statusCode = statusCode; } +/*! Returns the messageId of this \l{CoapPdu}. */ quint16 CoapPdu::messageId() const { return m_messageId; } +/*! Creates a random message id for this \l{CoapPdu} and sets the + message id to the created value. + + \sa setMessageId() +*/ void CoapPdu::createMessageId() { setMessageId((quint16)qrand() % 65536); } +/*! Sets the messageId of this \l{CoapPdu} to the given \a messageId. */ void CoapPdu::setMessageId(const quint16 &messageId) { m_messageId = messageId; } +/*! Returns the \l{CoapPdu::ContentType} of this \l{CoapPdu}. */ CoapPdu::ContentType CoapPdu::contentType() const { return m_contentType; } +/*! Sets the content type of this \l{CoapPdu} to the given \a contentType. + + \sa CoapPdu::ContentType +*/ void CoapPdu::setContentType(const CoapPdu::ContentType &contentType) { - // TODO: add the contentFormat option - m_contentType = contentType; } +/*! Returns the token of this \l{CoapPdu}. */ QByteArray CoapPdu::token() const { return m_token; } +/*! Creates a random token for this \l{CoapPdu} and sets the + token to the created value. + \sa setToken() +*/ void CoapPdu::createToken() { m_token.clear(); @@ -247,26 +271,34 @@ void CoapPdu::createToken() } } +/*! Sets the token of this \l{CoapPdu} to the given \a token. */ void CoapPdu::setToken(const QByteArray &token) { m_token = token; } +/*! Returns the payload of this \l{CoapPdu}. */ QByteArray CoapPdu::payload() const { return m_payload; } +/*! Sets the payload of this \l{CoapPdu} to the given \a payload. */ void CoapPdu::setPayload(const QByteArray &payload) { m_payload = payload; } +/*! Returns the list of \l{CoapOption}{CoapOptions} of this \l{CoapPdu}. */ QList CoapPdu::options() const { return m_options; } +/*! Adds the given \a option with the given \a data to this \l{CoapPdu}. + + \sa CoapOption +*/ void CoapPdu::addOption(const CoapOption::Option &option, const QByteArray &data) { // set pdu data from the option @@ -304,11 +336,13 @@ void CoapPdu::addOption(const CoapOption::Option &option, const QByteArray &data m_options.insert(index + 1, CoapOption(option, data)); } +/*! Returns the block of this \l{CoapPdu}. */ CoapPduBlock CoapPdu::block() const { return m_block; } +/*! Returns true if this \l{CoapPdu} has the given \a option. */ bool CoapPdu::hasOption(const CoapOption::Option &option) const { foreach (const CoapOption &o, m_options) { @@ -318,6 +352,7 @@ bool CoapPdu::hasOption(const CoapOption::Option &option) const return false; } +/*! Resets this \l{CoapPdu} to the default values. */ void CoapPdu::clear() { m_version = 1; @@ -331,11 +366,13 @@ void CoapPdu::clear() m_error = NoError; } +/*! Returns true if this \l{CoapPdu} has no errors. */ bool CoapPdu::isValid() const { return (m_error == NoError); } +/*! Returns the packed \l{CoapPdu} as byte array which are ready to send to the server.*/ QByteArray CoapPdu::pack() const { QByteArray pduData; @@ -499,6 +536,10 @@ void CoapPdu::unpack(const QByteArray &data) } } +/*! Writes the data of the given \a coapPdu to \a dbg. + + \sa CoapPdu +*/ QDebug operator<<(QDebug debug, const CoapPdu &coapPdu) { const QMetaObject &metaObject = CoapPdu::staticMetaObject; diff --git a/libguh/coap/coappdu.h b/libguh/coap/coappdu.h index ccee96b9..db418bfd 100644 --- a/libguh/coap/coappdu.h +++ b/libguh/coap/coappdu.h @@ -151,7 +151,6 @@ public: void clear(); bool isValid() const; - bool isNull() const; QByteArray pack() const; diff --git a/libguh/coap/coapreply.cpp b/libguh/coap/coapreply.cpp index 31703cbc..4ad6938c 100644 --- a/libguh/coap/coapreply.cpp +++ b/libguh/coap/coapreply.cpp @@ -66,7 +66,7 @@ */ /*! \fn void CoapReply::error(const Error &code); - This signal is emitted when an error occured. + This signal is emitted when an error occured. The given \a code represents the \l{CoapReply::Error}. \sa error(), errorString() */ @@ -91,13 +91,13 @@ #include -/*! Returns the request for this CoapReply. */ +/*! Returns the request for this \l{CoapReply}. */ CoapRequest CoapReply::request() const { return m_request; } -/*! Returns the payload of this CoapReply. The payload will be available once the CoapReply is finished. +/*! Returns the payload of this \l{CoapReply}. The payload will be available once the \l{CoapReply} is finished. \sa isFinished */ @@ -106,7 +106,7 @@ QByteArray CoapReply::payload() const return m_payload; } -/*! Returns true if the reply is finished. +/*! Returns true if the \l{CoapReply} is finished. \sa finished() */ @@ -115,7 +115,7 @@ bool CoapReply::isFinished() const return m_isFinished; } -/*! Returns true if the reply is running. +/*! Returns true if the \l{CoapReply} is running. \sa finished() */ @@ -124,7 +124,7 @@ bool CoapReply::isRunning() const return m_timer->isActive(); } -/*! Returns error code of the reply. +/*! Returns error \l{CoapReply::Error} of the \l{CoapReply}. \sa errorString() */ @@ -133,7 +133,7 @@ CoapReply::Error CoapReply::error() const return m_error; } -/*! Returns error string of the reply. +/*! Returns error string of the \l{CoapReply}. \sa error() */ @@ -161,16 +161,19 @@ QString CoapReply::errorString() const return errorString; } +/*! Returns the \l{CoapPdu::ContentType} of this \l{CoapReply}. */ CoapPdu::ContentType CoapReply::contentType() const { return m_contentType; } +/*! Returns the \l{CoapPdu::MessageType} of this \l{CoapReply}. */ CoapPdu::MessageType CoapReply::messageType() const { return m_messageType; } +/*! Returns the \l{CoapPdu::StatusCode} of this \l{CoapReply}. */ CoapPdu::StatusCode CoapReply::statusCode() const { return m_statusCode; @@ -219,6 +222,26 @@ void CoapReply::setMessageToken(const QByteArray &messageToken) m_messageToken = messageToken; } +bool CoapReply::observation() const +{ + return m_observation; +} + +void CoapReply::setObservation(const bool &observation) +{ + m_observation = observation; +} + +bool CoapReply::observationEnable() const +{ + return m_observationEnable; +} + +void CoapReply::setObservationEnable(const bool &observationEnable) +{ + m_observationEnable = observationEnable; +} + void CoapReply::setFinished() { m_isFinished = true; @@ -308,6 +331,10 @@ void CoapReply::setRequestData(const QByteArray &requestData) m_requestData = requestData; } +/*! Writes the data of the given \a reply to \a dbg. + + \sa CoapReply +*/ QDebug operator<<(QDebug debug, CoapReply *reply) { const QMetaObject &metaObject = CoapPdu::staticMetaObject; diff --git a/libguh/coap/coapreply.h b/libguh/coap/coapreply.h index 3f5a739c..33911dc4 100644 --- a/libguh/coap/coapreply.h +++ b/libguh/coap/coapreply.h @@ -108,6 +108,12 @@ private: QByteArray messageToken() const; void setMessageToken(const QByteArray &messageToken); + bool observation() const; + void setObservation(const bool &observation); + + bool observationEnable() const; + void setObservationEnable(const bool &observationEnable); + QHostAddress m_hostAddress; int m_port; CoapPdu::StatusCode m_requestMethod; @@ -117,6 +123,9 @@ private: int m_messageId; QByteArray m_messageToken; + bool m_observation; + bool m_observationEnable; + signals: void timeout(); void finished(); diff --git a/libguh/coap/corelink.cpp b/libguh/coap/corelink.cpp index f10e473a..26f32c2e 100644 --- a/libguh/coap/corelink.cpp +++ b/libguh/coap/corelink.cpp @@ -35,6 +35,7 @@ #include +/*! Constructs a \l{CoreLink}. */ CoreLink::CoreLink() : m_contentType(CoapPdu::TextPlain), m_maximumSize(-1), @@ -42,76 +43,94 @@ CoreLink::CoreLink() : { } +/*! Returns the path of this \l{CoreLink}. */ QString CoreLink::path() const { return m_path; } +/*! Sets the \a path of this \l{CoreLink}. */ void CoreLink::setPath(const QString &path) { m_path = path; } +/*! Returns the title of this \l{CoreLink}. */ QString CoreLink::title() const { return m_title; } +/*! Sets the \a title of this \l{CoreLink}. */ void CoreLink::setTitle(const QString &title) { m_title = title; } +/*! Returns the resource type of this \l{CoreLink}. */ QString CoreLink::resourceType() const { return m_resourceType; } +/*! Sets the resource type of this \l{CoreLink} to the given \a resourceType. */ void CoreLink::setResourceType(const QString &resourceType) { m_resourceType = resourceType; } +/*! Returns the interface description of this \l{CoreLink}. */ QString CoreLink::interfaceDescription() const { return m_interfaceDescription; } +/*! Sets the interface description of this \l{CoreLink} to the given \a interfaceDescription. */ void CoreLink::setInterfaceDescription(const QString &interfaceDescription) { m_interfaceDescription = interfaceDescription; } +/*! Returns the l{CoapPdu::ContentType} of this \l{CoreLink}. */ CoapPdu::ContentType CoreLink::contentType() const { return m_contentType; } +/*! Sets the l{CoapPdu::ContentType} of this \l{CoreLink} to the given \a contentType. */ void CoreLink::setContentType(const CoapPdu::ContentType &contentType) { m_contentType = contentType; } +/*! Returns the maximum payload size of this \l{CoreLink}. */ int CoreLink::maximumSize() const { return m_maximumSize; } +/*! Sets the maximum payload size of this \l{CoreLink} to the given \a maximumSize. */ void CoreLink::setMaximumSize(const int &maximumSize) { m_maximumSize = maximumSize; } +/*! Returns true if this \l{CoreLink} is observable. */ bool CoreLink::observable() const { return m_observable; } +/*! Sets this \l{CoreLink} \a observable. */ void CoreLink::setObservable(const bool &observable) { m_observable = observable; } +/*! Writes the data of the given \a link to \a dbg. + + \sa CoreLink +*/ QDebug operator<<(QDebug debug, const CoreLink &link) { const QMetaObject &metaObject = CoapPdu::staticMetaObject; diff --git a/libguh/coap/corelinkparser.cpp b/libguh/coap/corelinkparser.cpp index 534bb862..7cb44528 100644 --- a/libguh/coap/corelinkparser.cpp +++ b/libguh/coap/corelinkparser.cpp @@ -45,7 +45,7 @@ #include -/*! Constructs a CoRE link parser. The given \a data should contain a CoRE link list. */ +/*! Constructs a CoRE link parser with the given \a parent. The given \a data should contain a CoRE link list from the discovery. */ CoreLinkParser::CoreLinkParser(const QByteArray &data, QObject *parent) : QObject(parent), m_data(data) diff --git a/libguh/libguh.pro b/libguh/libguh.pro index e063ddb1..32ae1197 100644 --- a/libguh/libguh.pro +++ b/libguh/libguh.pro @@ -46,6 +46,7 @@ SOURCES += devicemanager.cpp \ coap/coappdublock.cpp \ coap/corelinkparser.cpp \ coap/corelink.cpp \ + coap/coapobserveresource.cpp \ types/action.cpp \ types/actiontype.cpp \ types/state.cpp \ @@ -90,6 +91,7 @@ HEADERS += devicemanager.h \ coap/coappdublock.h \ coap/corelinkparser.h \ coap/corelink.h \ + coap/coapobserveresource.h \ types/action.h \ types/actiontype.h \ types/state.h \