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 <flavio.santes@intel.com>
This commit is contained in:
Flavio Santes 2016-05-30 17:47:01 -05:00
parent 4a320be8a2
commit 0224e3577e
8 changed files with 377 additions and 0 deletions

View file

@ -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

View file

@ -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

View file

@ -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.

View file

@ -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

View file

@ -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

View file

@ -0,0 +1,27 @@
#include <zephyr.h>
#include <misc/shell.h>
#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);
}

View file

@ -0,0 +1,196 @@
#include "mqtt_shell.h"
#include <stdlib.h>
#include <misc/printk.h>
#include <misc/shell.h>
#include <errno.h>
#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;
}

View file

@ -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