mirror of
https://github.com/emsesp/EMS-ESP32.git
synced 2025-12-08 00:39:50 +03:00
experimental mqtt client supporting large packets
This commit is contained in:
@@ -4,6 +4,7 @@
|
||||
|
||||
#include "DisconnectReasons.hpp"
|
||||
#include "MessageProperties.hpp"
|
||||
#include "Errors.hpp"
|
||||
|
||||
namespace AsyncMqttClientInternals {
|
||||
// user callbacks
|
||||
@@ -12,9 +13,8 @@ typedef std::function<void(AsyncMqttClientDisconnectReason reason)> OnDisconnect
|
||||
typedef std::function<void(uint16_t packetId, uint8_t qos)> OnSubscribeUserCallback;
|
||||
typedef std::function<void(uint16_t packetId)> OnUnsubscribeUserCallback;
|
||||
typedef std::function<void(char* topic, char* payload, AsyncMqttClientMessageProperties properties, size_t len, size_t index, size_t total)> OnMessageUserCallback;
|
||||
// typedef std::pair<std::string, std::function<void(char* topic, char* payload, AsyncMqttClientMessageProperties properties, size_t len, size_t index, size_t total)>> onFilteredMessageUserCallback;
|
||||
typedef std::pair<char*, std::function<void(char* topic, char* payload, AsyncMqttClientMessageProperties properties, size_t len, size_t index, size_t total)>> onFilteredMessageUserCallback;
|
||||
typedef std::function<void(uint16_t packetId)> OnPublishUserCallback;
|
||||
typedef std::function<void(uint16_t packetId, AsyncMqttClientError error)> OnErrorUserCallback;
|
||||
|
||||
// internal callbacks
|
||||
typedef std::function<void(bool sessionPresent, uint8_t connectReturnCode)> OnConnAckInternalCallback;
|
||||
|
||||
6
lib/async-mqtt-client/src/AsyncMqttClient/Errors.hpp
Normal file
6
lib/async-mqtt-client/src/AsyncMqttClient/Errors.hpp
Normal file
@@ -0,0 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
enum class AsyncMqttClientError : uint8_t {
|
||||
MAX_RETRIES = 0,
|
||||
OUT_OF_MEMORY = 1
|
||||
};
|
||||
@@ -35,4 +35,27 @@ class Helpers {
|
||||
return bytesNeeded;
|
||||
}
|
||||
};
|
||||
|
||||
#if defined(ARDUINO_ARCH_ESP32)
|
||||
#define SEMAPHORE_TAKE() xSemaphoreTake(_xSemaphore, portMAX_DELAY)
|
||||
#define SEMAPHORE_GIVE() xSemaphoreGive(_xSemaphore)
|
||||
#define GET_FREE_MEMORY() ESP.getMaxAllocHeap()
|
||||
#include <esp32-hal-log.h>
|
||||
#elif defined(ARDUINO_ARCH_ESP8266)
|
||||
#define SEMAPHORE_TAKE(X) while (_xSemaphore) { /*ESP.wdtFeed();*/ } _xSemaphore = true
|
||||
#define SEMAPHORE_GIVE() _xSemaphore = false
|
||||
#define GET_FREE_MEMORY() ESP.getMaxFreeBlockSize()
|
||||
#if defined(DEBUG_ESP_PORT) && defined(DEBUG_ASYNC_MQTT_CLIENT)
|
||||
#define log_i(...) DEBUG_ESP_PORT.printf(__VA_ARGS__); DEBUG_ESP_PORT.print("\n")
|
||||
#define log_e(...) DEBUG_ESP_PORT.printf(__VA_ARGS__); DEBUG_ESP_PORT.print("\n")
|
||||
#define log_w(...) DEBUG_ESP_PORT.printf(__VA_ARGS__); DEBUG_ESP_PORT.print("\n")
|
||||
#else
|
||||
#define log_i(...)
|
||||
#define log_e(...)
|
||||
#define log_w(...)
|
||||
#endif
|
||||
#else
|
||||
#pragma error "No valid architecture"
|
||||
#endif
|
||||
|
||||
} // namespace AsyncMqttClientInternals
|
||||
|
||||
@@ -0,0 +1,162 @@
|
||||
#include "Connect.hpp"
|
||||
|
||||
using AsyncMqttClientInternals::ConnectOutPacket;
|
||||
|
||||
ConnectOutPacket::ConnectOutPacket(bool cleanSession,
|
||||
const char* username,
|
||||
const char* password,
|
||||
const char* willTopic,
|
||||
bool willRetain,
|
||||
uint8_t willQos,
|
||||
const char* willPayload,
|
||||
uint16_t willPayloadLength,
|
||||
uint16_t keepAlive,
|
||||
const char* clientId) {
|
||||
char fixedHeader[5];
|
||||
fixedHeader[0] = AsyncMqttClientInternals::PacketType.CONNECT;
|
||||
fixedHeader[0] = fixedHeader[0] << 4;
|
||||
fixedHeader[0] = fixedHeader[0] | AsyncMqttClientInternals::HeaderFlag.CONNECT_RESERVED;
|
||||
|
||||
uint16_t protocolNameLength = 4;
|
||||
char protocolNameLengthBytes[2];
|
||||
protocolNameLengthBytes[0] = protocolNameLength >> 8;
|
||||
protocolNameLengthBytes[1] = protocolNameLength & 0xFF;
|
||||
|
||||
char protocolLevel[1];
|
||||
protocolLevel[0] = 0x04;
|
||||
|
||||
char connectFlags[1];
|
||||
connectFlags[0] = 0;
|
||||
if (cleanSession) connectFlags[0] |= AsyncMqttClientInternals::ConnectFlag.CLEAN_SESSION;
|
||||
if (username != nullptr) connectFlags[0] |= AsyncMqttClientInternals::ConnectFlag.USERNAME;
|
||||
if (password != nullptr) connectFlags[0] |= AsyncMqttClientInternals::ConnectFlag.PASSWORD;
|
||||
if (willTopic != nullptr) {
|
||||
connectFlags[0] |= AsyncMqttClientInternals::ConnectFlag.WILL;
|
||||
if (willRetain) connectFlags[0] |= AsyncMqttClientInternals::ConnectFlag.WILL_RETAIN;
|
||||
switch (willQos) {
|
||||
case 0:
|
||||
connectFlags[0] |= AsyncMqttClientInternals::ConnectFlag.WILL_QOS0;
|
||||
break;
|
||||
case 1:
|
||||
connectFlags[0] |= AsyncMqttClientInternals::ConnectFlag.WILL_QOS1;
|
||||
break;
|
||||
case 2:
|
||||
connectFlags[0] |= AsyncMqttClientInternals::ConnectFlag.WILL_QOS2;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
char keepAliveBytes[2];
|
||||
keepAliveBytes[0] = keepAlive >> 8;
|
||||
keepAliveBytes[1] = keepAlive & 0xFF;
|
||||
|
||||
uint16_t clientIdLength = strlen(clientId);
|
||||
char clientIdLengthBytes[2];
|
||||
clientIdLengthBytes[0] = clientIdLength >> 8;
|
||||
clientIdLengthBytes[1] = clientIdLength & 0xFF;
|
||||
|
||||
// Optional fields
|
||||
uint16_t willTopicLength = 0;
|
||||
char willTopicLengthBytes[2];
|
||||
char willPayloadLengthBytes[2];
|
||||
if (willTopic != nullptr) {
|
||||
willTopicLength = strlen(willTopic);
|
||||
willTopicLengthBytes[0] = willTopicLength >> 8;
|
||||
willTopicLengthBytes[1] = willTopicLength & 0xFF;
|
||||
|
||||
if (willPayload != nullptr && willPayloadLength == 0) willPayloadLength = strlen(willPayload);
|
||||
|
||||
willPayloadLengthBytes[0] = willPayloadLength >> 8;
|
||||
willPayloadLengthBytes[1] = willPayloadLength & 0xFF;
|
||||
}
|
||||
|
||||
uint16_t usernameLength = 0;
|
||||
char usernameLengthBytes[2];
|
||||
if (username != nullptr) {
|
||||
usernameLength = strlen(username);
|
||||
usernameLengthBytes[0] = usernameLength >> 8;
|
||||
usernameLengthBytes[1] = usernameLength & 0xFF;
|
||||
}
|
||||
|
||||
uint16_t passwordLength = 0;
|
||||
char passwordLengthBytes[2];
|
||||
if (password != nullptr) {
|
||||
passwordLength = strlen(password);
|
||||
passwordLengthBytes[0] = passwordLength >> 8;
|
||||
passwordLengthBytes[1] = passwordLength & 0xFF;
|
||||
}
|
||||
|
||||
uint32_t remainingLength = 2 + protocolNameLength + 1 + 1 + 2 + 2 + clientIdLength; // always present
|
||||
if (willTopic != nullptr) remainingLength += 2 + willTopicLength + 2 + willPayloadLength;
|
||||
if (username != nullptr) remainingLength += 2 + usernameLength;
|
||||
if (password != nullptr) remainingLength += 2 + passwordLength;
|
||||
uint8_t remainingLengthLength = AsyncMqttClientInternals::Helpers::encodeRemainingLength(remainingLength, fixedHeader + 1);
|
||||
|
||||
uint32_t neededSpace = 1 + remainingLengthLength;
|
||||
neededSpace += 2;
|
||||
neededSpace += protocolNameLength;
|
||||
neededSpace += 1;
|
||||
neededSpace += 1;
|
||||
neededSpace += 2;
|
||||
neededSpace += 2;
|
||||
neededSpace += clientIdLength;
|
||||
if (willTopic != nullptr) {
|
||||
neededSpace += 2;
|
||||
neededSpace += willTopicLength;
|
||||
|
||||
neededSpace += 2;
|
||||
if (willPayload != nullptr) neededSpace += willPayloadLength;
|
||||
}
|
||||
if (username != nullptr) {
|
||||
neededSpace += 2;
|
||||
neededSpace += usernameLength;
|
||||
}
|
||||
if (password != nullptr) {
|
||||
neededSpace += 2;
|
||||
neededSpace += passwordLength;
|
||||
}
|
||||
|
||||
_data.reserve(neededSpace);
|
||||
|
||||
_data.insert(_data.end(), fixedHeader, fixedHeader + 1 + remainingLengthLength);
|
||||
|
||||
_data.push_back(protocolNameLengthBytes[0]);
|
||||
_data.push_back(protocolNameLengthBytes[1]);
|
||||
|
||||
_data.push_back('M');
|
||||
_data.push_back('Q');
|
||||
_data.push_back('T');
|
||||
_data.push_back('T');
|
||||
|
||||
_data.push_back(protocolLevel[0]);
|
||||
_data.push_back(connectFlags[0]);
|
||||
_data.push_back(keepAliveBytes[0]);
|
||||
_data.push_back(keepAliveBytes[1]);
|
||||
_data.push_back(clientIdLengthBytes[0]);
|
||||
_data.push_back(clientIdLengthBytes[1]);
|
||||
|
||||
_data.insert(_data.end(), clientId, clientId + clientIdLength);
|
||||
if (willTopic != nullptr) {
|
||||
_data.insert(_data.end(), willTopicLengthBytes, willTopicLengthBytes + 2);
|
||||
_data.insert(_data.end(), willTopic, willTopic + willTopicLength);
|
||||
|
||||
_data.insert(_data.end(), willPayloadLengthBytes, willPayloadLengthBytes + 2);
|
||||
if (willPayload != nullptr) _data.insert(_data.end(), willPayload, willPayload + willPayloadLength);
|
||||
}
|
||||
if (username != nullptr) {
|
||||
_data.insert(_data.end(), usernameLengthBytes, usernameLengthBytes + 2);
|
||||
_data.insert(_data.end(), username, username + usernameLength);
|
||||
}
|
||||
if (password != nullptr) {
|
||||
_data.insert(_data.end(), passwordLengthBytes, passwordLengthBytes + 2);
|
||||
_data.insert(_data.end(), password, password + passwordLength);
|
||||
}
|
||||
}
|
||||
|
||||
const uint8_t* ConnectOutPacket::data(size_t index) const {
|
||||
return &_data.data()[index];
|
||||
}
|
||||
|
||||
size_t ConnectOutPacket::size() const {
|
||||
return _data.size();
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
#include <cstring> // strlen
|
||||
|
||||
#include "OutPacket.hpp"
|
||||
#include "../../Flags.hpp"
|
||||
#include "../../Helpers.hpp"
|
||||
|
||||
namespace AsyncMqttClientInternals {
|
||||
class ConnectOutPacket : public OutPacket {
|
||||
public:
|
||||
ConnectOutPacket(bool cleanSession,
|
||||
const char* username,
|
||||
const char* password,
|
||||
const char* willTopic,
|
||||
bool willRetain,
|
||||
uint8_t willQos,
|
||||
const char* willPayload,
|
||||
uint16_t willPayloadLength,
|
||||
uint16_t keepAlive,
|
||||
const char* clientId);
|
||||
const uint8_t* data(size_t index = 0) const;
|
||||
size_t size() const;
|
||||
|
||||
private:
|
||||
std::vector<uint8_t> _data;
|
||||
};
|
||||
} // namespace AsyncMqttClientInternals
|
||||
@@ -0,0 +1,18 @@
|
||||
#include "Disconn.hpp"
|
||||
|
||||
using AsyncMqttClientInternals::DisconnOutPacket;
|
||||
|
||||
DisconnOutPacket::DisconnOutPacket() {
|
||||
_data[0] = AsyncMqttClientInternals::PacketType.DISCONNECT;
|
||||
_data[0] = _data[0] << 4;
|
||||
_data[0] = _data[0] | AsyncMqttClientInternals::HeaderFlag.DISCONNECT_RESERVED;
|
||||
_data[1] = 0;
|
||||
}
|
||||
|
||||
const uint8_t* DisconnOutPacket::data(size_t index) const {
|
||||
return &_data[index];
|
||||
}
|
||||
|
||||
size_t DisconnOutPacket::size() const {
|
||||
return 2;
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
#pragma once
|
||||
|
||||
#include "OutPacket.hpp"
|
||||
#include "../../Flags.hpp"
|
||||
#include "../../Helpers.hpp"
|
||||
|
||||
namespace AsyncMqttClientInternals {
|
||||
class DisconnOutPacket : public OutPacket {
|
||||
public:
|
||||
DisconnOutPacket();
|
||||
const uint8_t* data(size_t index = 0) const;
|
||||
size_t size() const;
|
||||
|
||||
private:
|
||||
uint8_t _data[2];
|
||||
};
|
||||
} // namespace AsyncMqttClientInternals
|
||||
@@ -0,0 +1,44 @@
|
||||
#include "OutPacket.hpp"
|
||||
|
||||
using AsyncMqttClientInternals::OutPacket;
|
||||
|
||||
OutPacket::OutPacket()
|
||||
: next(nullptr)
|
||||
, timeout(0)
|
||||
, noTries(0)
|
||||
, _released(true)
|
||||
, _packetId(0) {}
|
||||
|
||||
OutPacket::~OutPacket() {}
|
||||
|
||||
bool OutPacket::released() const {
|
||||
return _released;
|
||||
}
|
||||
|
||||
uint8_t OutPacket::packetType() const {
|
||||
return data(0)[0] >> 4;
|
||||
}
|
||||
|
||||
uint16_t OutPacket::packetId() const {
|
||||
return _packetId;
|
||||
}
|
||||
|
||||
uint8_t OutPacket::qos() const {
|
||||
if (packetType() == AsyncMqttClientInternals::PacketType.PUBLISH) {
|
||||
return (data()[1] & 0x06) >> 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void OutPacket::release() {
|
||||
_released = true;
|
||||
}
|
||||
|
||||
uint16_t OutPacket::_nextPacketId = 0;
|
||||
|
||||
uint16_t OutPacket::_getNextPacketId() {
|
||||
if (++_nextPacketId == 0) {
|
||||
++_nextPacketId;
|
||||
}
|
||||
return _nextPacketId;
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h> // uint*_t
|
||||
#include <stddef.h> // size_t
|
||||
#include <algorithm> // std::min
|
||||
|
||||
#include "../../Flags.hpp"
|
||||
|
||||
namespace AsyncMqttClientInternals {
|
||||
class OutPacket {
|
||||
public:
|
||||
OutPacket();
|
||||
virtual ~OutPacket();
|
||||
virtual const uint8_t* data(size_t index = 0) const = 0;
|
||||
virtual size_t size() const = 0;
|
||||
bool released() const;
|
||||
uint8_t packetType() const;
|
||||
uint16_t packetId() const;
|
||||
uint8_t qos() const;
|
||||
void release();
|
||||
|
||||
public:
|
||||
OutPacket* next;
|
||||
uint32_t timeout;
|
||||
uint8_t noTries;
|
||||
|
||||
protected:
|
||||
static uint16_t _getNextPacketId();
|
||||
bool _released;
|
||||
uint16_t _packetId;
|
||||
|
||||
private:
|
||||
static uint16_t _nextPacketId;
|
||||
};
|
||||
} // namespace AsyncMqttClientInternals
|
||||
@@ -0,0 +1,18 @@
|
||||
#include "PingReq.hpp"
|
||||
|
||||
using AsyncMqttClientInternals::PingReqOutPacket;
|
||||
|
||||
PingReqOutPacket::PingReqOutPacket() {
|
||||
_data[0] = AsyncMqttClientInternals::PacketType.PINGREQ;
|
||||
_data[0] = _data[0] << 4;
|
||||
_data[0] = _data[0] | AsyncMqttClientInternals::HeaderFlag.PINGREQ_RESERVED;
|
||||
_data[1] = 0;
|
||||
}
|
||||
|
||||
const uint8_t* PingReqOutPacket::data(size_t index) const {
|
||||
return &_data[index];;
|
||||
}
|
||||
|
||||
size_t PingReqOutPacket::size() const {
|
||||
return 2;
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
#pragma once
|
||||
|
||||
#include "OutPacket.hpp"
|
||||
#include "../../Flags.hpp"
|
||||
#include "../../Helpers.hpp"
|
||||
|
||||
namespace AsyncMqttClientInternals {
|
||||
class PingReqOutPacket : public OutPacket {
|
||||
public:
|
||||
PingReqOutPacket();
|
||||
const uint8_t* data(size_t index = 0) const;
|
||||
size_t size() const;
|
||||
|
||||
private:
|
||||
uint8_t _data[2];
|
||||
};
|
||||
} // namespace AsyncMqttClientInternals
|
||||
@@ -0,0 +1,26 @@
|
||||
#include "PubAck.hpp"
|
||||
|
||||
using AsyncMqttClientInternals::PubAckOutPacket;
|
||||
|
||||
PubAckOutPacket::PubAckOutPacket(PendingAck pendingAck) {
|
||||
_data[0] = pendingAck.packetType;
|
||||
_data[0] = _data[0] << 4;
|
||||
_data[0] = _data[0] | pendingAck.headerFlag;
|
||||
_data[1] = 2;
|
||||
_packetId = pendingAck.packetId;
|
||||
_data[2] = pendingAck.packetId >> 8;
|
||||
_data[3] = pendingAck.packetId & 0xFF;
|
||||
_released = false;
|
||||
if (packetType() == AsyncMqttClientInternals::PacketType.PUBREL ||
|
||||
packetType() == AsyncMqttClientInternals::PacketType.PUBREC) {
|
||||
_released = false;
|
||||
}
|
||||
}
|
||||
|
||||
const uint8_t* PubAckOutPacket::data(size_t index) const {
|
||||
return &_data[index];
|
||||
}
|
||||
|
||||
size_t PubAckOutPacket::size() const {
|
||||
return 4;
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
#pragma once
|
||||
|
||||
#include "OutPacket.hpp"
|
||||
#include "../../Flags.hpp"
|
||||
#include "../../Helpers.hpp"
|
||||
#include "../../Storage.hpp"
|
||||
|
||||
namespace AsyncMqttClientInternals {
|
||||
class PubAckOutPacket : public OutPacket {
|
||||
public:
|
||||
explicit PubAckOutPacket(PendingAck pendingAck);
|
||||
const uint8_t* data(size_t index = 0) const;
|
||||
size_t size() const;
|
||||
|
||||
private:
|
||||
uint8_t _data[4];
|
||||
};
|
||||
} // namespace AsyncMqttClientInternals
|
||||
@@ -0,0 +1,69 @@
|
||||
#include "Publish.hpp"
|
||||
|
||||
using AsyncMqttClientInternals::PublishOutPacket;
|
||||
|
||||
PublishOutPacket::PublishOutPacket(const char* topic, uint8_t qos, bool retain, const char* payload, size_t length) {
|
||||
char fixedHeader[5];
|
||||
fixedHeader[0] = AsyncMqttClientInternals::PacketType.PUBLISH;
|
||||
fixedHeader[0] = fixedHeader[0] << 4;
|
||||
// if (dup) fixedHeader[0] |= AsyncMqttClientInternals::HeaderFlag.PUBLISH_DUP;
|
||||
if (retain) fixedHeader[0] |= AsyncMqttClientInternals::HeaderFlag.PUBLISH_RETAIN;
|
||||
switch (qos) {
|
||||
case 0:
|
||||
fixedHeader[0] |= AsyncMqttClientInternals::HeaderFlag.PUBLISH_QOS0;
|
||||
break;
|
||||
case 1:
|
||||
fixedHeader[0] |= AsyncMqttClientInternals::HeaderFlag.PUBLISH_QOS1;
|
||||
break;
|
||||
case 2:
|
||||
fixedHeader[0] |= AsyncMqttClientInternals::HeaderFlag.PUBLISH_QOS2;
|
||||
break;
|
||||
}
|
||||
|
||||
uint16_t topicLength = strlen(topic);
|
||||
char topicLengthBytes[2];
|
||||
topicLengthBytes[0] = topicLength >> 8;
|
||||
topicLengthBytes[1] = topicLength & 0xFF;
|
||||
|
||||
uint32_t payloadLength = length;
|
||||
if (payload != nullptr && payloadLength == 0) payloadLength = strlen(payload);
|
||||
|
||||
uint32_t remainingLength = 2 + topicLength + payloadLength;
|
||||
if (qos != 0) remainingLength += 2;
|
||||
uint8_t remainingLengthLength = AsyncMqttClientInternals::Helpers::encodeRemainingLength(remainingLength, fixedHeader + 1);
|
||||
|
||||
size_t neededSpace = 0;
|
||||
neededSpace += 1 + remainingLengthLength;
|
||||
neededSpace += 2;
|
||||
neededSpace += topicLength;
|
||||
if (qos != 0) neededSpace += 2;
|
||||
if (payload != nullptr) neededSpace += payloadLength;
|
||||
|
||||
_data.reserve(neededSpace);
|
||||
|
||||
_packetId = (qos !=0) ? _getNextPacketId() : 1;
|
||||
char packetIdBytes[2];
|
||||
packetIdBytes[0] = _packetId >> 8;
|
||||
packetIdBytes[1] = _packetId & 0xFF;
|
||||
|
||||
_data.insert(_data.end(), fixedHeader, fixedHeader + 1 + remainingLengthLength);
|
||||
_data.insert(_data.end(), topicLengthBytes, topicLengthBytes + 2);
|
||||
_data.insert(_data.end(), topic, topic + topicLength);
|
||||
if (qos != 0) {
|
||||
_data.insert(_data.end(), packetIdBytes, packetIdBytes + 2);
|
||||
_released = false;
|
||||
}
|
||||
if (payload != nullptr) _data.insert(_data.end(), payload, payload + payloadLength);
|
||||
}
|
||||
|
||||
const uint8_t* PublishOutPacket::data(size_t index) const {
|
||||
return &_data.data()[index];
|
||||
}
|
||||
|
||||
size_t PublishOutPacket::size() const {
|
||||
return _data.size();
|
||||
}
|
||||
|
||||
void PublishOutPacket::setDup() {
|
||||
_data[0] |= AsyncMqttClientInternals::HeaderFlag.PUBLISH_DUP;
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstring> // strlen
|
||||
#include <vector>
|
||||
|
||||
#include "OutPacket.hpp"
|
||||
#include "../../Flags.hpp"
|
||||
#include "../../Helpers.hpp"
|
||||
#include "../../Storage.hpp"
|
||||
|
||||
namespace AsyncMqttClientInternals {
|
||||
class PublishOutPacket : public OutPacket {
|
||||
public:
|
||||
PublishOutPacket(const char* topic, uint8_t qos, bool retain, const char* payload, size_t length);
|
||||
const uint8_t* data(size_t index = 0) const;
|
||||
size_t size() const;
|
||||
|
||||
void setDup(); // you cannot unset dup
|
||||
|
||||
private:
|
||||
std::vector<uint8_t> _data;
|
||||
};
|
||||
} // namespace AsyncMqttClientInternals
|
||||
@@ -0,0 +1,49 @@
|
||||
#include "Subscribe.hpp"
|
||||
|
||||
using AsyncMqttClientInternals::SubscribeOutPacket;
|
||||
|
||||
SubscribeOutPacket::SubscribeOutPacket(const char* topic, uint8_t qos) {
|
||||
char fixedHeader[5];
|
||||
fixedHeader[0] = AsyncMqttClientInternals::PacketType.SUBSCRIBE;
|
||||
fixedHeader[0] = fixedHeader[0] << 4;
|
||||
fixedHeader[0] = fixedHeader[0] | AsyncMqttClientInternals::HeaderFlag.SUBSCRIBE_RESERVED;
|
||||
|
||||
uint16_t topicLength = strlen(topic);
|
||||
char topicLengthBytes[2];
|
||||
topicLengthBytes[0] = topicLength >> 8;
|
||||
topicLengthBytes[1] = topicLength & 0xFF;
|
||||
|
||||
char qosByte[1];
|
||||
qosByte[0] = qos;
|
||||
|
||||
uint8_t remainingLengthLength = AsyncMqttClientInternals::Helpers::encodeRemainingLength(2 + 2 + topicLength + 1, fixedHeader + 1);
|
||||
|
||||
size_t neededSpace = 0;
|
||||
neededSpace += 1 + remainingLengthLength;
|
||||
neededSpace += 2;
|
||||
neededSpace += 2;
|
||||
neededSpace += topicLength;
|
||||
neededSpace += 1;
|
||||
|
||||
_data.reserve(neededSpace);
|
||||
|
||||
_packetId = _getNextPacketId();
|
||||
char packetIdBytes[2];
|
||||
packetIdBytes[0] = _packetId >> 8;
|
||||
packetIdBytes[1] = _packetId & 0xFF;
|
||||
|
||||
_data.insert(_data.end(), fixedHeader, fixedHeader + 1 + remainingLengthLength);
|
||||
_data.insert(_data.end(), packetIdBytes, packetIdBytes + 2);
|
||||
_data.insert(_data.end(), topicLengthBytes, topicLengthBytes + 2);
|
||||
_data.insert(_data.end(), topic, topic + topicLength);
|
||||
_data.push_back(qosByte[0]);
|
||||
_released = false;
|
||||
}
|
||||
|
||||
const uint8_t* SubscribeOutPacket::data(size_t index) const {
|
||||
return &_data.data()[index];
|
||||
}
|
||||
|
||||
size_t SubscribeOutPacket::size() const {
|
||||
return _data.size();
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstring> // strlen
|
||||
#include <vector>
|
||||
|
||||
#include "OutPacket.hpp"
|
||||
#include "../../Flags.hpp"
|
||||
#include "../../Helpers.hpp"
|
||||
#include "../../Storage.hpp"
|
||||
|
||||
namespace AsyncMqttClientInternals {
|
||||
class SubscribeOutPacket : public OutPacket {
|
||||
public:
|
||||
SubscribeOutPacket(const char* topic, uint8_t qos);
|
||||
const uint8_t* data(size_t index = 0) const;
|
||||
size_t size() const;
|
||||
|
||||
private:
|
||||
std::vector<uint8_t> _data;
|
||||
};
|
||||
} // namespace AsyncMqttClientInternals
|
||||
@@ -0,0 +1,42 @@
|
||||
#include "Unsubscribe.hpp"
|
||||
|
||||
using AsyncMqttClientInternals::UnsubscribeOutPacket;
|
||||
|
||||
UnsubscribeOutPacket::UnsubscribeOutPacket(const char* topic) {
|
||||
char fixedHeader[5];
|
||||
fixedHeader[0] = AsyncMqttClientInternals::PacketType.UNSUBSCRIBE;
|
||||
fixedHeader[0] = fixedHeader[0] << 4;
|
||||
fixedHeader[0] = fixedHeader[0] | AsyncMqttClientInternals::HeaderFlag.UNSUBSCRIBE_RESERVED;
|
||||
|
||||
uint16_t topicLength = strlen(topic);
|
||||
char topicLengthBytes[2];
|
||||
topicLengthBytes[0] = topicLength >> 8;
|
||||
topicLengthBytes[1] = topicLength & 0xFF;
|
||||
|
||||
uint8_t remainingLengthLength = AsyncMqttClientInternals::Helpers::encodeRemainingLength(2 + 2 + topicLength, fixedHeader + 1);
|
||||
|
||||
size_t neededSpace = 0;
|
||||
neededSpace += 1 + remainingLengthLength;
|
||||
neededSpace += 2;
|
||||
neededSpace += 2;
|
||||
neededSpace += topicLength;
|
||||
|
||||
_packetId = _getNextPacketId();
|
||||
char packetIdBytes[2];
|
||||
packetIdBytes[0] = _packetId >> 8;
|
||||
packetIdBytes[1] = _packetId & 0xFF;
|
||||
|
||||
_data.insert(_data.end(), fixedHeader, fixedHeader + 1 + remainingLengthLength);
|
||||
_data.insert(_data.end(), packetIdBytes, packetIdBytes + 2);
|
||||
_data.insert(_data.end(), topicLengthBytes, topicLengthBytes + 2);
|
||||
_data.insert(_data.end(), topic, topic + topicLength);
|
||||
_released = false;
|
||||
}
|
||||
|
||||
const uint8_t* UnsubscribeOutPacket::data(size_t index) const {
|
||||
return &_data.data()[index];
|
||||
}
|
||||
|
||||
size_t UnsubscribeOutPacket::size() const {
|
||||
return _data.size();
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstring> // strlen
|
||||
#include <vector>
|
||||
|
||||
#include "OutPacket.hpp"
|
||||
#include "../../Flags.hpp"
|
||||
#include "../../Helpers.hpp"
|
||||
#include "../../Storage.hpp"
|
||||
|
||||
namespace AsyncMqttClientInternals {
|
||||
class UnsubscribeOutPacket : public OutPacket {
|
||||
public:
|
||||
explicit UnsubscribeOutPacket(const char* topic);
|
||||
const uint8_t* data(size_t index = 0) const;
|
||||
size_t size() const;
|
||||
|
||||
private:
|
||||
std::vector<uint8_t> _data;
|
||||
};
|
||||
} // namespace AsyncMqttClientInternals
|
||||
@@ -16,8 +16,7 @@ PublishPacket::PublishPacket(ParsingInformation* parsingInformation, OnMessageIn
|
||||
, _packetIdMsb(0)
|
||||
, _packetId(0)
|
||||
, _payloadLength(0)
|
||||
, _payloadBytesRead(0)
|
||||
, _ptempbuff(0) {
|
||||
, _payloadBytesRead(0) {
|
||||
_dup = _parsingInformation->packetFlags & HeaderFlag.PUBLISH_DUP;
|
||||
_retain = _parsingInformation->packetFlags & HeaderFlag.PUBLISH_RETAIN;
|
||||
char qosMasked = _parsingInformation->packetFlags & 0x06;
|
||||
@@ -79,36 +78,14 @@ void PublishPacket::_preparePayloadHandling(uint32_t payloadLength) {
|
||||
|
||||
void PublishPacket::parsePayload(char* data, size_t len, size_t* currentBytePosition) {
|
||||
size_t remainToRead = len - (*currentBytePosition);
|
||||
if (_payloadBytesRead + remainToRead > _payloadLength)
|
||||
remainToRead = _payloadLength - _payloadBytesRead;
|
||||
if (!_ignore) {
|
||||
if (remainToRead < _payloadLength) {
|
||||
if (!_ptempbuff) {
|
||||
_ptempbuff = new char[_payloadLength + 1];
|
||||
if (_ptempbuff == nullptr) {
|
||||
_ignore = true;
|
||||
return;
|
||||
}
|
||||
memset(_ptempbuff, 0, _payloadLength + 1);
|
||||
memcpy(&_ptempbuff[_payloadBytesRead], &data[(*currentBytePosition)], remainToRead);
|
||||
} else {
|
||||
memcpy(&_ptempbuff[_payloadBytesRead], &data[(*currentBytePosition)], remainToRead);
|
||||
if ((_payloadBytesRead + remainToRead) == _payloadLength) {
|
||||
_dataCallback(_parsingInformation->topicBuffer, _ptempbuff, _qos, _dup, _retain, _payloadLength, 0, _payloadLength, _packetId);
|
||||
delete[] _ptempbuff;
|
||||
_ptempbuff = NULL;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
_dataCallback(_parsingInformation->topicBuffer, &data[(*currentBytePosition)], _qos, _dup, _retain, remainToRead, _payloadBytesRead, _payloadLength, _packetId);
|
||||
}
|
||||
}
|
||||
if (_payloadBytesRead + remainToRead > _payloadLength) remainToRead = _payloadLength - _payloadBytesRead;
|
||||
|
||||
if (!_ignore) _dataCallback(_parsingInformation->topicBuffer, data + (*currentBytePosition), _qos, _dup, _retain, remainToRead, _payloadBytesRead, _payloadLength, _packetId);
|
||||
_payloadBytesRead += remainToRead;
|
||||
(*currentBytePosition) += remainToRead;
|
||||
|
||||
if (_payloadBytesRead == _payloadLength) {
|
||||
_parsingInformation->bufferState = BufferState::NONE;
|
||||
if (!_ignore)
|
||||
_completeCallback(_packetId, _qos);
|
||||
if (!_ignore) _completeCallback(_packetId, _qos);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,6 +34,5 @@ class PublishPacket : public Packet {
|
||||
uint16_t _packetId;
|
||||
uint32_t _payloadLength;
|
||||
uint32_t _payloadBytesRead;
|
||||
char* _ptempbuff;
|
||||
};
|
||||
} // namespace AsyncMqttClientInternals
|
||||
|
||||
Reference in New Issue
Block a user