初始提交
This commit is contained in:
37
dtest/mqtt_test/Makefile
Executable file
37
dtest/mqtt_test/Makefile
Executable file
@@ -0,0 +1,37 @@
|
||||
|
||||
# OUTPUT type
|
||||
# 1 - .out
|
||||
# 2 - .a
|
||||
# 3 - .so
|
||||
OUTPUT_TYPE = 0
|
||||
OUTPUT_NAME = mqtt
|
||||
|
||||
SUB_DIRS += src
|
||||
|
||||
|
||||
# predefined macro
|
||||
PRE_MARCO +=
|
||||
|
||||
# lib dir
|
||||
ADD_LIBDIR =
|
||||
|
||||
# lib need to ld together
|
||||
ADD_LIB =
|
||||
|
||||
ifdef TOPDIR
|
||||
include $(TOPDIR)/build/makefile.cfg
|
||||
else
|
||||
include $(CURDIR)/build/makefile.cfg
|
||||
TOPDIR = $(CURDIR)
|
||||
export TOPDIR
|
||||
endif
|
||||
|
||||
# display the obj files and output name
|
||||
debug:
|
||||
@echo TOPDIR=$(TOPDIR)
|
||||
@echo OUTPUT_LIB=$(OUTPUT_FULL_NAME)
|
||||
@echo DEPS=$(DEPS)
|
||||
@echo OBJECTS=$(OBJECTS)
|
||||
@echo SRCS=$(SRCS)
|
||||
@echo OBJECTS folder=$(foreach dirname, $(SUB_DIRS), $(addprefix $(BIN_DIR)/, $(dirname)))
|
||||
@echo output_name=$(OUTPUT_FULL_NAME)
|
58
dtest/mqtt_test/include/helpers.h
Executable file
58
dtest/mqtt_test/include/helpers.h
Executable file
@@ -0,0 +1,58 @@
|
||||
#ifndef LWMQTT_HELPERS_H
|
||||
#define LWMQTT_HELPERS_H
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
#include <lwmqtt.h>
|
||||
|
||||
/**
|
||||
* Reads a string object from the buffer and populates the passed object.
|
||||
*
|
||||
* @param str - The object into which the data is to be read.
|
||||
* @param pptr - Pointer to the output buffer - incremented by the number of bytes used & returned.
|
||||
* @param end_ptr - Pointer to the end of the data: do not read beyond.
|
||||
* @return One if successful, zero if not.
|
||||
*/
|
||||
bool lwmqtt_read_string(lwmqtt_string_t *str, unsigned char **pptr, unsigned char *end_ptr);
|
||||
|
||||
/**
|
||||
* Writes a string to an output buffer.
|
||||
*
|
||||
* @param pptr - Pointer to the output buffer - incremented by the number of bytes used & returned.
|
||||
* @param The string to write.
|
||||
*/
|
||||
void lwmqtt_write_string(unsigned char **pptr, lwmqtt_string_t string);
|
||||
|
||||
/**
|
||||
* Calculates an integer from two bytes read from the input buffer.
|
||||
*
|
||||
* @param pptr - Pointer to the input buffer - incremented by the number of bytes used & returned.
|
||||
* @return The integer value calculated.
|
||||
*/
|
||||
int lwmqtt_read_int(unsigned char **pptr);
|
||||
|
||||
/**
|
||||
* Reads one character from the input buffer.
|
||||
*
|
||||
* @param pptr - Pointer to the input buffer - incremented by the number of bytes used & returned.
|
||||
* @return The character read.
|
||||
*/
|
||||
unsigned char lwmqtt_read_char(unsigned char **pptr);
|
||||
|
||||
/**
|
||||
* Writes one character to an output buffer.
|
||||
*
|
||||
* @param pptr - Pointer to the output buffer - incremented by the number of bytes used & returned.
|
||||
* @param The character to write
|
||||
*/
|
||||
void lwmqtt_write_char(unsigned char **pptr, unsigned char chr);
|
||||
|
||||
/**
|
||||
* Writes an integer as 2 bytes to an output buffer.
|
||||
*
|
||||
* @param pptr - Pointer to the output buffer - incremented by the number of bytes used & returned.
|
||||
* @param The integer to write.
|
||||
*/
|
||||
void lwmqtt_write_int(unsigned char **pptr, int num);
|
||||
|
||||
#endif
|
318
dtest/mqtt_test/include/lwmqtt.h
Executable file
318
dtest/mqtt_test/include/lwmqtt.h
Executable file
@@ -0,0 +1,318 @@
|
||||
#ifndef LWMQTT_H
|
||||
#define LWMQTT_H
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
/**
|
||||
* The error type used by all exposed APIs.
|
||||
*/
|
||||
typedef enum {
|
||||
LWMQTT_SUCCESS = 0,
|
||||
LWMQTT_UNANSWERED_PIN = -1,
|
||||
LWMQTT_BUFFER_TOO_SHORT = -2,
|
||||
LWMQTT_REMAINING_LENGTH_OVERFLOW = -3,
|
||||
LWMQTT_LENGTH_MISMATCH = -4,
|
||||
LWMQTT_NOT_ENOUGH_DATA = -5,
|
||||
LWMQTT_NETWORK_CONNECT_ERROR = -6,
|
||||
LWMQTT_NETWORK_READ_ERROR = -7,
|
||||
LWMQTT_NETWORK_WRITE_ERR = -8,
|
||||
LWMQTT_NO_OR_WRONG_PACKET = -9,
|
||||
LWMQTT_CONNECTION_DENIED = -10,
|
||||
LWMQTT_DECODE_ERROR = -11
|
||||
} lwmqtt_err_t;
|
||||
|
||||
/**
|
||||
* A multi value string. Can be either a C string or a length prefixed string.
|
||||
*/
|
||||
typedef struct {
|
||||
int len;
|
||||
char *data;
|
||||
} lwmqtt_string_t;
|
||||
|
||||
/**
|
||||
* The initializer for string objects.
|
||||
*/
|
||||
#define lwmqtt_default_string \
|
||||
{ 0, NULL }
|
||||
|
||||
/**
|
||||
* Return a string object for the passed C string.
|
||||
*
|
||||
* @param str - The C string.
|
||||
* @return A string object.
|
||||
*/
|
||||
lwmqtt_string_t lwmqtt_str(const char *str);
|
||||
|
||||
/**
|
||||
* Compares a string object to a C string.
|
||||
*
|
||||
* @param a - The string object to compare.
|
||||
* @param b - The C string to compare.
|
||||
* @return Similarity e.g. strcmp().
|
||||
*/
|
||||
int lwmqtt_strcmp(lwmqtt_string_t *a, char *b);
|
||||
|
||||
/**
|
||||
* The available QOS levels.
|
||||
*/
|
||||
typedef enum { LWMQTT_QOS0 = 0, LWMQTT_QOS1 = 1, LWMQTT_QOS2 = 2 } lwmqtt_qos_t;
|
||||
|
||||
/**
|
||||
* The message object used to publish and receive messages.
|
||||
*/
|
||||
typedef struct {
|
||||
lwmqtt_qos_t qos;
|
||||
bool retained;
|
||||
void *payload;
|
||||
int payload_len;
|
||||
} lwmqtt_message_t;
|
||||
|
||||
/**
|
||||
* The initializer for messages objects.
|
||||
*/
|
||||
#define lwmqtt_default_message \
|
||||
{ LWMQTT_QOS0, false, NULL, 0 }
|
||||
|
||||
/**
|
||||
* Forward declaration of the client object.
|
||||
*/
|
||||
typedef struct lwmqtt_client_t lwmqtt_client_t;
|
||||
|
||||
/**
|
||||
* The callback used to read from a network object.
|
||||
*
|
||||
* The callbacks is expected to read up to the amount of bytes in to the passed buffer. It should block the specified
|
||||
* timeout and wait for more incoming data. It may set read to zero if no data is has been read.
|
||||
*/
|
||||
typedef lwmqtt_err_t (*lwmqtt_network_read_t)(lwmqtt_client_t *c, void *ref, unsigned char *buf, int len, int *read,
|
||||
unsigned int timeout);
|
||||
|
||||
/**
|
||||
* The callback used to write to a network object.
|
||||
*
|
||||
* The callback is expected to write up to the amount of bytes from the passed buffer. It should wait up to the
|
||||
* specified timeout to write the specified data to the network.
|
||||
*/
|
||||
typedef lwmqtt_err_t (*lwmqtt_network_write_t)(lwmqtt_client_t *c, void *ref, unsigned char *buf, int len, int *sent,
|
||||
unsigned int timeout);
|
||||
|
||||
/**
|
||||
* The callback used to set a timer.
|
||||
*/
|
||||
typedef void (*lwmqtt_timer_set_t)(lwmqtt_client_t *c, void *ref, unsigned int timeout);
|
||||
|
||||
/**
|
||||
* The callback used to get a timers value.
|
||||
*/
|
||||
typedef unsigned int (*lwmqtt_timer_get_t)(lwmqtt_client_t *c, void *ref);
|
||||
|
||||
/**
|
||||
* The callback used to forward incoming messages.
|
||||
*
|
||||
* Note: The callback is mostly executed because of a call to lwmqtt_yield() that processes incoming messages. However,
|
||||
* it is possible that the callback is also executed during a call to lwmqtt_subscribe(), lwmqtt_publish() or
|
||||
* lwmqtt_unsubscribe() if incoming messages are received between the required acknowledgements. It is therefore not
|
||||
* recommended to call any further lwmqtt methods in the callback as this might result in weird call stacks. The
|
||||
* callback should place the received messages in a queue and dispatch them after the caller has returned.
|
||||
*/
|
||||
typedef void (*lwmqtt_callback_t)(lwmqtt_client_t *, void *ref, lwmqtt_string_t *, lwmqtt_message_t *);
|
||||
|
||||
/**
|
||||
* The client object.
|
||||
*/
|
||||
struct lwmqtt_client_t {
|
||||
unsigned short next_packet_id;
|
||||
unsigned int keep_alive_interval;
|
||||
bool ping_outstanding;
|
||||
|
||||
int write_buf_size, read_buf_size;
|
||||
unsigned char *write_buf, *read_buf;
|
||||
|
||||
void *callback_ref;
|
||||
lwmqtt_callback_t callback;
|
||||
|
||||
void *network;
|
||||
lwmqtt_network_read_t network_read;
|
||||
lwmqtt_network_write_t network_write;
|
||||
|
||||
void *keep_alive_timer;
|
||||
void *command_timer;
|
||||
lwmqtt_timer_set_t timer_set;
|
||||
lwmqtt_timer_get_t timer_get;
|
||||
};
|
||||
|
||||
/**
|
||||
* Will initialize the specified client object.
|
||||
*
|
||||
* @param client - The client object.
|
||||
* @param write_buf - The write buffer.
|
||||
* @param write_buf_size - The write buffer size.
|
||||
* @param read_buf - The read buffer.
|
||||
* @param read_buf_size - The read buffer size.
|
||||
*/
|
||||
void lwmqtt_init(lwmqtt_client_t *client, unsigned char *write_buf, int write_buf_size, unsigned char *read_buf,
|
||||
int read_buf_size);
|
||||
|
||||
/**
|
||||
* Will set the network reference and callbacks for this client object.
|
||||
*
|
||||
* @param client - The client object.
|
||||
* @param ref - The reference to the network object.
|
||||
* @param read - The read callback.
|
||||
* @param write - The write callback.
|
||||
*/
|
||||
void lwmqtt_set_network(lwmqtt_client_t *client, void *ref, lwmqtt_network_read_t read, lwmqtt_network_write_t write);
|
||||
|
||||
/**
|
||||
* Will set the timer references and callbacks for this client objects.
|
||||
*
|
||||
* @param client - The client object.
|
||||
* @param keep_alive_timer - The reference to the keep alive timer.
|
||||
* @param network_timer - The reference to the network timer.
|
||||
* @param set - The set callback.
|
||||
* @param get - The get callback.
|
||||
*/
|
||||
void lwmqtt_set_timers(lwmqtt_client_t *client, void *keep_alive_timer, void *network_timer, lwmqtt_timer_set_t set,
|
||||
lwmqtt_timer_get_t get);
|
||||
|
||||
/**
|
||||
* Will set the callback used to receive incoming messages.
|
||||
*
|
||||
* @param client - The client object.
|
||||
* @param ref - A custom reference that will passed to the callback.
|
||||
* @param cb - The callback to be called.
|
||||
*/
|
||||
void lwmqtt_set_callback(lwmqtt_client_t *client, void *ref, lwmqtt_callback_t cb);
|
||||
|
||||
/**
|
||||
* The object defining the last will of a client.
|
||||
*/
|
||||
typedef struct {
|
||||
lwmqtt_string_t topic;
|
||||
lwmqtt_message_t message;
|
||||
} lwmqtt_will_t;
|
||||
|
||||
/**
|
||||
* The default initializer for the will object.
|
||||
*/
|
||||
#define lwmqtt_default_will \
|
||||
{ lwmqtt_default_string, lwmqtt_default_message }
|
||||
|
||||
/**
|
||||
* The object containing the connections options for a client.
|
||||
*/
|
||||
typedef struct {
|
||||
lwmqtt_string_t client_id;
|
||||
unsigned short keep_alive;
|
||||
bool clean_session;
|
||||
lwmqtt_string_t username;
|
||||
lwmqtt_string_t password;
|
||||
} lwmqtt_options_t;
|
||||
|
||||
/**
|
||||
* The default initializer for the options object.
|
||||
*/
|
||||
#define lwmqtt_default_options \
|
||||
{ lwmqtt_default_string, 60, 1, lwmqtt_default_string, lwmqtt_default_string }
|
||||
|
||||
/**
|
||||
* The available return codes transported by the connack packet.
|
||||
*/
|
||||
typedef enum {
|
||||
LWMQTT_CONNACK_CONNECTION_ACCEPTED = 0,
|
||||
LWMQTT_CONNACK_UNACCEPTABLE_PROTOCOL = 1,
|
||||
LWMQTT_CONNACK_IDENTIFIER_REJECTED = 2,
|
||||
LWMQTT_CONNACK_SERVER_UNAVAILABLE = 3,
|
||||
LWMQTT_CONNACK_BAD_USERNAME_OR_PASSWORD = 4,
|
||||
LWMQTT_CONNACK_NOT_AUTHORIZED = 5
|
||||
} lwmqtt_return_code_t;
|
||||
|
||||
/**
|
||||
* Will send a connect packet and wait for a connack response and set the return code.
|
||||
*
|
||||
* The network object must already be connected to the server. An error is returned if the broker rejects the
|
||||
* connection.
|
||||
*
|
||||
* @param client - The client object.
|
||||
* @param options - The options object.
|
||||
* @param will - The will object.
|
||||
* @param timeout - The command timeout.
|
||||
* @return An error value.
|
||||
*/
|
||||
lwmqtt_err_t lwmqtt_connect(lwmqtt_client_t *client, lwmqtt_options_t *options, lwmqtt_will_t *will,
|
||||
lwmqtt_return_code_t *return_code, unsigned int timeout);
|
||||
|
||||
/**
|
||||
* Will send a publish packet and wait for all acks to complete.
|
||||
*
|
||||
* Note: The message callback might be called with incoming messages as part of this call.
|
||||
*
|
||||
* @param client - The client object.
|
||||
* @param topic - The topic.
|
||||
* @param message - The message.
|
||||
* @param timeout - The command timeout.
|
||||
* @return An error value.
|
||||
*/
|
||||
lwmqtt_err_t lwmqtt_publish(lwmqtt_client_t *client, const char *topic, lwmqtt_message_t *msg, unsigned int timeout);
|
||||
|
||||
/**
|
||||
* Will send a subscribe packet with a single topic filter plus qos level and wait for the suback to complete.
|
||||
*
|
||||
* Note: The message callback might be called with incoming messages as part of this call.
|
||||
*
|
||||
* @param client - The client object.
|
||||
* @param topic_filter - The topic filter.
|
||||
* @param qos - The QoS level.
|
||||
* @param timeout - The command timeout.
|
||||
* @return An error value.
|
||||
*/
|
||||
lwmqtt_err_t lwmqtt_subscribe(lwmqtt_client_t *client, const char *topic_filter, lwmqtt_qos_t qos,
|
||||
unsigned int timeout);
|
||||
|
||||
/**
|
||||
* Will send an unsubscribe packet and wait for the unsuback to complete.
|
||||
*
|
||||
* Note: The message callback might be called with incoming messages as part of this call.
|
||||
*
|
||||
* @param client - The client object.
|
||||
* @param topic_filter - The topic filter.
|
||||
* @param timeout - The command timeout.
|
||||
* @return An error value.
|
||||
*/
|
||||
lwmqtt_err_t lwmqtt_unsubscribe(lwmqtt_client_t *client, const char *topic_filter, unsigned int timeout);
|
||||
|
||||
/**
|
||||
* Will send a disconnect packet and finish the client.
|
||||
*
|
||||
* @param client - The client object.
|
||||
* @param timeout - The command timeout.
|
||||
* @return An error value.
|
||||
*/
|
||||
lwmqtt_err_t lwmqtt_disconnect(lwmqtt_client_t *client, unsigned int timeout);
|
||||
|
||||
/**
|
||||
* Will yield control to the client and receive incoming packets from the network.
|
||||
*
|
||||
* Applications may peek on the network if there is data available to read before calling yield and potentially block
|
||||
* until the timeout is reached. Furthermore, applications may specify the amount of bytes available to read in order
|
||||
* to constrain the yield to only receive packets that are already inflight.
|
||||
*
|
||||
* Note: The message callback might be called with incoming messages as part of this call.
|
||||
*
|
||||
* @param client - The client object.
|
||||
* @param available - The available bytes to read.
|
||||
* @param timeout - The command timeout.
|
||||
* @return An error value.
|
||||
*/
|
||||
lwmqtt_err_t lwmqtt_yield(lwmqtt_client_t *client, unsigned int available, unsigned int timeout);
|
||||
|
||||
/**
|
||||
* Will yield control to the client to keep the connection alive.
|
||||
*
|
||||
* @param client - The client object.
|
||||
* @param timeout - The command timeout.
|
||||
* @return An error value.
|
||||
*/
|
||||
lwmqtt_err_t lwmqtt_keep_alive(lwmqtt_client_t *client, unsigned int timeout);
|
||||
|
||||
#endif // LWMQTT_H
|
195
dtest/mqtt_test/include/packet.h
Executable file
195
dtest/mqtt_test/include/packet.h
Executable file
@@ -0,0 +1,195 @@
|
||||
#ifndef LWMQTT_PACKET_H
|
||||
#define LWMQTT_PACKET_H
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
#include <lwmqtt.h>
|
||||
|
||||
#include "helpers.h"
|
||||
|
||||
/**
|
||||
* The available packet types.
|
||||
*/
|
||||
typedef enum {
|
||||
LWMQTT_NO_PACKET = 0,
|
||||
LWMQTT_CONNECT_PACKET = 1,
|
||||
LWMQTT_CONNACK_PACKET,
|
||||
LWMQTT_PUBLISH_PACKET,
|
||||
LWMQTT_PUBACK_PACKET,
|
||||
LWMQTT_PUBREC_PACKET,
|
||||
LWMQTT_PUBREL_PACKET,
|
||||
LWMQTT_PUBCOMP_PACKET,
|
||||
LWMQTT_SUBSCRIBE_PACKET,
|
||||
LWMQTT_SUBACK_PACKET,
|
||||
LWMQTT_UNSUBSCRIBE_PACKET,
|
||||
LWMQTT_UNSUBACK_PACKET,
|
||||
LWMQTT_PINGREQ_PACKET,
|
||||
LWMQTT_PINGRESP_PACKET,
|
||||
LWMQTT_DISCONNECT_PACKET
|
||||
} lwmqtt_packet_type_t;
|
||||
|
||||
/**
|
||||
* Will detect the packet type from the at least one byte long buffer.
|
||||
*
|
||||
* @param buf - The buffer from which the packet type will be detected.
|
||||
* @param packet_type - Pointer to the receiver of the packet type.
|
||||
* @return An error value.
|
||||
*/
|
||||
lwmqtt_err_t lwmqtt_detect_packet_type(unsigned char *buf, lwmqtt_packet_type_t *packet_type);
|
||||
|
||||
/**
|
||||
* Will detect the remaining length form the at least on byte long buffer.
|
||||
*
|
||||
* It will return LWMQTT_BUFFER_TOO_SHORT if the buffer is to short and an additional byte should be read from the
|
||||
* network. In case the remaining length is overflowed it will return LWMQTT_REMAINING_LENGTH_OVERFLOW.
|
||||
*
|
||||
* @param buf - The buffer from which the remaining length will be detected.
|
||||
* @param buf_len - The length in bytes of the supplied buffer.
|
||||
* @return An error value.
|
||||
*/
|
||||
lwmqtt_err_t lwmqtt_detect_remaining_length(unsigned char *buf, int buf_len, int *rem_len);
|
||||
|
||||
/**
|
||||
* Encodes a connect packet into the supplied buffer.
|
||||
*
|
||||
* @param buf - The buffer into which the packet will be encoded.
|
||||
* @param buf_len - The length in bytes of the supplied buffer.
|
||||
* @param len - The encoded length of the packet.
|
||||
* @param options - The options to be used to build the connect packet.
|
||||
* @param will - The last will and testament.
|
||||
* @return An error value.
|
||||
*/
|
||||
lwmqtt_err_t lwmqtt_encode_connect(unsigned char *buf, int buf_len, int *len, lwmqtt_options_t *options,
|
||||
lwmqtt_will_t *will);
|
||||
|
||||
/**
|
||||
* Decodes a connack packet from the supplied buffer.
|
||||
*
|
||||
* @param session_present - The session present flag.
|
||||
* @param return_code - The return code.
|
||||
* @param buf - The raw buffer data.
|
||||
* @param buf_len - The length in bytes of the supplied buffer.
|
||||
* @return An error value.
|
||||
*/
|
||||
lwmqtt_err_t lwmqtt_decode_connack(bool *session_present, lwmqtt_return_code_t *return_code, unsigned char *buf,
|
||||
int buf_len);
|
||||
|
||||
/**
|
||||
* Encodes a zero (disconnect) packet into the supplied buffer.
|
||||
*
|
||||
* @param buf - The buffer into which the packet will be encoded.
|
||||
* @param buf_len - The length in bytes of the supplied buffer.
|
||||
* @param len - The encoded length of the packet.
|
||||
* @param packet_type - The packets type.
|
||||
* @return An error value.
|
||||
*/
|
||||
lwmqtt_err_t lwmqtt_encode_zero(unsigned char *buf, int buf_len, int *len, lwmqtt_packet_type_t packet_type);
|
||||
|
||||
/**
|
||||
* Decodes an ack (puback, pubrec, pubrel, pubcomp, unsuback) packet from the supplied buffer.
|
||||
*
|
||||
* @param packet_type - The packet type.
|
||||
* @param dup - The dup flag.
|
||||
* @param packet_id - The packet id.
|
||||
* @param buf - The raw buffer data.
|
||||
* @param buf_len - The length in bytes of the supplied buffer.
|
||||
* @return An error value.
|
||||
*/
|
||||
lwmqtt_err_t lwmqtt_decode_ack(lwmqtt_packet_type_t *packet_type, bool *dup, unsigned short *packet_id,
|
||||
unsigned char *buf, int buf_len);
|
||||
|
||||
/**
|
||||
* Encodes an ack (puback, pubrec, pubrel, pubcomp) packet into the supplied buffer.
|
||||
*
|
||||
* @param buf - The buffer into which the packet will be encoded.
|
||||
* @param buf_len - The length in bytes of the supplied buffer.
|
||||
* @param len - The encoded length of the packet.
|
||||
* @param packet_type - The packets type.
|
||||
* @param dup - The dup flag.
|
||||
* @param packet_id - The packet id.
|
||||
* @return An error value.
|
||||
*/
|
||||
lwmqtt_err_t lwmqtt_encode_ack(unsigned char *buf, int buf_len, int *len, lwmqtt_packet_type_t packet_type, bool dup,
|
||||
unsigned short packet_id);
|
||||
|
||||
/**
|
||||
* Decodes a publish packet from the supplied buffer.
|
||||
*
|
||||
* @param dup - The dup flag.
|
||||
* @param qos - The QoS level.
|
||||
* @param retained- The retained flag.
|
||||
* @param packet_id - The packet id.
|
||||
* @param topic - The topic.
|
||||
* @param payload - The payload data.
|
||||
* @param payload_len - The length of the payload.
|
||||
* @param buf - The raw buffer data.
|
||||
* @param buf_len - The length in bytes of the supplied buffer.
|
||||
* @return An error value.
|
||||
*/
|
||||
lwmqtt_err_t lwmqtt_decode_publish(bool *dup, lwmqtt_qos_t *qos, bool *retained, unsigned short *packet_id,
|
||||
lwmqtt_string_t *topic, unsigned char **payload, int *payload_len,
|
||||
unsigned char *buf, int buf_len);
|
||||
|
||||
/**
|
||||
* Encodes a publish packet into the supplied buffer.
|
||||
*
|
||||
* @param buf - The buffer into which the packet will be encoded.
|
||||
* @param buf_len - The length in bytes of the supplied buffer.
|
||||
* @param len - The encoded length of the packet.
|
||||
* @param dup - The dup flag.
|
||||
* @param qos - The QoS level.
|
||||
* @param retained- The retained flag.
|
||||
* @param packet_id - The packet id.
|
||||
* @param topic - The topic.
|
||||
* @param payload - The payload data.
|
||||
* @param payload_len - The length of the payload.
|
||||
* @return An error value.
|
||||
*/
|
||||
lwmqtt_err_t lwmqtt_encode_publish(unsigned char *buf, int buf_len, int *len, bool dup, lwmqtt_qos_t qos, bool retained,
|
||||
unsigned short packet_id, lwmqtt_string_t topic, unsigned char *payload,
|
||||
int payload_len);
|
||||
|
||||
/**
|
||||
* Encodes a subscribe packet into the supplied buffer.
|
||||
*
|
||||
* @param buf - The buffer into which the packet will be encoded.
|
||||
* @param buf_len - The length in bytes of the supplied buffer.
|
||||
* @param len - The encoded length of the packet.
|
||||
* @param packet_id - The packet id.
|
||||
* @param count - The number of members in the topic_filters and qos_levels array.
|
||||
* @param topic_filters - The array of topic filter.
|
||||
* @param qos_levels - The array of requested QoS levels.
|
||||
* @return An error value.
|
||||
*/
|
||||
lwmqtt_err_t lwmqtt_encode_subscribe(unsigned char *buf, int buf_len, int *len, unsigned short packet_id, int count,
|
||||
lwmqtt_string_t *topic_filters, lwmqtt_qos_t *qos_levels);
|
||||
|
||||
/**
|
||||
* Decodes a suback packet from the supplied buffer.
|
||||
*
|
||||
* @param packet_id - The packet id.
|
||||
* @param max_count - The maximum number of members allowed in the granted_qos_levels array.
|
||||
* @param count - The number of members in the granted_qos_levels array.
|
||||
* @param granted_qos_levels - The granted QoS levels.
|
||||
* @param buf - The raw buffer data.
|
||||
* @param buf_len - The length in bytes of the supplied buffer.
|
||||
* @return An error value.
|
||||
*/
|
||||
lwmqtt_err_t lwmqtt_decode_suback(unsigned short *packet_id, int max_count, int *count,
|
||||
lwmqtt_qos_t *granted_qos_levels, unsigned char *buf, int buf_len);
|
||||
|
||||
/**
|
||||
* Encodes the supplied unsubscribe data into the supplied buffer, ready for sending
|
||||
*
|
||||
* @param buf - The buffer into which the packet will be encoded.
|
||||
* @param buf_len - The length in bytes of the supplied buffer.
|
||||
* @param len - The encoded length of the packet.
|
||||
* @param packet_id - The packet id.
|
||||
* @param count - The number of members in the topic_filters array.
|
||||
* @param topic_filters - The array of topic filters.
|
||||
* @return An error value.
|
||||
*/
|
||||
lwmqtt_err_t lwmqtt_encode_unsubscribe(unsigned char *buf, int buf_len, int *len, unsigned short packet_id, int count,
|
||||
lwmqtt_string_t *topic_filters);
|
||||
|
||||
#endif // LWMQTT_PACKET_H
|
27
dtest/mqtt_test/include/unix.h
Executable file
27
dtest/mqtt_test/include/unix.h
Executable file
@@ -0,0 +1,27 @@
|
||||
#ifndef LWMQTT_UNIX_H
|
||||
#define LWMQTT_UNIX_H
|
||||
|
||||
//#include <time.h>
|
||||
#include <lwmqtt.h>
|
||||
|
||||
//typedef struct { struct timeval end; } lwmqtt_unix_timer_t;
|
||||
typedef struct {int timeval;}lwmqtt_unix_timer_t;
|
||||
|
||||
void lwmqtt_unix_timer_set(lwmqtt_client_t *client, void *ref, unsigned int timeout);
|
||||
|
||||
unsigned int lwmqtt_unix_timer_get(lwmqtt_client_t *client, void *ref);
|
||||
|
||||
typedef struct { int socket; } lwmqtt_unix_network_t;
|
||||
|
||||
lwmqtt_err_t lwmqtt_unix_network_connect(lwmqtt_unix_network_t *network, char *host, int port);
|
||||
|
||||
void lwmqtt_unix_network_disconnect(lwmqtt_unix_network_t *network);
|
||||
|
||||
lwmqtt_err_t lwmqtt_unix_network_peek(lwmqtt_client_t *client, lwmqtt_unix_network_t *network, int *available);
|
||||
|
||||
lwmqtt_err_t lwmqtt_unix_network_read(lwmqtt_client_t *client, void *ref, unsigned char *buf, int len, int *read,
|
||||
unsigned int timeout);
|
||||
lwmqtt_err_t lwmqtt_unix_network_write(lwmqtt_client_t *client, void *ref, unsigned char *buf, int len, int *sent,
|
||||
unsigned int timeout);
|
||||
|
||||
#endif // LWMQTT_UNIX_H
|
64
dtest/mqtt_test/src/Makefile
Executable file
64
dtest/mqtt_test/src/Makefile
Executable file
@@ -0,0 +1,64 @@
|
||||
|
||||
# OUTPUT type
|
||||
# 1 - .out
|
||||
# 2 - .a
|
||||
# 3 - .so
|
||||
OUTPUT_TYPE = 1
|
||||
OUTPUT_NAME = mqttest
|
||||
|
||||
SUB_DIRS = $(TOPDIR)/common/os_shim/dtestos
|
||||
|
||||
ADD_INCLUDE += $(TOPDIR)/inc/io_lib $(TOPDIR)/plc/inc $(TOPDIR)/plc/halphy/inc $(TOPDIR)/inc/os_shim \
|
||||
$(TOPDIR)/common/compiler/gcc/inc $(TOPDIR)/plc/halmac/inc $(TOPDIR)/inc/utils $(TOPDIR)/plc/halmac/hw/inc/desc \
|
||||
$(TOPDIR)/plc/halmac/hw/inc/reg $(TOPDIR)/plc/halmac/hw/inc $(TOPDIR)/plc/halphy/hw/inc $(TOPDIR)/inc/driver \
|
||||
$(TOPDIR)/driver/inc $(TOPDIR)/dtest/mqtt_test/include
|
||||
|
||||
|
||||
# predefined macro
|
||||
PRE_MARCO +=
|
||||
|
||||
ADD_LIBDIR += $(TOPDIR)/common/utils $(TOPDIR)/plc/halphy \
|
||||
$(TOPDIR)/plc/halmac/hw $(TOPDIR)/startup/riscv \
|
||||
$(TOPDIR)/startup/cm3 $(TOPDIR)/plc/halmac
|
||||
|
||||
# becareful the seq of LIBs
|
||||
#ADD_LIB += halphy halmac
|
||||
|
||||
#LD_SCRIPT = link_rawdata.lds
|
||||
|
||||
ifeq ($(gcc),arm)
|
||||
OBJDUMP = arm-none-eabi-objdump
|
||||
ADD_INCLUDE += $(TOPDIR)/os/inc/cm3
|
||||
ADD_LIB += cm3
|
||||
else
|
||||
OBJDUMP = riscv32-unknown-elf-objdump
|
||||
ADD_INCLUDE += $(TOPDIR)/os/inc/riscv
|
||||
ADD_LIB += riscv
|
||||
endif
|
||||
|
||||
# iot_printf
|
||||
ADD_LIBDIR += $(TOPDIR)/driver $(TOPDIR)/common/io_lib $(TOPDIR)/common $(TOPDIR)/os
|
||||
ADD_LIB += driver io_lib
|
||||
|
||||
#####################################################
|
||||
|
||||
ifdef TOPDIR
|
||||
include $(TOPDIR)/build/makefile.cfg
|
||||
else
|
||||
include $(CURDIR)/build/makefile.cfg
|
||||
TOPDIR = $(CURDIR)
|
||||
export TOPDIR
|
||||
endif
|
||||
|
||||
dump:
|
||||
$(OBJDUMP) -D -S -l $(OUTPUT_FULL_NAME) > $(OUTPUT_FULL_NAME).dump
|
||||
|
||||
# display the obj files and output name
|
||||
debug:
|
||||
@echo TOPDIR=$(TOPDIR)
|
||||
@echo OUTPUT_LIB=$(OUTPUT_FULL_NAME)
|
||||
@echo DEPS=$(DEPS)
|
||||
@echo OBJECTS=$(OBJECTS)
|
||||
@echo SRCS=$(SRCS)
|
||||
@echo OBJECTS folder=$(foreach dirname, $(SUB_DIRS), $(addprefix $(BIN_DIR)/, $(dirname)))
|
||||
@echo output_name=$(OUTPUT_FULL_NAME)
|
595
dtest/mqtt_test/src/client.c
Executable file
595
dtest/mqtt_test/src/client.c
Executable file
@@ -0,0 +1,595 @@
|
||||
#include <string.h>
|
||||
|
||||
#include <lwmqtt.h>
|
||||
|
||||
#include "packet.h"
|
||||
|
||||
void lwmqtt_init(lwmqtt_client_t *client, unsigned char *write_buf, int write_buf_size, unsigned char *read_buf,
|
||||
int read_buf_size) {
|
||||
client->next_packet_id = 1;
|
||||
client->keep_alive_interval = 0;
|
||||
client->ping_outstanding = false;
|
||||
|
||||
client->write_buf = write_buf;
|
||||
client->write_buf_size = write_buf_size;
|
||||
client->read_buf = read_buf;
|
||||
client->read_buf_size = read_buf_size;
|
||||
client->callback = NULL;
|
||||
|
||||
client->network = NULL;
|
||||
client->network_read = NULL;
|
||||
client->network_write = NULL;
|
||||
|
||||
client->keep_alive_timer = NULL;
|
||||
client->command_timer = NULL;
|
||||
client->timer_set = NULL;
|
||||
client->timer_get = NULL;
|
||||
}
|
||||
|
||||
void lwmqtt_set_network(lwmqtt_client_t *client, void *ref, lwmqtt_network_read_t read, lwmqtt_network_write_t write) {
|
||||
client->network = ref;
|
||||
client->network_read = read;
|
||||
client->network_write = write;
|
||||
}
|
||||
|
||||
void lwmqtt_set_timers(lwmqtt_client_t *client, void *keep_alive_timer, void *network_timer, lwmqtt_timer_set_t set,
|
||||
lwmqtt_timer_get_t get) {
|
||||
client->keep_alive_timer = keep_alive_timer;
|
||||
client->command_timer = network_timer;
|
||||
client->timer_set = set;
|
||||
client->timer_get = get;
|
||||
|
||||
client->timer_set(client, client->keep_alive_timer, 0);
|
||||
client->timer_set(client, client->command_timer, 0);
|
||||
}
|
||||
|
||||
void lwmqtt_set_callback(lwmqtt_client_t *client, void *ref, lwmqtt_callback_t cb) {
|
||||
client->callback_ref = ref;
|
||||
client->callback = cb;
|
||||
}
|
||||
|
||||
static unsigned short lwmqtt_get_next_packet_id(lwmqtt_client_t *c) {
|
||||
return c->next_packet_id = (unsigned short)((c->next_packet_id == 65535) ? 1 : c->next_packet_id + 1);
|
||||
}
|
||||
|
||||
static lwmqtt_err_t lwmqtt_read_from_network(lwmqtt_client_t *c, int offset, int len) {
|
||||
// check read buffer capacity
|
||||
if (c->read_buf_size < offset + len) {
|
||||
return LWMQTT_BUFFER_TOO_SHORT;
|
||||
}
|
||||
|
||||
// prepare counter
|
||||
int read = 0;
|
||||
|
||||
// read while data is missing
|
||||
while (read < len) {
|
||||
// get remaining time
|
||||
unsigned int remaining_time = c->timer_get(c, c->command_timer);
|
||||
|
||||
// check timeout
|
||||
if (remaining_time <= 0) {
|
||||
return LWMQTT_NOT_ENOUGH_DATA;
|
||||
}
|
||||
|
||||
// read
|
||||
int partial_read = 0;
|
||||
lwmqtt_err_t err =
|
||||
c->network_read(c, c->network, c->read_buf + offset + read, len - read, &partial_read, remaining_time);
|
||||
if (err != LWMQTT_SUCCESS) {
|
||||
return err;
|
||||
}
|
||||
|
||||
// increment counter
|
||||
read += partial_read;
|
||||
}
|
||||
|
||||
return LWMQTT_SUCCESS;
|
||||
}
|
||||
|
||||
static lwmqtt_err_t lwmqtt_write_to_network(lwmqtt_client_t *c, int offset, int len) {
|
||||
// prepare counter
|
||||
int written = 0;
|
||||
|
||||
// write while data is left
|
||||
while (written < len) {
|
||||
// get remaining time
|
||||
unsigned int remaining_time = c->timer_get(c, c->command_timer);
|
||||
|
||||
// check timeout
|
||||
if (remaining_time <= 0) {
|
||||
return LWMQTT_NOT_ENOUGH_DATA;
|
||||
}
|
||||
|
||||
// read
|
||||
int partial_write = 0;
|
||||
lwmqtt_err_t err =
|
||||
c->network_write(c, c->network, c->write_buf + offset + written, len - written, &partial_write, remaining_time);
|
||||
if (err != LWMQTT_SUCCESS) {
|
||||
return err;
|
||||
}
|
||||
|
||||
// increment counter
|
||||
written += partial_write;
|
||||
}
|
||||
|
||||
return LWMQTT_SUCCESS;
|
||||
}
|
||||
|
||||
static lwmqtt_err_t lwmqtt_read_packet_in_buffer(lwmqtt_client_t *c, int *read, lwmqtt_packet_type_t *packet_type) {
|
||||
// read header byte
|
||||
lwmqtt_err_t err = lwmqtt_read_from_network(c, 0, 1);
|
||||
if (err != LWMQTT_SUCCESS) {
|
||||
*packet_type = LWMQTT_NO_PACKET;
|
||||
return err;
|
||||
}
|
||||
|
||||
// detect packet type
|
||||
err = lwmqtt_detect_packet_type(c->read_buf, packet_type);
|
||||
if (err != LWMQTT_SUCCESS) {
|
||||
return err;
|
||||
}
|
||||
|
||||
// prepare variables
|
||||
int len = 0;
|
||||
int rem_len = 0;
|
||||
|
||||
do {
|
||||
// adjust len
|
||||
len++;
|
||||
|
||||
// read next byte
|
||||
err = lwmqtt_read_from_network(c, len, 1);
|
||||
if (err != LWMQTT_SUCCESS) {
|
||||
return err;
|
||||
}
|
||||
|
||||
// attempt to detect remaining length
|
||||
err = lwmqtt_detect_remaining_length(c->read_buf + 1, len, &rem_len);
|
||||
} while (err == LWMQTT_BUFFER_TOO_SHORT);
|
||||
|
||||
// check final error
|
||||
if (err != LWMQTT_SUCCESS) {
|
||||
return err;
|
||||
}
|
||||
|
||||
// read the rest of the buffer if needed
|
||||
if (rem_len > 0) {
|
||||
err = lwmqtt_read_from_network(c, 1 + len, rem_len);
|
||||
if (err != LWMQTT_SUCCESS) {
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
// adjust counter
|
||||
*read += 1 + len + rem_len;
|
||||
|
||||
return LWMQTT_SUCCESS;
|
||||
}
|
||||
|
||||
static lwmqtt_err_t lwmqtt_send_packet_in_buffer(lwmqtt_client_t *c, int length) {
|
||||
// write to network
|
||||
lwmqtt_err_t err = lwmqtt_write_to_network(c, 0, length);
|
||||
if (err != LWMQTT_SUCCESS) {
|
||||
return err;
|
||||
}
|
||||
|
||||
// reset keep alive timer
|
||||
c->timer_set(c, c->keep_alive_timer, c->keep_alive_interval * 1000);
|
||||
|
||||
return LWMQTT_SUCCESS;
|
||||
}
|
||||
|
||||
static lwmqtt_err_t lwmqtt_cycle(lwmqtt_client_t *c, int *read, lwmqtt_packet_type_t *packet_type) {
|
||||
// read next packet from the network
|
||||
lwmqtt_err_t err = lwmqtt_read_packet_in_buffer(c, read, packet_type);
|
||||
if (err != LWMQTT_SUCCESS) {
|
||||
return err;
|
||||
} else if (*packet_type == LWMQTT_NO_PACKET) {
|
||||
return LWMQTT_SUCCESS;
|
||||
}
|
||||
|
||||
switch (*packet_type) {
|
||||
// handle publish packets
|
||||
case LWMQTT_PUBLISH_PACKET: {
|
||||
// decode publish packet
|
||||
lwmqtt_string_t topic = lwmqtt_default_string;
|
||||
lwmqtt_message_t msg;
|
||||
bool dup;
|
||||
unsigned short packet_id;
|
||||
err = lwmqtt_decode_publish(&dup, &msg.qos, &msg.retained, &packet_id, &topic, (unsigned char **)&msg.payload,
|
||||
&msg.payload_len, c->read_buf, c->read_buf_size);
|
||||
if (err != LWMQTT_SUCCESS) {
|
||||
return err;
|
||||
}
|
||||
|
||||
// call callback if set
|
||||
if (c->callback != NULL) {
|
||||
c->callback(c, c->callback_ref, &topic, &msg);
|
||||
}
|
||||
|
||||
// break early if qos zero
|
||||
if (msg.qos == LWMQTT_QOS0) {
|
||||
break;
|
||||
}
|
||||
|
||||
// define ack packet
|
||||
lwmqtt_packet_type_t ack_type = LWMQTT_NO_PACKET;
|
||||
if (msg.qos == LWMQTT_QOS1) {
|
||||
ack_type = LWMQTT_PUBREC_PACKET;
|
||||
} else if (msg.qos == LWMQTT_QOS2) {
|
||||
ack_type = LWMQTT_PUBREL_PACKET;
|
||||
}
|
||||
|
||||
// encode ack packet
|
||||
int len;
|
||||
err = lwmqtt_encode_ack(c->write_buf, c->write_buf_size, &len, ack_type, false, packet_id);
|
||||
if (err != LWMQTT_SUCCESS) {
|
||||
return err;
|
||||
}
|
||||
|
||||
// send ack packet
|
||||
err = lwmqtt_send_packet_in_buffer(c, len);
|
||||
if (err != LWMQTT_SUCCESS) {
|
||||
return err;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
// handle pubrec packets
|
||||
case LWMQTT_PUBREC_PACKET: {
|
||||
// decode pubrec packet
|
||||
bool dup;
|
||||
unsigned short packet_id;
|
||||
err = lwmqtt_decode_ack(packet_type, &dup, &packet_id, c->read_buf, c->read_buf_size);
|
||||
if (err != LWMQTT_SUCCESS) {
|
||||
return err;
|
||||
}
|
||||
|
||||
// encode pubrel packet
|
||||
int len;
|
||||
err = lwmqtt_encode_ack(c->write_buf, c->write_buf_size, &len, LWMQTT_PUBREL_PACKET, 0, packet_id);
|
||||
if (err != LWMQTT_SUCCESS) {
|
||||
return err;
|
||||
}
|
||||
|
||||
// send pubrel packet
|
||||
err = lwmqtt_send_packet_in_buffer(c, len);
|
||||
if (err != LWMQTT_SUCCESS) {
|
||||
return err;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
// handle pubrel packets
|
||||
case LWMQTT_PUBREL_PACKET: {
|
||||
// decode pubrec packet
|
||||
bool dup;
|
||||
unsigned short packet_id;
|
||||
err = lwmqtt_decode_ack(packet_type, &dup, &packet_id, c->read_buf, c->read_buf_size);
|
||||
if (err != LWMQTT_SUCCESS) {
|
||||
return err;
|
||||
}
|
||||
|
||||
// encode pubcomp packet
|
||||
int len;
|
||||
err = lwmqtt_encode_ack(c->write_buf, c->write_buf_size, &len, LWMQTT_PUBCOMP_PACKET, 0, packet_id);
|
||||
if (err != LWMQTT_SUCCESS) {
|
||||
return err;
|
||||
}
|
||||
|
||||
// send pubcomp packet
|
||||
err = lwmqtt_send_packet_in_buffer(c, len);
|
||||
if (err != LWMQTT_SUCCESS) {
|
||||
return err;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
// handle pingresp packets
|
||||
case LWMQTT_PINGRESP_PACKET: {
|
||||
// set flag
|
||||
c->ping_outstanding = false;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
// handle all other packets
|
||||
default: { break; }
|
||||
}
|
||||
|
||||
return LWMQTT_SUCCESS;
|
||||
}
|
||||
|
||||
static lwmqtt_err_t lwmqtt_cycle_until(lwmqtt_client_t *c, lwmqtt_packet_type_t *packet_type, unsigned int available,
|
||||
lwmqtt_packet_type_t needle) {
|
||||
// prepare counter
|
||||
int read = 0;
|
||||
|
||||
// loop until timeout has been reached
|
||||
do {
|
||||
// do one cycle
|
||||
lwmqtt_err_t err = lwmqtt_cycle(c, &read, packet_type);
|
||||
if (err != LWMQTT_SUCCESS) {
|
||||
return err;
|
||||
}
|
||||
|
||||
// check if needle has been found
|
||||
if (needle != LWMQTT_NO_PACKET && *packet_type == needle) {
|
||||
return LWMQTT_SUCCESS;
|
||||
}
|
||||
} while (c->timer_get(c, c->command_timer) > 0 && (available == 0 || read < available));
|
||||
|
||||
return LWMQTT_SUCCESS;
|
||||
}
|
||||
|
||||
lwmqtt_err_t lwmqtt_yield(lwmqtt_client_t *client, unsigned int available, unsigned int timeout) {
|
||||
// set timeout
|
||||
client->timer_set(client, client->command_timer, timeout);
|
||||
|
||||
// cycle until timeout has been reached
|
||||
lwmqtt_packet_type_t packet_type = LWMQTT_NO_PACKET;
|
||||
lwmqtt_err_t err = lwmqtt_cycle_until(client, &packet_type, available, LWMQTT_NO_PACKET);
|
||||
if (err != LWMQTT_SUCCESS) {
|
||||
return err;
|
||||
}
|
||||
|
||||
return LWMQTT_SUCCESS;
|
||||
}
|
||||
|
||||
lwmqtt_err_t lwmqtt_connect(lwmqtt_client_t *client, lwmqtt_options_t *options, lwmqtt_will_t *will,
|
||||
lwmqtt_return_code_t *return_code, unsigned int timeout) {
|
||||
// set timer to command timeout
|
||||
client->timer_set(client, client->command_timer, timeout);
|
||||
|
||||
// save keep alive interval
|
||||
client->keep_alive_interval = options->keep_alive;
|
||||
|
||||
// set keep alive timer
|
||||
if (client->keep_alive_interval > 0) {
|
||||
client->timer_set(client, client->keep_alive_timer, client->keep_alive_interval * 1000);
|
||||
}
|
||||
|
||||
// encode connect packet
|
||||
int len;
|
||||
lwmqtt_err_t err = lwmqtt_encode_connect(client->write_buf, client->write_buf_size, &len, options, will);
|
||||
if (err != LWMQTT_SUCCESS) {
|
||||
return err;
|
||||
}
|
||||
|
||||
// send packet
|
||||
err = lwmqtt_send_packet_in_buffer(client, len);
|
||||
if (err != LWMQTT_SUCCESS) {
|
||||
return err;
|
||||
}
|
||||
|
||||
// wait for connack packet
|
||||
lwmqtt_packet_type_t packet_type = LWMQTT_NO_PACKET;
|
||||
err = lwmqtt_cycle_until(client, &packet_type, 0, LWMQTT_CONNACK_PACKET);
|
||||
if (err != LWMQTT_SUCCESS) {
|
||||
return err;
|
||||
} else if (packet_type != LWMQTT_CONNACK_PACKET) {
|
||||
return LWMQTT_NO_OR_WRONG_PACKET;
|
||||
}
|
||||
|
||||
// decode connack packet
|
||||
bool session_present;
|
||||
err = lwmqtt_decode_connack(&session_present, return_code, client->read_buf, client->read_buf_size);
|
||||
if (err != LWMQTT_SUCCESS) {
|
||||
return err;
|
||||
}
|
||||
|
||||
// return error if connection was not accepted
|
||||
if (*return_code != LWMQTT_CONNACK_CONNECTION_ACCEPTED) {
|
||||
return LWMQTT_CONNECTION_DENIED;
|
||||
}
|
||||
|
||||
return LWMQTT_SUCCESS;
|
||||
}
|
||||
|
||||
lwmqtt_err_t lwmqtt_subscribe(lwmqtt_client_t *client, const char *topic_filter, lwmqtt_qos_t qos,
|
||||
unsigned int timeout) {
|
||||
// set timeout
|
||||
client->timer_set(client, client->command_timer, timeout);
|
||||
|
||||
// prepare string
|
||||
lwmqtt_string_t str = lwmqtt_str(topic_filter);
|
||||
|
||||
// encode subscribe packet
|
||||
int len;
|
||||
lwmqtt_err_t err = lwmqtt_encode_subscribe(client->write_buf, client->write_buf_size, &len,
|
||||
lwmqtt_get_next_packet_id(client), 1, &str, &qos);
|
||||
if (err != LWMQTT_SUCCESS) {
|
||||
return err;
|
||||
}
|
||||
|
||||
// send packet
|
||||
err = lwmqtt_send_packet_in_buffer(client, len);
|
||||
if (err != LWMQTT_SUCCESS) {
|
||||
return err;
|
||||
}
|
||||
|
||||
// wait for suback packet
|
||||
lwmqtt_packet_type_t packet_type = LWMQTT_NO_PACKET;
|
||||
err = lwmqtt_cycle_until(client, &packet_type, 0, LWMQTT_SUBACK_PACKET);
|
||||
if (err != LWMQTT_SUCCESS) {
|
||||
return err;
|
||||
} else if (packet_type != LWMQTT_SUBACK_PACKET) {
|
||||
return LWMQTT_NO_OR_WRONG_PACKET;
|
||||
}
|
||||
|
||||
// decode packet
|
||||
int count = 0;
|
||||
lwmqtt_qos_t grantedQoS;
|
||||
unsigned short packet_id;
|
||||
err = lwmqtt_decode_suback(&packet_id, 1, &count, &grantedQoS, client->read_buf, client->read_buf_size);
|
||||
if (err == LWMQTT_SUCCESS) {
|
||||
return err;
|
||||
}
|
||||
|
||||
return LWMQTT_SUCCESS;
|
||||
}
|
||||
|
||||
lwmqtt_err_t lwmqtt_unsubscribe(lwmqtt_client_t *client, const char *topic_filter, unsigned int timeout) {
|
||||
// set timer
|
||||
client->timer_set(client, client->command_timer, timeout);
|
||||
|
||||
// prepare string
|
||||
lwmqtt_string_t str = lwmqtt_str(topic_filter);
|
||||
|
||||
// encode unsubscribe packet
|
||||
int len;
|
||||
lwmqtt_err_t err = lwmqtt_encode_unsubscribe(client->write_buf, client->write_buf_size, &len,
|
||||
lwmqtt_get_next_packet_id(client), 1, &str);
|
||||
if (err != LWMQTT_SUCCESS) {
|
||||
return err;
|
||||
}
|
||||
|
||||
// send unsubscribe packet
|
||||
err = lwmqtt_send_packet_in_buffer(client, len);
|
||||
if (err != LWMQTT_SUCCESS) {
|
||||
return err;
|
||||
}
|
||||
|
||||
// wait for unsuback packet
|
||||
lwmqtt_packet_type_t packet_type = LWMQTT_NO_PACKET;
|
||||
err = lwmqtt_cycle_until(client, &packet_type, 0, LWMQTT_UNSUBACK_PACKET);
|
||||
if (err != LWMQTT_SUCCESS) {
|
||||
return err;
|
||||
} else if (packet_type != LWMQTT_UNSUBACK_PACKET) {
|
||||
return LWMQTT_NO_OR_WRONG_PACKET;
|
||||
}
|
||||
|
||||
// decode unsuback packet
|
||||
bool dup;
|
||||
unsigned short packet_id;
|
||||
err = lwmqtt_decode_ack(&packet_type, &dup, &packet_id, client->read_buf, client->read_buf_size);
|
||||
if (err != LWMQTT_SUCCESS) {
|
||||
return err;
|
||||
}
|
||||
|
||||
return LWMQTT_SUCCESS;
|
||||
}
|
||||
|
||||
lwmqtt_err_t lwmqtt_publish(lwmqtt_client_t *client, const char *topic, lwmqtt_message_t *message,
|
||||
unsigned int timeout) {
|
||||
// prepare string
|
||||
lwmqtt_string_t str = lwmqtt_str(topic);
|
||||
|
||||
// set timer
|
||||
client->timer_set(client, client->command_timer, timeout);
|
||||
|
||||
// add packet id if at least qos 1
|
||||
unsigned short packet_id = 0;
|
||||
if (message->qos == LWMQTT_QOS1 || message->qos == LWMQTT_QOS2) {
|
||||
packet_id = lwmqtt_get_next_packet_id(client);
|
||||
}
|
||||
|
||||
// encode publish packet
|
||||
int len = 0;
|
||||
lwmqtt_err_t err = lwmqtt_encode_publish(client->write_buf, client->write_buf_size, &len, 0, message->qos,
|
||||
(char)(message->retained ? 1 : 0), packet_id, str,
|
||||
(unsigned char *)message->payload, message->payload_len);
|
||||
if (err != LWMQTT_SUCCESS) {
|
||||
return err;
|
||||
}
|
||||
|
||||
// send packet
|
||||
err = lwmqtt_send_packet_in_buffer(client, len);
|
||||
if (err != LWMQTT_SUCCESS) {
|
||||
return err;
|
||||
}
|
||||
|
||||
// immediately return on qos zero
|
||||
if (message->qos == LWMQTT_QOS0) {
|
||||
return LWMQTT_SUCCESS;
|
||||
}
|
||||
|
||||
// define ack packet
|
||||
lwmqtt_packet_type_t ack_type = LWMQTT_NO_PACKET;
|
||||
if (message->qos == LWMQTT_QOS1) {
|
||||
ack_type = LWMQTT_PUBACK_PACKET;
|
||||
} else if (message->qos == LWMQTT_QOS2) {
|
||||
ack_type = LWMQTT_PUBCOMP_PACKET;
|
||||
}
|
||||
|
||||
// wait for ack packet
|
||||
lwmqtt_packet_type_t packet_type = LWMQTT_NO_PACKET;
|
||||
err = lwmqtt_cycle_until(client, &packet_type, 0, ack_type);
|
||||
if (err != LWMQTT_SUCCESS) {
|
||||
return err;
|
||||
} else if (packet_type != ack_type) {
|
||||
return LWMQTT_NO_OR_WRONG_PACKET;
|
||||
}
|
||||
|
||||
// decode ack packet
|
||||
bool dup;
|
||||
err = lwmqtt_decode_ack(&packet_type, &dup, &packet_id, client->read_buf, client->read_buf_size);
|
||||
if (err != LWMQTT_SUCCESS) {
|
||||
return err;
|
||||
}
|
||||
|
||||
return LWMQTT_SUCCESS;
|
||||
}
|
||||
|
||||
lwmqtt_err_t lwmqtt_disconnect(lwmqtt_client_t *client, unsigned int timeout) {
|
||||
// set timer
|
||||
client->timer_set(client, client->command_timer, timeout);
|
||||
|
||||
// encode disconnect packet
|
||||
int len;
|
||||
lwmqtt_err_t err = lwmqtt_encode_zero(client->write_buf, client->write_buf_size, &len, LWMQTT_DISCONNECT_PACKET);
|
||||
if (err != LWMQTT_SUCCESS) {
|
||||
return err;
|
||||
}
|
||||
|
||||
// send disconnected packet
|
||||
err = lwmqtt_send_packet_in_buffer(client, len);
|
||||
if (err != LWMQTT_SUCCESS) {
|
||||
return err;
|
||||
}
|
||||
|
||||
return LWMQTT_SUCCESS;
|
||||
}
|
||||
|
||||
lwmqtt_err_t lwmqtt_keep_alive(lwmqtt_client_t *client, unsigned int timeout) {
|
||||
// set timer
|
||||
client->timer_set(client, client->command_timer, timeout);
|
||||
|
||||
// return immediately if keep alive interval is zero
|
||||
if (client->keep_alive_interval == 0) {
|
||||
return LWMQTT_SUCCESS;
|
||||
}
|
||||
|
||||
// return immediately if no ping is due
|
||||
if (client->timer_get(client, client->keep_alive_timer) > 0) {
|
||||
return LWMQTT_SUCCESS;
|
||||
}
|
||||
|
||||
// a ping is due
|
||||
|
||||
// fail immediately if a ping is still outstanding
|
||||
if (client->ping_outstanding) {
|
||||
return LWMQTT_UNANSWERED_PIN;
|
||||
}
|
||||
|
||||
// encode pingreq packet
|
||||
int len;
|
||||
lwmqtt_err_t err = lwmqtt_encode_zero(client->write_buf, client->write_buf_size, &len, LWMQTT_PINGREQ_PACKET);
|
||||
if (err != LWMQTT_SUCCESS) {
|
||||
return err;
|
||||
}
|
||||
|
||||
// send packet
|
||||
err = lwmqtt_send_packet_in_buffer(client, len);
|
||||
if (err != LWMQTT_SUCCESS) {
|
||||
return err;
|
||||
}
|
||||
|
||||
// set flag
|
||||
client->ping_outstanding = true;
|
||||
|
||||
return LWMQTT_SUCCESS;
|
||||
}
|
100
dtest/mqtt_test/src/helpers.c
Executable file
100
dtest/mqtt_test/src/helpers.c
Executable file
@@ -0,0 +1,100 @@
|
||||
#include <string.h>
|
||||
|
||||
#include "helpers.h"
|
||||
|
||||
lwmqtt_string_t lwmqtt_str(const char *str) { return (lwmqtt_string_t){(int)strlen(str), (char *)str}; }
|
||||
|
||||
int lwmqtt_strcmp(lwmqtt_string_t *a, char *b) {
|
||||
// get length of b
|
||||
int len = (int)strlen(b);
|
||||
|
||||
// otherwise check if length matches
|
||||
if (len != a->len) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
// compare memory
|
||||
return strncmp(a->data, b, (size_t)len);
|
||||
}
|
||||
|
||||
void lwmqtt_write_string(unsigned char **pptr, lwmqtt_string_t string) {
|
||||
// write length prefixed string if length is given
|
||||
if (string.len > 0) {
|
||||
lwmqtt_write_int(pptr, string.len);
|
||||
memcpy(*pptr, string.data, string.len);
|
||||
*pptr += string.len;
|
||||
return;
|
||||
}
|
||||
|
||||
// write zero
|
||||
lwmqtt_write_int(pptr, 0);
|
||||
}
|
||||
|
||||
bool lwmqtt_read_string(lwmqtt_string_t *str, unsigned char **pptr, unsigned char *end_ptr) {
|
||||
// check if at lest 2 bytes
|
||||
if (end_ptr - (*pptr) <= 1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// read length
|
||||
int len = lwmqtt_read_int(pptr);
|
||||
|
||||
// check if string end is overflowing the end pointer
|
||||
if (&(*pptr)[len] > end_ptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// set string
|
||||
str->len = len;
|
||||
str->data = (char *)*pptr;
|
||||
|
||||
// advance pointer
|
||||
*pptr += str->len;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int lwmqtt_read_int(unsigned char **pptr) {
|
||||
// get pointer
|
||||
unsigned char *ptr = *pptr;
|
||||
|
||||
// read two byte integer
|
||||
int num = 256 * (*ptr) + (*(ptr + 1));
|
||||
|
||||
// adjust pointer
|
||||
*pptr += 2;
|
||||
|
||||
return num;
|
||||
}
|
||||
|
||||
unsigned char lwmqtt_read_char(unsigned char **pptr) {
|
||||
// read single char
|
||||
unsigned char chr = **pptr;
|
||||
|
||||
// adjust pointer
|
||||
(*pptr)++;
|
||||
|
||||
return chr;
|
||||
}
|
||||
|
||||
void lwmqtt_write_char(unsigned char **pptr, unsigned char chr) {
|
||||
// write single char
|
||||
**pptr = chr;
|
||||
|
||||
// adjust pointer
|
||||
(*pptr)++;
|
||||
}
|
||||
|
||||
void lwmqtt_write_int(unsigned char **pptr, int num) {
|
||||
// write first byte
|
||||
**pptr = (unsigned char)(num / 256);
|
||||
|
||||
// adjust pointer
|
||||
(*pptr)++;
|
||||
|
||||
// write second byte
|
||||
**pptr = (unsigned char)(num % 256);
|
||||
|
||||
// adjust pointer
|
||||
(*pptr)++;
|
||||
}
|
74
dtest/mqtt_test/src/main.c
Executable file
74
dtest/mqtt_test/src/main.c
Executable file
@@ -0,0 +1,74 @@
|
||||
//#include <stdio.h>
|
||||
//#include <stdlib.h>
|
||||
#include "os_types.h"
|
||||
#include "dbg_io.h"
|
||||
#include "iot_diag.h"
|
||||
#include "iot_io.h"
|
||||
|
||||
#include <lwmqtt.h>
|
||||
#include <unix.h>
|
||||
|
||||
#define COMMAND_TIMEOUT 5000
|
||||
|
||||
static void message_arrived(lwmqtt_client_t *c, void *ref, lwmqtt_string_t *t, lwmqtt_message_t *m) {
|
||||
iot_printf("message_arrived: %.*s => %.*s\n", t->len, t->data, m->payload_len, (char *)m->payload);
|
||||
}
|
||||
|
||||
unsigned char buf1[512], buf2[512];
|
||||
lwmqtt_client_t client;
|
||||
|
||||
|
||||
int main() {
|
||||
|
||||
|
||||
lwmqtt_unix_network_t network;
|
||||
lwmqtt_unix_timer_t timer1, timer2;
|
||||
|
||||
|
||||
lwmqtt_init(&client, buf1, 512, buf2, 512);
|
||||
|
||||
lwmqtt_set_network(&client, &network, lwmqtt_unix_network_read, lwmqtt_unix_network_write);
|
||||
lwmqtt_set_timers(&client, &timer1, &timer2, lwmqtt_unix_timer_set, lwmqtt_unix_timer_get);
|
||||
lwmqtt_set_callback(&client, NULL, message_arrived);
|
||||
|
||||
lwmqtt_err_t err = lwmqtt_unix_network_connect(&network, "broker.shiftr.io", 1883);
|
||||
if (err != LWMQTT_SUCCESS) {
|
||||
iot_printf("failed lwmqtt_unix_network_connect: %d\n", err);
|
||||
return 1;
|
||||
}
|
||||
|
||||
lwmqtt_options_t data = lwmqtt_default_options;
|
||||
data.client_id = lwmqtt_str("lwmqtt");
|
||||
data.username = lwmqtt_str("try");
|
||||
data.password = lwmqtt_str("try");
|
||||
data.keep_alive = 5;
|
||||
|
||||
lwmqtt_return_code_t return_code;
|
||||
err = lwmqtt_connect(&client, &data, 0, &return_code, COMMAND_TIMEOUT);
|
||||
if (err != LWMQTT_SUCCESS) {
|
||||
iot_printf("failed lwmqtt_connect: %d (%d)\n", err, return_code);
|
||||
return 1;
|
||||
}
|
||||
|
||||
iot_printf("connected!\n");
|
||||
|
||||
err = lwmqtt_subscribe(&client, "hello", LWMQTT_QOS0, COMMAND_TIMEOUT);
|
||||
if (err != LWMQTT_SUCCESS) {
|
||||
iot_printf("failed lwmqtt_subscribe: %d (%d)\n", err, return_code);
|
||||
return 1;
|
||||
}
|
||||
|
||||
while (true) {
|
||||
err = lwmqtt_yield(&client, 0, COMMAND_TIMEOUT);
|
||||
if (err != LWMQTT_SUCCESS) {
|
||||
iot_printf("failed lwmqtt_yield: %d\n", err);
|
||||
return 1;
|
||||
}
|
||||
|
||||
err = lwmqtt_keep_alive(&client, COMMAND_TIMEOUT);
|
||||
if (err != LWMQTT_SUCCESS) {
|
||||
iot_printf("failed lwmqtt_keep_alive: %d\n", err);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
579
dtest/mqtt_test/src/packet.c
Executable file
579
dtest/mqtt_test/src/packet.c
Executable file
@@ -0,0 +1,579 @@
|
||||
#include <lwmqtt.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "packet.h"
|
||||
|
||||
typedef union {
|
||||
unsigned char byte;
|
||||
struct {
|
||||
unsigned int retain : 1;
|
||||
unsigned int qos : 2;
|
||||
unsigned int dup : 1;
|
||||
unsigned int type : 4;
|
||||
} bits;
|
||||
} lwmqtt_header_t;
|
||||
|
||||
static int lwmqtt_encode_remaining_length(unsigned char *buf, int rem_len) {
|
||||
// init len counter
|
||||
int len = 0;
|
||||
|
||||
// encode variadic number
|
||||
do {
|
||||
// calculate current digit
|
||||
unsigned char d = (unsigned char)(rem_len % 128);
|
||||
|
||||
// change remaining length
|
||||
rem_len /= 128;
|
||||
|
||||
// if there are more digits to encode, set the top bit of this digit
|
||||
if (rem_len > 0) {
|
||||
d |= 0x80;
|
||||
}
|
||||
|
||||
// set digit
|
||||
buf[len++] = d;
|
||||
} while (rem_len > 0);
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
static int lwmqtt_total_header_length(int rem_len) {
|
||||
if (rem_len < 128) {
|
||||
return 1 + 1;
|
||||
} else if (rem_len < 16384) {
|
||||
return 1 + 2;
|
||||
} else if (rem_len < 2097151) {
|
||||
return 1 + 3;
|
||||
} else {
|
||||
return 1 + 4;
|
||||
}
|
||||
}
|
||||
|
||||
static lwmqtt_err_t lwmqtt_decode_remaining_length(unsigned char **buf, int buf_len, int *rem_len) {
|
||||
unsigned char c;
|
||||
int multiplier = 1;
|
||||
int len = 0;
|
||||
|
||||
*rem_len = 0;
|
||||
do {
|
||||
len++;
|
||||
|
||||
// return error if the passed buffer is to short
|
||||
if (buf_len < len) {
|
||||
return LWMQTT_BUFFER_TOO_SHORT;
|
||||
}
|
||||
|
||||
// return error if the length has overflowed
|
||||
if (len > 4) {
|
||||
return LWMQTT_REMAINING_LENGTH_OVERFLOW;
|
||||
}
|
||||
|
||||
c = (*buf)[len - 1];
|
||||
|
||||
*rem_len += (c & 127) * multiplier;
|
||||
multiplier *= 128;
|
||||
} while ((c & 128) != 0);
|
||||
|
||||
*buf += len;
|
||||
|
||||
return LWMQTT_SUCCESS;
|
||||
}
|
||||
|
||||
lwmqtt_err_t lwmqtt_detect_packet_type(unsigned char *buf, lwmqtt_packet_type_t *packet_type) {
|
||||
// prepare pointer
|
||||
unsigned char *ptr = buf;
|
||||
|
||||
// read header
|
||||
lwmqtt_header_t header;
|
||||
header.byte = lwmqtt_read_char(&ptr);
|
||||
|
||||
// check if packet type is correct and can be received
|
||||
switch ((lwmqtt_packet_type_t)header.bits.type) {
|
||||
case LWMQTT_CONNACK_PACKET:
|
||||
case LWMQTT_PUBLISH_PACKET:
|
||||
case LWMQTT_PUBACK_PACKET:
|
||||
case LWMQTT_PUBREC_PACKET:
|
||||
case LWMQTT_PUBREL_PACKET:
|
||||
case LWMQTT_PUBCOMP_PACKET:
|
||||
case LWMQTT_SUBACK_PACKET:
|
||||
case LWMQTT_UNSUBACK_PACKET:
|
||||
case LWMQTT_PINGRESP_PACKET:
|
||||
*packet_type = (lwmqtt_packet_type_t)header.bits.type;
|
||||
return LWMQTT_SUCCESS;
|
||||
default:
|
||||
*packet_type = LWMQTT_NO_PACKET;
|
||||
return LWMQTT_DECODE_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
lwmqtt_err_t lwmqtt_detect_remaining_length(unsigned char *buf, int buf_len, int *rem_len) {
|
||||
// prepare pointer
|
||||
unsigned char *ptr = buf;
|
||||
|
||||
// attempt to decode remaining length
|
||||
return lwmqtt_decode_remaining_length(&ptr, buf_len, rem_len);
|
||||
}
|
||||
|
||||
typedef union {
|
||||
unsigned char byte;
|
||||
struct {
|
||||
unsigned int _ : 1;
|
||||
unsigned int clean_session : 1;
|
||||
unsigned int will : 1;
|
||||
unsigned int will_qos : 2;
|
||||
unsigned int will_retain : 1;
|
||||
unsigned int password : 1;
|
||||
unsigned int username : 1;
|
||||
} bits;
|
||||
} lwmqtt_connect_flags_t;
|
||||
|
||||
typedef union {
|
||||
unsigned char byte;
|
||||
struct {
|
||||
unsigned int _ : 7;
|
||||
unsigned int session_present : 1;
|
||||
} bits;
|
||||
} lwmqtt_connack_flags_t;
|
||||
|
||||
lwmqtt_err_t lwmqtt_encode_connect(unsigned char *buf, int buf_len, int *len, lwmqtt_options_t *options,
|
||||
lwmqtt_will_t *will) {
|
||||
// prepare pointer
|
||||
unsigned char *ptr = buf;
|
||||
|
||||
/* calculate remaining length */
|
||||
|
||||
// fixed header is 10
|
||||
int rem_len = 10;
|
||||
|
||||
// add client id
|
||||
rem_len += options->client_id.len + 2;
|
||||
|
||||
// add will if present
|
||||
if (will != NULL) {
|
||||
rem_len += will->topic.len + 2 + will->message.payload_len + 2;
|
||||
}
|
||||
|
||||
// add username if present
|
||||
if (options->username.len > 0) {
|
||||
rem_len += options->username.len + 2;
|
||||
|
||||
// add password if present
|
||||
if (options->password.len > 0) {
|
||||
rem_len += options->password.len + 2;
|
||||
}
|
||||
}
|
||||
|
||||
// check buffer capacity
|
||||
if (lwmqtt_total_header_length(rem_len) + rem_len > buf_len) {
|
||||
return LWMQTT_BUFFER_TOO_SHORT;
|
||||
}
|
||||
|
||||
/* encode packet */
|
||||
|
||||
// write header
|
||||
lwmqtt_header_t header = {0};
|
||||
header.bits.type = LWMQTT_CONNECT_PACKET;
|
||||
lwmqtt_write_char(&ptr, header.byte);
|
||||
|
||||
// write remaining length
|
||||
ptr += lwmqtt_encode_remaining_length(ptr, rem_len);
|
||||
|
||||
// write version
|
||||
lwmqtt_write_string(&ptr, lwmqtt_str("MQTT"));
|
||||
lwmqtt_write_char(&ptr, 4);
|
||||
|
||||
// prepare flags
|
||||
lwmqtt_connect_flags_t flags = {0};
|
||||
flags.bits.clean_session = options->clean_session ? 1 : 0;
|
||||
|
||||
// set will flags if present
|
||||
if (will != NULL) {
|
||||
flags.bits.will = 1;
|
||||
flags.bits.will_qos = (unsigned int)will->message.qos;
|
||||
flags.bits.will_retain = will->message.retained ? 1 : 0;
|
||||
}
|
||||
|
||||
// set username flag if present
|
||||
if (options->username.len > 0) {
|
||||
flags.bits.username = 1;
|
||||
|
||||
// set password flag if present
|
||||
if (options->password.len > 0) {
|
||||
flags.bits.password = 1;
|
||||
}
|
||||
}
|
||||
|
||||
// write flags
|
||||
lwmqtt_write_char(&ptr, flags.byte);
|
||||
|
||||
// write keep alive
|
||||
lwmqtt_write_int(&ptr, options->keep_alive);
|
||||
|
||||
// write client id
|
||||
lwmqtt_write_string(&ptr, options->client_id);
|
||||
|
||||
// write will topic and payload if present
|
||||
if (will != NULL) {
|
||||
lwmqtt_write_string(&ptr, will->topic);
|
||||
lwmqtt_write_int(&ptr, will->message.payload_len);
|
||||
memcpy(ptr, will->message.payload, will->message.payload_len);
|
||||
ptr += will->message.payload_len;
|
||||
}
|
||||
|
||||
// write username if present
|
||||
if (flags.bits.username) {
|
||||
lwmqtt_write_string(&ptr, options->username);
|
||||
|
||||
// write password if present
|
||||
if (flags.bits.password) {
|
||||
lwmqtt_write_string(&ptr, options->password);
|
||||
}
|
||||
}
|
||||
|
||||
// set written length
|
||||
*len = (int)(ptr - buf);
|
||||
|
||||
return LWMQTT_SUCCESS;
|
||||
}
|
||||
|
||||
lwmqtt_err_t lwmqtt_decode_connack(bool *session_present, lwmqtt_return_code_t *return_code, unsigned char *buf,
|
||||
int buf_len) {
|
||||
// prepare pointer
|
||||
unsigned char *ptr = buf;
|
||||
|
||||
// read header
|
||||
lwmqtt_header_t header;
|
||||
header.byte = lwmqtt_read_char(&ptr);
|
||||
if (header.bits.type != LWMQTT_CONNACK_PACKET) {
|
||||
return LWMQTT_DECODE_ERROR;
|
||||
}
|
||||
|
||||
// read remaining length
|
||||
int rem_len;
|
||||
lwmqtt_err_t err = lwmqtt_decode_remaining_length(&ptr, buf_len - 1, &rem_len);
|
||||
if (err != LWMQTT_SUCCESS) {
|
||||
return err;
|
||||
}
|
||||
|
||||
// check lengths
|
||||
if (rem_len != 2 || buf_len < rem_len + 2) {
|
||||
return LWMQTT_LENGTH_MISMATCH;
|
||||
}
|
||||
|
||||
// read flags
|
||||
lwmqtt_connack_flags_t flags;
|
||||
flags.byte = lwmqtt_read_char(&ptr);
|
||||
*session_present = flags.bits.session_present == 1;
|
||||
*return_code = (lwmqtt_return_code_t)lwmqtt_read_char(&ptr);
|
||||
|
||||
return LWMQTT_SUCCESS;
|
||||
}
|
||||
|
||||
lwmqtt_err_t lwmqtt_encode_zero(unsigned char *buf, int buf_len, int *len, lwmqtt_packet_type_t packet_type) {
|
||||
// prepare pointer
|
||||
unsigned char *ptr = buf;
|
||||
|
||||
// check buffer length
|
||||
if (buf_len < 2) {
|
||||
return LWMQTT_BUFFER_TOO_SHORT;
|
||||
}
|
||||
|
||||
// write header
|
||||
lwmqtt_header_t header = {0};
|
||||
header.bits.type = packet_type;
|
||||
lwmqtt_write_char(&ptr, header.byte);
|
||||
|
||||
// write remaining length
|
||||
ptr += lwmqtt_encode_remaining_length(ptr, 0);
|
||||
|
||||
// set length
|
||||
*len = (int)(ptr - buf);
|
||||
|
||||
return LWMQTT_SUCCESS;
|
||||
}
|
||||
|
||||
lwmqtt_err_t lwmqtt_decode_ack(lwmqtt_packet_type_t *packet_type, bool *dup, unsigned short *packet_id,
|
||||
unsigned char *buf, int buf_len) {
|
||||
// prepare pointer
|
||||
unsigned char *ptr = buf;
|
||||
|
||||
// read header
|
||||
lwmqtt_header_t header = {0};
|
||||
header.byte = lwmqtt_read_char(&ptr);
|
||||
*dup = header.bits.dup == 1;
|
||||
*packet_type = (lwmqtt_packet_type_t)header.bits.type;
|
||||
|
||||
// read remaining length
|
||||
int rem_len;
|
||||
lwmqtt_err_t err = lwmqtt_decode_remaining_length(&ptr, buf_len - 1, &rem_len);
|
||||
if (err != LWMQTT_SUCCESS) {
|
||||
return err;
|
||||
}
|
||||
|
||||
// check lengths
|
||||
if (rem_len != 2 || buf_len < rem_len + 2) {
|
||||
return LWMQTT_LENGTH_MISMATCH;
|
||||
}
|
||||
|
||||
// read packet id
|
||||
*packet_id = (unsigned short)lwmqtt_read_int(&ptr);
|
||||
|
||||
return LWMQTT_SUCCESS;
|
||||
}
|
||||
|
||||
lwmqtt_err_t lwmqtt_encode_ack(unsigned char *buf, int buf_len, int *len, lwmqtt_packet_type_t packet_type, bool dup,
|
||||
unsigned short packet_id) {
|
||||
// prepare pointer
|
||||
unsigned char *ptr = buf;
|
||||
|
||||
// check buffer size
|
||||
if (buf_len < 4) {
|
||||
return LWMQTT_BUFFER_TOO_SHORT;
|
||||
}
|
||||
|
||||
// write header
|
||||
lwmqtt_header_t header = {0};
|
||||
header.bits.type = packet_type;
|
||||
header.bits.dup = dup ? 1 : 0;
|
||||
header.bits.qos = (packet_type == LWMQTT_PUBREL_PACKET) ? 1 : 0;
|
||||
lwmqtt_write_char(&ptr, header.byte);
|
||||
|
||||
// write remaining length
|
||||
ptr += lwmqtt_encode_remaining_length(ptr, 2);
|
||||
|
||||
// write packet id
|
||||
lwmqtt_write_int(&ptr, packet_id);
|
||||
|
||||
// set written length
|
||||
*len = (int)(ptr - buf);
|
||||
|
||||
return LWMQTT_SUCCESS;
|
||||
}
|
||||
|
||||
lwmqtt_err_t lwmqtt_decode_publish(bool *dup, lwmqtt_qos_t *qos, bool *retained, unsigned short *packet_id,
|
||||
lwmqtt_string_t *topic, unsigned char **payload, int *payload_len,
|
||||
unsigned char *buf, int buf_len) {
|
||||
// prepare pointer
|
||||
unsigned char *ptr = buf;
|
||||
|
||||
// read header
|
||||
lwmqtt_header_t header;
|
||||
header.byte = lwmqtt_read_char(&ptr);
|
||||
if (header.bits.type != LWMQTT_PUBLISH_PACKET) {
|
||||
return LWMQTT_DECODE_ERROR;
|
||||
}
|
||||
|
||||
// set dup
|
||||
*dup = header.bits.dup == 1;
|
||||
|
||||
// set qos
|
||||
*qos = (lwmqtt_qos_t)header.bits.qos;
|
||||
|
||||
// set retained
|
||||
*retained = header.bits.retain == 1;
|
||||
|
||||
// read remaining length
|
||||
int rem_len;
|
||||
lwmqtt_err_t err = lwmqtt_decode_remaining_length(&ptr, buf_len - 1, &rem_len);
|
||||
if (err != LWMQTT_SUCCESS) {
|
||||
return err;
|
||||
}
|
||||
|
||||
// check lengths
|
||||
if (buf_len < rem_len + 2) {
|
||||
return LWMQTT_LENGTH_MISMATCH;
|
||||
}
|
||||
|
||||
// calculate end pointer
|
||||
unsigned char *end_ptr = ptr + rem_len;
|
||||
|
||||
// do we have enough data to read the topic?
|
||||
if (!lwmqtt_read_string(topic, &ptr, end_ptr) || end_ptr - ptr < 0) {
|
||||
return LWMQTT_DECODE_ERROR;
|
||||
}
|
||||
|
||||
// read packet id if qos is at least 1
|
||||
if (*qos > 0) {
|
||||
*packet_id = (unsigned short)lwmqtt_read_int(&ptr);
|
||||
} else {
|
||||
*packet_id = 0;
|
||||
}
|
||||
|
||||
// set payload
|
||||
*payload_len = (int)(end_ptr - ptr);
|
||||
*payload = ptr;
|
||||
|
||||
return LWMQTT_SUCCESS;
|
||||
}
|
||||
|
||||
lwmqtt_err_t lwmqtt_encode_publish(unsigned char *buf, int buf_len, int *len, bool dup, lwmqtt_qos_t qos, bool retained,
|
||||
unsigned short packet_id, lwmqtt_string_t topic, unsigned char *payload,
|
||||
int payload_len) {
|
||||
// prepare pointer
|
||||
unsigned char *ptr = buf;
|
||||
|
||||
// prepare remaining length
|
||||
int rem_len = 2 + topic.len + payload_len;
|
||||
|
||||
// add packet id if qos is at least 1
|
||||
if (qos > 0) {
|
||||
rem_len += 2;
|
||||
}
|
||||
|
||||
// check buffer size
|
||||
if (lwmqtt_total_header_length(rem_len) + rem_len > buf_len) {
|
||||
return LWMQTT_BUFFER_TOO_SHORT;
|
||||
}
|
||||
|
||||
// write header
|
||||
lwmqtt_header_t header = {0};
|
||||
header.bits.type = LWMQTT_PUBLISH_PACKET;
|
||||
header.bits.dup = dup ? 1 : 0;
|
||||
header.bits.qos = (unsigned int)qos;
|
||||
header.bits.retain = retained ? 1 : 0;
|
||||
lwmqtt_write_char(&ptr, header.byte);
|
||||
|
||||
// write remaining length
|
||||
ptr += lwmqtt_encode_remaining_length(ptr, rem_len);
|
||||
|
||||
// write topic
|
||||
lwmqtt_write_string(&ptr, topic);
|
||||
|
||||
// write packet id if qos is at least 1
|
||||
if (qos > 0) {
|
||||
lwmqtt_write_int(&ptr, packet_id);
|
||||
}
|
||||
|
||||
// write payload
|
||||
memcpy(ptr, payload, payload_len);
|
||||
ptr += payload_len;
|
||||
|
||||
// set length
|
||||
*len = (int)(ptr - buf);
|
||||
|
||||
return LWMQTT_SUCCESS;
|
||||
}
|
||||
|
||||
lwmqtt_err_t lwmqtt_encode_subscribe(unsigned char *buf, int buf_len, int *len, unsigned short packet_id, int count,
|
||||
lwmqtt_string_t *topic_filters, lwmqtt_qos_t *qos_levels) {
|
||||
// prepare pointer
|
||||
unsigned char *ptr = buf;
|
||||
|
||||
// prepare remaining length
|
||||
int rem_len = 2;
|
||||
|
||||
// add all topics
|
||||
for (int i = 0; i < count; i++) {
|
||||
rem_len += 2 + topic_filters[i].len + 1;
|
||||
}
|
||||
|
||||
// check buffer size
|
||||
if (lwmqtt_total_header_length(rem_len) + rem_len > buf_len) {
|
||||
return LWMQTT_BUFFER_TOO_SHORT;
|
||||
}
|
||||
|
||||
// write header
|
||||
lwmqtt_header_t header = {0};
|
||||
header.bits.type = LWMQTT_SUBSCRIBE_PACKET;
|
||||
header.bits.qos = 1;
|
||||
lwmqtt_write_char(&ptr, header.byte);
|
||||
|
||||
// write remaining length
|
||||
ptr += lwmqtt_encode_remaining_length(ptr, rem_len);
|
||||
|
||||
// write packet id
|
||||
lwmqtt_write_int(&ptr, packet_id);
|
||||
|
||||
// write all topics
|
||||
for (int i = 0; i < count; i++) {
|
||||
lwmqtt_write_string(&ptr, topic_filters[i]);
|
||||
lwmqtt_write_char(&ptr, (unsigned char)qos_levels[i]);
|
||||
}
|
||||
|
||||
// set length
|
||||
*len = (int)(ptr - buf);
|
||||
|
||||
return LWMQTT_SUCCESS;
|
||||
}
|
||||
|
||||
lwmqtt_err_t lwmqtt_decode_suback(unsigned short *packet_id, int max_count, int *count,
|
||||
lwmqtt_qos_t *granted_qos_levels, unsigned char *buf, int buf_len) {
|
||||
// prepare pointer
|
||||
unsigned char *ptr = buf;
|
||||
|
||||
// read header
|
||||
lwmqtt_header_t header;
|
||||
header.byte = lwmqtt_read_char(&ptr);
|
||||
if (header.bits.type != LWMQTT_SUBACK_PACKET) {
|
||||
return LWMQTT_DECODE_ERROR;
|
||||
}
|
||||
|
||||
// read remaining length
|
||||
int rem_len;
|
||||
lwmqtt_err_t err = lwmqtt_decode_remaining_length(&ptr, buf_len - 1, &rem_len);
|
||||
if (err != LWMQTT_SUCCESS) {
|
||||
return err;
|
||||
}
|
||||
|
||||
unsigned char *end_ptr = ptr + rem_len;
|
||||
|
||||
if (end_ptr - ptr < 2) {
|
||||
return LWMQTT_LENGTH_MISMATCH;
|
||||
}
|
||||
|
||||
// read packet id
|
||||
*packet_id = (unsigned short)lwmqtt_read_int(&ptr);
|
||||
|
||||
// read all suback codes
|
||||
*count = 0;
|
||||
while (ptr < end_ptr) {
|
||||
if (*count > max_count) {
|
||||
return LWMQTT_DECODE_ERROR;
|
||||
}
|
||||
|
||||
granted_qos_levels[(*count)++] = (lwmqtt_qos_t)lwmqtt_read_char(&ptr);
|
||||
}
|
||||
|
||||
return LWMQTT_SUCCESS;
|
||||
}
|
||||
|
||||
lwmqtt_err_t lwmqtt_encode_unsubscribe(unsigned char *buf, int buf_len, int *len, unsigned short packet_id, int count,
|
||||
lwmqtt_string_t *topic_filters) {
|
||||
// prepare pointer
|
||||
unsigned char *ptr = buf;
|
||||
|
||||
// prepare remaining length
|
||||
int rem_len = 2;
|
||||
|
||||
// add all topics
|
||||
for (int i = 0; i < count; i++) {
|
||||
rem_len += 2 + topic_filters[i].len;
|
||||
}
|
||||
|
||||
// check buffer size
|
||||
if (lwmqtt_total_header_length(rem_len) + rem_len > buf_len) {
|
||||
return LWMQTT_BUFFER_TOO_SHORT;
|
||||
}
|
||||
|
||||
// write header
|
||||
lwmqtt_header_t header = {0};
|
||||
header.bits.type = LWMQTT_UNSUBSCRIBE_PACKET;
|
||||
header.bits.qos = 1;
|
||||
lwmqtt_write_char(&ptr, header.byte);
|
||||
|
||||
// write remaining length
|
||||
ptr += lwmqtt_encode_remaining_length(ptr, rem_len);
|
||||
|
||||
// write packet id
|
||||
lwmqtt_write_int(&ptr, packet_id);
|
||||
|
||||
// write topics
|
||||
for (int i = 0; i < count; i++) {
|
||||
lwmqtt_write_string(&ptr, topic_filters[i]);
|
||||
}
|
||||
|
||||
// set length
|
||||
*len = (int)(ptr - buf);
|
||||
|
||||
return LWMQTT_SUCCESS;
|
||||
}
|
32
dtest/mqtt_test/src/unix.c
Executable file
32
dtest/mqtt_test/src/unix.c
Executable file
@@ -0,0 +1,32 @@
|
||||
#include <unix.h>
|
||||
|
||||
void lwmqtt_unix_timer_set(lwmqtt_client_t *client, void *ref, unsigned int timeout) {
|
||||
|
||||
}
|
||||
|
||||
unsigned int lwmqtt_unix_timer_get(lwmqtt_client_t *client, void *ref) {
|
||||
return LWMQTT_SUCCESS;
|
||||
}
|
||||
|
||||
lwmqtt_err_t lwmqtt_unix_network_connect(lwmqtt_unix_network_t *network, char *host, int port) {
|
||||
|
||||
return LWMQTT_SUCCESS;
|
||||
}
|
||||
|
||||
void lwmqtt_unix_network_disconnect(lwmqtt_unix_network_t *network) {
|
||||
|
||||
}
|
||||
|
||||
lwmqtt_err_t lwmqtt_unix_network_peek(lwmqtt_client_t *client, lwmqtt_unix_network_t *network, int *available) {
|
||||
return LWMQTT_SUCCESS;
|
||||
}
|
||||
|
||||
lwmqtt_err_t lwmqtt_unix_network_read(lwmqtt_client_t *client, void *ref, unsigned char *buffer, int len, int *read,
|
||||
unsigned int timeout) {
|
||||
return LWMQTT_SUCCESS;
|
||||
}
|
||||
|
||||
lwmqtt_err_t lwmqtt_unix_network_write(lwmqtt_client_t *client, void *ref, unsigned char *buffer, int len, int *sent,
|
||||
unsigned int timeout) {
|
||||
return LWMQTT_SUCCESS;
|
||||
}
|
Reference in New Issue
Block a user