初始提交

This commit is contained in:
2024-09-28 14:24:04 +08:00
commit c756587541
5564 changed files with 2413077 additions and 0 deletions

37
dtest/mqtt_test/Makefile Executable file
View 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)

View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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;
}