From 0224e3577edf6d38e3af26dbd6733ce66d810e0c Mon Sep 17 00:00:00 2001 From: Flavio Santes Date: Mon, 30 May 2016 17:47:01 -0500 Subject: [PATCH] samples/net/mqtt: Add a MQTT interactive shell Add a MQTT interactive shell that can connect, disconnect, subscribe, publish, read published messages and ping to the MQTT gateway. Origin: Original Jira: ZEP-364 Change-Id: Ie85e7b8b9290cb8e80548886aea74a8427b2323b Signed-off-by: Flavio Santes --- samples/net/paho_mqtt_shell/Kbuild | 10 + samples/net/paho_mqtt_shell/Makefile | 23 ++ samples/net/paho_mqtt_shell/README | 63 ++++++ samples/net/paho_mqtt_shell/prj_ethernet.conf | 18 ++ samples/net/paho_mqtt_shell/src/Makefile | 27 +++ samples/net/paho_mqtt_shell/src/main.c | 27 +++ samples/net/paho_mqtt_shell/src/mqtt_shell.c | 196 ++++++++++++++++++ samples/net/paho_mqtt_shell/src/mqtt_shell.h | 13 ++ 8 files changed, 377 insertions(+) create mode 100644 samples/net/paho_mqtt_shell/Kbuild create mode 100644 samples/net/paho_mqtt_shell/Makefile create mode 100644 samples/net/paho_mqtt_shell/README create mode 100644 samples/net/paho_mqtt_shell/prj_ethernet.conf create mode 100644 samples/net/paho_mqtt_shell/src/Makefile create mode 100644 samples/net/paho_mqtt_shell/src/main.c create mode 100644 samples/net/paho_mqtt_shell/src/mqtt_shell.c create mode 100644 samples/net/paho_mqtt_shell/src/mqtt_shell.h diff --git a/samples/net/paho_mqtt_shell/Kbuild b/samples/net/paho_mqtt_shell/Kbuild new file mode 100644 index 00000000000..991ee5c4811 --- /dev/null +++ b/samples/net/paho_mqtt_shell/Kbuild @@ -0,0 +1,10 @@ +subdir-ccflags-y += -I$(SOURCE_DIR)/paho/MQTTPacket/src + +obj-y += src/ +obj-y += paho/MQTTPacket/src/MQTTSubscribeClient.o +obj-y += paho/MQTTPacket/src/MQTTFormat.o +obj-y += paho/MQTTPacket/src/MQTTUnsubscribeClient.o +obj-y += paho/MQTTPacket/src/MQTTDeserializePublish.o +obj-y += paho/MQTTPacket/src/MQTTSerializePublish.o +obj-y += paho/MQTTPacket/src/MQTTConnectClient.o +obj-y += paho/MQTTPacket/src/MQTTPacket.o diff --git a/samples/net/paho_mqtt_shell/Makefile b/samples/net/paho_mqtt_shell/Makefile new file mode 100644 index 00000000000..92ec997ba69 --- /dev/null +++ b/samples/net/paho_mqtt_shell/Makefile @@ -0,0 +1,23 @@ +# +# Copyright (c) 2016 Intel Corporation +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +KERNEL_TYPE = nano +BOARD = galileo +CONF_FILE = prj_ethernet.conf + +SOURCE_DIR = $(ZEPHYR_BASE)/samples/net/paho_mqtt_shell + +include $(ZEPHYR_BASE)/Makefile.inc diff --git a/samples/net/paho_mqtt_shell/README b/samples/net/paho_mqtt_shell/README new file mode 100644 index 00000000000..6ae0f4e28e8 --- /dev/null +++ b/samples/net/paho_mqtt_shell/README @@ -0,0 +1,63 @@ +MQTT shell example +================== + +This sample shows how to create an interactive MQTT client using the +Zephyr shell and the Paho's MQTT Library. + +Instructions +------------ + +1. Read carefully the README file in samples/net/paho_mqtt_client. + +2. Clone Paho's MQTT Library: + +git clone https://git.eclipse.org/r/paho/org.eclipse.paho.mqtt.embedded-c paho + +3. make pristine && make are enough to build this sample. + +So far, IPv4 addresses are still hard-coded in the config.h file. + +Quick guide +----------- + +The Zephyr shell allows you to type commands in the debug console. + +To connect with the gateway, use the following command: + +mqtt_shell> repeat_until_ok connect zephyr_galileo + +repeat_until_ok will iterate until the command returns 0. + +To ping the gateway: + +mqtt_shell> ping + +To subscribe to any zephyr's subtopic, type the following command: + +mqtt_shell> subscribe zephyr/# + +In your host, open another terminal and publish some random messages: + +mosquitto_pub -t "zephyr/lamps" -m "lamp1:OK" + +mosquitto_pub -t "zephyr/doors" -m "door3:OPEN" + +To read these messages from Galileo, type: + +mqtt_shell> read +topic: zephyr/lamps, msg: lamp1:OK + +mqtt_shell> read +topic: zephyr/doors, msg: door3:OPEN + +Observe that the Galileo MQTT shell is subscribed to "zephyr/#". + +To publish a message: + +mqtt_shell> publish zephyr "Hello!" + +To repeat a command multiple times: + +mqtt_shell> repeat 5 ping + +This will send 5 consecutive pings to the gateway. diff --git a/samples/net/paho_mqtt_shell/prj_ethernet.conf b/samples/net/paho_mqtt_shell/prj_ethernet.conf new file mode 100644 index 00000000000..719ea567ae3 --- /dev/null +++ b/samples/net/paho_mqtt_shell/prj_ethernet.conf @@ -0,0 +1,18 @@ +CONFIG_MINIMAL_LIBC_EXTENDED=y +CONFIG_CONSOLE_HANDLER=y +CONFIG_CONSOLE_HANDLER_SHELL=y +CONFIG_PRINTK=y + +CONFIG_NETWORKING=y +CONFIG_ETHERNET=y +CONFIG_ETH_DW=y + +CONFIG_NANO_TIMEOUTS=y +CONFIG_NETWORKING_WITH_TCP=y +CONFIG_NETWORKING_WITH_IPV4=y +CONFIG_NETWORKING_IPV6_NO_ND=y + +CONFIG_IP_BUF_RX_SIZE=4 +CONFIG_IP_BUF_TX_SIZE=4 + +#CONFIG_NETWORKING_WITH_LOGGING=y diff --git a/samples/net/paho_mqtt_shell/src/Makefile b/samples/net/paho_mqtt_shell/src/Makefile new file mode 100644 index 00000000000..5020e7d9ece --- /dev/null +++ b/samples/net/paho_mqtt_shell/src/Makefile @@ -0,0 +1,27 @@ +# +# Copyright (c) 2016 Intel Corporation +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +ccflags-y +=-I${srctree}/net/ip/contiki +ccflags-y +=-I${srctree}/net/ip/contiki/os/lib +ccflags-y +=-I${srctree}/net/ip/contiki/os +ccflags-y +=-I${srctree}/net/ip + +ccflags-y += -I${srctree}/samples/net/paho_mqtt_client/src + +obj-y += main.o +obj-y += mqtt_shell.o +obj-y += ../../paho_mqtt_client/src/mqtt.o +obj-y += ../../paho_mqtt_client/src/tcp.o diff --git a/samples/net/paho_mqtt_shell/src/main.c b/samples/net/paho_mqtt_shell/src/main.c new file mode 100644 index 00000000000..7e36c9b94d4 --- /dev/null +++ b/samples/net/paho_mqtt_shell/src/main.c @@ -0,0 +1,27 @@ +#include +#include + +#include "tcp.h" +#include "mqtt_shell.h" + +#define RC_MSG(rc) (rc) == 0 ? "success" : "failure" +#define STACK_SIZE 1024 + +uint8_t stack[STACK_SIZE]; + +extern struct shell_cmd commands[]; +extern struct net_context *ctx; + +void fiber(void) +{ + shell_init("mqtt_shell> ", commands); +} + +void main(void) +{ + net_init(); + tcp_init(&ctx); + + task_fiber_start(stack, STACK_SIZE, (nano_fiber_entry_t)fiber, + 0, 0, 7, 0); +} diff --git a/samples/net/paho_mqtt_shell/src/mqtt_shell.c b/samples/net/paho_mqtt_shell/src/mqtt_shell.c new file mode 100644 index 00000000000..2e12db42a69 --- /dev/null +++ b/samples/net/paho_mqtt_shell/src/mqtt_shell.c @@ -0,0 +1,196 @@ +#include "mqtt_shell.h" + +#include +#include +#include +#include + +#include "config.h" +#include "tcp.h" +#include "mqtt.h" + +char *client_name = "zephyr_client"; +char *topic = "zephyr"; +char *msg = "Hello World from Zephyr!"; + +struct net_context *ctx; + +struct shell_cmd commands[] = { + /* do not move 'repeat_until_ok' and 'repeat' */ + { "repeat_until_ok", shell_repeat_until_ok }, + { "repeat", shell_repeat }, + { "connect", shell_connect }, + { "disconnect", shell_disconnect }, + { "subscribe", shell_subs }, + { "ping", shell_ping }, + { "publish", shell_pub }, + { "read", shell_read }, + { NULL, NULL } +}; + +int find_cb(int (**ptr)(int, char **), char *action) +{ + int i; + + *ptr = NULL; + for (i = 2; commands[i].cmd_name; i++) { + if (strcmp(commands[i].cmd_name, action) == 0) { + *ptr = commands[i].cb; + } + } + + return ptr == NULL ? -EINVAL : 0; +} + +int shell_repeat_until_ok(int argc, char *argv[]) +{ + int (*ptr)(int, char **) = NULL; + + if (argc < 2) { + printk("Usage: repeat_until_ok command\n"); + } + if (find_cb(&ptr, argv[1]) != 0) { + printk("Unable to execute action\n"); + return -EINVAL; + } + + while (ptr(argc-1, argv+1) != 0) { + } + + return 0; +} + +int shell_repeat(int argc, char *argv[]) +{ + int (*ptr)(int, char **) = NULL; + char *action; + int i; + int n; + + if (argc < 3) { + printk("Usage: repeat n command\n"); + } + + action = argv[2]; + if (find_cb(&ptr, argv[2]) != 0) { + printk("Unable to execute action\n"); + return -EINVAL; + } + + n = atoi(argv[1]); + for (i = 0; i < n; i++) { + ptr(argc-2, argv+2); + } + + return 0; +} + +int shell_connect(int argc, char *argv[]) +{ + int rc; + + if (argc < 2) { + printk("Using default client name '%s'.\n" + "Usage: connect: connect client_name\n", client_name); + rc = mqtt_connect(ctx, client_name); + } else { + rc = mqtt_connect(ctx, argv[1]); + } + + if (rc != 0) { + printk("Connect: failure\n"); + return rc; + } + + return 0; +} + +int shell_disconnect(int argc, char *argv[]) +{ + int rc; + + ARG_UNUSED(argc); + ARG_UNUSED(argv); + + rc = mqtt_disconnect(ctx); + if (rc != 0) { + printk("Disconnect: failure\n"); + return rc; + } + + return 0; +} + +int shell_subs(int argc, char *argv[]) +{ + int rc; + + if (argc < 2) { + printk("Using default topic '%s'.\n" + "Usage: subscribe topic\n", topic); + rc = mqtt_subscribe(ctx, topic); + } else { + rc = mqtt_subscribe(ctx, argv[1]); + } + + if (rc != 0) { + printk("Subscribe: failure\n"); + return rc; + } + + return 0; +} + +int shell_ping(int argc, char *argv[]) +{ + int rc; + + ARG_UNUSED(argc); + ARG_UNUSED(argv); + + rc = mqtt_pingreq(ctx); + if (rc != 0) { + printk("Ping: failure\n"); + return rc; + } + + return 0; +} + +int shell_pub(int argc, char *argv[]) +{ + int rc; + + if (argc < 3) { + printk("Publishing to default topic '%s'.\n" + "Usage: publish topic msg\n", topic); + rc = mqtt_publish(ctx, topic, msg); + } else { + rc = mqtt_publish(ctx, argv[1], argv[2]); + } + + if (rc != 0) { + printk("Publish: failure\n"); + return rc; + } + + return 0; +} + +int shell_read(int argc, char *argv[]) +{ + char received_topic[32]; + char received_msg[64]; + int rc; + + ARG_UNUSED(argc); + ARG_UNUSED(argv); + + rc = mqtt_publish_read(ctx, received_topic, received_msg); + if (rc == 0) { + printk("topic: %s, msg: %s\n", received_topic, received_msg); + return 0; + } + + return rc; +} diff --git a/samples/net/paho_mqtt_shell/src/mqtt_shell.h b/samples/net/paho_mqtt_shell/src/mqtt_shell.h new file mode 100644 index 00000000000..80086c142c5 --- /dev/null +++ b/samples/net/paho_mqtt_shell/src/mqtt_shell.h @@ -0,0 +1,13 @@ +#ifndef _MQTT_SHELL_H_ +#define _MQTT_SHELL_H_ + +int shell_repeat_until_ok(int argc, char *argv[]); +int shell_repeat(int argc, char *argv[]); +int shell_connect(int argc, char *argv[]); +int shell_disconnect(int argc, char *argv[]); +int shell_subs(int argc, char *argv[]); +int shell_ping(int argc, char *argv[]); +int shell_pub(int argc, char *argv[]); +int shell_read(int argc, char *argv[]); + +#endif