samples/net: Add a sample for a CoAP client

Change-Id: I17d88081eb719e55d97a5a034f6861e01ebb6a52
Signed-off-by: Vinicius Costa Gomes <vinicius.gomes@intel.com>
This commit is contained in:
Vinicius Costa Gomes 2016-06-17 19:21:33 -03:00 committed by Anas Nashif
parent 97ea9b19ea
commit 8dad0093d3
7 changed files with 302 additions and 0 deletions

View file

@ -61,3 +61,14 @@ GET method.
It can be run similar to the echo_server sample: using two terminals,
(1) for zoap_server, run 'make server' in its directory, (2) for
zoap_client, run 'make client' in the zoap_client test directory.
zoap_client
-----------
The Zoap client application does a single request against a 'a/light'
resource, which has the first response lost (so retransmissions are
basically verified).
Please refer to the section above about how to run these applications
together.

View file

@ -0,0 +1,25 @@
# Makefile - coap server test application
#
# 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.
#
MDEF_FILE = prj.mdef
KERNEL_TYPE ?= nano
BOARD = qemu_x86
CONF_FILE = prj.conf
include $(ZEPHYR_BASE)/Makefile.inc
include $(ZEPHYR_BASE)/samples/net/common/Makefile.ipstack

View file

@ -0,0 +1,15 @@
CONFIG_NANOKERNEL=y
CONFIG_NANO_TIMEOUTS=y
CONFIG_NANO_WORKQUEUE=y
CONFIG_NETWORKING=y
CONFIG_NETWORKING_DEBUG_UART=y
CONFIG_NETWORKING_IPV6_NO_ND=y
CONFIG_NETWORKING_TESTING=y
CONFIG_NETWORKING_UART=y
CONFIG_NETWORKING_WITH_IPV6=y
CONFIG_NETWORKING_WITH_LOGGING=y
CONFIG_NETWORKING_WITH_LOOPBACK=y
CONFIG_NETWORK_IP_STACK_DEBUG_FULL=y
CONFIG_NET_TESTING=y
CONFIG_SYSTEM_WORKQUEUE=y
CONFIG_ZOAP=y

View file

@ -0,0 +1,5 @@
% Application : zoap server
% TASK NAME PRIO ENTRY STACK GROUPS
% ===================================================
TASK MAIN 7 main 2048 [EXE]

View file

@ -0,0 +1,11 @@
ccflags-y +=-I${ZEPHYR_BASE}/net/ip
ccflags-y +=-I${ZEPHYR_BASE}/net/ip/contiki
ccflags-y +=-I${ZEPHYR_BASE}/net/ip/contiki/os/lib
ccflags-y +=-I${ZEPHYR_BASE}/net/ip/contiki/os
ifeq ($(CONFIG_NET_TESTING), y)
ccflags-y +=-I${ZEPHYR_BASE}/samples/net/common/
ccflags-y +=-DNET_TESTING_SERVER=1
endif
obj-y = zoap-client.o

View file

@ -0,0 +1,231 @@
/*
* 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.
*/
#include <errno.h>
#include <stdio.h>
#include <misc/nano_work.h>
#include <net/net_core.h>
#include <net/net_socket.h>
#include <net/net_ip.h>
#include <net/ip_buf.h>
#include <net_testing.h>
#include <zoap.h>
#define MY_COAP_PORT 9998
#define STACKSIZE 2000
#define NUM_PENDINGS 3
#define NUM_REPLIES 3
#define ALL_NODES_LOCAL_COAP_MCAST \
{ { { 0xff, 0x02, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xfd } } }
char fiberStack[STACKSIZE];
static struct net_context *send_context, *receive_context;
struct zoap_pending pendings[NUM_PENDINGS];
struct zoap_reply replies[NUM_REPLIES];
struct nano_delayed_work retransmit_work;
static const char * const a_light_path[] = { "a", "light", NULL };
static void msg_dump(const char *s, uint8_t *data, unsigned len)
{
unsigned i;
printf("%s: ", s);
for (i = 0; i < len; i++)
printf("%02x ", data[i]);
printf("(%u bytes)\n", len);
}
static int resource_reply_cb(const struct zoap_packet *response,
struct zoap_reply *reply, const void *from)
{
struct net_buf *buf = response->buf;
msg_dump("reply", buf->data, buf->len);
return 0;
}
static void udp_receive(void)
{
struct zoap_packet response;
struct zoap_pending *pending;
struct zoap_reply *reply;
struct net_buf *buf;
int r;
while (true) {
buf = net_receive(receive_context, TICKS_UNLIMITED);
if (!buf) {
continue;
}
r = zoap_packet_parse(&response, buf);
if (r < 0) {
printf("Invalid data received (%d)\n", r);
continue;
}
pending = zoap_pending_received(&response, pendings,
NUM_PENDINGS);
if (pending) {
/* If necessary cancel retransmissions */
}
reply = zoap_response_received(&response, buf,
replies, NUM_REPLIES);
if (!reply) {
printf("No handler for response (%d)\n", r);
continue;
}
}
}
static void retransmit_request(struct nano_work *work)
{
struct zoap_pending *pending;
struct zoap_packet *request;
struct net_buf *buf;
int r, timeout;
pending = zoap_pending_next_to_expire(pendings, NUM_PENDINGS);
if (!pending) {
return;
}
request = &pending->request;
buf = request->buf;
r = net_send(buf);
if (r < 0) {
return;
}
if (!zoap_pending_cycle(pending)) {
net_buf_unref(buf);
zoap_pending_clear(pending);
return;
}
timeout = pending->timeout * (sys_clock_ticks_per_sec / MSEC_PER_SEC);
nano_delayed_work_submit(&retransmit_work, timeout);
}
void main(void)
{
static struct net_addr mcast_addr = {
.in6_addr = ALL_NODES_LOCAL_COAP_MCAST,
.family = AF_INET6 };
static struct net_addr any_addr = { .in6_addr = IN6ADDR_ANY_INIT,
.family = AF_INET6 };
struct zoap_packet request;
struct zoap_pending *pending;
struct zoap_reply *reply;
const char * const *p;
struct net_buf *buf;
int r, timeout;
uint8_t observe = 0;
net_init();
net_testing_setup();
send_context = net_context_get(IPPROTO_UDP,
&mcast_addr, MY_COAP_PORT,
&any_addr, MY_COAP_PORT);
receive_context = net_context_get(IPPROTO_UDP,
&any_addr, MY_COAP_PORT,
&mcast_addr, MY_COAP_PORT);
task_fiber_start(&fiberStack[0], STACKSIZE,
(nano_fiber_entry_t) udp_receive, 0, 0, 7, 0);
nano_delayed_work_init(&retransmit_work, retransmit_request);
buf = ip_buf_get_tx(send_context);
if (!buf) {
printk("Unable to get TX buffer, not enough memory.\n");
return;
}
r = zoap_packet_init(&request, buf);
if (r < 0) {
return;
}
/* FIXME: Could be that zoap_packet_init() sets some defaults */
zoap_header_set_version(&request, 1);
zoap_header_set_type(&request, ZOAP_TYPE_CON);
zoap_header_set_code(&request, ZOAP_METHOD_GET);
zoap_header_set_id(&request, zoap_next_id());
/* Enable observing the resource. */
r = zoap_add_option(&request, ZOAP_OPTION_OBSERVE,
&observe, sizeof(observe));
if (r < 0) {
printk("Unable add option to request.\n");
return;
}
for (p = a_light_path; p && *p; p++) {
r = zoap_add_option(&request, ZOAP_OPTION_URI_PATH,
*p, strlen(*p));
if (r < 0) {
printk("Unable add option to request.\n");
return;
}
}
pending = zoap_pending_next_unused(pendings, NUM_PENDINGS);
if (!pending) {
printk("Unable to find a free pending to track "
"retransmissions.\n");
return;
}
r = zoap_pending_init(pending, &request);
if (r < 0) {
printk("Unable to initialize a pending retransmission.\n");
return;
}
reply = zoap_reply_next_unused(replies, NUM_REPLIES);
if (!reply) {
printk("No resources for waiting for replies.\n");
return;
}
zoap_reply_init(reply, &request);
reply->reply = resource_reply_cb;
r = net_send(buf);
if (r < 0) {
printk("Error sending the packet (%d).\n", r);
}
zoap_pending_cycle(pending);
timeout = pending->timeout * (sys_clock_ticks_per_sec / MSEC_PER_SEC);
nano_delayed_work_submit(&retransmit_work, timeout);
}

View file

@ -0,0 +1,4 @@
[test]
tags = net
build_only = true
arch_whitelist = x86