diff options
author | Flavio Santes <flavio.santes@intel.com> | 2016-12-19 12:15:00 -0600 |
---|---|---|
committer | Jukka Rissanen <jukka.rissanen@linux.intel.com> | 2017-02-03 15:59:18 +0200 |
commit | 59b1384885f775ffd6a5aa5368cfc1ba7f9cbf70 (patch) | |
tree | 77619b65d75920e3047def31091f566cb8841473 /samples | |
parent | 02bd8411dc07570cdb4971ae7ae42918094d649d (diff) |
net/mqtt: Add the MQTT Publisher sample application
This commit adds the MQTT Publisher sample application for Zephyr.
The following MQTT API routines are exercised in this sample:
- mqtt_init
- mqtt_tx_connect
- mqtt_tx_pingreq
- mqtt_tx_publish
- mqtt_tx_disconnect
The following MQTT API data structures are used in this application:
- struct mqtt_ctx
- struct mqtt_connect_msg
- struct mqtt_publish_msg
This sample application exemplifies how to send MQTT PUBLISH messages
with different QoS values.
A README file is also included in this patch.
Change-Id: I2b41b276d5178a2cd1b07b031c38bff481885fff
Signed-off-by: Flavio Santes <flavio.santes@intel.com>
Diffstat (limited to 'samples')
-rw-r--r-- | samples/net/mqtt_publisher/Makefile | 14 | ||||
-rw-r--r-- | samples/net/mqtt_publisher/README.rst | 236 | ||||
-rw-r--r-- | samples/net/mqtt_publisher/prj_frdm_k64f.conf | 36 | ||||
-rw-r--r-- | samples/net/mqtt_publisher/src/Makefile | 8 | ||||
-rw-r--r-- | samples/net/mqtt_publisher/src/config.h | 37 | ||||
-rw-r--r-- | samples/net/mqtt_publisher/src/main.c | 410 | ||||
-rw-r--r-- | samples/net/mqtt_publisher/testcase.ini | 4 |
7 files changed, 745 insertions, 0 deletions
diff --git a/samples/net/mqtt_publisher/Makefile b/samples/net/mqtt_publisher/Makefile new file mode 100644 index 000000000..e2b27bdfb --- /dev/null +++ b/samples/net/mqtt_publisher/Makefile @@ -0,0 +1,14 @@ +# +# Copyright (c) 2017 Intel Corporation +# +# SPDX-License-Identifier: Apache-2.0 +# + +BOARD ?= frdm_k64f +CONF_FILE ?= prj_$(BOARD).conf + +include $(ZEPHYR_BASE)/Makefile.inc + +ifeq ($(BOARD), qemu_x86) + include $(ZEPHYR_BASE)/samples/net/common/Makefile.ipstack +endif diff --git a/samples/net/mqtt_publisher/README.rst b/samples/net/mqtt_publisher/README.rst new file mode 100644 index 000000000..be597f125 --- /dev/null +++ b/samples/net/mqtt_publisher/README.rst @@ -0,0 +1,236 @@ +MQTT Publisher +############## + +Overview +******** + +`MQTT <http://mqtt.org/>`_ (MQ Telemetry Transport) is a lightweight +publish/subscribe messaging protocol optimized for small sensors and +mobile devices. + +The Zephyr MQTT Publisher sample application is a MQTT v3.1.1 +client that sends MQTT PUBLISH messages to a MQTT broker. +See the `MQTT V3.1.1 spec`_ for more information. + +.. _MQTT V3.1.1 spec: http://docs.oasis-open.org/mqtt/mqtt/v3.1.1/mqtt-v3.1.1.html + +The source code of this sample application can be found at: +:file:`samples/net/mqtt_publisher`. + +Requirements +************ + +- Linux machine +- Freedom Board (FRDM-K64F) +- Mosquitto server: any version that supports MQTT v3.1.1. This sample + was tested with mosquitto 1.3.4. +- Mosquitto subscriber +- LAN for testing purposes (Ethernet) + +Build and Running +***************** + +Currently, this sample application only supports static IP addresses. +Open the :file:`src/config.h` file and set the IP addresses according +to the LAN environment. +Alternatively, set the IP addresses in the :file:`prj_frdm_k64f.conf` file. + +This file :file:`src/config.h` also contains some variables that may be changed: + +MQTT broker TCP port: + +.. code-block:: c + + #define SERVER_PORT 1883 + +Application sleep time: + +.. code-block:: c + + #define APP_SLEEP_MSECS 500 + +Application RX and TX timeout: + +.. code-block:: c + + #define APP_TX_RX_TIMEOUT 300 + +Max number of connection tries: + +.. code-block:: c + + #define APP_CONNECT_TRIES 10 + +Max number of MQTT PUBLISH iterations + +.. code-block:: c + + #define APP_MAX_ITERATIONS 5 + +On your Linux host computer, open a terminal window, locate the source code +of this sample application (i.e. :file:`samples/net/mqtt_publisher`) and type: + +.. code-block:: console + + make BOARD=frdm_k64f + +Open another terminal window and type: + +.. code-block:: console + + sudo mosquitto -v -p 1883 + +Open another terminal window and type: + +.. code-block:: console + + mosquito_sub -t sensors + +Sample output +============= + +This is the output from the FRDM UART console, with: + +.. code-block:: c + + #define APP_MAX_ITERATIONS 5 + +.. code-block:: console + + [dev/eth_mcux] [INF] eth_0_init: Enabled 100M full-duplex mode. + [dev/eth_mcux] [DBG] eth_0_init: MAC 00:04:9f:3e:1a:0a + [publisher:233] network_setup: 0 <OK> + [publisher:258] mqtt_init: 0 <OK> + [connect_cb:81] user_data: CONNECTED + [try_to_connect:212] mqtt_tx_connect: 0 <OK> + [publisher:276] try_to_connect: 0 <OK> + [publisher:285] mqtt_tx_pingreq: 0 <OK> + [publisher:290] mqtt_tx_publish: 0 <OK> + [publish_cb:149] <MQTT_PUBACK> packet id: 1888, user_data: PUBLISH + [publisher:295] mqtt_tx_publish: 0 <OK> + [publish_cb:149] <MQTT_PUBREC> packet id: 16356, user_data: PUBLISH + [publish_cb:149] <MQTT_PUBCOMP> packet id: 16356, user_data: PUBLISH + [publisher:300] mqtt_tx_publish: 0 <OK> + [publisher:285] mqtt_tx_pingreq: 0 <OK> + [publisher:290] mqtt_tx_publish: 0 <OK> + [publish_cb:149] <MQTT_PUBACK> packet id: 45861, user_data: PUBLISH + [publisher:295] mqtt_tx_publish: 0 <OK> + [publish_cb:149] <MQTT_PUBREC> packet id: 53870, user_data: PUBLISH + [publish_cb:149] <MQTT_PUBCOMP> packet id: 53870, user_data: PUBLISH + [publisher:300] mqtt_tx_publish: 0 <OK> + [publisher:285] mqtt_tx_pingreq: 0 <OK> + [publisher:290] mqtt_tx_publish: 0 <OK> + [publish_cb:149] <MQTT_PUBACK> packet id: 60144, user_data: PUBLISH + [publisher:295] mqtt_tx_publish: 0 <OK> + [publish_cb:149] <MQTT_PUBREC> packet id: 6561, user_data: PUBLISH + [publish_cb:149] <MQTT_PUBCOMP> packet id: 6561, user_data: PUBLISH + [publisher:300] mqtt_tx_publish: 0 <OK> + [publisher:285] mqtt_tx_pingreq: 0 <OK> + [publisher:290] mqtt_tx_publish: 0 <OK> + [publish_cb:149] <MQTT_PUBACK> packet id: 38355, user_data: PUBLISH + [publisher:295] mqtt_tx_publish: 0 <OK> + [publish_cb:149] <MQTT_PUBREC> packet id: 60656, user_data: PUBLISH + [publish_cb:149] <MQTT_PUBCOMP> packet id: 60656, user_data: PUBLISH + [publisher:300] mqtt_tx_publish: 0 <OK> + [publisher:285] mqtt_tx_pingreq: 0 <OK> + [publisher:290] mqtt_tx_publish: 0 <OK> + [publish_cb:149] <MQTT_PUBACK> packet id: 28420, user_data: PUBLISH + [publisher:295] mqtt_tx_publish: 0 <OK> + [publish_cb:149] <MQTT_PUBREC> packet id: 49829, user_data: PUBLISH + [publish_cb:149] <MQTT_PUBCOMP> packet id: 49829, user_data: PUBLISH + [publisher:300] mqtt_tx_publish: 0 <OK> + [disconnect_cb:101] user_data: DISCONNECTED + [publisher:304] mqtt_tx_disconnect: 0 <OK> + + Bye! + +The line: + +.. code-block:: console + + [try_to_connect:220] mqtt_connect: -5 <ERROR> + +means that an error was detected and a new connect message will be sent. + +The MQTT API is asynchronous, so messages are displayed as the callbacks are +executed. + +This is the information that the subscriber will receive: + +.. code-block:: console + + mosquitto_sub -t sensors + DOORS:OPEN_QoS0 + DOORS:OPEN_QoS1 + DOORS:OPEN_QoS2 + DOORS:OPEN_QoS0 + DOORS:OPEN_QoS1 + DOORS:OPEN_QoS2 + DOORS:OPEN_QoS0 + DOORS:OPEN_QoS1 + DOORS:OPEN_QoS2 + DOORS:OPEN_QoS0 + DOORS:OPEN_QoS1 + DOORS:OPEN_QoS2 + DOORS:OPEN_QoS0 + DOORS:OPEN_QoS1 + DOORS:OPEN_QoS2 + +This is the output from the MQTT broker: + +.. code-block:: console + + sudo mosquitto -v + 1485663791: mosquitto version 1.3.4 (build date 2014-08-17 00:14:52-0300) starting + 1485663791: Using default config. + 1485663791: Opening ipv4 listen socket on port 1883. + 1485663791: Opening ipv6 listen socket on port 1883. + 1485663797: New connection from 192.168.1.101 on port 1883. + 1485663797: New client connected from 192.168.1.101 as zephyr_publisher (c1, k0). + 1485663797: Sending CONNACK to zephyr_publisher (0) + 1485663798: Received PINGREQ from zephyr_publisher + 1485663798: Sending PINGRESP to zephyr_publisher + 1485663798: Received PUBLISH from zephyr_publisher (d0, q0, r0, m0, 'sensors', ... (15 bytes)) + 1485663799: Received PUBLISH from zephyr_publisher (d0, q1, r0, m1888, 'sensors', ... (15 bytes)) + 1485663799: Sending PUBACK to zephyr_publisher (Mid: 1888) + 1485663799: Received PUBLISH from zephyr_publisher (d0, q2, r0, m16356, 'sensors', ... (15 bytes)) + 1485663799: Sending PUBREC to zephyr_publisher (Mid: 16356) + 1485663799: Received PUBREL from zephyr_publisher (Mid: 16356) + 1485663799: Sending PUBCOMP to zephyr_publisher (Mid: 16356) + 1485663800: Received PINGREQ from zephyr_publisher + 1485663800: Sending PINGRESP to zephyr_publisher + 1485663800: Received PUBLISH from zephyr_publisher (d0, q0, r0, m0, 'sensors', ... (15 bytes)) + 1485663801: Received PUBLISH from zephyr_publisher (d0, q1, r0, m45861, 'sensors', ... (15 bytes)) + 1485663801: Sending PUBACK to zephyr_publisher (Mid: 45861) + 1485663801: Received PUBLISH from zephyr_publisher (d0, q2, r0, m53870, 'sensors', ... (15 bytes)) + 1485663801: Sending PUBREC to zephyr_publisher (Mid: 53870) + 1485663801: Received PUBREL from zephyr_publisher (Mid: 53870) + 1485663801: Sending PUBCOMP to zephyr_publisher (Mid: 53870) + 1485663802: Received PINGREQ from zephyr_publisher + 1485663802: Sending PINGRESP to zephyr_publisher + 1485663802: Received PUBLISH from zephyr_publisher (d0, q0, r0, m0, 'sensors', ... (15 bytes)) + 1485663803: Received PUBLISH from zephyr_publisher (d0, q1, r0, m60144, 'sensors', ... (15 bytes)) + 1485663803: Sending PUBACK to zephyr_publisher (Mid: 60144) + 1485663803: Received PUBLISH from zephyr_publisher (d0, q2, r0, m6561, 'sensors', ... (15 bytes)) + 1485663803: Sending PUBREC to zephyr_publisher (Mid: 6561) + 1485663803: Received PUBREL from zephyr_publisher (Mid: 6561) + 1485663803: Sending PUBCOMP to zephyr_publisher (Mid: 6561) + 1485663804: Received PINGREQ from zephyr_publisher + 1485663804: Sending PINGRESP to zephyr_publisher + 1485663804: Received PUBLISH from zephyr_publisher (d0, q0, r0, m0, 'sensors', ... (15 bytes)) + 1485663805: Received PUBLISH from zephyr_publisher (d0, q1, r0, m38355, 'sensors', ... (15 bytes)) + 1485663805: Sending PUBACK to zephyr_publisher (Mid: 38355) + 1485663805: Received PUBLISH from zephyr_publisher (d0, q2, r0, m60656, 'sensors', ... (15 bytes)) + 1485663805: Sending PUBREC to zephyr_publisher (Mid: 60656) + 1485663805: Received PUBREL from zephyr_publisher (Mid: 60656) + 1485663805: Sending PUBCOMP to zephyr_publisher (Mid: 60656) + 1485663806: Received PINGREQ from zephyr_publisher + 1485663806: Sending PINGRESP to zephyr_publisher + 1485663806: Received PUBLISH from zephyr_publisher (d0, q0, r0, m0, 'sensors', ... (15 bytes)) + 1485663807: Received PUBLISH from zephyr_publisher (d0, q1, r0, m28420, 'sensors', ... (15 bytes)) + 1485663807: Sending PUBACK to zephyr_publisher (Mid: 28420) + 1485663807: Received PUBLISH from zephyr_publisher (d0, q2, r0, m49829, 'sensors', ... (15 bytes)) + 1485663807: Sending PUBREC to zephyr_publisher (Mid: 49829) + 1485663807: Received PUBREL from zephyr_publisher (Mid: 49829) + 1485663807: Sending PUBCOMP to zephyr_publisher (Mid: 49829) + 1485663808: Received DISCONNECT from zephyr_publisher diff --git a/samples/net/mqtt_publisher/prj_frdm_k64f.conf b/samples/net/mqtt_publisher/prj_frdm_k64f.conf new file mode 100644 index 000000000..2df75a2ba --- /dev/null +++ b/samples/net/mqtt_publisher/prj_frdm_k64f.conf @@ -0,0 +1,36 @@ +CONFIG_NETWORKING=y +CONFIG_NET_TCP=y +CONFIG_RANDOM_GENERATOR=y +CONFIG_NET_ARP=y +CONFIG_NET_L2_ETHERNET=y +CONFIG_NET_LOG=y +CONFIG_INIT_STACKS=y + +CONFIG_NET_NBUF_RX_COUNT=16 +CONFIG_NET_NBUF_TX_COUNT=16 +CONFIG_NET_NBUF_DATA_COUNT=16 + +CONFIG_NET_IPV6_RA_RDNSS=y +CONFIG_NET_IFACE_UNICAST_IPV4_ADDR_COUNT=3 + +CONFIG_PRINTK=y +#CONFIG_NET_DEBUG_NET_BUF=y + +CONFIG_NET_IPV4=n +# Enable IPv6 support +CONFIG_NET_IPV6=y + +# Enable the MQTT Lib +CONFIG_MQTT_LIB=y + +CONFIG_NET_SAMPLES_IP_ADDRESSES=y +CONFIG_NET_SAMPLES_MY_IPV6_ADDR="2001:db8::1" +CONFIG_NET_SAMPLES_PEER_IPV6_ADDR="2001:db8::2" + +CONFIG_NET_SAMPLES_MY_IPV4_ADDR="192.168.1.101" +CONFIG_NET_SAMPLES_PEER_IPV4_ADDR="192.168.1.10" + +CONFIG_MAIN_STACK_SIZE=2048 + +# For IPv6 +CONFIG_NET_NBUF_DATA_SIZE=256 diff --git a/samples/net/mqtt_publisher/src/Makefile b/samples/net/mqtt_publisher/src/Makefile new file mode 100644 index 000000000..9715a81e7 --- /dev/null +++ b/samples/net/mqtt_publisher/src/Makefile @@ -0,0 +1,8 @@ +# +# Copyright (c) 2017 Intel Corporation +# +# SPDX-License-Identifier: Apache-2.0 +# + +obj-y += main.o + diff --git a/samples/net/mqtt_publisher/src/config.h b/samples/net/mqtt_publisher/src/config.h new file mode 100644 index 000000000..e9e4d3ec0 --- /dev/null +++ b/samples/net/mqtt_publisher/src/config.h @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2017 Intel Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef __CONFIG_H__ +#define __CONFIG_H__ + +#ifdef CONFIG_NET_SAMPLES_IP_ADDRESSES +#ifdef CONFIG_NET_IPV6 +#define ZEPHYR_ADDR CONFIG_NET_SAMPLES_MY_IPV6_ADDR +#define SERVER_ADDR CONFIG_NET_SAMPLES_PEER_IPV6_ADDR +#else +#define ZEPHYR_ADDR CONFIG_NET_SAMPLES_MY_IPV4_ADDR +#define SERVER_ADDR CONFIG_NET_SAMPLES_PEER_IPV4_ADDR +#endif +#else +#ifdef CONFIG_NET_IPV6 +#define ZEPHYR_ADDR "2001:db8::1" +#define SERVER_ADDR "2001:db8::2" +#else +#define ZEPHYR_ADDR "192.168.1.101" +#define SERVER_ADDR "192.168.1.10" +#endif +#endif + +#define SERVER_PORT 1883 + +#define APP_SLEEP_MSECS 500 +#define APP_TX_RX_TIMEOUT 300 + +#define APP_CONNECT_TRIES 10 + +#define APP_MAX_ITERATIONS 100 + +#endif diff --git a/samples/net/mqtt_publisher/src/main.c b/samples/net/mqtt_publisher/src/main.c new file mode 100644 index 000000000..909a1d211 --- /dev/null +++ b/samples/net/mqtt_publisher/src/main.c @@ -0,0 +1,410 @@ +/* + * Copyright (c) 2017 Intel Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include <zephyr.h> +#include <net/mqtt.h> + +#include <net/net_context.h> +#include <net/nbuf.h> + +#include <misc/printk.h> +#include <string.h> +#include <errno.h> + +#include "config.h" + +/** + * @brief mqtt_client_ctx Container of some structures used by the + * publisher app. + */ +struct mqtt_client_ctx { + /** + * The connect message structure is only used during the connect + * stage. Developers must set some msg properties before calling the + * mqtt_tx_connect routine. See below. + */ + struct mqtt_connect_msg connect_msg; + /** + * This is the message that will be received by the server + * (MQTT broker). + */ + struct mqtt_publish_msg pub_msg; + + /** + * This is the MQTT application context variable. + */ + struct mqtt_ctx mqtt_ctx; + + /** + * This variable will be passed to the connect callback, declared inside + * the mqtt context struct. If not used, it could be set to NULL. + */ + void *connect_data; + + /** + * This variable will be passed to the disconnect callback, declared + * inside the mqtt context struct. If not used, it could be set to NULL. + */ + void *disconnect_data; + + /** + * This variable will be passed to the publish_tx callback, declared + * inside the mqtt context struct. If not used, it could be set to NULL. + */ + void *publish_data; +}; + +/* This is the network context structure. */ +static struct net_context *net_ctx; + +/* The mqtt client struct */ +static struct mqtt_client_ctx client_ctx; + +/* This routine sets some basic properties for the network context variable */ +static +int network_setup(struct net_context **net_ctx, const char *local_addr, + const char *server_addr, uint16_t server_port); + +/* The signature of this routine must match the connect callback declared at + * the mqtt.h header. + */ +static +void connect_cb(struct mqtt_ctx *mqtt_ctx) +{ + struct mqtt_client_ctx *client_ctx; + + client_ctx = CONTAINER_OF(mqtt_ctx, struct mqtt_client_ctx, mqtt_ctx); + + printk("[%s:%d]", __func__, __LINE__); + + if (client_ctx->connect_data) { + printk(" user_data: %s", + (const char *)client_ctx->connect_data); + } + + printk("\n"); +} + +/* The signature of this routine must match the disconnect callback declared at + * the mqtt.h header. + */ +static +void disconnect_cb(struct mqtt_ctx *mqtt_ctx) +{ + struct mqtt_client_ctx *client_ctx; + + client_ctx = CONTAINER_OF(mqtt_ctx, struct mqtt_client_ctx, mqtt_ctx); + + printk("[%s:%d]", __func__, __LINE__); + + if (client_ctx->disconnect_data) { + printk(" user_data: %s", + (const char *)client_ctx->disconnect_data); + } + + printk("\n"); +} + +/** + * The signature of this routine must match the publish_tx callback declared at + * the mqtt.h header. + * + * NOTE: we have two callbacks for MQTT Publish related stuff: + * - publish_tx, for publishers + * - publish_rx, for subscribers + * + * Applications must keep a "message database" with pkt_id's. So far, this is + * not implemented here. For example, if we receive a PUBREC message with an + * unknown pkt_id, this routine must return an error, for example -EINVAL or + * any negative value. + */ +static +int publish_cb(struct mqtt_ctx *mqtt_ctx, uint16_t pkt_id, + enum mqtt_packet type) +{ + struct mqtt_client_ctx *client_ctx; + const char *str; + int rc = 0; + + client_ctx = CONTAINER_OF(mqtt_ctx, struct mqtt_client_ctx, mqtt_ctx); + + switch (type) { + case MQTT_PUBACK: + str = "MQTT_PUBACK"; + break; + case MQTT_PUBCOMP: + str = "MQTT_PUBCOMP"; + break; + case MQTT_PUBREC: + str = "MQTT_PUBREC"; + break; + default: + rc = -EINVAL; + str = "Invalid MQTT packet"; + } + + printk("[%s:%d] <%s> packet id: %u", __func__, __LINE__, str, pkt_id); + + if (client_ctx->publish_data) { + printk(", user_data: %s", + (const char *)client_ctx->publish_data); + } + + printk("\n"); + + return rc; +} + +/** + * The signature of this routine must match the malformed callback declared at + * the mqtt.h header. + */ +static +void malformed_cb(struct mqtt_ctx *mqtt_ctx, uint16_t pkt_type) +{ + printk("[%s:%d] pkt_type: %u\n", __func__, __LINE__, pkt_type); +} + +static const char topic[] = "sensors"; + +char payload[] = "DOORS:OPEN_QoSx"; + +static +void prepare_mqtt_publish_msg(struct mqtt_publish_msg *pub_msg, + enum mqtt_qos qos) +{ + payload[strlen(payload) - 1] = '0' + qos; + + /* MQTT message payload may be anything, we we use C strings */ + pub_msg->msg = payload; + /* Payload's length */ + pub_msg->msg_len = strlen(client_ctx.pub_msg.msg); + /* MQTT Quality of Service */ + pub_msg->qos = qos; + /* Message's topic */ + pub_msg->topic = (char *)topic; + pub_msg->topic_len = strlen(client_ctx.pub_msg.topic); + /* Packet Identifier, always use different values */ + pub_msg->pkt_id = sys_rand32_get(); + +} + +#define RC_STR(rc) ((rc) == 0 ? "OK" : "ERROR") + +#define PRINT_RESULT(func, rc) \ + printk("[%s:%d] %s: %d <%s>\n", __func__, __LINE__, \ + (func), rc, RC_STR(rc)) + +/* In this routine we block until the connected variable is 1 */ +static +int try_to_connect(struct mqtt_client_ctx *client_ctx) +{ + int i = 0; + + while (i++ < APP_CONNECT_TRIES && !client_ctx->mqtt_ctx.connected) { + int rc; + + rc = mqtt_tx_connect(&client_ctx->mqtt_ctx, + &client_ctx->connect_msg); + k_sleep(APP_SLEEP_MSECS); + PRINT_RESULT("mqtt_tx_connect", rc); + if (rc != 0) { + continue; + } + } + + if (client_ctx->mqtt_ctx.connected) { + return 0; + } + + return -EINVAL; +} + +static +void publisher(void) +{ + int i, rc; + + /* The net_ctx variable must be ready BEFORE passing it to the MQTT API. + */ + rc = network_setup(&net_ctx, ZEPHYR_ADDR, SERVER_ADDR, SERVER_PORT); + PRINT_RESULT("network_setup", rc); + if (rc != 0) { + goto exit_app; + } + + /* Set everything to 0 and later just assign the required fields. */ + memset(&client_ctx, 0x00, sizeof(client_ctx)); + + /* The network context is the only field that must be set BEFORE + * calling the mqtt_init routine. + */ + client_ctx.mqtt_ctx.net_ctx = net_ctx; + + /* connect, disconnect and malformed may be set to NULL */ + client_ctx.mqtt_ctx.connect = connect_cb; + + client_ctx.mqtt_ctx.disconnect = disconnect_cb; + client_ctx.mqtt_ctx.malformed = malformed_cb; + + client_ctx.mqtt_ctx.net_timeout = APP_TX_RX_TIMEOUT; + + /* Publisher apps TX the MQTT PUBLISH msg */ + client_ctx.mqtt_ctx.publish_tx = publish_cb; + + rc = mqtt_init(&client_ctx.mqtt_ctx, MQTT_APP_PUBLISHER); + PRINT_RESULT("mqtt_init", rc); + if (rc != 0) { + goto exit_app; + } + + /* The connect message will be sent to the MQTT server (broker). + * If clean_session here is 0, the mqtt_ctx clean_session variable + * will be set to 0 also. Please don't do that, set always to 1. + * Clean session = 0 is not yet supported. + */ + client_ctx.connect_msg.client_id = "zephyr_publisher"; + client_ctx.connect_msg.clean_session = 1; + + client_ctx.connect_data = "CONNECTED"; + client_ctx.disconnect_data = "DISCONNECTED"; + client_ctx.publish_data = "PUBLISH"; + + rc = try_to_connect(&client_ctx); + PRINT_RESULT("try_to_connect", rc); + if (rc != 0) { + goto exit_app; + } + + i = 0; + while (i++ < APP_MAX_ITERATIONS) { + rc = mqtt_tx_pingreq(&client_ctx.mqtt_ctx); + k_sleep(APP_SLEEP_MSECS); + PRINT_RESULT("mqtt_tx_pingreq", rc); + + prepare_mqtt_publish_msg(&client_ctx.pub_msg, MQTT_QoS0); + rc = mqtt_tx_publish(&client_ctx.mqtt_ctx, &client_ctx.pub_msg); + k_sleep(APP_SLEEP_MSECS); + PRINT_RESULT("mqtt_tx_publish", rc); + + prepare_mqtt_publish_msg(&client_ctx.pub_msg, MQTT_QoS1); + rc = mqtt_tx_publish(&client_ctx.mqtt_ctx, &client_ctx.pub_msg); + k_sleep(APP_SLEEP_MSECS); + PRINT_RESULT("mqtt_tx_publish", rc); + + prepare_mqtt_publish_msg(&client_ctx.pub_msg, MQTT_QoS2); + rc = mqtt_tx_publish(&client_ctx.mqtt_ctx, &client_ctx.pub_msg); + k_sleep(APP_SLEEP_MSECS); + PRINT_RESULT("mqtt_tx_publish", rc); + } + + rc = mqtt_tx_disconnect(&client_ctx.mqtt_ctx); + PRINT_RESULT("mqtt_tx_disconnect", rc); + +exit_app: + net_context_put(net_ctx); + printk("\nBye!\n"); +} + +static +int set_addr(struct sockaddr *sock_addr, const char *addr, uint16_t port) +{ + void *ptr; + int rc; + +#ifdef CONFIG_NET_IPV6 + net_sin6(sock_addr)->sin6_port = htons(port); + sock_addr->family = AF_INET6; + ptr = &(net_sin6(sock_addr)->sin6_addr); + rc = net_addr_pton(AF_INET6, addr, ptr); +#else + net_sin(sock_addr)->sin_port = htons(port); + sock_addr->family = AF_INET; + ptr = &(net_sin(sock_addr)->sin_addr); + rc = net_addr_pton(AF_INET, addr, ptr); +#endif + + if (rc) { + printk("Invalid IP address: %s\n", addr); + } + + return rc; +} + +int network_setup(struct net_context **net_ctx, const char *local_addr, + const char *server_addr, uint16_t server_port) +{ +#ifdef CONFIG_NET_IPV6 + socklen_t addr_len = sizeof(struct sockaddr_in6); + sa_family_t family = AF_INET6; + +#else + socklen_t addr_len = sizeof(struct sockaddr_in); + sa_family_t family = AF_INET; +#endif + struct sockaddr local_sock; + struct sockaddr server_sock; + void *p; + int rc; + + rc = set_addr(&local_sock, local_addr, 0); + if (rc) { + printk("set_addr (local) error\n"); + return rc; + } + +#ifdef CONFIG_NET_IPV6 + p = net_if_ipv6_addr_add(net_if_get_default(), + &net_sin6(&local_sock)->sin6_addr, + NET_ADDR_MANUAL, 0); +#else + p = net_if_ipv4_addr_add(net_if_get_default(), + &net_sin(&local_sock)->sin_addr, + NET_ADDR_MANUAL, 0); +#endif + + if (!p) { + return -EINVAL; + } + + rc = net_context_get(family, SOCK_STREAM, IPPROTO_TCP, net_ctx); + if (rc) { + printk("net_context_get error\n"); + return rc; + } + + rc = net_context_bind(*net_ctx, &local_sock, addr_len); + if (rc) { + printk("net_context_bind error\n"); + goto lb_exit; + } + + rc = set_addr(&server_sock, server_addr, server_port); + if (rc) { + printk("set_addr (server) error\n"); + goto lb_exit; + } + + rc = net_context_connect(*net_ctx, &server_sock, addr_len, NULL, + APP_SLEEP_MSECS, NULL); + if (rc) { + printk("net_context_connect error\n" + "Is the server (broker) up and running?\n"); + goto lb_exit; + } + + return 0; + +lb_exit: + net_context_put(*net_ctx); + + return rc; +} + +void main(void) +{ + publisher(); +} diff --git a/samples/net/mqtt_publisher/testcase.ini b/samples/net/mqtt_publisher/testcase.ini new file mode 100644 index 000000000..16ecfdae3 --- /dev/null +++ b/samples/net/mqtt_publisher/testcase.ini @@ -0,0 +1,4 @@ +[test] +tags = net mqtt +build_only = true +platform_whitelist = frdm_k64f |