Skip to content
This repository has been archived by the owner on Sep 20, 2022. It is now read-only.

Commit

Permalink
Merge pull request #44 from smlng/coap-chat
Browse files Browse the repository at this point in the history
coap-chat: a simple chat application using gCoAP
  • Loading branch information
kb2ma authored Oct 13, 2018
2 parents 2abd9f3 + 2377418 commit 39a974e
Show file tree
Hide file tree
Showing 4 changed files with 263 additions and 0 deletions.
29 changes: 29 additions & 0 deletions coap-chat/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# name of your application
APPLICATION = coap_chat

# If no BOARD is found in the environment, use this default:
BOARD ?= native

# This has to be the absolute path to the RIOT base directory:
RIOTBASE ?= $(CURDIR)/../../RIOT

USEMODULE += gnrc_netdev_default
USEMODULE += auto_init_gnrc_netif
# Specify the mandatory networking modules
USEMODULE += gnrc_ipv6_default
USEMODULE += gcoap
# Additional networking modules that can be dropped if not needed
USEMODULE += gnrc_icmpv6_echo
# Add also the shell, some shell commands
USEMODULE += shell
USEMODULE += shell_commands

# Comment this out to disable code in RIOT that does safety checking
# which is not needed in a production environment but helps in the
# development process:
DEVELHELP ?= 0

# Change this to 0 show compiler invocation lines by default:
QUIET ?= 1

include $(RIOTBASE)/Makefile.include
36 changes: 36 additions & 0 deletions coap-chat/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
## About

This application provides a simple command line chat using (g)CoAP as transport.
It allows to send (short) messages to any (IPv6) address reachable by the node.
All messages are sent to and received for a CoAP resource with path `/chat`.

## Usage

To send messages use the `chat` shell command, it can be invoked as follows:

```
chat <destination> <nickname> <message>
```

- **destination:** a reachable IPv6 address, may even be multicast `ff02::1`
- **nickname:** your chat nickname, anything is allowed, but keep it short
- **message:** what ever text you want to share, be brief, size is limited

The message format is plain text and will be send as *nickname: message*, the
maximum message size is 63 chars - so keep *nickname* and *message* short :)
Please be aware that all CoAP messages are sent as non-confirmable, hence there
is no retransmission in case of packet loss.

## Notes

The code base of this application aims for simplicity, thus it only provides
a minimalistic set of functions. An advanced CoAP application can be found in
the [RIOT examples](https://github.com/RIOT-OS/RIOT/tree/master/examples/gcoap).

The application also ships with a number of standard shell commands, such as
`ifconfig` to allow for network interface configuration. Just type `help` in
the shell to see a full list and description of all available commands.

By default this application is configured to run as an IPv6 node, i.e. it does
not include any routing or relaying functionality - such needs to be handled
by other nodes.
127 changes: 127 additions & 0 deletions coap-chat/coap.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
/*
* Copyright (c) 2018 HAW Hamburg
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/

/**
* @ingroup applications
* @{
*
* @file
* @brief coap-chat - CoAP helper functions
*
* @author Sebastian Meiling <s@mlng.net>
*
* @}
*/

#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "net/gcoap.h"

#define ENABLE_DEBUG (0)
#include "debug.h"

#define COAP_CHAT_PATH "/chat"

static ssize_t _chat_handler(coap_pkt_t *pdu, uint8_t *buf, size_t len, void *ctx);

/* CoAP resources */
static const coap_resource_t _resources[] = {
{ COAP_CHAT_PATH, COAP_POST, _chat_handler, NULL },
};

static gcoap_listener_t _listener = {
&_resources[0],
sizeof(_resources) / sizeof(_resources[0]),
NULL
};

static ssize_t _chat_handler(coap_pkt_t *pdu, uint8_t *buf, size_t len, void *ctx)
{
(void)ctx;

if (pdu->payload_len > 0) {
printf("\n[ CHAT ] %.*s\n\n", pdu->payload_len, (char *)pdu->payload);
return gcoap_response(pdu, buf, len, COAP_CODE_CHANGED);
}
return gcoap_response(pdu, buf, len, COAP_CODE_BAD_REQUEST);
}

static size_t _send(uint8_t *buf, size_t len, char *addr_str)
{
ipv6_addr_t addr;
sock_udp_ep_t remote;

remote.family = AF_INET6;

/* parse for interface */
int iface = ipv6_addr_split_iface(addr_str);
if (iface == -1) {
if (gnrc_netif_numof() == 1) {
/* assign the single interface found in gnrc_netif_numof() */
remote.netif = (uint16_t)gnrc_netif_iter(NULL)->pid;
}
else {
remote.netif = SOCK_ADDR_ANY_NETIF;
}
}
else {
if (gnrc_netif_get_by_pid(iface) == NULL) {
DEBUG("[CoAP] interface not valid");
return 0;
}
remote.netif = iface;
}

/* parse destination address */
if (ipv6_addr_from_str(&addr, addr_str) == NULL) {
DEBUG("[CoAP] unable to parse destination address");
return 0;
}
if ((remote.netif == SOCK_ADDR_ANY_NETIF) && ipv6_addr_is_link_local(&addr)) {
DEBUG("[CoAP] must specify interface for link local target");
return 0;
}
memcpy(&remote.addr.ipv6[0], &addr.u8[0], sizeof(addr.u8));

/* parse port */
remote.port = GCOAP_PORT;

return gcoap_req_send2(buf, len, &remote, NULL);
}

int coap_post(char *addr, char *msgbuf, size_t msglen)
{
assert(msglen < GCOAP_PDU_BUF_SIZE);

coap_pkt_t pdu;
uint8_t buf[GCOAP_PDU_BUF_SIZE];
size_t len = 0;

gcoap_req_init(&pdu, buf, GCOAP_PDU_BUF_SIZE, COAP_POST, COAP_CHAT_PATH);

memcpy(pdu.payload, msgbuf, msglen);

len = gcoap_finish(&pdu, msglen, COAP_FORMAT_TEXT);

DEBUG("[CoAP] coap_post: sending msg ID %u, %u bytes\n",
coap_get_id(&pdu), (unsigned) len);

if (!_send(buf, len, addr)) {
puts("[CoAP] coap_post: msg send failed");
return -1;
}
return len;
}

void coap_init(void)
{
gcoap_register_listener(&_listener);
}
71 changes: 71 additions & 0 deletions coap-chat/main.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
/*
* Copyright (c) 2018 HAW Hamburg
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/

/**
* @ingroup applications
* @{
*
* @file
* @brief coap-chat - Main loop and shell handlers
*
* @author Sebastian Meiling <s@mlng.net>
*
* @}
*/

#include <stdio.h>
#include "msg.h"

#include "net/gcoap.h"
#include "kernel_types.h"
#include "shell.h"

#define BUFLEN (64U)
#define MAIN_QUEUE_SIZE (4)

static msg_t _main_msg_queue[MAIN_QUEUE_SIZE];

extern int coap_post(const char *addr, const char *buf, size_t buflen);
extern void coap_init(void);

int chat(int argc, char **argv)
{
if (argc < 4) {
puts("usage: chat <addr> <nick> <msg>");
return 1;
}

char buf[BUFLEN] = { 0 };
size_t len = snprintf(buf, BUFLEN, "%s: %s", argv[2], argv[3]);
for (int i = 4; i < argc; ++i) {
len += snprintf(buf + len, BUFLEN - len, " %s", argv[i]);
}
coap_post(argv[1], buf, len);

return 0;
}

static const shell_command_t shell_commands[] = {
{ "chat", "CoAP chat", chat },
{ NULL, NULL, NULL }
};

int main(void)
{
/* for the thread running the shell */
msg_init_queue(_main_msg_queue, MAIN_QUEUE_SIZE);
/* init coap listener */
coap_init();
/* start shell */
puts("All up, running the shell now");
char line_buf[SHELL_DEFAULT_BUFSIZE];
shell_run(shell_commands, line_buf, SHELL_DEFAULT_BUFSIZE);

/* should never be reached */
return 0;
}

0 comments on commit 39a974e

Please sign in to comment.