Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix errors with publishing and minor changes. #7

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
96 changes: 80 additions & 16 deletions MqttSnClient.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@
template<class MqttSnMessageHandler_SocketInterface>
class MqttSnMessageHandler;


struct topic_registration {
char *topic_name;
uint16_t topic_id;
Expand Down Expand Up @@ -158,9 +157,10 @@ class MqttSnClient {
return true;
}

// Publish using normal topic
bool publish(char *payload, char *topic_name, int8_t qos) {

// check if payload is not too long
// N.B Short topics not handled
// check if payload is not too long
uint16_t payload_length = 0;
uint8_t msg_publish_without_payload_length = 7;
if (strlen(payload) + 1 > socketInterface.getMaximumMessageLength() - msg_publish_without_payload_length) {
Expand All @@ -185,23 +185,28 @@ class MqttSnClient {
}
}
}

// check if topic_name is already registered
uint16_t topic_id = 0;
if (this->registration.topic_name == topic_name) {
uint8_t topic_type = REGISTERED; // normal
uint16_t topic_id = 0;
if (strlen(topic_name) != 2) {
// check if topic_name is already registered
if (this->registration.topic_name == topic_name) {
topic_id = registration.topic_id;
} else if (this->publish_registration.topic_name == topic_name) {
} else if (this->publish_registration.topic_name == topic_name) {
topic_id = publish_registration.topic_id;
} else {
} else {
// it is not registered - register it now
topic_id = register_topic(topic_name);
}
if (topic_id == 0) {
}
if (topic_id == 0) {
// TODO check if compatible or if gateway deliveres 0 too (then change return type of register_topic)
return false;
}
publish_registration.topic_id = topic_id;

}
publish_registration.topic_id = topic_id;
}
else { // short topic
topic_id = (uint16_t)((topic_name[1] << 8) | topic_name[0]);
topic_type = SHORTTOPIC;
}

uint16_t msg_id = this->increment_and_get_msg_id_counter();
if (qos == 0) {
Expand All @@ -211,8 +216,8 @@ class MqttSnClient {
this->set_await_message(MQTTSN_PUBACK);
}

mqttSnMessageHandler.send_publish(&gw_address, (uint8_t *) payload, payload_length, msg_id, topic_id, true,
false, qos, false);
mqttSnMessageHandler.send_publish(&gw_address, (uint8_t *) payload, payload_length, msg_id,
topic_id, topic_type, false, qos, false);
if (qos > 0) {
while (this->await_msg_type != MQTTSN_PINGREQ) {
// wait until we have no other messages in flight
Expand All @@ -224,6 +229,65 @@ class MqttSnClient {
return true;
}

// Publish using pre-defined topic
bool publish(char *payload, uint16_t predef_topic_id, int8_t qos) {

// check if payload is not too long
uint16_t payload_length = 0;
uint8_t msg_publish_without_payload_length = 7;
if (strlen(payload) + 1 > socketInterface.getMaximumMessageLength() - msg_publish_without_payload_length) {
// payload is too long
return false;
}
payload_length = strlen(payload) + 1;
if (qos == 2) {
// TODO not implemented yet
return false;
}
if (qos < -1 || qos > 2) {
// invalid qos
return false;
}

if (qos > 0) {
while (this->await_msg_type != MQTTSN_PINGREQ) {
// wait until we have no other messages are in flight
if (!socketInterface.loop()) {
return false;
}
}
}

// check if topic_name is already registered
uint16_t topic_id = 0;
if (predef_topic_id != 0) {
topic_id = (uint16_t)((predef_topic_id >> 8) | (predef_topic_id << 8)); // swap high/low bytes
}
else {
return false;
}

uint16_t msg_id = this->increment_and_get_msg_id_counter();
if (qos == 0) {
msg_id = 0;
}
if (qos == 1) {
this->set_await_message(MQTTSN_PUBACK);
}

mqttSnMessageHandler.send_publish(&gw_address, (uint8_t *) payload, payload_length, msg_id,
topic_id, PREDEFINED, false, qos, false); // RJM
if (qos > 0) {
while (this->await_msg_type != MQTTSN_PINGREQ) {
// wait until we have no other messages in flight
if (!socketInterface.loop()) {
return false;
}
}
}
return true;
}

uint16_t register_topic(char *topic_name) {
while (this->await_msg_type != MQTTSN_PINGREQ) {
// wait until we have no other messages in flight
Expand Down
4 changes: 2 additions & 2 deletions MqttSnMessageHandler.h
Original file line number Diff line number Diff line change
Expand Up @@ -247,8 +247,8 @@ class MqttSnMessageHandler {


void send_publish(device_address *address, uint8_t *data, uint8_t data_len, uint16_t msg_id,
uint16_t topic_id, bool short_topic, bool retain, uint8_t qos, bool dup) {
msg_publish to_send(dup, qos, retain, short_topic, topic_id, msg_id, data, data_len);
uint16_t topic_id, uint8_t topic_type, bool retain, uint8_t qos, bool dup) {
msg_publish to_send(dup, qos, retain, topic_type, topic_id, msg_id, data, data_len);
if (!socketInterface.send(address, (uint8_t *) &to_send, (uint16_t) to_send.length)) {
mqttSnClient.notify_socket_disconnected();
}
Expand Down
60 changes: 60 additions & 0 deletions Readme-topics-info.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
Topics and Topic IDs - Excerpts from the MQTT-SN standard.
--------------------

TopicIdType:indicates whether the field TopicId or TopicName included in this
message contains a:

+ a normal topic id (set to “0b00”),
+ pre-defined topic id (set to “0b01”),
+ short topic name (set to “0b10”).

The value “0b11” is reserved.

Refer to sections 3 and 6.7 for the definition of the various types of topic ids.

“Pre-defined” topic ids and “short” topic names are introduced, for which no
registration is required. Pre-defined topic ids are also a two-byte long
replacement of the topic name, their mapping to the topic names is however
known in advance by both the client’s application and the
gateway/server. Therefore both sides can start using pre-defined topic ids;
there is no need for a registration as in the case of “normal” topic ids
mentioned above.

Short topic names are topic names that have a fixed length of two octets.
They are short enough for being carried together with the data within PUBLISH
messages. As for pre-defined topic ids, there is also no need for a
registration for short topic names

6.7 Pre-defined topic ids and short topic names. As described in Section 6.5,
a topic id is a two-byte long replacement of the string-based topic name. A
client needs to use the REGISTER procedure to inform the gateway about the
topic name it wants to employ and gets from the gateway the corresponding
topic id. It then will use this topic id in the PUBLISH messages it sends to
the gateway. In the opposite direction, the PUBLISH messages also contain a
2-byte topic id (instead of the string-based topic name). The client is
informed about the relation between topic id and topic name by means of
either a former SUBSCRIBE procedure or a REGISTER procedure started by the
gateway

A “pre-defined” topic id is a topic id whose mapping to a topic name is known
in advance by both the client’s application and the gateway. This is
indicated in the Flags field of the message. When using pre-defined topic ids
both sides can start immediately with the sending of PUBLISH messages; there
is no need for the REGISTER procedure as in the case of ”normal” topic
ids. When receiving a PUBLISH message with a pre-defined topic id of which
the mapping to a topic name is unknown, the receiver should return a PUBACK
with the ReturnCode = “Rejection: invalid topic Id”. Note that this error
situation cannot be resolved by means of re-registering as in the case of
normal topic id. A client is still required to subscribe to a pre-defined
topic id, if it wants to receive PUBLISH messages relating to that topic id.
To avoid confusion between a pre-defined topic id and a two-byte short topic
name, the SUBSCRIBE message contains a flag indicating whether it is
subscribing for a short topic name or a pre-defined topic id. A “short” topic
name is a topic name that has a fixed length of two octets. It could be
carried together with the data within a PUBLISH message, thus no REGISTER
procedure is needed for a short topic name. Otherwise, all rules that apply
to normal topic names also apply to short topic names. Note however that it
does not make sense to do wildcarding in subscriptions to short topic names,
because it is not possible to define a meaningful name hierarchy with only
two characters.

2 changes: 1 addition & 1 deletion System.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ void System::sleep(uint32_t duration) {
}

void System::exit() {
#if defined(ESP8266)
#if defined(ESP8266) or defined(ESP32)
ESP.restart();
#elif defined(ARDUINO_AVR_UNO) || defined(ARDUINO_AVR_YUN) || defined(ARDUINO_AVR_MEGA2560)
asm volatile (" jmp 0");
Expand Down
6 changes: 3 additions & 3 deletions TransmissionProtocolUartBridge.h
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ enum CONFIGURATION_STATUS {
// #define PARSERDATADEBUG
// #define PARSERADDRESSDEBUG
#define SERIAL_BUFFER_SIZE 200
#define RECEIVE_BUFFER_SIZE 64
#define RECEIVE_BUFFER_SZ 64
#define SEND_BUFFER_SIZE 64

template<class TransmissionProtocolUartBridge_SocketInterface>
Expand Down Expand Up @@ -93,7 +93,7 @@ class TransmissionProtocolUartBridge {

// ReceiveBuffer
device_address receive_address;
uint8_t receive_buffer[RECEIVE_BUFFER_SIZE];
uint8_t receive_buffer[RECEIVE_BUFFER_SZ];
uint16_t receive_buffer_length = 0;
Stream *stream;

Expand Down Expand Up @@ -178,7 +178,7 @@ class TransmissionProtocolUartBridge {
}

void resetChip() {
#if defined(ESP8266)
#if defined(ESP8266) or defined(ESP32) // RJM
stream->print(F("OK RESET\n"));
delay(500);
ESP.restart();
Expand Down
6 changes: 5 additions & 1 deletion WiFiUdpSocket.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,11 @@

#include "MqttSnMessageHandler.h"
#include "SocketInterface.h"
#ifdef ESP32
#include <WiFi.h>
#else
#include <ESP8266WiFi.h>
#endif
#include <WiFiUdp.h>

#define RECEIVE_BUFFER_SIZE 255
Expand Down Expand Up @@ -40,7 +44,7 @@ class WiFiUdpSocket : SocketInterface {

device_address *getAddress() override {
IPAddress localIP = WiFi.localIP();
uint16_t localPort = wiFiUdp.localPort();
uint16_t localPort = port;
convertIPAddressAndPortToDeviceAddress(localIP, localPort, own_address);
return &own_address;
}
Expand Down
19 changes: 14 additions & 5 deletions mqttsn_messages.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,11 @@ THE SOFTWARE.
#include "global_defines.h"
#include <stdint.h>

// Types of topic IDs
#define REGISTERED 0 // registered in this session
#define PREDEFINED 1 // known to gateway (no need to register)
#define SHORTTOPIC 2 // only two characters (no need to register)

#define PROTOCOL_ID 0x01

#define FLAG_NO_FLAGS 0x00
Expand Down Expand Up @@ -277,7 +282,7 @@ struct msg_publish : public message_header {
uint16_t message_id;
uint8_t data[UINT8_MAX - 7];

msg_publish(bool dup, int8_t qos, bool retain, bool short_topic, uint16_t topic_id, uint16_t msg_id,
msg_publish(bool dup, int8_t qos, bool retain, uint8_t topic_type, uint16_t topic_id, uint16_t msg_id,
const uint8_t *s_data, uint8_t s_data_len) : topic_id(topic_id), message_id(msg_id) {
memset(this, 0, sizeof(this));
this->length = ((uint8_t) 7) + s_data_len;
Expand All @@ -289,10 +294,14 @@ struct msg_publish : public message_header {
if (retain) {
this->flags |= FLAG_RETAIN;
}
if (short_topic) {
this->flags |= FLAG_TOPIC_SHORT_NAME;
} else {
this->flags |= FLAG_TOPIC_PREDEFINED_ID;
if (topic_type == REGISTERED) {
this->flags |= FLAG_TOPIC_NAME; // Normal
}
else if (topic_type == PREDEFINED) { // Previously known to gateway
this->flags |= FLAG_TOPIC_PREDEFINED_ID;
}
else if (topic_type == SHORTTOPIC) { // Short topic
this->flags |= FLAG_TOPIC_SHORT_NAME;
}
if (qos == 0) {
this->flags |= FLAG_QOS_0;
Expand Down