blob: 1c75ed68cf16b4f110ad73a93bb006b285e1b7de [file] [log] [blame]
/*
* Copyright (c) 2017 Intel Corporation
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <logging/log.h>
LOG_MODULE_REGISTER(net_nats_sample, LOG_LEVEL_DBG);
#include <drivers/gpio.h>
#include <net/net_context.h>
#include <net/net_core.h>
#include <net/net_if.h>
#include <zephyr.h>
#include "nats.h"
/* LED */
#ifndef DT_ALIAS_LED0_GPIOS_CONTROLLER
#ifdef LED0_GPIO_PORT
#define DT_ALIAS_LED0_GPIOS_CONTROLLER LED0_GPIO_PORT
#else
#define DT_ALIAS_LED0_GPIOS_CONTROLLER "(fail)"
#define DT_ALIAS_LED0_GPIOS_PIN 0
#endif
#endif
#define LED_GPIO_NAME DT_ALIAS_LED0_GPIOS_CONTROLLER
#define LED_PIN DT_ALIAS_LED0_GPIOS_PIN
static struct device *led0;
static bool fake_led;
/* Network Config */
#if defined(CONFIG_NET_IPV6)
#define NATS_AF_INET AF_INET6
#define NATS_SOCKADDR_IN sockaddr_in6
#if defined(CONFIG_NET_CONFIG_MY_IPV6_ADDR)
#define NATS_LOCAL_IP_ADDR CONFIG_NET_CONFIG_MY_IPV6_ADDR
#else
#define NATS_LOCAL_IP_ADDR "2001:db8::1"
#endif /* CONFIG_NET_CONFIG_MY_IPV6_ADDR */
#if defined(CONFIG_NET_CONFIG_PEER_IPV6_ADDR)
#define NATS_PEER_IP_ADDR CONFIG_NET_CONFIG_PEER_IPV6_ADDR
#else
#define NATS_PEER_IP_ADDR "2001:db8::2"
#endif /* CONFIG_NET_CONFIG_PEER_IPV6_ADDR */
#else /* CONFIG_NET_IPV4 */
#define NATS_AF_INET AF_INET
#define NATS_SOCKADDR_IN sockaddr_in
#if defined(CONFIG_NET_CONFIG_MY_IPV4_ADDR)
#define NATS_LOCAL_IP_ADDR CONFIG_NET_CONFIG_MY_IPV4_ADDR
#else
#define NATS_LOCAL_IP_ADDR "192.168.0.1"
#endif /* CONFIG_NET_CONFIG_MY_IPV4_ADDR */
#if defined(CONFIG_NET_CONFIG_PEER_IPV4_ADDR)
#define NATS_PEER_IP_ADDR CONFIG_NET_CONFIG_PEER_IPV4_ADDR
#else
#define NATS_PEER_IP_ADDR "192.168.0.2"
#endif /* CONFIG_NET_CONFIG_PEER_IPV4_ADDR */
#endif
/* DNS API */
#define DNS_PORT 53
#define DNS_SLEEP_MSECS 400
/* Default server */
#define DEFAULT_PORT 4222
static void panic(const char *msg)
{
LOG_ERR("Panic: %s", msg);
for (;;) {
k_sleep(K_FOREVER);
}
}
static int in_addr_set(sa_family_t family,
const char *ip_addr,
int port,
struct sockaddr *_sockaddr)
{
int rc = 0;
_sockaddr->sa_family = family;
if (ip_addr) {
if (family == AF_INET6) {
rc = net_addr_pton(family,
ip_addr,
&net_sin6(_sockaddr)->sin6_addr);
} else {
rc = net_addr_pton(family,
ip_addr,
&net_sin(_sockaddr)->sin_addr);
}
if (rc < 0) {
LOG_ERR("Invalid IP address: %s", log_strdup(ip_addr));
return -EINVAL;
}
}
if (port >= 0) {
if (family == AF_INET6) {
net_sin6(_sockaddr)->sin6_port = htons(port);
} else {
net_sin(_sockaddr)->sin_port = htons(port);
}
}
return rc;
}
static void initialize_network(void)
{
struct net_if *iface;
LOG_INF("Initializing network");
iface = net_if_get_default();
if (!iface) {
panic("No default network interface");
}
/* TODO: IPV6 DHCP */
#if defined(CONFIG_NET_IPV4) && defined(CONFIG_NET_DHCPV4)
net_dhcpv4_start(iface);
/* delay so DHCPv4 can assign IP */
/* TODO: add a timeout/retry */
LOG_INF("Waiting for DHCP ...");
do {
k_sleep(K_SECONDS(1));
} while (net_ipv4_is_addr_unspecified(&iface->dhcpv4.requested_ip));
LOG_INF("Done!");
/* TODO: add a timeout */
LOG_INF("Waiting for IP assginment ...");
do {
k_sleep(K_SECONDS(1));
} while (!net_ipv4_is_my_addr(&iface->dhcpv4.requested_ip));
LOG_INF("Done!");
#else
struct sockaddr addr;
if (in_addr_set(NATS_AF_INET, NATS_LOCAL_IP_ADDR, 0,
&addr) < 0) {
LOG_ERR("Invalid IP address: %s",
NATS_LOCAL_IP_ADDR);
}
#if defined(CONFIG_NET_IPV6)
net_if_ipv6_addr_add(iface,
&net_sin6(&addr)->sin6_addr,
NET_ADDR_MANUAL, 0);
#else
net_if_ipv4_addr_add(iface,
&net_sin(&addr)->sin_addr,
NET_ADDR_MANUAL, 0);
#endif
#endif /* CONFIG_NET_IPV4 && CONFIG_NET_DHCPV4 */
}
static bool read_led(void)
{
u32_t led = 0U;
int r;
if (!led0) {
return fake_led;
}
r = gpio_pin_read(led0, LED_PIN, &led);
if (r < 0) {
return false;
}
return !led;
}
static void write_led(const struct nats *nats,
const struct nats_msg *msg,
bool state)
{
char *pubstate;
int ret;
if (!led0) {
fake_led = state;
} else {
gpio_pin_write(led0, LED_PIN, !state);
}
pubstate = state ? "on" : "off";
ret = nats_publish(nats, "led0", 0, msg->reply_to, 0,
pubstate, strlen(pubstate));
if (ret < 0) {
printk("Failed to publish: %d\n", ret);
} else {
printk("*** Turning LED %s\n", pubstate);
}
}
static int on_msg_received(const struct nats *nats,
const struct nats_msg *msg)
{
if (!strcmp(msg->subject, "led0")) {
if (msg->payload_len == 2 && !strcmp(msg->payload, "on")) {
write_led(nats, msg, true);
return 0;
}
if (msg->payload_len == 3 && !strcmp(msg->payload, "off")) {
write_led(nats, msg, false);
return 0;
}
if (msg->payload_len == 6 && !strcmp(msg->payload, "toggle")) {
write_led(nats, msg, !read_led());
return 0;
}
return -EINVAL;
}
return -ENOENT;
}
static void initialize_hardware(void)
{
LOG_INF("Initializing hardware");
led0 = device_get_binding(LED_GPIO_NAME);
if (led0) {
gpio_pin_configure(led0, LED_PIN, GPIO_DIR_OUT);
}
}
static int connect(struct nats *nats, u16_t port)
{
#if defined(CONFIG_NET_IPV4) && defined(CONFIG_NET_DHCPV4)
struct net_if *iface;
#endif
struct sockaddr dst_addr, src_addr;
int ret;
LOG_INF("Connecting...");
ret = net_context_get(NATS_AF_INET, SOCK_STREAM, IPPROTO_TCP,
&nats->conn);
if (ret < 0) {
LOG_DBG("Could not get new context: %d", ret);
return ret;
}
/* TODO: IPV6 DHCP */
#if defined(CONFIG_NET_IPV4) && defined(CONFIG_NET_DHCPV4)
iface = net_if_get_default();
net_ipaddr_copy(&net_sin(&src_addr)->sin_addr,
&iface->dhcpv4.requested_ip);
ret = in_addr_set(NATS_AF_INET, NULL, 0, &src_addr);
#else
ret = in_addr_set(NATS_AF_INET, NATS_LOCAL_IP_ADDR,
0, &src_addr);
if (ret < 0) {
goto connect_exit;
}
#endif
ret = in_addr_set(NATS_AF_INET, NATS_PEER_IP_ADDR,
port, &dst_addr);
if (ret < 0) {
goto connect_exit;
}
ret = net_context_bind(nats->conn, &src_addr,
sizeof(struct NATS_SOCKADDR_IN));
if (ret < 0) {
LOG_DBG("Could not bind to local address: %d", -ret);
goto connect_exit;
}
ret = nats_connect(nats, &dst_addr, sizeof(struct NATS_SOCKADDR_IN));
if (!ret) {
return 0;
}
connect_exit:
net_context_put(nats->conn);
return ret;
}
static void nats_client(void)
{
struct nats nats = {
.on_message = on_msg_received
};
LOG_INF("NATS Client Sample");
initialize_network();
initialize_hardware();
if (connect(&nats, DEFAULT_PORT) < 0) {
panic("Could not connect to NATS server");
}
if (nats_subscribe(&nats, "led0", 0, NULL, 0,
"sub132984012384098", 0) < 0) {
panic("Could not subscribe to `led0` topic");
}
}
void main(void)
{
nats_client();
}