[submodule "components/mbedtls/mbedtls"]
path = components/mbedtls/mbedtls
url = https://github.com/espressif/mbedtls.git
+
+[submodule "components/asio/asio"]
+ path = components/asio/asio
+ url = https://github.com/espressif/asio.git
--- /dev/null
+Subproject commit 55efc179b76139c8f9b44bf22a4aba4803f7a7bd
--- /dev/null
+COMPONENT_ADD_INCLUDEDIRS := asio/asio/include port/include
+COMPONENT_PRIV_INCLUDEDIRS := private_include
+COMPONENT_SRCDIRS := asio/asio/src
+COMPONENT_OBJEXCLUDE := asio/asio/src/asio_ssl.o
+
+COMPONENT_SUBMODULES += asio
--- /dev/null
+// Copyright 2018 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 _ESP_ASIO_CONFIG_H_
+#define _ESP_ASIO_CONFIG_H_
+
+//
+// Enabling exceptions only when they are enabled in menuconfig
+//
+# include <sdkconfig.h>
+# ifndef CONFIG_CXX_EXCEPTIONS
+# define ASIO_NO_EXCEPTIONS
+# endif // CONFIG_CXX_EXCEPTIONS
+
+//
+// LWIP compatifility inet and address macros/functions
+//
+# define LWIP_COMPAT_SOCKET_INET 1
+# define LWIP_COMPAT_SOCKET_ADDR 1
+
+//
+// Specific ASIO feature flags
+//
+# define ASIO_DISABLE_SERIAL_PORT
+# define ASIO_SEPARATE_COMPILATION
+# define ASIO_STANDALONE
+# define ASIO_NO_TYPEID
+# define ASIO_DISABLE_SIGNAL
+# define ASIO_HAS_PTHREADS
+# define ASIO_DISABLE_EPOLL
+# define ASIO_DISABLE_EVENTFD
+# define ASIO_DISABLE_SIGNAL
+# define ASIO_DISABLE_SIGACTION
+
+#endif // _ESP_ASIO_CONFIG_H_
--- /dev/null
+
+// Copyright 2018 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 _ESP_EXCEPTION_H_
+#define _ESP_EXCEPTION_H_
+
+//
+// This exception stub is enabled only if exceptions are disabled in menuconfig
+//
+#if !defined(CONFIG_CXX_EXCEPTIONS) && defined (ASIO_NO_EXCEPTIONS)
+
+#include "esp_log.h"
+
+//
+// asio exception stub
+//
+namespace asio {
+namespace detail {
+template <typename Exception>
+void throw_exception(const Exception& e)
+{
+ ESP_LOGE("esp32_asio_exception", "Caught exception: %s!", e.what());
+ abort();
+}
+}}
+#endif // CONFIG_CXX_EXCEPTIONS==1 && defined (ASIO_NO_EXCEPTIONS)
+
+#endif // _ESP_EXCEPTION_H_
#define NUM_SOCKETS MEMP_NUM_NETCONN
+#if !defined IOV_MAX
+#define IOV_MAX 0xFFFF
+#elif IOV_MAX > 0xFFFF
+#error "IOV_MAX larger than supported by LwIP"
+#endif /* IOV_MAX */
+
/** This is overridable for the rare case where more than 255 threads
* select on the same socket...
*/
return (err == ERR_OK ? (int)written : -1);
}
+ssize_t
+lwip_recvmsg(int s, struct msghdr *message, int flags)
+{
+ struct lwip_sock *sock;
+ int i;
+ ssize_t buflen;
+
+ LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvmsg(%d, message=%p, flags=0x%x)\n", s, (void *)message, flags));
+ LWIP_ERROR("lwip_recvmsg: invalid message pointer", message != NULL, return ERR_ARG;);
+ LWIP_ERROR("lwip_recvmsg: unsupported flags", (flags & ~(MSG_PEEK|MSG_DONTWAIT)) == 0,
+ set_errno(EOPNOTSUPP); return -1;);
+
+ if ((message->msg_iovlen <= 0) || (message->msg_iovlen > IOV_MAX)) {
+ set_errno(EMSGSIZE);
+ return -1;
+ }
+
+ sock = get_socket(s);
+ if (!sock) {
+ return -1;
+ }
+
+ /* check for valid vectors */
+ buflen = 0;
+ for (i = 0; i < message->msg_iovlen; i++) {
+ if ((message->msg_iov[i].iov_base == NULL) || ((ssize_t)message->msg_iov[i].iov_len <= 0) ||
+ ((size_t)(ssize_t)message->msg_iov[i].iov_len != message->msg_iov[i].iov_len) ||
+ ((ssize_t)(buflen + (ssize_t)message->msg_iov[i].iov_len) <= 0)) {
+ sock_set_errno(sock, ERR_VAL);
+ return -1;
+ }
+ buflen = (ssize_t)(buflen + (ssize_t)message->msg_iov[i].iov_len);
+ }
+
+ int recv_flags = flags;
+ message->msg_flags = 0;
+ /* recv the data */
+ buflen = 0;
+ for (i = 0; i < message->msg_iovlen; i++) {
+ /* try to receive into this vector's buffer */
+ ssize_t recvd_local = lwip_recvfrom(s, message->msg_iov[i].iov_base, message->msg_iov[i].iov_len, recv_flags, NULL, NULL);
+ if (recvd_local > 0) {
+ /* sum up received bytes */
+ buflen += recvd_local;
+ }
+ if ((recvd_local < 0) || (recvd_local < (int)message->msg_iov[i].iov_len) ||
+ (flags & MSG_PEEK)) {
+ /* returned prematurely (or peeking, which might actually be limitated to the first iov) */
+ if (buflen <= 0) {
+ /* nothing received at all, propagate the error */
+ buflen = recvd_local;
+ }
+ break;
+ }
+ /* pass MSG_DONTWAIT to lwip_recv_tcp() to prevent waiting for more data */
+ recv_flags |= MSG_DONTWAIT;
+ }
+ if (buflen > 0) {
+ /* reset socket error since we have received something */
+ sock_set_errno(sock, 0);
+ }
+
+ return buflen;
+}
+
int
lwip_sendmsg(int s, const struct msghdr *msg, int flags)
{
LWIP_API_UNLOCK();
}
+int
+lwip_recvmsg_r(int s, struct msghdr *msg, int flags)
+{
+ LWIP_API_LOCK();
+ __ret = lwip_recvmsg(s, msg, flags);
+ LWIP_API_UNLOCK();
+}
+
int
lwip_listen_r(int s, int backlog)
{
struct addrinfo **res);
#if LWIP_COMPAT_SOCKETS
+#if LWIP_COMPAT_SOCKET_ADDR == 1
+/* Some libraries have problems with inet_... being macros, so please use this define
+ to declare normal functions */
+static inline int gethostbyname_r(const char *name, struct hostent *ret, char *buf, size_t buflen, struct hostent **result, int *h_errnop)
+{ return lwip_gethostbyname_r(name, ret, buf, buflen, result, h_errnop); }
+static inline struct hostent *gethostbyname(const char *name)
+{ return lwip_gethostbyname(name); }
+static inline void freeaddrinfo(struct addrinfo *ai)
+{ lwip_freeaddrinfo(ai); }
+static inline int getaddrinfo(const char *nodename, const char *servname, const struct addrinfo *hints, struct addrinfo **res)
+{ return lwip_getaddrinfo(nodename, servname, hints, res); }
+#else
+/* By default fall back to original inet_... macros */
+
#define gethostbyname(name) lwip_gethostbyname(name)
#define gethostbyname_r(name, ret, buf, buflen, result, h_errnop) \
lwip_gethostbyname_r(name, ret, buf, buflen, result, h_errnop)
#define freeaddrinfo(addrinfo) lwip_freeaddrinfo(addrinfo)
#define getaddrinfo(nodname, servname, hints, res) \
lwip_getaddrinfo(nodname, servname, hints, res)
+#endif /* LWIP_COMPAT_SOCKET_ADDR == 1 */
#endif /* LWIP_COMPAT_SOCKETS */
#ifdef __cplusplus
#if LWIP_COMPAT_SOCKETS != 2
#if ESP_THREAD_SAFE
-
int lwip_accept_r(int s, struct sockaddr *addr, socklen_t *addrlen);
int lwip_bind_r(int s, const struct sockaddr *name, socklen_t namelen);
int lwip_shutdown_r(int s, int how);
int lwip_close_r(int s);
int lwip_connect_r(int s, const struct sockaddr *name, socklen_t namelen);
int lwip_listen_r(int s, int backlog);
+int lwip_recvmsg_r(int s, struct msghdr *message, int flags);
int lwip_recv_r(int s, void *mem, size_t len, int flags);
int lwip_read_r(int s, void *mem, size_t len);
int lwip_recvfrom_r(int s, void *mem, size_t len, int flags,
{ return lwip_connect_r(s,name,namelen); }
static inline int listen(int s,int backlog)
{ return lwip_listen_r(s,backlog); }
+static inline int recvmsg(int sockfd, struct msghdr *msg, int flags)
+{ return lwip_recvmsg_r(sockfd, msg, flags); }
static inline int recv(int s,void *mem,size_t len,int flags)
{ return lwip_recv_r(s,mem,len,flags); }
static inline int recvfrom(int s,void *mem,size_t len,int flags,struct sockaddr *from,socklen_t *fromlen)
{ return lwip_connect(s,name,namelen); }
static inline int listen(int s,int backlog)
{ return lwip_listen(s,backlog); }
+static inline int recvmsg(int sockfd, struct msghdr *msg, int flags)
+{ return lwip_recvmsg(sockfd, msg, flags); }
static inline int recv(int s,void *mem,size_t len,int flags)
{ return lwip_recv(s,mem,len,flags); }
static inline int recvfrom(int s,void *mem,size_t len,int flags,struct sockaddr *from,socklen_t *fromlen)
#endif /* LWIP_COMPAT_SOCKETS != 2 */
#if LWIP_IPV4 && LWIP_IPV6
-#define inet_ntop(af,src,dst,size) \
+#define lwip_inet_ntop(af,src,dst,size) \
(((af) == AF_INET6) ? ip6addr_ntoa_r((const ip6_addr_t*)(src),(dst),(size)) \
: (((af) == AF_INET) ? ip4addr_ntoa_r((const ip4_addr_t*)(src),(dst),(size)) : NULL))
-#define inet_pton(af,src,dst) \
+#define lwip_inet_pton(af,src,dst) \
(((af) == AF_INET6) ? ip6addr_aton((src),(ip6_addr_t*)(dst)) \
: (((af) == AF_INET) ? ip4addr_aton((src),(ip4_addr_t*)(dst)) : 0))
#elif LWIP_IPV4 /* LWIP_IPV4 && LWIP_IPV6 */
-#define inet_ntop(af,src,dst,size) \
+#define lwip_inet_ntop(af,src,dst,size) \
(((af) == AF_INET) ? ip4addr_ntoa_r((const ip4_addr_t*)(src),(dst),(size)) : NULL)
-#define inet_pton(af,src,dst) \
+#define lwip_inet_pton(af,src,dst) \
(((af) == AF_INET) ? ip4addr_aton((src),(ip4_addr_t*)(dst)) : 0)
#else /* LWIP_IPV4 && LWIP_IPV6 */
-#define inet_ntop(af,src,dst,size) \
+#define lwip_inet_ntop(af,src,dst,size) \
(((af) == AF_INET6) ? ip6addr_ntoa_r((const ip6_addr_t*)(src),(dst),(size)) : NULL)
-#define inet_pton(af,src,dst) \
+#define lwip_inet_pton(af,src,dst) \
(((af) == AF_INET6) ? ip6addr_aton((src),(ip6_addr_t*)(dst)) : 0)
#endif /* LWIP_IPV4 && LWIP_IPV6 */
+#if LWIP_COMPAT_SOCKET_INET == 1
+/* Some libraries have problems with inet_... being macros, so please use this define
+ to declare normal functions */
+static inline const char *inet_ntop(int af, const void *src, char *dst, socklen_t size)
+{ lwip_inet_ntop(af, src, dst, size); return dst; }
+static inline int inet_pton(int af, const char *src, void *dst)
+{ lwip_inet_pton(af, src, dst); return 1; }
+#else
+/* By default fall back to original inet_... macros */
+# define inet_ntop(a,b,c,d) lwip_inet_ntop(a,b,c,d)
+# define inet_pton(a,b,c) lwip_inet_pton(a,b,c)
+#endif /* LWIP_COMPAT_SOCKET_INET */
+
#endif /* LWIP_COMPAT_SOCKETS */
#ifdef __cplusplus
*/
#include "lwip/netdb.h"
+
+#ifdef ESP_PLATFORM
+int getnameinfo(const struct sockaddr *addr, socklen_t addrlen,
+ char *host, socklen_t hostlen,
+ char *serv, socklen_t servlen, int flags);
+
+#endif
--- /dev/null
+
+// Copyright 2018 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 _ESP_PLATFORM_ERRNO_H_
+#define _ESP_PLATFORM_ERRNO_H_
+
+#include_next "errno.h"
+
+//
+// Possibly define some missing errors
+//
+#ifndef ESHUTDOWN
+#define ESHUTDOWN 108 /* Cannot send after transport endpoint shutdown */
+#endif
+
+#ifndef EAI_SOCKTYPE
+#define EAI_SOCKTYPE 10 /* ai_socktype not supported */
+#endif
+
+#ifndef EAI_AGAIN
+#define EAI_AGAIN 2 /* temporary failure in name resolution */
+#endif
+
+#ifndef EAI_BADFLAGS
+#define EAI_BADFLAGS 3 /* invalid value for ai_flags */
+#endif
+
+#endif // _ESP_PLATFORM_ERRNO_H_
--- /dev/null
+// Copyright 2018 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 _ESP_PLATFORM_NET_IF_H_
+#define _ESP_PLATFORM_NET_IF_H_
+
+#define MSG_DONTROUTE 0x4 /* send without using routing tables */
+#define SOCK_SEQPACKET 5 /* sequenced packet stream */
+#define MSG_EOR 0x8 /* data completes record */
+#define SOCK_SEQPACKET 5 /* sequenced packet stream */
+#define SOMAXCONN 128
+
+#define IF_NAMESIZE 16
+
+#define IPV6_UNICAST_HOPS 4 /* int; IP6 hops */
+
+#define NI_MAXHOST 1025
+#define NI_MAXSERV 32
+#define NI_NUMERICSERV 0x00000008
+#define NI_DGRAM 0x00000010
+
+
+struct ipv6_mreq {
+ struct in6_addr ipv6mr_multiaddr;
+ unsigned int ipv6mr_interface;
+};
+
+typedef u32_t socklen_t;
+
+
+unsigned int if_nametoindex(const char *ifname);
+
+char *if_indextoname(unsigned int ifindex, char *ifname);
+
+#endif // _ESP_PLATFORM_NET_IF_H_
--- /dev/null
+// Copyright 2018 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 __ESP_PLATFORM_PTHREAD_H__
+#define __ESP_PLATFORM_PTHREAD_H__
+
+#include <sys/types.h>
+#include <sys/time.h>
+#include_next <pthread.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+int pthread_condattr_getclock(const pthread_condattr_t * attr, clockid_t * clock_id);
+
+int pthread_condattr_setclock(pthread_condattr_t *attr, clockid_t clock_id);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // __ESP_PLATFORM_PTHREAD_H__
--- /dev/null
+// Copyright 2018 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 _ESP_PLATFORM_SYS_POLL_H_
+#define _ESP_PLATFORM_SYS_POLL_H_
+
+#define POLLIN 0x0001 /* any readable data available */
+#define POLLOUT 0x0004 /* file descriptor is writeable */
+#define POLLPRI 0x0002 /* OOB/Urgent readable data */
+#define POLLERR 0x0008 /* some poll error occurred */
+#define POLLHUP 0x0010 /* file descriptor was "hung up" */
+
+struct pollfd {
+ int fd; /* The descriptor. */
+ short events; /* The event(s) is/are specified here. */
+ short revents; /* Events found are returned here. */
+};
+
+typedef unsigned int nfds_t;
+int poll(struct pollfd *fds, nfds_t nfds, int timeout);
+
+#endif // _ESP_PLATFORM_SYS_POLL_H_
--- /dev/null
+// Copyright 2018 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 _ESP_PLATFORM_SYS_UIO_H_
+#define _ESP_PLATFORM_SYS_UIO_H_
+
+int writev(int s, const struct iovec *iov, int iovcnt);
+
+ssize_t readv(int fd, const struct iovec *iov, int iovcnt);
+
+#endif // _ESP_PLATFORM_SYS_UIO_H_
--- /dev/null
+// Copyright 2018 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 _ESP_PLATFORM_SYS_UN_H_
+#define _ESP_PLATFORM_SYS_UN_H_
+
+#define AF_UNIX 1 /* local to host (pipes) */
+
+struct sockaddr_un {
+ short sun_family; /*AF_UNIX*/
+ char sun_path[108]; /*path name */
+};
+
+#endif // _ESP_PLATFORM_SYS_UN_H_
#include_next <sys/unistd.h>
int _EXFUN(truncate, (const char *, off_t __length));
+int _EXFUN(gethostname, (char *__name, size_t __len));
#ifdef __cplusplus
}
--- /dev/null
+#include <pthread.h>
+#include "esp_log.h"
+
+const static char *TAG = "esp32_asio_pthread";
+
+int pthread_condattr_setclock(pthread_condattr_t *attr, clockid_t clock_id)
+{
+ ESP_LOGW(TAG, "%s: not yet supported!", __FUNCTION__);
+ return 0;
+}
#pragma once
+#ifdef __cplusplus
+extern "C" {
+#endif
+
int ioctl(int fd, int request, ...);
+#ifdef __cplusplus
+}
+#endif
* :component_file:`SD/MMC driver <sdmmc/sdmmc_cmd.c>` is derived from `OpenBSD SD/MMC driver`_, Copyright (c) 2006 Uwe Stuehler, and is licensed under BSD license.
+* :component:`Asio <asio>`, Copyright (c) 2003-2018 Christopher M. Kohlhoff is licensed under the Boost Software License.
+
Build Tools
-----------
.. _OpenBSD SD/MMC driver: https://github.com/openbsd/src/blob/f303646/sys/dev/sdmmc/sdmmc.c
.. _Mbed TLS: https://github.com/ARMmbed/mbedtls
.. _spiffs: https://github.com/pellepl/spiffs
-
+.. _asio: https://github.com/chriskohlhoff/asio
--- /dev/null
+ASIO port
+=========
+
+Overview
+--------
+Asio is a cross-platform C++ library, see https://think-async.com. It provides a consistent asynchronous model using a modern C++ approach.
+
+
+ASIO documentation
+^^^^^^^^^^^^^^^^^^
+Please refer to the original asio documentation at https://think-async.com/Asio/Documentation.
+Asio also comes with a number of examples which could be find under Documentation/Examples on that web site.
+
+Supported features
+^^^^^^^^^^^^^^^^^^
+ESP platform port currently supports only network asynchronous socket operations; does not support serial port and ssl.
+Internal asio settings for ESP include
+- EXCEPTIONS: Supported, choice in menuconfig
+- SIGNAL, SIGACTION: Not supported
+- EPOLL, EVENTFD: Not supported
+- TYPEID: Disabled by default, but supported in toolchain and asio (provided stdlib recompiled with -frtti)
+
+Application Example
+-------------------
+ESP examples are based on standard asio examples `examples/protocols/asio`:
+- udp_echo_server
+- tcp_echo_server
+- chat_client
+- chat_server
+Please refer to the specific example README.md for details
+
+
ESP-TLS <esp_tls>
HTTP Client <esp_http_client>
HTTP Server <http_server>
+ ASIO <asio>
Example code for this API section is provided in :example:`protocols` directory of ESP-IDF examples.
--- /dev/null
+.. include:: ../../../en/api-reference/protocols/asio.rst
\ No newline at end of file
--- /dev/null
+#
+# This is a project Makefile. It is assumed the directory this Makefile resides in is a
+# project subdirectory.
+#
+PROJECT_NAME := asio_chatclient
+
+include $(IDF_PATH)/make/project.mk
--- /dev/null
+# ASIO chat server example
+
+Simple asio chat client using WiFi STA
+
+## Example workflow
+
+- WiFi STA is started and trying to connect to the access point defined through `make menuconfig`
+- Once connected and acquired IP address ASIO chat client connects to a corresponding server whose port number and ip are defined through `make menuconfig`
+- Chat client receives all messages from other chat clients, also it sends message received from stdin using `make monitor`
+
+## Running the example
+
+- Run `make menuconfig` to configure the access point's SSID and Password and server ip address and port number
+- Start chat server either on host machine or as another ESP device running chat_server example
+- Run `make flash monitor` to build and upload the example to your board and connect to it's serial terminal
+- Wait for WiFi to connect to your access point
+- Receive and send messages to/from other clients on stdin/stdout via serial terminal.
+
+See the README.md file in the upper level 'examples' directory for more information about examples.
--- /dev/null
+import re
+import os
+import sys
+from socket import *
+from threading import Thread
+import time
+
+# this is a test case write with tiny-test-fw.
+# to run test cases outside tiny-test-fw,
+# we need to set environment variable `TEST_FW_PATH`,
+# then get and insert `TEST_FW_PATH` to sys path before import FW module
+test_fw_path = os.getenv("TEST_FW_PATH")
+if test_fw_path and test_fw_path not in sys.path:
+ sys.path.insert(0, test_fw_path)
+
+import TinyFW
+import IDF
+
+global g_client_response;
+global g_msg_to_client;
+
+g_client_response = ""
+g_msg_to_client = " 3XYZ"
+
+def get_my_ip():
+ s1 = socket(AF_INET, SOCK_DGRAM)
+ s1.connect(("8.8.8.8", 80))
+ my_ip = s1.getsockname()[0]
+ s1.close()
+ return my_ip
+
+def chat_server_sketch(my_ip):
+ global g_client_response
+ print("Starting the server on {}".format(my_ip))
+ port=2222
+ s=socket(AF_INET, SOCK_STREAM)
+ s.bind((my_ip, port))
+ s.listen(1)
+ q,addr=s.accept()
+ print("connection accepted")
+ q.send(g_msg_to_client)
+ data = q.recv(1024)
+ # check if received initial empty message
+ if (len(data)>4):
+ g_client_response = data
+ else:
+ g_client_response = q.recv(1024)
+ print("received from client {}".format(g_client_response))
+ s.close()
+ print("server closed")
+
+@IDF.idf_example_test(env_tag="Example_WIFI")
+def test_examples_protocol_asio_chat_client(env, extra_data):
+ """
+ steps: |
+ 1. Test to start simple tcp server
+ 2. `dut1` joins AP
+ 3. Test injects server IP to `dut1`via stdin
+ 4. Test evaluates `dut1` receives a message server placed
+ 5. Test injects a message to `dut1` to be sent as chat_client message
+ 6. Test evaluates received test message in host server
+ """
+ global g_client_response
+ global g_msg_to_client
+ test_msg="ABC"
+ dut1 = env.get_dut("chat_client", "examples/protocols/asio/chat_client")
+ # check and log bin size
+ binary_file = os.path.join(dut1.app.binary_path, "asio_chatclient.bin")
+ bin_size = os.path.getsize(binary_file)
+ IDF.log_performance("asio_chatclient_size", "{}KB".format(bin_size//1024))
+ IDF.check_performance("asio_chatclient_size", bin_size//1024)
+ # 1. start a tcp server on the host
+ host_ip = get_my_ip()
+ thread1 = Thread(target = chat_server_sketch, args = (host_ip,))
+ thread1.start()
+ # 2. start the dut test and wait till client gets IP address
+ dut1.start_app()
+ data = dut1.expect(re.compile(r" sta ip: ([^,]+),"))
+ # 3. send host's IP to the client i.e. the `dut1`
+ dut1.write(host_ip)
+ # 4. client `dut1` should receive a message
+ dut1.expect(g_msg_to_client[4:]) # Strip out the front 4 bytes of message len (see chat_message protocol)
+ # 5. write test message from `dut1` chat_client to the server
+ dut1.write(test_msg)
+ while g_client_response == "":
+ time.sleep(1)
+ print(g_client_response)
+ # 6. evaluate host_server received this message
+ if (g_client_response[4:] == test_msg):
+ print("PASS: Received correct message")
+ pass
+ else:
+ print("Failure!")
+ raise ValueError('Wrong data received from asi tcp server: {} (expected:{})'.format(g_client_response, test_msg))
+ thread1.join()
+
+if __name__ == '__main__':
+ test_examples_protocol_asio_chat_client()
--- /dev/null
+#
+# Component Makefile
+#
+# This Makefile should, at the very least, just include $(SDK_PATH)/Makefile. By default,
+# this will take the sources in the src/ directory, compile them and link them into
+# lib(subdirectory_name).a in the build directory. This behaviour is entirely configurable,
+# please read the SDK documents if you need to do this.
+#
+
+COMPONENT_SRCDIRS = .
--- /dev/null
+/* Common WiFi Init as STA for ASIO examples
+
+ 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 "freertos/FreeRTOS.h"
+#include "freertos/task.h"
+#include "freertos/event_groups.h"
+#include "esp_system.h"
+#include "esp_wifi.h"
+#include "esp_event_loop.h"
+#include "esp_log.h"
+#include "nvs_flash.h"
+#include "driver/uart.h"
+#include "esp_console.h"
+#include "esp_vfs_dev.h"
+
+#include "lwip/err.h"
+#include "lwip/sys.h"
+
+#include <cstring>
+
+/* 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_ESP_WIFI_SSID CONFIG_ESP_WIFI_SSID
+#define EXAMPLE_ESP_WIFI_PASS CONFIG_ESP_WIFI_PASSWORD
+
+/* FreeRTOS event group to signal when we are connected*/
+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 int WIFI_CONNECTED_BIT = BIT0;
+
+static const char *TAG = "asio example wifi init";
+
+/**
+ * Definition of ASIO main method, which is called after network initialized
+ */
+void asio_main();
+
+static esp_err_t 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:
+ ESP_LOGI(TAG, "got ip:%s",
+ ip4addr_ntoa(&event->event_info.got_ip.ip_info.ip));
+ xEventGroupSetBits(wifi_event_group, WIFI_CONNECTED_BIT);
+ break;
+ case SYSTEM_EVENT_AP_STACONNECTED:
+ ESP_LOGI(TAG, "station:" MACSTR " join, AID=%d",
+ MAC2STR(event->event_info.sta_connected.mac),
+ event->event_info.sta_connected.aid);
+ break;
+ case SYSTEM_EVENT_AP_STADISCONNECTED:
+ ESP_LOGI(TAG, "station:" MACSTR "leave, AID=%d",
+ MAC2STR(event->event_info.sta_disconnected.mac),
+ event->event_info.sta_disconnected.aid);
+ break;
+ case SYSTEM_EVENT_STA_DISCONNECTED:
+ esp_wifi_connect();
+ xEventGroupClearBits(wifi_event_group, WIFI_CONNECTED_BIT);
+ break;
+ default:
+ break;
+ }
+ return ESP_OK;
+}
+
+void wifi_init_sta()
+{
+ wifi_event_group = xEventGroupCreate();
+
+ tcpip_adapter_init();
+ ESP_ERROR_CHECK(esp_event_loop_init(event_handler, NULL) );
+
+ wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
+ ESP_ERROR_CHECK(esp_wifi_init(&cfg));
+ wifi_config_t wifi_config;
+ // zero out the config struct to ensure defaults are setup
+ memset(&wifi_config, 0, sizeof(wifi_sta_config_t));
+ // only copy ssid&password from example config
+ strcpy((char*)(wifi_config.sta.ssid), EXAMPLE_ESP_WIFI_SSID);
+ strcpy((char*)(wifi_config.sta.password), EXAMPLE_ESP_WIFI_PASS);
+
+ ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA) );
+ ESP_ERROR_CHECK(esp_wifi_set_config(ESP_IF_WIFI_STA, &wifi_config) );
+ ESP_ERROR_CHECK(esp_wifi_start() );
+
+ ESP_LOGI(TAG, "wifi_init_sta finished.");
+ ESP_LOGI(TAG, "connect to ap SSID:%s password:%s",
+ EXAMPLE_ESP_WIFI_SSID, EXAMPLE_ESP_WIFI_PASS);
+}
+
+extern "C" void app_main()
+{
+ //Initialize NVS
+ esp_err_t ret = nvs_flash_init();
+ if (ret == ESP_ERR_NVS_NO_FREE_PAGES) {
+ ESP_ERROR_CHECK(nvs_flash_erase());
+ ret = nvs_flash_init();
+ }
+ ESP_ERROR_CHECK(ret);
+
+ ESP_LOGI(TAG, "ESP_WIFI_MODE_AP");
+ wifi_init_sta();
+
+ // Initialize VFS & UART so we can use std::cout/cin
+ setvbuf(stdin, NULL, _IONBF, 0);
+ setvbuf(stdout, NULL, _IONBF, 0);
+ /* Install UART driver for interrupt-driven reads and writes */
+ ESP_ERROR_CHECK( uart_driver_install( (uart_port_t)CONFIG_CONSOLE_UART_NUM,
+ 256, 0, 0, NULL, 0) );
+ /* Tell VFS to use UART driver */
+ esp_vfs_dev_uart_use_driver(CONFIG_CONSOLE_UART_NUM);
+ esp_vfs_dev_uart_set_rx_line_endings(ESP_LINE_ENDINGS_CR);
+ /* Move the caret to the beginning of the next line on '\n' */
+ esp_vfs_dev_uart_set_tx_line_endings(ESP_LINE_ENDINGS_CRLF);
+
+ // wait till we receive IP, so asio realated code can be started
+ xEventGroupWaitBits(wifi_event_group, WIFI_CONNECTED_BIT, 1, 1, portMAX_DELAY);
+
+ // network is ready, let's proceed with ASIO example
+ asio_main();
+}
--- /dev/null
+menu "Example Configuration"
+
+config ESP_WIFI_SSID
+ string "WiFi SSID"
+ default "myssid"
+ help
+ SSID (network name) for the example to connect to.
+
+config ESP_WIFI_PASSWORD
+ string "WiFi Password"
+ default "mypassword"
+ help
+ WiFi password (WPA or WPA2) for the example to use.
+
+config EXAMPLE_PORT
+ string "asio example port number"
+ default "2222"
+ help
+ Port number used by ASIO example
+
+config EXAMPLE_SERVER_IP
+ string "asio example server ip for this client to connect to (leave defalut=FROM_STDIN to enter the server address via serial terminal)"
+ default "FROM_STDIN"
+ help
+ Please set the host name or ip address of corespondant server running
+
+endmenu
--- /dev/null
+//
+// chat_client.cpp
+// ~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#include <cstdlib>
+#include <deque>
+#include <iostream>
+#include <thread>
+#include "asio.hpp"
+#include "chat_message.hpp"
+
+using asio::ip::tcp;
+
+typedef std::deque<chat_message> chat_message_queue;
+
+class chat_client
+{
+public:
+ chat_client(asio::io_context& io_context,
+ const tcp::resolver::results_type& endpoints)
+ : io_context_(io_context),
+ socket_(io_context)
+ {
+ do_connect(endpoints);
+ }
+
+ void write(const chat_message& msg)
+ {
+ asio::post(io_context_,
+ [this, msg]()
+ {
+ bool write_in_progress = !write_msgs_.empty();
+ write_msgs_.push_back(msg);
+ if (!write_in_progress)
+ {
+ do_write();
+ }
+ });
+ }
+
+ void close()
+ {
+ asio::post(io_context_, [this]() { socket_.close(); });
+ }
+
+private:
+ void do_connect(const tcp::resolver::results_type& endpoints)
+ {
+ asio::async_connect(socket_, endpoints,
+ [this](std::error_code ec, tcp::endpoint)
+ {
+ if (!ec)
+ {
+ do_read_header();
+ }
+ });
+ }
+
+ void do_read_header()
+ {
+ asio::async_read(socket_,
+ asio::buffer(read_msg_.data(), chat_message::header_length),
+ [this](std::error_code ec, std::size_t /*length*/)
+ {
+ if (!ec && read_msg_.decode_header())
+ {
+ do_read_body();
+ }
+ else
+ {
+ socket_.close();
+ }
+ });
+ }
+
+ void do_read_body()
+ {
+ asio::async_read(socket_,
+ asio::buffer(read_msg_.body(), read_msg_.body_length()),
+ [this](std::error_code ec, std::size_t /*length*/)
+ {
+ if (!ec)
+ {
+ std::cout.write(read_msg_.body(), read_msg_.body_length());
+ std::cout << "\n";
+ do_read_header();
+ }
+ else
+ {
+ socket_.close();
+ }
+ });
+ }
+
+ void do_write()
+ {
+ asio::async_write(socket_,
+ asio::buffer(write_msgs_.front().data(),
+ write_msgs_.front().length()),
+ [this](std::error_code ec, std::size_t /*length*/)
+ {
+ if (!ec)
+ {
+ write_msgs_.pop_front();
+ if (!write_msgs_.empty())
+ {
+ do_write();
+ }
+ }
+ else
+ {
+ socket_.close();
+ }
+ });
+ }
+
+private:
+ asio::io_context& io_context_;
+ tcp::socket socket_;
+ chat_message read_msg_;
+ chat_message_queue write_msgs_;
+};
+
+void read_line(char * line, int max_chars);
+
+
+void asio_main()
+{
+ std::string name(CONFIG_EXAMPLE_SERVER_IP);
+ std::string port(CONFIG_EXAMPLE_PORT);
+ char line[chat_message::max_body_length + 1] = { 0 };
+
+ if (name == "FROM_STDIN") {
+ std::cout << "Please enter ip address of chat server" << std::endl;
+ if (std::cin.getline(line, chat_message::max_body_length + 1)) {
+ name = line;
+ std::cout << "Chat server IP:" << name << std::endl;
+ }
+ }
+
+ asio::io_context io_context;
+ tcp::resolver resolver(io_context);
+ auto endpoints = resolver.resolve(name, port);
+
+ chat_client c(io_context, endpoints);
+
+ std::thread t([&io_context](){ io_context.run(); });
+
+ while (std::cin.getline(line, chat_message::max_body_length + 1) && std::string(line) != "exit\n") {
+ chat_message msg;
+ msg.body_length(std::strlen(line));
+ std::memcpy(msg.body(), line, msg.body_length());
+ msg.encode_header();
+ c.write(msg);
+ }
+
+ c.close();
+ t.join();
+}
--- /dev/null
+//
+// chat_message.hpp
+// ~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef CHAT_MESSAGE_HPP
+#define CHAT_MESSAGE_HPP
+
+#include <cstdio>
+#include <cstdlib>
+#include <cstring>
+
+class chat_message
+{
+public:
+ enum { header_length = 4 };
+ enum { max_body_length = 512 };
+
+ chat_message()
+ : body_length_(0)
+ {
+ }
+
+ const char* data() const
+ {
+ return data_;
+ }
+
+ char* data()
+ {
+ return data_;
+ }
+
+ std::size_t length() const
+ {
+ return header_length + body_length_;
+ }
+
+ const char* body() const
+ {
+ return data_ + header_length;
+ }
+
+ char* body()
+ {
+ return data_ + header_length;
+ }
+
+ std::size_t body_length() const
+ {
+ return body_length_;
+ }
+
+ void body_length(std::size_t new_length)
+ {
+ body_length_ = new_length;
+ if (body_length_ > max_body_length)
+ body_length_ = max_body_length;
+ }
+
+ bool decode_header()
+ {
+ char header[header_length + 1] = "";
+ std::strncat(header, data_, header_length);
+ body_length_ = std::atoi(header);
+ if (body_length_ > max_body_length)
+ {
+ body_length_ = 0;
+ return false;
+ }
+ return true;
+ }
+
+ void encode_header()
+ {
+ char header[header_length + 1] = "";
+ std::sprintf(header, "%4d", static_cast<int>(body_length_));
+ std::memcpy(data_, header, header_length);
+ }
+
+private:
+ char data_[header_length + max_body_length];
+ std::size_t body_length_;
+};
+
+#endif // CHAT_MESSAGE_HPP
--- /dev/null
+#
+# Main component makefile.
+#
+# This Makefile can be left empty. By default, it will take the sources in the
+# src/ directory, compile them and link them into lib(subdirectory_name).a
+# in the build directory. This behaviour is entirely configurable,
+# please read the ESP-IDF documents if you need to do this.
+#
--- /dev/null
+CONFIG_MAIN_TASK_STACK_SIZE=8192
--- /dev/null
+#
+# This is a project Makefile. It is assumed the directory this Makefile resides in is a
+# project subdirectory.
+#
+PROJECT_NAME := asio_chatserver
+
+include $(IDF_PATH)/make/project.mk
--- /dev/null
+# ASIO chat server example
+
+Simple asio chat server using WiFi STA
+
+## Example workflow
+
+- WiFi STA is started and trying to connect to the access point defined through `make menuconfig`
+- Once connected and acquired IP address, ASIO chat server is started on port number defined through `make menuconfig`
+- Chat server echoes a message (received from any client) to all connected clients
+
+## Running the example
+
+- Run `make menuconfig` to configure the access point's SSID and Password and port number
+- Run `make flash monitor` to build and upload the example to your board and connect to it's serial terminal
+- Wait for WiFi to connect to your access point (note the IP address)
+- Connect to the server using multiple clients, for example using any option below
+ - build and run asi chat client on your host machine
+ - run chat_client asio example on ESP platform
+ - since chat message consist of ascii size and message, it is possible to
+ netcat `nc IP PORT` and type for example ` 4ABC<CR>` to transmit 'ABC\n'
+
+See the README.md file in the upper level 'examples' directory for more information about examples.
--- /dev/null
+import re
+import os
+import sys
+from socket import *
+
+
+# this is a test case write with tiny-test-fw.
+# to run test cases outside tiny-test-fw,
+# we need to set environment variable `TEST_FW_PATH`,
+# then get and insert `TEST_FW_PATH` to sys path before import FW module
+test_fw_path = os.getenv("TEST_FW_PATH")
+if test_fw_path and test_fw_path not in sys.path:
+ sys.path.insert(0, test_fw_path)
+
+import TinyFW
+import IDF
+
+
+
+
+@IDF.idf_example_test(env_tag="Example_WIFI")
+def test_examples_protocol_asio_chat_server(env, extra_data):
+ """
+ steps: |
+ 1. join AP
+ 2. Start server
+ 3. Test connects to server and sends a test message
+ 4. Test evaluates received test message from server
+ """
+ test_msg=" 4ABC\n"
+ dut1 = env.get_dut("chat_server", "examples/protocols/asio/chat_server")
+ # check and log bin size
+ binary_file = os.path.join(dut1.app.binary_path, "asio_chatserver.bin")
+ bin_size = os.path.getsize(binary_file)
+ IDF.log_performance("asio_chatserver_bin_size", "{}KB".format(bin_size//1024))
+ IDF.check_performance("asio_chatserver_size", bin_size//1024)
+ # 1. start test
+ dut1.start_app()
+ # 2. get the server IP address
+ data = dut1.expect(re.compile(r" sta ip: ([^,]+),"))
+ # 3. create tcp client and connect to server
+ cli = socket(AF_INET,SOCK_STREAM)
+ cli.connect((data[0],80))
+ cli.send(test_msg)
+ data = cli.recv(1024)
+ # 4. check the message received back from the server
+ if (data == test_msg):
+ print("PASS: Received correct message {}".format(data))
+ pass
+ else:
+ print("Failure!")
+ raise ValueError('Wrong data received from asi tcp server: {} (expoected:{})'.format(data, test_msg))
+
+
+if __name__ == '__main__':
+ test_examples_protocol_asio_chat_server()
--- /dev/null
+#
+# Component Makefile
+#
+# This Makefile should, at the very least, just include $(SDK_PATH)/Makefile. By default,
+# this will take the sources in the src/ directory, compile them and link them into
+# lib(subdirectory_name).a in the build directory. This behaviour is entirely configurable,
+# please read the SDK documents if you need to do this.
+#
+
+COMPONENT_SRCDIRS = .
--- /dev/null
+/* Common WiFi Init as STA for ASIO examples
+
+ 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 "freertos/FreeRTOS.h"
+#include "freertos/task.h"
+#include "freertos/event_groups.h"
+#include "esp_system.h"
+#include "esp_wifi.h"
+#include "esp_event_loop.h"
+#include "esp_log.h"
+#include "nvs_flash.h"
+#include "driver/uart.h"
+#include "esp_console.h"
+#include "esp_vfs_dev.h"
+
+#include "lwip/err.h"
+#include "lwip/sys.h"
+
+#include <cstring>
+
+/* 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_ESP_WIFI_SSID CONFIG_ESP_WIFI_SSID
+#define EXAMPLE_ESP_WIFI_PASS CONFIG_ESP_WIFI_PASSWORD
+
+/* FreeRTOS event group to signal when we are connected*/
+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 int WIFI_CONNECTED_BIT = BIT0;
+
+static const char *TAG = "asio example wifi init";
+
+/**
+ * Definition of ASIO main method, which is called after network initialized
+ */
+void asio_main();
+
+static esp_err_t 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:
+ ESP_LOGI(TAG, "got ip:%s",
+ ip4addr_ntoa(&event->event_info.got_ip.ip_info.ip));
+ xEventGroupSetBits(wifi_event_group, WIFI_CONNECTED_BIT);
+ break;
+ case SYSTEM_EVENT_AP_STACONNECTED:
+ ESP_LOGI(TAG, "station:" MACSTR " join, AID=%d",
+ MAC2STR(event->event_info.sta_connected.mac),
+ event->event_info.sta_connected.aid);
+ break;
+ case SYSTEM_EVENT_AP_STADISCONNECTED:
+ ESP_LOGI(TAG, "station:" MACSTR "leave, AID=%d",
+ MAC2STR(event->event_info.sta_disconnected.mac),
+ event->event_info.sta_disconnected.aid);
+ break;
+ case SYSTEM_EVENT_STA_DISCONNECTED:
+ esp_wifi_connect();
+ xEventGroupClearBits(wifi_event_group, WIFI_CONNECTED_BIT);
+ break;
+ default:
+ break;
+ }
+ return ESP_OK;
+}
+
+void wifi_init_sta()
+{
+ wifi_event_group = xEventGroupCreate();
+
+ tcpip_adapter_init();
+ ESP_ERROR_CHECK(esp_event_loop_init(event_handler, NULL) );
+
+ wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
+ ESP_ERROR_CHECK(esp_wifi_init(&cfg));
+ wifi_config_t wifi_config;
+ // zero out the config struct to ensure defaults are setup
+ memset(&wifi_config, 0, sizeof(wifi_sta_config_t));
+ // only copy ssid&password from example config
+ strcpy((char*)(wifi_config.sta.ssid), EXAMPLE_ESP_WIFI_SSID);
+ strcpy((char*)(wifi_config.sta.password), EXAMPLE_ESP_WIFI_PASS);
+
+ ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA) );
+ ESP_ERROR_CHECK(esp_wifi_set_config(ESP_IF_WIFI_STA, &wifi_config) );
+ ESP_ERROR_CHECK(esp_wifi_start() );
+
+ ESP_LOGI(TAG, "wifi_init_sta finished.");
+ ESP_LOGI(TAG, "connect to ap SSID:%s password:%s",
+ EXAMPLE_ESP_WIFI_SSID, EXAMPLE_ESP_WIFI_PASS);
+}
+
+extern "C" void app_main()
+{
+ //Initialize NVS
+ esp_err_t ret = nvs_flash_init();
+ if (ret == ESP_ERR_NVS_NO_FREE_PAGES) {
+ ESP_ERROR_CHECK(nvs_flash_erase());
+ ret = nvs_flash_init();
+ }
+ ESP_ERROR_CHECK(ret);
+
+ ESP_LOGI(TAG, "ESP_WIFI_MODE_AP");
+ wifi_init_sta();
+
+ // Initialize VFS & UART so we can use std::cout/cin
+ setvbuf(stdin, NULL, _IONBF, 0);
+ setvbuf(stdout, NULL, _IONBF, 0);
+ /* Install UART driver for interrupt-driven reads and writes */
+ ESP_ERROR_CHECK( uart_driver_install( (uart_port_t)CONFIG_CONSOLE_UART_NUM,
+ 256, 0, 0, NULL, 0) );
+ /* Tell VFS to use UART driver */
+ esp_vfs_dev_uart_use_driver(CONFIG_CONSOLE_UART_NUM);
+ esp_vfs_dev_uart_set_rx_line_endings(ESP_LINE_ENDINGS_CR);
+ /* Move the caret to the beginning of the next line on '\n' */
+ esp_vfs_dev_uart_set_tx_line_endings(ESP_LINE_ENDINGS_CRLF);
+
+ // wait till we receive IP, so asio realated code can be started
+ xEventGroupWaitBits(wifi_event_group, WIFI_CONNECTED_BIT, 1, 1, portMAX_DELAY);
+
+ // network is ready, let's proceed with ASIO example
+ asio_main();
+}
--- /dev/null
+menu "Example Configuration"
+
+config ESP_WIFI_SSID
+ string "WiFi SSID"
+ default "myssid"
+ help
+ SSID (network name) for the example to connect to.
+
+config ESP_WIFI_PASSWORD
+ string "WiFi Password"
+ default "mypassword"
+ help
+ WiFi password (WPA or WPA2) for the example to use.
+
+config EXAMPLE_PORT
+ string "asio example port number"
+ default "80"
+ help
+ Port number used by ASIO example
+
+endmenu
--- /dev/null
+//
+// chat_message.hpp
+// ~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef CHAT_MESSAGE_HPP
+#define CHAT_MESSAGE_HPP
+
+#include <cstdio>
+#include <cstdlib>
+#include <cstring>
+
+class chat_message
+{
+public:
+ enum { header_length = 4 };
+ enum { max_body_length = 512 };
+
+ chat_message()
+ : body_length_(0)
+ {
+ }
+
+ const char* data() const
+ {
+ return data_;
+ }
+
+ char* data()
+ {
+ return data_;
+ }
+
+ std::size_t length() const
+ {
+ return header_length + body_length_;
+ }
+
+ const char* body() const
+ {
+ return data_ + header_length;
+ }
+
+ char* body()
+ {
+ return data_ + header_length;
+ }
+
+ std::size_t body_length() const
+ {
+ return body_length_;
+ }
+
+ void body_length(std::size_t new_length)
+ {
+ body_length_ = new_length;
+ if (body_length_ > max_body_length)
+ body_length_ = max_body_length;
+ }
+
+ bool decode_header()
+ {
+ char header[header_length + 1] = "";
+ std::strncat(header, data_, header_length);
+ body_length_ = std::atoi(header);
+ if (body_length_ > max_body_length)
+ {
+ body_length_ = 0;
+ return false;
+ }
+ return true;
+ }
+
+ void encode_header()
+ {
+ char header[header_length + 1] = "";
+ std::sprintf(header, "%4d", static_cast<int>(body_length_));
+ std::memcpy(data_, header, header_length);
+ }
+
+private:
+ char data_[header_length + max_body_length];
+ std::size_t body_length_;
+};
+
+#endif // CHAT_MESSAGE_HPP
--- /dev/null
+//
+// chat_server.cpp
+// ~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#include <cstdlib>
+#include <deque>
+#include <iostream>
+#include <list>
+#include <memory>
+#include <set>
+#include <utility>
+#include "asio.hpp"
+#include "chat_message.hpp"
+
+using asio::ip::tcp;
+
+//----------------------------------------------------------------------
+
+typedef std::deque<chat_message> chat_message_queue;
+
+//----------------------------------------------------------------------
+
+class chat_participant
+{
+public:
+ virtual ~chat_participant() {}
+ virtual void deliver(const chat_message& msg) = 0;
+};
+
+typedef std::shared_ptr<chat_participant> chat_participant_ptr;
+
+//----------------------------------------------------------------------
+
+class chat_room
+{
+public:
+ void join(chat_participant_ptr participant)
+ {
+ participants_.insert(participant);
+ for (auto msg: recent_msgs_)
+ participant->deliver(msg);
+ }
+
+ void leave(chat_participant_ptr participant)
+ {
+ participants_.erase(participant);
+ }
+
+ void deliver(const chat_message& msg)
+ {
+ recent_msgs_.push_back(msg);
+ while (recent_msgs_.size() > max_recent_msgs)
+ recent_msgs_.pop_front();
+
+ for (auto participant: participants_)
+ participant->deliver(msg);
+ }
+
+private:
+ std::set<chat_participant_ptr> participants_;
+ enum { max_recent_msgs = 100 };
+ chat_message_queue recent_msgs_;
+};
+
+//----------------------------------------------------------------------
+
+class chat_session
+ : public chat_participant,
+ public std::enable_shared_from_this<chat_session>
+{
+public:
+ chat_session(tcp::socket socket, chat_room& room)
+ : socket_(std::move(socket)),
+ room_(room)
+ {
+ }
+
+ void start()
+ {
+ room_.join(shared_from_this());
+ do_read_header();
+ }
+
+ void deliver(const chat_message& msg)
+ {
+ bool write_in_progress = !write_msgs_.empty();
+ write_msgs_.push_back(msg);
+ if (!write_in_progress)
+ {
+ do_write();
+ }
+ }
+
+private:
+ void do_read_header()
+ {
+ auto self(shared_from_this());
+ asio::async_read(socket_,
+ asio::buffer(read_msg_.data(), chat_message::header_length),
+ [this, self](std::error_code ec, std::size_t /*length*/)
+ {
+ if (!ec && read_msg_.decode_header())
+ {
+ do_read_body();
+ }
+ else
+ {
+ room_.leave(shared_from_this());
+ }
+ });
+ }
+
+ void do_read_body()
+ {
+ auto self(shared_from_this());
+ asio::async_read(socket_,
+ asio::buffer(read_msg_.body(), read_msg_.body_length()),
+ [this, self](std::error_code ec, std::size_t /*length*/)
+ {
+ if (!ec)
+ {
+ room_.deliver(read_msg_);
+ do_read_header();
+ }
+ else
+ {
+ room_.leave(shared_from_this());
+ }
+ });
+ }
+
+ void do_write()
+ {
+ auto self(shared_from_this());
+ asio::async_write(socket_,
+ asio::buffer(write_msgs_.front().data(),
+ write_msgs_.front().length()),
+ [this, self](std::error_code ec, std::size_t /*length*/)
+ {
+ if (!ec)
+ {
+ write_msgs_.pop_front();
+ if (!write_msgs_.empty())
+ {
+ do_write();
+ }
+ }
+ else
+ {
+ room_.leave(shared_from_this());
+ }
+ });
+ }
+
+ tcp::socket socket_;
+ chat_room& room_;
+ chat_message read_msg_;
+ chat_message_queue write_msgs_;
+};
+
+//----------------------------------------------------------------------
+
+class chat_server
+{
+public:
+ chat_server(asio::io_context& io_context,
+ const tcp::endpoint& endpoint)
+ : acceptor_(io_context, endpoint)
+ {
+ do_accept();
+ }
+
+private:
+ void do_accept()
+ {
+ acceptor_.async_accept(
+ [this](std::error_code ec, tcp::socket socket)
+ {
+ if (!ec)
+ {
+ std::make_shared<chat_session>(std::move(socket), room_)->start();
+ }
+
+ do_accept();
+ });
+ }
+
+ tcp::acceptor acceptor_;
+ chat_room room_;
+};
+
+//----------------------------------------------------------------------
+
+int asio_main()
+{
+ asio::io_context io_context;
+
+ std::list<chat_server> servers;
+
+ {
+ tcp::endpoint endpoint(tcp::v4(), std::atoi(CONFIG_EXAMPLE_PORT));
+ servers.emplace_back(io_context, endpoint);
+ }
+
+ io_context.run();
+
+ return 0;
+}
--- /dev/null
+#
+# Main component makefile.
+#
+# This Makefile can be left empty. By default, it will take the sources in the
+# src/ directory, compile them and link them into lib(subdirectory_name).a
+# in the build directory. This behaviour is entirely configurable,
+# please read the ESP-IDF documents if you need to do this.
+#
--- /dev/null
+CONFIG_MAIN_TASK_STACK_SIZE=8192
--- /dev/null
+#
+# This is a project Makefile. It is assumed the directory this Makefile resides in is a
+# project subdirectory.
+#
+PROJECT_NAME := asio_tcp_echoserver
+
+include $(IDF_PATH)/make/project.mk
--- /dev/null
+# ASIO tcp echo server example
+
+Simple asio echo server using WiFi STA
+
+## Example workflow
+
+- WiFi STA is started and trying to connect to the access point defined through `make menuconfig`
+- Once connected and acquired IP address, ASIO tcp server is started on port number defined through `make menuconfig`
+- Server receives and echoes back messages transmitted from client
+
+## Running the example
+
+- Run `make menuconfig` to configure the access point's SSID and Password and port number
+- Run `make flash monitor` to build and upload the example to your board and connect to it's serial terminal
+- Wait for WiFi to connect to your access point (note the IP address)
+- You can now send a tcp message and check it is repeated, for example using netcat `nc IP PORT`
+
+See the README.md file in the upper level 'examples' directory for more information about examples.
--- /dev/null
+import re
+import os
+import sys
+from socket import *
+
+
+# this is a test case write with tiny-test-fw.
+# to run test cases outside tiny-test-fw,
+# we need to set environment variable `TEST_FW_PATH`,
+# then get and insert `TEST_FW_PATH` to sys path before import FW module
+test_fw_path = os.getenv("TEST_FW_PATH")
+if test_fw_path and test_fw_path not in sys.path:
+ sys.path.insert(0, test_fw_path)
+
+import TinyFW
+import IDF
+
+
+
+
+@IDF.idf_example_test(env_tag="Example_WIFI")
+def test_examples_protocol_asio_tcp_server(env, extra_data):
+ """
+ steps: |
+ 1. join AP
+ 2. Start server
+ 3. Test connects to server and sends a test message
+ 4. Test evaluates received test message from server
+ 5. Test evaluates received test message on server stdout
+ """
+ test_msg="echo message from client to server"
+ dut1 = env.get_dut("tcp_echo_server", "examples/protocols/asio/tcp_echo_server")
+ # check and log bin size
+ binary_file = os.path.join(dut1.app.binary_path, "asio_tcp_echoserver.bin")
+ bin_size = os.path.getsize(binary_file)
+ IDF.log_performance("asio_tcp_echoserver_bin_size", "{}KB".format(bin_size//1024))
+ IDF.check_performance("asio_tcp_echoserver_size", bin_size//1024)
+ # 1. start test
+ dut1.start_app()
+ # 2. get the server IP address
+ data = dut1.expect(re.compile(r" sta ip: ([^,]+),"))
+ # 3. create tcp client and connect to server
+ cli = socket(AF_INET,SOCK_STREAM)
+ cli.connect((data[0],80))
+ cli.send(test_msg)
+ data = cli.recv(1024)
+ # 4. check the message received back from the server
+ if (data == test_msg):
+ print("PASS: Received correct message")
+ pass
+ else:
+ print("Failure!")
+ raise ValueError('Wrong data received from asi tcp server: {} (expoected:{})'.format(data, test_msg))
+ # 5. check the client message appears also on server terminal
+ dut1.expect(test_msg)
+
+
+if __name__ == '__main__':
+ test_examples_protocol_asio_tcp_server()
--- /dev/null
+#
+# Component Makefile
+#
+# This Makefile should, at the very least, just include $(SDK_PATH)/Makefile. By default,
+# this will take the sources in the src/ directory, compile them and link them into
+# lib(subdirectory_name).a in the build directory. This behaviour is entirely configurable,
+# please read the SDK documents if you need to do this.
+#
+
+COMPONENT_SRCDIRS = .
--- /dev/null
+/* Common WiFi Init as STA for ASIO examples
+
+ 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 "freertos/FreeRTOS.h"
+#include "freertos/task.h"
+#include "freertos/event_groups.h"
+#include "esp_system.h"
+#include "esp_wifi.h"
+#include "esp_event_loop.h"
+#include "esp_log.h"
+#include "nvs_flash.h"
+#include "driver/uart.h"
+#include "esp_console.h"
+#include "esp_vfs_dev.h"
+
+#include "lwip/err.h"
+#include "lwip/sys.h"
+
+#include <cstring>
+
+/* 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_ESP_WIFI_SSID CONFIG_ESP_WIFI_SSID
+#define EXAMPLE_ESP_WIFI_PASS CONFIG_ESP_WIFI_PASSWORD
+
+/* FreeRTOS event group to signal when we are connected*/
+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 int WIFI_CONNECTED_BIT = BIT0;
+
+static const char *TAG = "asio example wifi init";
+
+/**
+ * Definition of ASIO main method, which is called after network initialized
+ */
+void asio_main();
+
+static esp_err_t 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:
+ ESP_LOGI(TAG, "got ip:%s",
+ ip4addr_ntoa(&event->event_info.got_ip.ip_info.ip));
+ xEventGroupSetBits(wifi_event_group, WIFI_CONNECTED_BIT);
+ break;
+ case SYSTEM_EVENT_AP_STACONNECTED:
+ ESP_LOGI(TAG, "station:" MACSTR " join, AID=%d",
+ MAC2STR(event->event_info.sta_connected.mac),
+ event->event_info.sta_connected.aid);
+ break;
+ case SYSTEM_EVENT_AP_STADISCONNECTED:
+ ESP_LOGI(TAG, "station:" MACSTR "leave, AID=%d",
+ MAC2STR(event->event_info.sta_disconnected.mac),
+ event->event_info.sta_disconnected.aid);
+ break;
+ case SYSTEM_EVENT_STA_DISCONNECTED:
+ esp_wifi_connect();
+ xEventGroupClearBits(wifi_event_group, WIFI_CONNECTED_BIT);
+ break;
+ default:
+ break;
+ }
+ return ESP_OK;
+}
+
+void wifi_init_sta()
+{
+ wifi_event_group = xEventGroupCreate();
+
+ tcpip_adapter_init();
+ ESP_ERROR_CHECK(esp_event_loop_init(event_handler, NULL) );
+
+ wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
+ ESP_ERROR_CHECK(esp_wifi_init(&cfg));
+ wifi_config_t wifi_config;
+ // zero out the config struct to ensure defaults are setup
+ memset(&wifi_config, 0, sizeof(wifi_sta_config_t));
+ // only copy ssid&password from example config
+ strcpy((char*)(wifi_config.sta.ssid), EXAMPLE_ESP_WIFI_SSID);
+ strcpy((char*)(wifi_config.sta.password), EXAMPLE_ESP_WIFI_PASS);
+
+ ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA) );
+ ESP_ERROR_CHECK(esp_wifi_set_config(ESP_IF_WIFI_STA, &wifi_config) );
+ ESP_ERROR_CHECK(esp_wifi_start() );
+
+ ESP_LOGI(TAG, "wifi_init_sta finished.");
+ ESP_LOGI(TAG, "connect to ap SSID:%s password:%s",
+ EXAMPLE_ESP_WIFI_SSID, EXAMPLE_ESP_WIFI_PASS);
+}
+
+extern "C" void app_main()
+{
+ //Initialize NVS
+ esp_err_t ret = nvs_flash_init();
+ if (ret == ESP_ERR_NVS_NO_FREE_PAGES) {
+ ESP_ERROR_CHECK(nvs_flash_erase());
+ ret = nvs_flash_init();
+ }
+ ESP_ERROR_CHECK(ret);
+
+ ESP_LOGI(TAG, "ESP_WIFI_MODE_AP");
+ wifi_init_sta();
+
+ // Initialize VFS & UART so we can use std::cout/cin
+ setvbuf(stdin, NULL, _IONBF, 0);
+ setvbuf(stdout, NULL, _IONBF, 0);
+ /* Install UART driver for interrupt-driven reads and writes */
+ ESP_ERROR_CHECK( uart_driver_install( (uart_port_t)CONFIG_CONSOLE_UART_NUM,
+ 256, 0, 0, NULL, 0) );
+ /* Tell VFS to use UART driver */
+ esp_vfs_dev_uart_use_driver(CONFIG_CONSOLE_UART_NUM);
+ esp_vfs_dev_uart_set_rx_line_endings(ESP_LINE_ENDINGS_CR);
+ /* Move the caret to the beginning of the next line on '\n' */
+ esp_vfs_dev_uart_set_tx_line_endings(ESP_LINE_ENDINGS_CRLF);
+
+ // wait till we receive IP, so asio realated code can be started
+ xEventGroupWaitBits(wifi_event_group, WIFI_CONNECTED_BIT, 1, 1, portMAX_DELAY);
+
+ // network is ready, let's proceed with ASIO example
+ asio_main();
+}
--- /dev/null
+menu "Example Configuration"
+
+config ESP_WIFI_SSID
+ string "WiFi SSID"
+ default "myssid"
+ help
+ SSID (network name) for the example to connect to.
+
+config ESP_WIFI_PASSWORD
+ string "WiFi Password"
+ default "mypassword"
+ help
+ WiFi password (WPA or WPA2) for the example to use.
+
+config EXAMPLE_PORT
+ string "asio example port number"
+ default "80"
+ help
+ Port number used by ASIO example
+
+endmenu
--- /dev/null
+#
+# Main component makefile.
+#
+# This Makefile can be left empty. By default, it will take the sources in the
+# src/ directory, compile them and link them into lib(subdirectory_name).a
+# in the build directory. This behaviour is entirely configurable,
+# please read the ESP-IDF documents if you need to do this.
+#
+
--- /dev/null
+#include "asio.hpp"
+#include <string>
+#include <iostream>
+
+using asio::ip::tcp;
+
+class session
+ : public std::enable_shared_from_this<session>
+{
+public:
+ session(tcp::socket socket)
+ : socket_(std::move(socket))
+ {
+ }
+
+ void start()
+ {
+ do_read();
+ }
+
+private:
+ void do_read()
+ {
+ auto self(shared_from_this());
+ socket_.async_read_some(asio::buffer(data_, max_length),
+ [this, self](std::error_code ec, std::size_t length)
+ {
+ if (!ec)
+ {
+ std::cout << data_ << std::endl;
+ do_write(length);
+ }
+ });
+ }
+
+ void do_write(std::size_t length)
+ {
+ auto self(shared_from_this());
+ asio::async_write(socket_, asio::buffer(data_, length),
+ [this, self](std::error_code ec, std::size_t length)
+ {
+ if (!ec)
+ {
+ do_read();
+ }
+ });
+ }
+
+ tcp::socket socket_;
+ enum { max_length = 1024 };
+ char data_[max_length];
+};
+
+class server
+{
+public:
+ server(asio::io_context& io_context, short port)
+ : acceptor_(io_context, tcp::endpoint(tcp::v4(), port))
+ {
+ do_accept();
+ }
+
+private:
+ void do_accept()
+ {
+ acceptor_.async_accept(
+ [this](std::error_code ec, tcp::socket socket)
+ {
+ if (!ec)
+ {
+ std::make_shared<session>(std::move(socket))->start();
+ }
+
+ do_accept();
+ });
+ }
+
+ tcp::acceptor acceptor_;
+};
+
+
+void asio_main()
+{
+
+ asio::io_context io_context;
+
+ server s(io_context, std::atoi(CONFIG_EXAMPLE_PORT));
+
+ io_context.run();
+
+}
\ No newline at end of file
--- /dev/null
+CONFIG_MAIN_TASK_STACK_SIZE=8192
--- /dev/null
+#
+# This is a project Makefile. It is assumed the directory this Makefile resides in is a
+# project subdirectory.
+#
+PROJECT_NAME := asio_udp_echoserver
+
+include $(IDF_PATH)/make/project.mk
--- /dev/null
+# ASIO udp echo server example
+
+Simple asio echo server using WiFi STA
+
+## Example workflow
+
+- WiFi STA is started and trying to connect to the access point defined through `make menuconfig`
+- Once connected and acquired IP address, ASIO udp server is started on port number defined through `make menuconfig`
+- Server receives and echoes back messages transmitted from client
+
+## Running the example
+
+- Run `make menuconfig` to configure the access point's SSID and Password and port number
+- Run `make flash monitor` to build and upload the example to your board and connect to it's serial terminal
+- Wait for WiFi to connect to your access point (note the IP address)
+- You can now send a udp message and check it is repeated, for example using netcat `nc -u IP PORT`
+
+See the README.md file in the upper level 'examples' directory for more information about examples.
--- /dev/null
+import re
+import os
+import sys
+from socket import *
+
+
+# this is a test case write with tiny-test-fw.
+# to run test cases outside tiny-test-fw,
+# we need to set environment variable `TEST_FW_PATH`,
+# then get and insert `TEST_FW_PATH` to sys path before import FW module
+test_fw_path = os.getenv("TEST_FW_PATH")
+if test_fw_path and test_fw_path not in sys.path:
+ sys.path.insert(0, test_fw_path)
+
+import TinyFW
+import IDF
+
+
+
+
+@IDF.idf_example_test(env_tag="Example_WIFI")
+def test_examples_protocol_asio_udp_server(env, extra_data):
+ """
+ steps: |
+ 1. join AP
+ 2. Start server
+ 3. Test connects to server and sends a test message
+ 4. Test evaluates received test message from server
+ 5. Test evaluates received test message on server stdout
+ """
+ test_msg="echo message from client to server"
+ dut1 = env.get_dut("udp_echo_server", "examples/protocols/asio/udp_echo_server")
+ # check and log bin size
+ binary_file = os.path.join(dut1.app.binary_path, "asio_udp_echoserver.bin")
+ bin_size = os.path.getsize(binary_file)
+ IDF.log_performance("asio_udp_echoserver_bin_size", "{}KB".format(bin_size//1024))
+ IDF.check_performance("asio_udp_echoserver_size", bin_size//1024)
+ # 1. start test
+ dut1.start_app()
+ # 2. get the server IP address
+ data = dut1.expect(re.compile(r" sta ip: ([^,]+),"))
+ # 3. create tcp client and connect to server
+ cli = socket(AF_INET, SOCK_DGRAM)
+ cli.connect((data[0], 80))
+ cli.send(test_msg)
+ data = cli.recv(1024)
+ # 4. check the message received back from the server
+ if (data == test_msg):
+ print("PASS: Received correct message")
+ pass
+ else:
+ print("Failure!")
+ raise ValueError('Wrong data received from asi udp server: {} (expoected:{})'.format(data, test_msg))
+ # 5. check the client message appears also on server terminal
+ dut1.expect(test_msg)
+
+if __name__ == '__main__':
+ test_examples_protocol_asio_udp_server()
--- /dev/null
+#
+# Component Makefile
+#
+# This Makefile should, at the very least, just include $(SDK_PATH)/Makefile. By default,
+# this will take the sources in the src/ directory, compile them and link them into
+# lib(subdirectory_name).a in the build directory. This behaviour is entirely configurable,
+# please read the SDK documents if you need to do this.
+#
+
+COMPONENT_SRCDIRS = .
--- /dev/null
+/* Common WiFi Init as STA for ASIO examples
+
+ 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 "freertos/FreeRTOS.h"
+#include "freertos/task.h"
+#include "freertos/event_groups.h"
+#include "esp_system.h"
+#include "esp_wifi.h"
+#include "esp_event_loop.h"
+#include "esp_log.h"
+#include "nvs_flash.h"
+#include "driver/uart.h"
+#include "esp_console.h"
+#include "esp_vfs_dev.h"
+
+#include "lwip/err.h"
+#include "lwip/sys.h"
+
+#include <cstring>
+
+/* 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_ESP_WIFI_SSID CONFIG_ESP_WIFI_SSID
+#define EXAMPLE_ESP_WIFI_PASS CONFIG_ESP_WIFI_PASSWORD
+
+/* FreeRTOS event group to signal when we are connected*/
+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 int WIFI_CONNECTED_BIT = BIT0;
+
+static const char *TAG = "asio example wifi init";
+
+/**
+ * Definition of ASIO main method, which is called after network initialized
+ */
+void asio_main();
+
+static esp_err_t 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:
+ ESP_LOGI(TAG, "got ip:%s",
+ ip4addr_ntoa(&event->event_info.got_ip.ip_info.ip));
+ xEventGroupSetBits(wifi_event_group, WIFI_CONNECTED_BIT);
+ break;
+ case SYSTEM_EVENT_AP_STACONNECTED:
+ ESP_LOGI(TAG, "station:" MACSTR " join, AID=%d",
+ MAC2STR(event->event_info.sta_connected.mac),
+ event->event_info.sta_connected.aid);
+ break;
+ case SYSTEM_EVENT_AP_STADISCONNECTED:
+ ESP_LOGI(TAG, "station:" MACSTR "leave, AID=%d",
+ MAC2STR(event->event_info.sta_disconnected.mac),
+ event->event_info.sta_disconnected.aid);
+ break;
+ case SYSTEM_EVENT_STA_DISCONNECTED:
+ esp_wifi_connect();
+ xEventGroupClearBits(wifi_event_group, WIFI_CONNECTED_BIT);
+ break;
+ default:
+ break;
+ }
+ return ESP_OK;
+}
+
+void wifi_init_sta()
+{
+ wifi_event_group = xEventGroupCreate();
+
+ tcpip_adapter_init();
+ ESP_ERROR_CHECK(esp_event_loop_init(event_handler, NULL) );
+
+ wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
+ ESP_ERROR_CHECK(esp_wifi_init(&cfg));
+ wifi_config_t wifi_config;
+ // zero out the config struct to ensure defaults are setup
+ memset(&wifi_config, 0, sizeof(wifi_sta_config_t));
+ // only copy ssid&password from example config
+ strcpy((char*)(wifi_config.sta.ssid), EXAMPLE_ESP_WIFI_SSID);
+ strcpy((char*)(wifi_config.sta.password), EXAMPLE_ESP_WIFI_PASS);
+
+ ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA) );
+ ESP_ERROR_CHECK(esp_wifi_set_config(ESP_IF_WIFI_STA, &wifi_config) );
+ ESP_ERROR_CHECK(esp_wifi_start() );
+
+ ESP_LOGI(TAG, "wifi_init_sta finished.");
+ ESP_LOGI(TAG, "connect to ap SSID:%s password:%s",
+ EXAMPLE_ESP_WIFI_SSID, EXAMPLE_ESP_WIFI_PASS);
+}
+
+extern "C" void app_main()
+{
+ //Initialize NVS
+ esp_err_t ret = nvs_flash_init();
+ if (ret == ESP_ERR_NVS_NO_FREE_PAGES) {
+ ESP_ERROR_CHECK(nvs_flash_erase());
+ ret = nvs_flash_init();
+ }
+ ESP_ERROR_CHECK(ret);
+
+ ESP_LOGI(TAG, "ESP_WIFI_MODE_AP");
+ wifi_init_sta();
+
+ // Initialize VFS & UART so we can use std::cout/cin
+ setvbuf(stdin, NULL, _IONBF, 0);
+ setvbuf(stdout, NULL, _IONBF, 0);
+ /* Install UART driver for interrupt-driven reads and writes */
+ ESP_ERROR_CHECK( uart_driver_install( (uart_port_t)CONFIG_CONSOLE_UART_NUM,
+ 256, 0, 0, NULL, 0) );
+ /* Tell VFS to use UART driver */
+ esp_vfs_dev_uart_use_driver(CONFIG_CONSOLE_UART_NUM);
+ esp_vfs_dev_uart_set_rx_line_endings(ESP_LINE_ENDINGS_CR);
+ /* Move the caret to the beginning of the next line on '\n' */
+ esp_vfs_dev_uart_set_tx_line_endings(ESP_LINE_ENDINGS_CRLF);
+
+ // wait till we receive IP, so asio realated code can be started
+ xEventGroupWaitBits(wifi_event_group, WIFI_CONNECTED_BIT, 1, 1, portMAX_DELAY);
+
+ // network is ready, let's proceed with ASIO example
+ asio_main();
+}
--- /dev/null
+menu "Example Configuration"
+
+config ESP_WIFI_SSID
+ string "WiFi SSID"
+ default "myssid"
+ help
+ SSID (network name) for the example to connect to.
+
+config ESP_WIFI_PASSWORD
+ string "WiFi Password"
+ default "mypassword"
+ help
+ WiFi password (WPA or WPA2) for the example to use.
+
+config EXAMPLE_PORT
+ string "asio example port number"
+ default "80"
+ help
+ Port number used by ASIO example
+
+endmenu
--- /dev/null
+#
+# Main component makefile.
+#
+# This Makefile can be left empty. By default, it will take the sources in the
+# src/ directory, compile them and link them into lib(subdirectory_name).a
+# in the build directory. This behaviour is entirely configurable,
+# please read the ESP-IDF documents if you need to do this.
+#
--- /dev/null
+//
+// async_udp_echo_server.cpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#include <cstdlib>
+#include <iostream>
+
+#include "asio.hpp"
+
+using asio::ip::udp;
+
+class server
+{
+public:
+ server(asio::io_context& io_context, short port)
+ : socket_(io_context, udp::endpoint(udp::v4(), port))
+ {
+ do_receive();
+ }
+
+ void do_receive()
+ {
+ socket_.async_receive_from(
+ asio::buffer(data_, max_length), sender_endpoint_,
+ [this](std::error_code ec, std::size_t bytes_recvd)
+ {
+ if (!ec && bytes_recvd > 0)
+ {
+ std::cout << data_ << std::endl;
+ do_send(bytes_recvd);
+ }
+ else
+ {
+ do_receive();
+ }
+ });
+ }
+
+ void do_send(std::size_t length)
+ {
+ socket_.async_send_to(
+ asio::buffer(data_, length), sender_endpoint_,
+ [this](std::error_code /*ec*/, std::size_t bytes /*bytes_sent*/)
+ {
+ do_receive();
+ });
+ }
+
+private:
+ udp::socket socket_;
+ udp::endpoint sender_endpoint_;
+ enum { max_length = 1024 };
+ char data_[max_length];
+};
+
+void asio_main()
+{
+ asio::io_context io_context;
+
+ server s(io_context, std::atoi(CONFIG_EXAMPLE_PORT));
+
+ io_context.run();
+}
--- /dev/null
+CONFIG_MAIN_TASK_STACK_SIZE=8192
--- /dev/null
+/* Common WiFi Init as STA for ASIO examples
+
+ 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 "freertos/FreeRTOS.h"
+#include "freertos/task.h"
+#include "freertos/event_groups.h"
+#include "esp_system.h"
+#include "esp_wifi.h"
+#include "esp_event_loop.h"
+#include "esp_log.h"
+#include "nvs_flash.h"
+#include "driver/uart.h"
+#include "esp_console.h"
+#include "esp_vfs_dev.h"
+
+#include "lwip/err.h"
+#include "lwip/sys.h"
+
+#include <cstring>
+
+/* 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_ESP_WIFI_SSID CONFIG_ESP_WIFI_SSID
+#define EXAMPLE_ESP_WIFI_PASS CONFIG_ESP_WIFI_PASSWORD
+
+/* FreeRTOS event group to signal when we are connected*/
+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 int WIFI_CONNECTED_BIT = BIT0;
+
+static const char *TAG = "asio example wifi init";
+
+/**
+ * Definition of ASIO main method, which is called after network initialized
+ */
+void asio_main();
+
+static esp_err_t 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:
+ ESP_LOGI(TAG, "got ip:%s",
+ ip4addr_ntoa(&event->event_info.got_ip.ip_info.ip));
+ xEventGroupSetBits(wifi_event_group, WIFI_CONNECTED_BIT);
+ break;
+ case SYSTEM_EVENT_AP_STACONNECTED:
+ ESP_LOGI(TAG, "station:" MACSTR " join, AID=%d",
+ MAC2STR(event->event_info.sta_connected.mac),
+ event->event_info.sta_connected.aid);
+ break;
+ case SYSTEM_EVENT_AP_STADISCONNECTED:
+ ESP_LOGI(TAG, "station:" MACSTR "leave, AID=%d",
+ MAC2STR(event->event_info.sta_disconnected.mac),
+ event->event_info.sta_disconnected.aid);
+ break;
+ case SYSTEM_EVENT_STA_DISCONNECTED:
+ esp_wifi_connect();
+ xEventGroupClearBits(wifi_event_group, WIFI_CONNECTED_BIT);
+ break;
+ default:
+ break;
+ }
+ return ESP_OK;
+}
+
+void wifi_init_sta()
+{
+ wifi_event_group = xEventGroupCreate();
+
+ tcpip_adapter_init();
+ ESP_ERROR_CHECK(esp_event_loop_init(event_handler, NULL) );
+
+ wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
+ ESP_ERROR_CHECK(esp_wifi_init(&cfg));
+ wifi_config_t wifi_config;
+ // zero out the config struct to ensure defaults are setup
+ memset(&wifi_config, 0, sizeof(wifi_sta_config_t));
+ // only copy ssid&password from example config
+ strcpy((char*)(wifi_config.sta.ssid), EXAMPLE_ESP_WIFI_SSID);
+ strcpy((char*)(wifi_config.sta.password), EXAMPLE_ESP_WIFI_PASS);
+
+ ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA) );
+ ESP_ERROR_CHECK(esp_wifi_set_config(ESP_IF_WIFI_STA, &wifi_config) );
+ ESP_ERROR_CHECK(esp_wifi_start() );
+
+ ESP_LOGI(TAG, "wifi_init_sta finished.");
+ ESP_LOGI(TAG, "connect to ap SSID:%s password:%s",
+ EXAMPLE_ESP_WIFI_SSID, EXAMPLE_ESP_WIFI_PASS);
+}
+
+extern "C" void app_main()
+{
+ //Initialize NVS
+ esp_err_t ret = nvs_flash_init();
+ if (ret == ESP_ERR_NVS_NO_FREE_PAGES) {
+ ESP_ERROR_CHECK(nvs_flash_erase());
+ ret = nvs_flash_init();
+ }
+ ESP_ERROR_CHECK(ret);
+
+ ESP_LOGI(TAG, "ESP_WIFI_MODE_AP");
+ wifi_init_sta();
+
+ // Initialize VFS & UART so we can use std::cout/cin
+ setvbuf(stdin, NULL, _IONBF, 0);
+ setvbuf(stdout, NULL, _IONBF, 0);
+ /* Install UART driver for interrupt-driven reads and writes */
+ ESP_ERROR_CHECK( uart_driver_install( (uart_port_t)CONFIG_CONSOLE_UART_NUM,
+ 256, 0, 0, NULL, 0) );
+ /* Tell VFS to use UART driver */
+ esp_vfs_dev_uart_use_driver(CONFIG_CONSOLE_UART_NUM);
+ esp_vfs_dev_uart_set_rx_line_endings(ESP_LINE_ENDINGS_CR);
+ /* Move the caret to the beginning of the next line on '\n' */
+ esp_vfs_dev_uart_set_tx_line_endings(ESP_LINE_ENDINGS_CRLF);
+
+ // wait till we receive IP, so asio realated code can be started
+ xEventGroupWaitBits(wifi_event_group, WIFI_CONNECTED_BIT, 1, 1, portMAX_DELAY);
+
+ // network is ready, let's proceed with ASIO example
+ asio_main();
+}
components/micro-ecc/micro-ecc @GENERAL_MIRROR_SERVER@/idf/micro-ecc.git ALLOW_TO_SYNC_FROM_PUBLIC
components/nghttp/nghttp2 @GENERAL_MIRROR_SERVER@/idf/nghttp2.git ALLOW_TO_SYNC_FROM_PUBLIC
components/spiffs/spiffs @GENERAL_MIRROR_SERVER@/idf/spiffs.git ALLOW_TO_SYNC_FROM_PUBLIC
+components/asio/asio @GENERAL_MIRROR_SERVER@/idf/asio.git
third-party/mruby @GENERAL_MIRROR_SERVER@/idf/mruby.git ALLOW_TO_SYNC_FROM_PUBLIC
third-party/neverbleed @GENERAL_MIRROR_SERVER@/idf/neverbleed.git ALLOW_TO_SYNC_FROM_PUBLIC