Merge branch 'feature/CoAP' into 'master'

Add CoAP feature

Add CoAP protocol, support client and server test demo.

See merge request !303
This commit is contained in:
Wu Jian Gang 2017-01-06 15:37:09 +08:00
commit c943fabcda
21 changed files with 1185 additions and 3 deletions

3
.gitmodules vendored
View file

@ -10,3 +10,6 @@
[submodule "components/micro-ecc/micro-ecc"]
path = components/micro-ecc/micro-ecc
url = https://github.com/kmackay/micro-ecc.git
[submodule "components/coap/libcoap"]
path = components/coap/libcoap
url = https://github.com/obgm/libcoap.git

View file

@ -0,0 +1 @@
CFLAGS += -DWITH_POSIX

View file

@ -0,0 +1,9 @@
#
# Component Makefile
#
COMPONENT_ADD_INCLUDEDIRS := port/include port/include/coap libcoap/include libcoap/include/coap
COMPONENT_OBJS = libcoap/src/address.o libcoap/src/async.o libcoap/src/block.o libcoap/src/coap_time.o libcoap/src/debug.o libcoap/src/encode.o libcoap/src/hashkey.o libcoap/src/mem.o libcoap/src/net.o libcoap/src/option.o libcoap/src/pdu.o libcoap/src/resource.o libcoap/src/str.o libcoap/src/subscribe.o libcoap/src/uri.o port/coap_io_socket.o
COMPONENT_SRCDIRS := libcoap/src libcoap port

@ -0,0 +1 @@
Subproject commit 6468887a12666f88b8704d797fc176cd4f40ee4c

View file

@ -0,0 +1,468 @@
/*
* Network function implementation with socket for ESP32 platform.
*
* Uses libcoap software implementation for failover when concurrent
* network operations are in use.
*
* coap_io.h -- Default network I/O functions for libcoap
*
* Copyright (C) 2012,2014 Olaf Bergmann <bergmann@tzi.org>
*
* Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
*
* This file is part of the CoAP library libcoap. Please see
* README for terms of use.
*/
#include "coap_config.h"
#ifdef HAVE_STDIO_H
# include <stdio.h>
#endif
#ifdef HAVE_SYS_SELECT_H
# include <sys/select.h>
#endif
#ifdef HAVE_SYS_SOCKET_H
# include <sys/socket.h>
#endif
#ifdef HAVE_NETINET_IN_H
# include <netinet/in.h>
#endif
#ifdef HAVE_SYS_UIO_H
# include <sys/uio.h>
#endif
#ifdef HAVE_UNISTD_H
# include <unistd.h>
#endif
#include <errno.h>
#ifdef WITH_CONTIKI
# include "uip.h"
#endif
#include "pdu.h"
#include "debug.h"
#include "mem.h"
#include "coap_io.h"
#ifdef WITH_POSIX
/* define generic PKTINFO for IPv4 */
#if defined(IP_PKTINFO)
# define GEN_IP_PKTINFO IP_PKTINFO
#elif defined(IP_RECVDSTADDR)
# define GEN_IP_PKTINFO IP_RECVDSTADDR
#else
# error "Need IP_PKTINFO or IP_RECVDSTADDR to request ancillary data from OS."
#endif /* IP_PKTINFO */
/* define generic KTINFO for IPv6 */
#ifdef IPV6_RECVPKTINFO
# define GEN_IPV6_PKTINFO IPV6_RECVPKTINFO
#elif defined(IPV6_PKTINFO)
# define GEN_IPV6_PKTINFO IPV6_PKTINFO
#else
# error "Need IPV6_PKTINFO or IPV6_RECVPKTINFO to request ancillary data from OS."
#endif /* IPV6_RECVPKTINFO */
struct coap_packet_t {
coap_if_handle_t hnd; /**< the interface handle */
coap_address_t src; /**< the packet's source address */
coap_address_t dst; /**< the packet's destination address */
const coap_endpoint_t *interface;
int ifindex;
void *session; /**< opaque session data */
size_t length; /**< length of payload */
unsigned char payload[]; /**< payload */
};
#endif
#ifdef CUSTOM_COAP_NETWORK_ENDPOINT
#ifdef WITH_CONTIKI
static int ep_initialized = 0;
static inline struct coap_endpoint_t *
coap_malloc_contiki_endpoint() {
static struct coap_endpoint_t ep;
if (ep_initialized) {
return NULL;
} else {
ep_initialized = 1;
return &ep;
}
}
static inline void
coap_free_contiki_endpoint(struct coap_endpoint_t *ep) {
ep_initialized = 0;
}
coap_endpoint_t *
coap_new_endpoint(const coap_address_t *addr, int flags) {
struct coap_endpoint_t *ep = coap_malloc_contiki_endpoint();
if (ep) {
memset(ep, 0, sizeof(struct coap_endpoint_t));
ep->handle.conn = udp_new(NULL, 0, NULL);
if (!ep->handle.conn) {
coap_free_endpoint(ep);
return NULL;
}
coap_address_init(&ep->addr);
uip_ipaddr_copy(&ep->addr.addr, &addr->addr);
ep->addr.port = addr->port;
udp_bind((struct uip_udp_conn *)ep->handle.conn, addr->port);
}
return ep;
}
void
coap_free_endpoint(coap_endpoint_t *ep) {
if (ep) {
if (ep->handle.conn) {
uip_udp_remove((struct uip_udp_conn *)ep->handle.conn);
}
coap_free_contiki_endpoint(ep);
}
}
#else /* WITH_CONTIKI */
static inline struct coap_endpoint_t *
coap_malloc_posix_endpoint(void) {
return (struct coap_endpoint_t *)coap_malloc(sizeof(struct coap_endpoint_t));
}
static inline void
coap_free_posix_endpoint(struct coap_endpoint_t *ep) {
coap_free(ep);
}
coap_endpoint_t *
coap_new_endpoint(const coap_address_t *addr, int flags) {
int sockfd = socket(addr->addr.sa.sa_family, SOCK_DGRAM, 0);
int on = 1;
struct coap_endpoint_t *ep;
if (sockfd < 0) {
coap_log(LOG_WARNING, "coap_new_endpoint: socket");
return NULL;
}
if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0)
coap_log(LOG_WARNING, "coap_new_endpoint: setsockopt SO_REUSEADDR");
if (bind(sockfd, &addr->addr.sa, addr->size) < 0) {
coap_log(LOG_WARNING, "coap_new_endpoint: bind");
close (sockfd);
return NULL;
}
ep = coap_malloc_posix_endpoint();
if (!ep) {
coap_log(LOG_WARNING, "coap_new_endpoint: malloc");
close(sockfd);
return NULL;
}
memset(ep, 0, sizeof(struct coap_endpoint_t));
ep->handle.fd = sockfd;
ep->flags = flags;
ep->addr.size = addr->size;
if (getsockname(sockfd, &ep->addr.addr.sa, &ep->addr.size) < 0) {
coap_log(LOG_WARNING, "coap_new_endpoint: cannot determine local address");
close (sockfd);
return NULL;
}
#ifndef NDEBUG
if (LOG_DEBUG <= coap_get_log_level()) {
#ifndef INET6_ADDRSTRLEN
#define INET6_ADDRSTRLEN 40
#endif
unsigned char addr_str[INET6_ADDRSTRLEN+8];
if (coap_print_addr(&ep->addr, addr_str, INET6_ADDRSTRLEN+8)) {
debug("created %sendpoint %s\n",
ep->flags & COAP_ENDPOINT_DTLS ? "DTLS " : "",
addr_str);
}
}
#endif /* NDEBUG */
return (coap_endpoint_t *)ep;
}
void
coap_free_endpoint(coap_endpoint_t *ep) {
if(ep) {
if (ep->handle.fd >= 0)
close(ep->handle.fd);
coap_free_posix_endpoint((struct coap_endpoint_t *)ep);
}
}
#endif /* WITH_CONTIKI */
#endif /* CUSTOM_COAP_NETWORK_ENDPOINT */
#ifdef CUSTOM_COAP_NETWORK_SEND
#if defined(WITH_POSIX) != defined(HAVE_NETINET_IN_H)
/* define struct in6_pktinfo and struct in_pktinfo if not available
FIXME: check with configure
*/
struct in6_pktinfo {
struct in6_addr ipi6_addr; /* src/dst IPv6 address */
unsigned int ipi6_ifindex; /* send/recv interface index */
};
struct in_pktinfo {
int ipi_ifindex;
struct in_addr ipi_spec_dst;
struct in_addr ipi_addr;
};
#endif
#if defined(WITH_POSIX) && !defined(SOL_IP)
/* Solaris expects level IPPROTO_IP for ancillary data. */
#define SOL_IP IPPROTO_IP
#endif
#ifdef __GNUC__
#define UNUSED_PARAM __attribute__ ((unused))
#else /* not a GCC */
#define UNUSED_PARAM
#endif /* GCC */
ssize_t
coap_network_send(struct coap_context_t *context UNUSED_PARAM,
const coap_endpoint_t *local_interface,
const coap_address_t *dst,
unsigned char *data,
size_t datalen) {
struct coap_endpoint_t *ep =
(struct coap_endpoint_t *)local_interface;
#ifndef WITH_CONTIKI
return sendto(ep->handle.fd, data, datalen, 0, (struct sockaddr*)&dst->addr.sa, sizeof(struct sockaddr));
#else /* WITH_CONTIKI */
/* FIXME: untested */
/* FIXME: is there a way to check if send was successful? */
uip_udp_packet_sendto((struct uip_udp_conn *)ep->handle.conn, data, datalen,
&dst->addr, dst->port);
return datalen;
#endif /* WITH_CONTIKI */
}
#endif /* CUSTOM_COAP_NETWORK_SEND */
#ifdef CUSTOM_COAP_NETWORK_READ
#define SIN6(A) ((struct sockaddr_in6 *)(A))
#ifdef WITH_POSIX
static coap_packet_t *
coap_malloc_packet(void) {
coap_packet_t *packet;
const size_t need = sizeof(coap_packet_t) + COAP_MAX_PDU_SIZE;
packet = (coap_packet_t *)coap_malloc(need);
if (packet) {
memset(packet, 0, need);
}
return packet;
}
void
coap_free_packet(coap_packet_t *packet) {
coap_free(packet);
}
#endif /* WITH_POSIX */
#ifdef WITH_CONTIKI
static inline coap_packet_t *
coap_malloc_packet(void) {
return (coap_packet_t *)coap_malloc_type(COAP_PACKET, 0);
}
void
coap_free_packet(coap_packet_t *packet) {
coap_free_type(COAP_PACKET, packet);
}
#endif /* WITH_CONTIKI */
static inline size_t
coap_get_max_packetlength(const coap_packet_t *packet UNUSED_PARAM) {
return COAP_MAX_PDU_SIZE;
}
void
coap_packet_populate_endpoint(coap_packet_t *packet, coap_endpoint_t *target)
{
target->handle = packet->interface->handle;
memcpy(&target->addr, &packet->dst, sizeof(target->addr));
target->ifindex = packet->ifindex;
target->flags = 0; /* FIXME */
}
void
coap_packet_copy_source(coap_packet_t *packet, coap_address_t *target)
{
memcpy(target, &packet->src, sizeof(coap_address_t));
}
void
coap_packet_get_memmapped(coap_packet_t *packet, unsigned char **address, size_t *length)
{
*address = packet->payload;
*length = packet->length;
}
/**
* Checks if a message with destination address @p dst matches the
* local interface with address @p local. This function returns @c 1
* if @p dst is a valid match, and @c 0 otherwise.
*/
static inline int
is_local_if(const coap_address_t *local, const coap_address_t *dst) {
return coap_address_isany(local) || coap_address_equals(dst, local) ||
coap_is_mcast(dst);
}
ssize_t
coap_network_read(coap_endpoint_t *ep, coap_packet_t **packet) {
ssize_t len = -1;
#ifdef WITH_POSIX
#define SOC_APPDATA_LEN 1460
char *soc_appdata = NULL;
struct sockaddr_in soc_srcipaddr;
socklen_t soc_srcsize = sizeof(struct sockaddr_in);
#endif /* WITH_POSIX */
assert(ep);
assert(packet);
*packet = coap_malloc_packet();
if (!*packet) {
warn("coap_network_read: insufficient memory, drop packet\n");
return -1;
}
coap_address_init(&(*packet)->dst); /* the local interface address */
coap_address_init(&(*packet)->src); /* the remote peer */
#ifdef WITH_POSIX
soc_appdata = coap_malloc(SOC_APPDATA_LEN);
if (soc_appdata){
len = recvfrom(ep->handle.fd, soc_appdata, SOC_APPDATA_LEN, 0, (struct sockaddr *)&soc_srcipaddr, (socklen_t *)&soc_srcsize);
if (len < 0){
coap_log(LOG_WARNING, "coap_network_read: %s\n", strerror(errno));
goto error;
} else {
/* use getsockname() to get the local port */
(*packet)->dst.size = sizeof((*packet)->dst.addr);
if (getsockname(ep->handle.fd, &(*packet)->dst.addr.sa, &(*packet)->dst.size) < 0) {
coap_log(LOG_DEBUG, "cannot determine local port\n");
goto error;
}
/* local interface for IPv4 */
(*packet)->src.size = sizeof((*packet)->src.addr);
memcpy(&(*packet)->src.addr.sa, &soc_srcipaddr, (*packet)->src.size);
if (len > coap_get_max_packetlength(*packet)) {
/* FIXME: we might want to send back a response */
warn("discarded oversized packet\n");
goto error;
}
if (!is_local_if(&ep->addr, &(*packet)->dst)) {
coap_log(LOG_DEBUG, "packet received on wrong interface, dropped\n");
printf("error 3\n");
goto error;
}
(*packet)->length = len;
memcpy(&(*packet)->payload, soc_appdata, len);
}
coap_free(soc_appdata);
soc_appdata = NULL;
} else {
goto error;
}
#endif /* WITH_POSIX */
#ifdef WITH_CONTIKI
/* FIXME: untested, make this work */
#define UIP_IP_BUF ((struct uip_ip_hdr *)&uip_buf[UIP_LLH_LEN])
#define UIP_UDP_BUF ((struct uip_udp_hdr *)&uip_buf[UIP_LLIPH_LEN])
if(uip_newdata()) {
uip_ipaddr_copy(&(*packet)->src.addr, &UIP_IP_BUF->srcipaddr);
(*packet)->src.port = UIP_UDP_BUF->srcport;
uip_ipaddr_copy(&(*packet)->dst.addr, &UIP_IP_BUF->destipaddr);
(*packet)->dst.port = UIP_UDP_BUF->destport;
if (!is_local_if(&ep->addr, &(*packet)->dst)) {
coap_log(LOG_DEBUG, "packet received on wrong interface, dropped\n");
goto error;
}
len = uip_datalen();
if (len > coap_get_max_packetlength(*packet)) {
/* FIXME: we might want to send back a response */
warn("discarded oversized packet\n");
return -1;
}
((char *)uip_appdata)[len] = 0;
#ifndef NDEBUG
if (LOG_DEBUG <= coap_get_log_level()) {
#ifndef INET6_ADDRSTRLEN
#define INET6_ADDRSTRLEN 40
#endif
unsigned char addr_str[INET6_ADDRSTRLEN+8];
if (coap_print_addr(&(*packet)->src, addr_str, INET6_ADDRSTRLEN+8)) {
debug("received %zd bytes from %s\n", len, addr_str);
}
}
#endif /* NDEBUG */
(*packet)->length = len;
memcpy(&(*packet)->payload, uip_appdata, len);
}
#undef UIP_IP_BUF
#undef UIP_UDP_BUF
#endif /* WITH_CONTIKI */
#ifdef WITH_LWIP
#error "coap_network_read() not implemented on this platform"
#endif
(*packet)->interface = ep;
return len;
error:
#ifdef WITH_POSIX
if (soc_appdata)
coap_free(soc_appdata);
soc_appdata = NULL;
#endif
coap_free_packet(*packet);
*packet = NULL;
return -1;
}
#undef SIN6
#endif /* CUSTOM_COAP_NETWORK_READ */

View file

@ -0,0 +1,50 @@
/* Modify head file implementation for ESP32 platform.
*
* Uses libcoap software implementation for failover when concurrent
* define operations are in use.
*
* coap.h -- main header file for CoAP stack of libcoap
*
* Copyright (C) 2010-2012,2015-2016 Olaf Bergmann <bergmann@tzi.org>
* 2015 Carsten Schoenert <c.schoenert@t-online.de>
*
* Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
*
* This file is part of the CoAP library libcoap. Please see README for terms
* of use.
*/
#ifndef _COAP_H_
#define _COAP_H_
#include "libcoap.h"
#ifdef __cplusplus
extern "C" {
#endif
#include "address.h"
#include "async.h"
#include "bits.h"
#include "block.h"
#include "coap_io.h"
#include "coap_time.h"
#include "debug.h"
#include "encode.h"
#include "mem.h"
#include "net.h"
#include "option.h"
#include "pdu.h"
#include "prng.h"
#include "resource.h"
#include "str.h"
#include "subscribe.h"
#include "uri.h"
#include "uthash.h"
#include "utlist.h"
#ifdef __cplusplus
}
#endif
#endif /* _COAP_H_ */

View file

@ -0,0 +1,39 @@
/*
* libcoap configure implementation for ESP32 platform.
*
* Uses libcoap software implementation for failover when concurrent
* configure operations are in use.
*
* coap.h -- main header file for CoAP stack of libcoap
*
* Copyright (C) 2010-2012,2015-2016 Olaf Bergmann <bergmann@tzi.org>
* 2015 Carsten Schoenert <c.schoenert@t-online.de>
*
* Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
*
* This file is part of the CoAP library libcoap. Please see README for terms
* of use.
*/
#ifndef _CONFIG_H_
#define _CONFIG_H_
#ifdef WITH_POSIX
#include "coap_config_posix.h"
#endif
#define HAVE_STDIO_H
#define HAVE_ASSERT_H
#define PACKAGE_STRING PACKAGE_NAME PACKAGE_VERSION
/* it's just provided by libc. i hope we don't get too many of those, as
* actually we'd need autotools again to find out what environment we're
* building in */
#define HAVE_STRNLEN 1
#define HAVE_LIMITS_H
#define COAP_RESOURCES_NOHASH
#endif /* _CONFIG_H_ */

View file

@ -0,0 +1,41 @@
/*
* libcoap configure implementation for ESP32 platform.
*
* Uses libcoap software implementation for failover when concurrent
* configure operations are in use.
*
* coap.h -- main header file for CoAP stack of libcoap
*
* Copyright (C) 2010-2012,2015-2016 Olaf Bergmann <bergmann@tzi.org>
* 2015 Carsten Schoenert <c.schoenert@t-online.de>
*
* Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
*
* This file is part of the CoAP library libcoap. Please see README for terms
* of use.
*/
#ifndef COAP_CONFIG_POSIX_H_
#define COAP_CONFIG_POSIX_H_
#ifdef WITH_POSIX
#include <sys/socket.h>
#define HAVE_SYS_SOCKET_H
#define HAVE_MALLOC
#define HAVE_ARPA_INET_H
#define IP_PKTINFO IP_MULTICAST_IF
#define IPV6_PKTINFO IPV6_V6ONLY
#define PACKAGE_NAME "libcoap-posix"
#define PACKAGE_VERSION "?"
#define CUSTOM_COAP_NETWORK_ENDPOINT
#define CUSTOM_COAP_NETWORK_SEND
#define CUSTOM_COAP_NETWORK_READ
#endif
#endif /* COAP_CONFIG_POSIX_H_ */

View file

@ -0,0 +1,20 @@
// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
//
// 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.
#ifndef INET_H_
#define INET_H_
#include "lwip/inet.h"
#endif /* INET_H_ */

View file

@ -0,0 +1,22 @@
// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
//
// 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.
#ifndef IN_H_
#define IN_H_
#include "lwip/inet.h"
#define IN6_IS_ADDR_MULTICAST(a) IN_MULTICAST(a)
#endif /* IN_H_ */

View file

@ -1,4 +1 @@
# Anyone compiling mbedTLS code needs the name of the
# alternative config file
CFLAGS += -DHAVE_CONFIG_H

View file

@ -0,0 +1,9 @@
#
# This is a project Makefile. It is assumed the directory this Makefile resides in is a
# project subdirectory.
#
PROJECT_NAME := coap_client
include $(IDF_PATH)/make/project.mk

View file

@ -0,0 +1,34 @@
menu "Example Configuration"
config TARGET_DOMAIN
string "Target Domain"
default "californium.eclipse.org"
help
Target domain for the example to connect to.
config TARGET_DOMAIN_URI
string "Target Uri"
default "coap://californium.eclipse.org"
help
Target uri for the example to use.
config TARGET_PORT_NUMBER
int "Target port number"
range 0 65535
default 5683
help
Target port number for the example to connect to.
config WIFI_SSID
string "WiFi SSID"
default "myssid"
help
SSID (network name) for the example to connect to.
config WIFI_PASSWORD
string "WiFi Password"
default "mypassword"
help
WiFi password (WPA or WPA2) for the example to use.
endmenu

View file

@ -0,0 +1,176 @@
/* CoAP client Example
This example code is in the Public Domain (or CC0 licensed, at your option.)
Unless required by applicable law or agreed to in writing, this
software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
CONDITIONS OF ANY KIND, either express or implied.
*/
#include "coap_client.h"
#include <string.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/event_groups.h"
#include "esp_log.h"
#include "esp_wifi.h"
#include "esp_event_loop.h"
#include "nvs_flash.h"
#include <sys/socket.h>
#include "coap_config.h"
#include "resource.h"
#include "coap.h"
static EventGroupHandle_t wifi_event_group;
/* The event group allows multiple bits for each event,
but we only care about one event - are we connected
to the AP with an IP? */
const static int CONNECTED_BIT = BIT0;
const static char *TAG = "CoAP_demo";
static void message_handler(struct coap_context_t *ctx, const coap_endpoint_t *local_interface, const coap_address_t *remote,
coap_pdu_t *sent, coap_pdu_t *received,
const coap_tid_t id)
{
unsigned char* data = NULL;
size_t data_len;
if (COAP_RESPONSE_CLASS(received->hdr->code) == 2) {
if (coap_get_data(received, &data_len, &data)) {
printf("Received: %s\n", data);
}
}
}
static void coap_demo_thread(void *p)
{
coap_context_t* ctx = NULL;
coap_address_t dst_addr, src_addr;
static coap_uri_t uri;
fd_set readfds;
struct timeval tv;
int flags, result;
coap_pdu_t* request = NULL;
const char* server_uri = COAP_DEFAULT_DEMO_URI;
uint8_t get_method = 1;
coap_address_init(&src_addr);
src_addr.addr.sin.sin_family = AF_INET;
src_addr.addr.sin.sin_port = htons(0);
src_addr.addr.sin.sin_addr.s_addr = INADDR_ANY;
ctx = coap_new_context(&src_addr);
if (ctx) {
coap_address_init(&dst_addr);
dst_addr.addr.sin.sin_family = AF_INET;
dst_addr.addr.sin.sin_port = htons(COAP_DEFAULT_PORT);
dst_addr.addr.sin.sin_addr.s_addr = inet_addr(COAP_DEFAULT_DEMO_ADDR);
coap_split_uri((const uint8_t *)server_uri, strlen(server_uri), &uri);
request = coap_new_pdu();
if (request){
request->hdr->type = COAP_MESSAGE_CON;
request->hdr->id = coap_new_message_id(ctx);
request->hdr->code = get_method;
coap_add_option(request, COAP_OPTION_URI_PATH, uri.path.length, uri.path.s);
coap_register_response_handler(ctx, message_handler);
coap_send_confirmed(ctx, ctx->endpoint, &dst_addr, request);
flags = fcntl(ctx->sockfd, F_GETFL, 0);
fcntl(ctx->sockfd, F_SETFL, flags|O_NONBLOCK);
tv.tv_usec = COAP_DEFAULT_TIME_USEC;
tv.tv_sec = COAP_DEFAULT_TIME_SEC;
for(;;) {
FD_ZERO(&readfds);
FD_CLR( ctx->sockfd, &readfds );
FD_SET( ctx->sockfd, &readfds );
result = select( FD_SETSIZE, &readfds, 0, 0, &tv );
if (result > 0) {
if (FD_ISSET( ctx->sockfd, &readfds ))
coap_read(ctx);
} else if (result < 0) {
break;
} else {
printf("select timeout\n");
}
}
}
coap_free_context(ctx);
}
vTaskDelete(NULL);
}
static void coap_server_init(void)
{
int ret = pdPASS;
xTaskHandle coap_handle = NULL;
ret = xTaskCreate(coap_demo_thread,
COAP_DEMO_THREAD_NAME,
COAP_DEMO_THREAD_STACK_WORDS,
NULL,
COAP_DEMO_THREAD_PRORIOTY,
&coap_handle);
if (ret != pdPASS) {
ESP_LOGI(TAG, "create thread %s failed", COAP_DEMO_THREAD_NAME);
}
}
static esp_err_t wifi_event_handler(void *ctx, system_event_t *event)
{
switch(event->event_id) {
case SYSTEM_EVENT_STA_START:
esp_wifi_connect();
break;
case SYSTEM_EVENT_STA_GOT_IP:
xEventGroupSetBits(wifi_event_group, CONNECTED_BIT);
coap_server_init();
break;
case SYSTEM_EVENT_STA_DISCONNECTED:
/* This is a workaround as ESP32 WiFi libs don't currently
auto-reassociate. */
esp_wifi_connect();
xEventGroupClearBits(wifi_event_group, CONNECTED_BIT);
break;
default:
break;
}
return ESP_OK;
}
static void wifi_conn_init(void)
{
tcpip_adapter_init();
wifi_event_group = xEventGroupCreate();
ESP_ERROR_CHECK( esp_event_loop_init(wifi_event_handler, NULL) );
wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
ESP_ERROR_CHECK( esp_wifi_init(&cfg) );
ESP_ERROR_CHECK( esp_wifi_set_storage(WIFI_STORAGE_RAM) );
wifi_config_t wifi_config = {
.sta = {
.ssid = EXAMPLE_WIFI_SSID,
.password = EXAMPLE_WIFI_PASS,
},
};
ESP_ERROR_CHECK( esp_wifi_set_mode(WIFI_MODE_STA) );
ESP_ERROR_CHECK( esp_wifi_set_config(WIFI_IF_STA, &wifi_config) );
ESP_ERROR_CHECK( esp_wifi_start() );
}
void app_main(void)
{
nvs_flash_init();
wifi_conn_init();
}

View file

@ -0,0 +1,43 @@
/* CoAP client Example
This example code is in the Public Domain (or CC0 licensed, at your option.)
Unless required by applicable law or agreed to in writing, this
software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
CONDITIONS OF ANY KIND, either express or implied.
*/
#ifndef _COAP_CLIENT_H_
#define _COAP_CLIENT_H_
#include <sdkconfig.h>
/* The examples use simple WiFi configuration that you can set via
'make menuconfig'.
If you'd rather not, just change the below entries to strings with
the config you want - ie #define EXAMPLE_WIFI_SSID "mywifissid"
*/
#define EXAMPLE_WIFI_SSID CONFIG_WIFI_SSID
#define EXAMPLE_WIFI_PASS CONFIG_WIFI_PASSWORD
#define COAP_DEMO_THREAD_NAME "CoAP_demo"
#define COAP_DEMO_THREAD_STACK_WORDS 10240
#define COAP_DEMO_THREAD_PRORIOTY 8
#define COAP_DEFAULT_TIME_SEC 5
#define COAP_DEFAULT_TIME_USEC 0
/* The examples use domain of "californium.eclipse.org",uri "coap://californium.eclipse.org" and port number of 5683 that
you can set via 'make menuconfig'.
If you'd rather not, just change the below entries to strings with
the config you want - ie #define COAP_DEFAULT_DEMO_ADDR "californium.eclipse.org"
, ie #define COAP_DEFAULT_DEMO_URI "coap://californium.eclipse.org" and ie #define COAP_DEFAULT_PORT 5683
*/
#define COAP_DEFAULT_PORT CONFIG_TARGET_PORT_NUMBER
#define COAP_DEFAULT_DEMO_ADDR CONFIG_TARGET_DOMAIN
#define COAP_DEFAULT_DEMO_URI CONFIG_TARGET_DOMAIN_URI
#endif

View file

@ -0,0 +1,5 @@
#
# "main" pseudo-component makefile.
#
# (Uses default behaviour of compiling all source files in directory, adding 'include' to include path.)

View file

@ -0,0 +1,9 @@
#
# This is a project Makefile. It is assumed the directory this Makefile resides in is a
# project subdirectory.
#
PROJECT_NAME := coap_server
include $(IDF_PATH)/make/project.mk

View file

@ -0,0 +1,22 @@
menu "Example Configuration"
config LOCAL_PORT_NUMBER
int "Local port number"
range 0 65535
default 5683
help
Local port number for the example to use.
config WIFI_SSID
string "WiFi SSID"
default "myssid"
help
SSID (network name) for the example to connect to.
config WIFI_PASSWORD
string "WiFi Password"
default "mypassword"
help
WiFi password (WPA or WPA2) for the example to use.
endmenu

View file

@ -0,0 +1,190 @@
/* CoAP server Example
This example code is in the Public Domain (or CC0 licensed, at your option.)
Unless required by applicable law or agreed to in writing, this
software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
CONDITIONS OF ANY KIND, either express or implied.
*/
#include "coap_server.h"
#include <string.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/event_groups.h"
#include "esp_log.h"
#include "esp_wifi.h"
#include "esp_event_loop.h"
#include "nvs_flash.h"
#include <sys/socket.h>
#include "coap_config.h"
#include "resource.h"
#include "coap.h"
static EventGroupHandle_t wifi_event_group;
/* The event group allows multiple bits for each event,
but we only care about one event - are we connected
to the AP with an IP? */
const static int CONNECTED_BIT = BIT0;
const static char *TAG = "CoAP_demo";
static coap_async_state_t *async = NULL;
static void
send_async_response(coap_context_t *ctx, const coap_endpoint_t *local_if)
{
coap_pdu_t *response;
unsigned char buf[3];
const char* response_data = "Hello World!";
size_t size = sizeof(coap_hdr_t) + 20;
response = coap_pdu_init(async->flags & COAP_MESSAGE_CON, COAP_RESPONSE_CODE(205), 0, size);
response->hdr->id = coap_new_message_id(ctx);
if (async->tokenlen)
coap_add_token(response, async->tokenlen, async->token);
coap_add_option(response, COAP_OPTION_CONTENT_TYPE, coap_encode_var_bytes(buf, COAP_MEDIATYPE_TEXT_PLAIN), buf);
coap_add_data (response, strlen(response_data), (unsigned char *)response_data);
if (coap_send(ctx, local_if, &async->peer, response) == COAP_INVALID_TID) {
}
coap_delete_pdu(response);
coap_async_state_t *tmp;
coap_remove_async(ctx, async->id, &tmp);
coap_free_async(async);
async = NULL;
}
/*
* The resource handler
*/
static void
async_handler(coap_context_t *ctx, struct coap_resource_t *resource,
const coap_endpoint_t *local_interface, coap_address_t *peer,
coap_pdu_t *request, str *token, coap_pdu_t *response)
{
async = coap_register_async(ctx, peer, request, COAP_ASYNC_SEPARATE | COAP_ASYNC_CONFIRM, (void*)"no data");
}
static void coap_demo_thread(void *p)
{
coap_context_t* ctx = NULL;
coap_address_t serv_addr;
coap_resource_t* resource = NULL;
fd_set readfds;
struct timeval tv;
int flags = 0;
/* Prepare the CoAP server socket */
coap_address_init(&serv_addr);
serv_addr.addr.sin.sin_family = AF_INET;
serv_addr.addr.sin.sin_addr.s_addr = INADDR_ANY;
serv_addr.addr.sin.sin_port = htons(COAP_DEFAULT_PORT);
ctx = coap_new_context(&serv_addr);
if (ctx) {
flags = fcntl(ctx->sockfd, F_GETFL, 0);
fcntl(ctx->sockfd, F_SETFL, flags|O_NONBLOCK);
tv.tv_usec = COAP_DEFAULT_TIME_USEC;
tv.tv_sec = COAP_DEFAULT_TIME_SEC;
/* Initialize the resource */
resource = coap_resource_init((unsigned char *)"Espressif", 9, 0);
if (resource){
coap_register_handler(resource, COAP_REQUEST_GET, async_handler);
coap_add_resource(ctx, resource);
/*For incoming connections*/
for (;;) {
FD_ZERO(&readfds);
FD_CLR( ctx->sockfd, &readfds);
FD_SET( ctx->sockfd, &readfds);
int result = select( FD_SETSIZE, &readfds, 0, 0, &tv );
if (result > 0){
if (FD_ISSET( ctx->sockfd, &readfds ))
coap_read(ctx);
} else if (result < 0){
break;
} else {
printf("select timeout\n");
}
if (async)
send_async_response(ctx, ctx->endpoint);
}
}
coap_free_context(ctx);
}
vTaskDelete(NULL);
}
static void coap_server_init(void)
{
int ret = pdPASS;
xTaskHandle coap_handle = NULL;
ret = xTaskCreate(coap_demo_thread,
COAP_DEMO_THREAD_NAME,
COAP_DEMO_THREAD_STACK_WORDS,
NULL,
COAP_DEMO_THREAD_PRORIOTY,
&coap_handle);
if (ret != pdPASS) {
ESP_LOGI(TAG, "create thread %s failed", COAP_DEMO_THREAD_NAME);
}
}
static esp_err_t wifi_event_handler(void *ctx, system_event_t *event)
{
switch(event->event_id) {
case SYSTEM_EVENT_STA_START:
esp_wifi_connect();
break;
case SYSTEM_EVENT_STA_GOT_IP:
xEventGroupSetBits(wifi_event_group, CONNECTED_BIT);
coap_server_init();
break;
case SYSTEM_EVENT_STA_DISCONNECTED:
/* This is a workaround as ESP32 WiFi libs don't currently
auto-reassociate. */
esp_wifi_connect();
xEventGroupClearBits(wifi_event_group, CONNECTED_BIT);
break;
default:
break;
}
return ESP_OK;
}
static void wifi_conn_init(void)
{
tcpip_adapter_init();
wifi_event_group = xEventGroupCreate();
ESP_ERROR_CHECK( esp_event_loop_init(wifi_event_handler, NULL) );
wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
ESP_ERROR_CHECK( esp_wifi_init(&cfg) );
ESP_ERROR_CHECK( esp_wifi_set_storage(WIFI_STORAGE_RAM) );
wifi_config_t wifi_config = {
.sta = {
.ssid = EXAMPLE_WIFI_SSID,
.password = EXAMPLE_WIFI_PASS,
},
};
ESP_ERROR_CHECK( esp_wifi_set_mode(WIFI_MODE_STA) );
ESP_ERROR_CHECK( esp_wifi_set_config(WIFI_IF_STA, &wifi_config) );
ESP_ERROR_CHECK( esp_wifi_start() );
}
void app_main(void)
{
nvs_flash_init();
wifi_conn_init();
}

View file

@ -0,0 +1,38 @@
/* CoAP server Example
This example code is in the Public Domain (or CC0 licensed, at your option.)
Unless required by applicable law or agreed to in writing, this
software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
CONDITIONS OF ANY KIND, either express or implied.
*/
#ifndef _COAP_SERVER_H_
#define _COAP_SERVER_H_
#include <sdkconfig.h>
/* The examples use simple WiFi configuration that you can set via
'make menuconfig'.
If you'd rather not, just change the below entries to strings with
the config you want - ie #define EXAMPLE_WIFI_SSID "mywifissid"
*/
#define EXAMPLE_WIFI_SSID CONFIG_WIFI_SSID
#define EXAMPLE_WIFI_PASS CONFIG_WIFI_PASSWORD
#define COAP_DEMO_THREAD_NAME "CoAP_demo"
#define COAP_DEMO_THREAD_STACK_WORDS 10240
#define COAP_DEMO_THREAD_PRORIOTY 8
/* The examples use local port number of 5683 that you can set via 'make menuconfig'.
If you'd rather not, just change the below entries to strings with
the config you want - ie #define OPENSSL_DEMO_TARGET_TCP_PORT 5683
*/
#define COAP_DEFAULT_PORT CONFIG_LOCAL_PORT_NUMBER
#define COAP_DEFAULT_TIME_SEC 5
#define COAP_DEFAULT_TIME_USEC 0
#endif

View file

@ -0,0 +1,5 @@
#
# "main" pseudo-component makefile.
#
# (Uses default behaviour of compiling all source files in directory, adding 'include' to include path.)