mirror of
https://github.com/espressif/esp-protocols.git
synced 2025-07-18 13:02:21 +02:00
examples: Asio tests consolidation to use loopback interface
Closes IDF-3072 * Original commit: espressif/esp-idf@a06357ab62
This commit is contained in:
committed by
gabsuren
parent
cb2375827b
commit
91262baede
@ -7,4 +7,4 @@ cmake_minimum_required(VERSION 3.5)
|
|||||||
set(EXTRA_COMPONENT_DIRS $ENV{IDF_PATH}/examples/common_components/protocol_examples_common)
|
set(EXTRA_COMPONENT_DIRS $ENV{IDF_PATH}/examples/common_components/protocol_examples_common)
|
||||||
|
|
||||||
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||||
project(asio_chat_client)
|
project(asio_chat)
|
@ -2,7 +2,7 @@
|
|||||||
# This is a project Makefile. It is assumed the directory this Makefile resides in is a
|
# This is a project Makefile. It is assumed the directory this Makefile resides in is a
|
||||||
# project subdirectory.
|
# project subdirectory.
|
||||||
#
|
#
|
||||||
PROJECT_NAME := asio_chat_server
|
PROJECT_NAME := asio_chat
|
||||||
|
|
||||||
EXTRA_COMPONENT_DIRS = $(IDF_PATH)/examples/common_components/protocol_examples_common
|
EXTRA_COMPONENT_DIRS = $(IDF_PATH)/examples/common_components/protocol_examples_common
|
||||||
|
|
62
examples/protocols/asio/asio_chat/README.md
Normal file
62
examples/protocols/asio/asio_chat/README.md
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
|
||||||
|
# Asio chat client and server examples
|
||||||
|
|
||||||
|
(See the README.md file in the upper level 'examples' directory for more information about examples.)
|
||||||
|
|
||||||
|
The application aims to demonstrate a simple use of Asio library in different modes.
|
||||||
|
In project settings it could be configured to run either a Asio chat server, a Asio chat client, or both.
|
||||||
|
|
||||||
|
## How to use example
|
||||||
|
|
||||||
|
The example is configured by default as an Asio chat client.
|
||||||
|
|
||||||
|
Note that the example uses string representation of IP addresses and ports.
|
||||||
|
|
||||||
|
You can find the upstream asio chat implementation [here] https://github.com/chriskohlhoff/asio/tree/master/asio/src/examples/cpp11/chat
|
||||||
|
|
||||||
|
### Asio Client
|
||||||
|
|
||||||
|
In the client mode, the example connects to the configured address, sends the message, which was inserted as an input in the terminal, and receives a response.
|
||||||
|
|
||||||
|
### Asio Server
|
||||||
|
|
||||||
|
In the server mode, Asio chat server with a specified port number is created and being polled till a connection request from the client arrives.
|
||||||
|
Chat server echoes a message (received from any client) to all connected clients.
|
||||||
|
|
||||||
|
## Configure the project
|
||||||
|
|
||||||
|
```
|
||||||
|
idf.py menuconfig
|
||||||
|
```
|
||||||
|
|
||||||
|
Set following parameters under Example Configuration Options:
|
||||||
|
|
||||||
|
* Set `EXAMPLE_CHAT_SERVER` to use the example as an ASIO chat server
|
||||||
|
* Configure `EXAMPLE_CHAT_SERVER_BIND_PORT` to the port number.
|
||||||
|
|
||||||
|
* Set `EXAMPLE_CHAT_CLIENT` to use the example as an ASIO chat client
|
||||||
|
* Configure `EXAMPLE_CHAT_CLIENT_CONNECT_ADDRESS` to a string representation of the address to connect the client to.
|
||||||
|
* Configure `EXAMPLE_CHAT_CLIENT_CONNECT_PORT` to the port number.
|
||||||
|
|
||||||
|
* Configure Wi-Fi or Ethernet under "Example Connection Configuration" menu. See "Establishing Wi-Fi or Ethernet Connection" section in [examples/protocols/README.md](../../README.md) for more d etails.
|
||||||
|
|
||||||
|
## Running the example in server mode
|
||||||
|
|
||||||
|
- Configure the example according "Configure the project" section.
|
||||||
|
- Run `idf.py -p PORT flash monitor` to build and upload the example to your board and connect to it's serial terminal.
|
||||||
|
- Wait for the board to connect to WiFi or Ethernet (note the IP address).
|
||||||
|
- Connect to the server using multiple clients, for example using any option below.
|
||||||
|
- build and run asio chat client on your host machine
|
||||||
|
- run chat_client asio example on ESP platform
|
||||||
|
- since chat messages consists of ASCII size and message, it is possible to
|
||||||
|
netcat `nc IP PORT` and type for example ` 4ABC<CR>` to transmit 'ABC\n'
|
||||||
|
|
||||||
|
## Running the example in client mode
|
||||||
|
|
||||||
|
- Configure the example according "Configure the project" section.
|
||||||
|
- Start chat server either on host machine or as another ESP device running chat_server example.
|
||||||
|
- Run `idf.py -p PORT flash monitor` to build and upload the example to your board and connect to it's serial terminal.
|
||||||
|
- Wait for the board to connect to WiFi or Ethernet.
|
||||||
|
- 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.
|
29
examples/protocols/asio/asio_chat/example_test.py
Normal file
29
examples/protocols/asio/asio_chat/example_test.py
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
# 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.
|
||||||
|
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
from __future__ import print_function, unicode_literals
|
||||||
|
|
||||||
|
import re
|
||||||
|
|
||||||
|
import ttfw_idf
|
||||||
|
|
||||||
|
|
||||||
|
@ttfw_idf.idf_example_test(env_tag='Example_GENERIC')
|
||||||
|
def test_examples_asio_chat(env, _): # type: (ttfw_idf.TinyFW.Env, None) -> None
|
||||||
|
msg = 'asio-chat: received hi'
|
||||||
|
dut = env.get_dut('asio_chat', 'examples/protocols/asio/asio_chat')
|
||||||
|
# start the test and expect the client to receive back it's original data
|
||||||
|
dut.start_app()
|
||||||
|
dut.expect(re.compile(r'{}'.format('Waiting for input')), timeout=30)
|
||||||
|
dut.write(msg)
|
||||||
|
dut.write('exit')
|
||||||
|
dut.expect(re.compile(r'{}'.format(msg)), timeout=30)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
test_examples_asio_chat()
|
2
examples/protocols/asio/asio_chat/main/CMakeLists.txt
Normal file
2
examples/protocols/asio/asio_chat/main/CMakeLists.txt
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
idf_component_register(SRCS "asio_chat.cpp"
|
||||||
|
INCLUDE_DIRS ".")
|
39
examples/protocols/asio/asio_chat/main/Kconfig.projbuild
Normal file
39
examples/protocols/asio/asio_chat/main/Kconfig.projbuild
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
menu "Example Configuration"
|
||||||
|
|
||||||
|
config EXAMPLE_CHAT_SERVER
|
||||||
|
bool "Asio example chat server"
|
||||||
|
default n
|
||||||
|
help
|
||||||
|
This example will setup a chat server, binds it to the specified address
|
||||||
|
and starts listening.
|
||||||
|
|
||||||
|
if EXAMPLE_CHAT_SERVER
|
||||||
|
config EXAMPLE_CHAT_SERVER_BIND_PORT
|
||||||
|
string "Asio example server bind port"
|
||||||
|
default "3344"
|
||||||
|
help
|
||||||
|
Server listener's socket would be bound to this port.
|
||||||
|
endif
|
||||||
|
|
||||||
|
config EXAMPLE_CHAT_CLIENT
|
||||||
|
bool "Asio example chat client"
|
||||||
|
default y
|
||||||
|
help
|
||||||
|
This example will setup an asio chat client.
|
||||||
|
and sends the data.
|
||||||
|
|
||||||
|
if EXAMPLE_CHAT_CLIENT
|
||||||
|
config EXAMPLE_CHAT_CLIENT_CONNECT_ADDRESS
|
||||||
|
string "Client connection address"
|
||||||
|
default "192.168.0.1"
|
||||||
|
help
|
||||||
|
Client's socket would connect to this address/host.
|
||||||
|
|
||||||
|
config EXAMPLE_CHAT_CLIENT_CONNECT_PORT
|
||||||
|
string "Client connection port"
|
||||||
|
default "3344"
|
||||||
|
help
|
||||||
|
Client's connection port.
|
||||||
|
endif
|
||||||
|
|
||||||
|
endmenu
|
119
examples/protocols/asio/asio_chat/main/asio_chat.cpp
Normal file
119
examples/protocols/asio/asio_chat/main/asio_chat.cpp
Normal file
@ -0,0 +1,119 @@
|
|||||||
|
/* ASIO chat server 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 "protocol_examples_common.h"
|
||||||
|
#include "esp_log.h"
|
||||||
|
#include "esp_event.h"
|
||||||
|
#include "nvs_flash.h"
|
||||||
|
#include "server.hpp"
|
||||||
|
#include "client.hpp"
|
||||||
|
#include <thread>
|
||||||
|
#include <pthread.h>
|
||||||
|
|
||||||
|
using asio::ip::tcp;
|
||||||
|
|
||||||
|
static const char *TAG = "asio-chat";
|
||||||
|
|
||||||
|
// This variable is necessary for `python test` execution, it provides synchronisation between server/client(as server should be started before client)
|
||||||
|
std::mutex server_ready;
|
||||||
|
|
||||||
|
#ifdef CONFIG_EXAMPLE_CHAT_CLIENT
|
||||||
|
static void get_string(char *line, size_t size)
|
||||||
|
{
|
||||||
|
int count = 0;
|
||||||
|
while (count < size) {
|
||||||
|
int c = fgetc(stdin);
|
||||||
|
if (c == '\n') {
|
||||||
|
line[count] = '\0';
|
||||||
|
break;
|
||||||
|
} else if (c > 0 && c < 127) {
|
||||||
|
line[count] = c;
|
||||||
|
++count;
|
||||||
|
}
|
||||||
|
vTaskDelay(10 / portTICK_PERIOD_MS);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void start_client(void)
|
||||||
|
{
|
||||||
|
const std::string port(CONFIG_EXAMPLE_CHAT_CLIENT_CONNECT_PORT);
|
||||||
|
const std::string name(CONFIG_EXAMPLE_CHAT_CLIENT_CONNECT_ADDRESS);
|
||||||
|
asio::io_context io_context;
|
||||||
|
char line[128];
|
||||||
|
|
||||||
|
tcp::resolver resolver(io_context);
|
||||||
|
auto endpoints = resolver.resolve(name, port);
|
||||||
|
chat_client c(io_context, endpoints);
|
||||||
|
#ifdef CONFIG_EXAMPLE_CHAT_SERVER
|
||||||
|
std::lock_guard<std::mutex> guard(server_ready);
|
||||||
|
#endif
|
||||||
|
std::thread t([&io_context]() { try {
|
||||||
|
io_context.run();
|
||||||
|
} catch (const std::exception &e) {
|
||||||
|
ESP_LOGE(TAG, "Exception occured during client thread execution %s", e.what());
|
||||||
|
}
|
||||||
|
catch (...) {
|
||||||
|
ESP_LOGE(TAG, "Unknown exception");
|
||||||
|
}});
|
||||||
|
do {
|
||||||
|
ESP_LOGI(TAG, "CLIENT: Waiting for input");
|
||||||
|
get_string(line, sizeof(line));
|
||||||
|
|
||||||
|
chat_message msg;
|
||||||
|
msg.body_length(std::strlen(line));
|
||||||
|
std::memcpy(msg.body(), line, msg.body_length());
|
||||||
|
msg.encode_header();
|
||||||
|
c.write(msg);
|
||||||
|
sleep(1);
|
||||||
|
} while (strcmp(line, "exit") != 0);
|
||||||
|
|
||||||
|
c.close();
|
||||||
|
t.join();
|
||||||
|
}
|
||||||
|
#endif // CONFIG_EXAMPLE_CHAT_CLIENT
|
||||||
|
|
||||||
|
extern "C" void app_main(void)
|
||||||
|
{
|
||||||
|
ESP_ERROR_CHECK(nvs_flash_init());
|
||||||
|
esp_netif_init();
|
||||||
|
ESP_ERROR_CHECK(esp_event_loop_create_default());
|
||||||
|
|
||||||
|
/* This helper function configures Wi-Fi or Ethernet, as selected in menuconfig.
|
||||||
|
* Read "Establishing Wi-Fi or Ethernet Connection" section in
|
||||||
|
* examples/protocols/README.md for more information about this function.
|
||||||
|
*/
|
||||||
|
ESP_ERROR_CHECK(example_connect());
|
||||||
|
|
||||||
|
try {
|
||||||
|
#ifdef CONFIG_EXAMPLE_CHAT_SERVER
|
||||||
|
asio::io_context io_context;
|
||||||
|
chat_server server(io_context, tcp::endpoint(tcp::v4(), std::atoi(CONFIG_EXAMPLE_CHAT_SERVER_BIND_PORT)));
|
||||||
|
std::thread t = std::thread([&io_context]() { // Chat server starting here
|
||||||
|
try {
|
||||||
|
io_context.run();
|
||||||
|
} catch (const std::exception &e) {
|
||||||
|
ESP_LOGE(TAG, "Exception occured during server thread execution %s", e.what());
|
||||||
|
}
|
||||||
|
catch (...) {
|
||||||
|
ESP_LOGE(TAG, "Unknown exception");
|
||||||
|
}});;
|
||||||
|
#endif
|
||||||
|
#ifdef CONFIG_EXAMPLE_CHAT_CLIENT
|
||||||
|
start_client();
|
||||||
|
#endif
|
||||||
|
#ifdef CONFIG_EXAMPLE_CHAT_SERVER
|
||||||
|
t.join();
|
||||||
|
#endif
|
||||||
|
} catch (const std::exception &e) {
|
||||||
|
ESP_LOGE(TAG, "Exception occured during run %s", e.what());
|
||||||
|
} catch (...) {
|
||||||
|
ESP_LOGE(TAG, "Unknown exception");
|
||||||
|
}
|
||||||
|
ESP_ERROR_CHECK(example_disconnect());
|
||||||
|
}
|
126
examples/protocols/asio/asio_chat/main/client.hpp
Normal file
126
examples/protocols/asio/asio_chat/main/client.hpp
Normal file
@ -0,0 +1,126 @@
|
|||||||
|
//
|
||||||
|
// client.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_CLIENT_HPP
|
||||||
|
#define CHAT_CLIENT_HPP
|
||||||
|
|
||||||
|
#include <deque>
|
||||||
|
#include "asio.hpp"
|
||||||
|
#include "chat_message.hpp"
|
||||||
|
|
||||||
|
typedef std::deque<chat_message> chat_message_queue;
|
||||||
|
|
||||||
|
class chat_client
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
chat_client(asio::io_context& io_context,
|
||||||
|
const asio::ip::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 asio::ip::tcp::resolver::results_type& endpoints)
|
||||||
|
{
|
||||||
|
asio::async_connect(socket_, endpoints,
|
||||||
|
[this](std::error_code ec, asio::ip::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)
|
||||||
|
{
|
||||||
|
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_;
|
||||||
|
asio::ip::tcp::socket socket_;
|
||||||
|
chat_message read_msg_;
|
||||||
|
chat_message_queue write_msgs_;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // CHAT_CLIENT_HPP
|
@ -1,5 +1,5 @@
|
|||||||
//
|
//
|
||||||
// chat_server.cpp
|
// server.hpp
|
||||||
// ~~~~~~~~~~~~~~~
|
// ~~~~~~~~~~~~~~~
|
||||||
//
|
//
|
||||||
// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com)
|
// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com)
|
||||||
@ -8,28 +8,25 @@
|
|||||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||||
//
|
//
|
||||||
|
|
||||||
#include <cstdlib>
|
#ifndef CHAT_SERVER_HPP
|
||||||
#include <deque>
|
#define CHAT_SERVER_HPP
|
||||||
#include <iostream>
|
|
||||||
#include <list>
|
#include <list>
|
||||||
#include <memory>
|
|
||||||
#include <set>
|
#include <set>
|
||||||
|
#include <deque>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
#include "asio.hpp"
|
#include "asio.hpp"
|
||||||
#include "chat_message.hpp"
|
#include "chat_message.hpp"
|
||||||
#include "protocol_examples_common.h"
|
|
||||||
#include "esp_event.h"
|
|
||||||
#include "nvs_flash.h"
|
|
||||||
|
|
||||||
|
|
||||||
using asio::ip::tcp;
|
|
||||||
|
|
||||||
//----------------------------------------------------------------------
|
//----------------------------------------------------------------------
|
||||||
|
|
||||||
typedef std::deque<chat_message> chat_message_queue;
|
typedef std::deque<chat_message> chat_message_queue;
|
||||||
|
|
||||||
|
extern std::mutex server_ready;
|
||||||
|
|
||||||
//----------------------------------------------------------------------
|
//----------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
class chat_participant
|
class chat_participant
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@ -74,12 +71,13 @@ private:
|
|||||||
|
|
||||||
//----------------------------------------------------------------------
|
//----------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
class chat_session
|
class chat_session
|
||||||
: public chat_participant,
|
: public chat_participant,
|
||||||
public std::enable_shared_from_this<chat_session>
|
public std::enable_shared_from_this<chat_session>
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
chat_session(tcp::socket socket, chat_room& room)
|
chat_session(asio::ip::tcp::socket socket, chat_room& room)
|
||||||
: socket_(std::move(socket)),
|
: socket_(std::move(socket)),
|
||||||
room_(room)
|
room_(room)
|
||||||
{
|
{
|
||||||
@ -129,6 +127,7 @@ private:
|
|||||||
{
|
{
|
||||||
if (!ec)
|
if (!ec)
|
||||||
{
|
{
|
||||||
|
ESP_LOGD("asio-chat:", "%s", read_msg_.body());
|
||||||
room_.deliver(read_msg_);
|
room_.deliver(read_msg_);
|
||||||
do_read_header();
|
do_read_header();
|
||||||
}
|
}
|
||||||
@ -162,11 +161,11 @@ private:
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
tcp::socket socket_;
|
asio::ip::tcp::socket socket_;
|
||||||
chat_room& room_;
|
chat_room& room_;
|
||||||
chat_message read_msg_;
|
chat_message read_msg_;
|
||||||
chat_message_queue write_msgs_;
|
chat_message_queue write_msgs_;
|
||||||
};
|
};
|
||||||
|
|
||||||
//----------------------------------------------------------------------
|
//----------------------------------------------------------------------
|
||||||
|
|
||||||
@ -174,7 +173,7 @@ class chat_server
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
chat_server(asio::io_context& io_context,
|
chat_server(asio::io_context& io_context,
|
||||||
const tcp::endpoint& endpoint)
|
const asio::ip::tcp::endpoint& endpoint)
|
||||||
: acceptor_(io_context, endpoint)
|
: acceptor_(io_context, endpoint)
|
||||||
{
|
{
|
||||||
do_accept();
|
do_accept();
|
||||||
@ -183,8 +182,9 @@ public:
|
|||||||
private:
|
private:
|
||||||
void do_accept()
|
void do_accept()
|
||||||
{
|
{
|
||||||
|
std::lock_guard<std::mutex> guard(server_ready);
|
||||||
acceptor_.async_accept(
|
acceptor_.async_accept(
|
||||||
[this](std::error_code ec, tcp::socket socket)
|
[this](std::error_code ec, asio::ip::tcp::socket socket)
|
||||||
{
|
{
|
||||||
if (!ec)
|
if (!ec)
|
||||||
{
|
{
|
||||||
@ -195,37 +195,8 @@ private:
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
tcp::acceptor acceptor_;
|
asio::ip::tcp::acceptor acceptor_;
|
||||||
chat_room room_;
|
chat_room room_;
|
||||||
};
|
};
|
||||||
|
|
||||||
//----------------------------------------------------------------------
|
#endif // CHAT_SERVER_HPP
|
||||||
|
|
||||||
extern "C" void app_main(void)
|
|
||||||
{
|
|
||||||
ESP_ERROR_CHECK(nvs_flash_init());
|
|
||||||
esp_netif_init();
|
|
||||||
ESP_ERROR_CHECK(esp_event_loop_create_default());
|
|
||||||
|
|
||||||
/* This helper function configures Wi-Fi or Ethernet, as selected in menuconfig.
|
|
||||||
* Read "Establishing Wi-Fi or Ethernet Connection" section in
|
|
||||||
* examples/protocols/README.md for more information about this function.
|
|
||||||
*/
|
|
||||||
ESP_ERROR_CHECK(example_connect());
|
|
||||||
|
|
||||||
/* This helper function configures blocking UART I/O */
|
|
||||||
ESP_ERROR_CHECK(example_configure_stdin_stdout());
|
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::cout << "ASIO engine is up and running" << std::endl;
|
|
||||||
|
|
||||||
io_context.run();
|
|
||||||
}
|
|
6
examples/protocols/asio/asio_chat/sdkconfig.ci
Normal file
6
examples/protocols/asio/asio_chat/sdkconfig.ci
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
CONFIG_EXAMPLE_CONNECT_WIFI=n
|
||||||
|
CONFIG_EXAMPLE_CONNECT_ETHERNET=n
|
||||||
|
CONFIG_EXAMPLE_CHAT_CLIENT=y
|
||||||
|
CONFIG_EXAMPLE_CHAT_SERVER=y
|
||||||
|
CONFIG_LOG_DEFAULT_LEVEL_DEBUG=y
|
||||||
|
CONFIG_EXAMPLE_CHAT_CLIENT_CONNECT_ADDRESS="localhost"
|
2
examples/protocols/asio/asio_chat/sdkconfig.defaults
Normal file
2
examples/protocols/asio/asio_chat/sdkconfig.defaults
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
CONFIG_ESP_MAIN_TASK_STACK_SIZE=8192
|
||||||
|
CONFIG_COMPILER_CXX_EXCEPTIONS=y
|
@ -1,9 +0,0 @@
|
|||||||
#
|
|
||||||
# This is a project Makefile. It is assumed the directory this Makefile resides in is a
|
|
||||||
# project subdirectory.
|
|
||||||
#
|
|
||||||
PROJECT_NAME := asio_chat_client
|
|
||||||
|
|
||||||
EXTRA_COMPONENT_DIRS = $(IDF_PATH)/examples/common_components/protocol_examples_common
|
|
||||||
|
|
||||||
include $(IDF_PATH)/make/project.mk
|
|
@ -1,20 +0,0 @@
|
|||||||
# Asio chat client example
|
|
||||||
|
|
||||||
Simple Asio chat client using WiFi STA or Ethernet.
|
|
||||||
|
|
||||||
## Example workflow
|
|
||||||
|
|
||||||
- Wi-Fi or Ethernet connection is established, and IP address is obtained.
|
|
||||||
- Asio chat client connects to the corresponding server whose port number and IP are defined through the project configuration menu.
|
|
||||||
- Chat client receives all messages from other chat clients, also it sends message received from stdin using `idf.py -p PORT monitor`.
|
|
||||||
|
|
||||||
## Running the example
|
|
||||||
|
|
||||||
- Open the project configuration menu (`idf.py menuconfig`) to configure Wi-Fi or Ethernet. See "Establishing Wi-Fi or Ethernet Connection" section in [examples/protocols/README.md](../../README.md) for more details.
|
|
||||||
- Set server IP address and port number in menuconfig, "Example configuration".
|
|
||||||
- Start chat server either on host machine or as another ESP device running chat_server example.
|
|
||||||
- Run `idf.py -p PORT flash monitor` to build and upload the example to your board and connect to it's serial terminal.
|
|
||||||
- Wait for the board to connect to WiFi or Ethernet.
|
|
||||||
- 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.
|
|
@ -1,94 +0,0 @@
|
|||||||
import os
|
|
||||||
import re
|
|
||||||
import socket
|
|
||||||
import time
|
|
||||||
from threading import Thread
|
|
||||||
|
|
||||||
import ttfw_idf
|
|
||||||
|
|
||||||
global g_client_response
|
|
||||||
global g_msg_to_client
|
|
||||||
|
|
||||||
g_client_response = b''
|
|
||||||
g_msg_to_client = b' 3XYZ'
|
|
||||||
|
|
||||||
|
|
||||||
def get_my_ip():
|
|
||||||
s1 = socket.socket(socket.AF_INET, socket.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.socket(socket.AF_INET, socket.SOCK_STREAM)
|
|
||||||
s.settimeout(600)
|
|
||||||
s.bind((my_ip, port))
|
|
||||||
s.listen(1)
|
|
||||||
q,addr = s.accept()
|
|
||||||
print('connection accepted')
|
|
||||||
q.settimeout(30)
|
|
||||||
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')
|
|
||||||
|
|
||||||
|
|
||||||
@ttfw_idf.idf_example_test(env_tag='Example_WIFI_Protocols')
|
|
||||||
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', dut_class=ttfw_idf.ESP32DUT)
|
|
||||||
# check and log bin size
|
|
||||||
binary_file = os.path.join(dut1.app.binary_path, 'asio_chat_client.bin')
|
|
||||||
bin_size = os.path.getsize(binary_file)
|
|
||||||
ttfw_idf.log_performance('asio_chat_client_size', '{}KB'.format(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()
|
|
||||||
dut1.expect(re.compile(r' IPv4 address: ([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)'), timeout=30)
|
|
||||||
# 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:].decode()) # 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 len(g_client_response) == 0:
|
|
||||||
time.sleep(1)
|
|
||||||
g_client_response = g_client_response.decode()
|
|
||||||
print(g_client_response)
|
|
||||||
# 6. evaluate host_server received this message
|
|
||||||
if (g_client_response[4:7] == 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[4:7], test_msg))
|
|
||||||
thread1.join()
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
|
||||||
test_examples_protocol_asio_chat_client()
|
|
@ -1,2 +0,0 @@
|
|||||||
idf_component_register(SRCS "chat_client.cpp"
|
|
||||||
INCLUDE_DIRS ".")
|
|
@ -1,16 +0,0 @@
|
|||||||
menu "Example Configuration"
|
|
||||||
|
|
||||||
config EXAMPLE_PORT
|
|
||||||
string "Asio example server port number"
|
|
||||||
default "2222"
|
|
||||||
help
|
|
||||||
Port number used by Asio example.
|
|
||||||
|
|
||||||
config EXAMPLE_SERVER_IP
|
|
||||||
string "Asio example server ip"
|
|
||||||
default "FROM_STDIN"
|
|
||||||
help
|
|
||||||
Asio example server ip for this client to connect to.
|
|
||||||
Leave default "FROM_STDIN" to enter the server address via serial terminal.
|
|
||||||
|
|
||||||
endmenu
|
|
@ -1,183 +0,0 @@
|
|||||||
//
|
|
||||||
// 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"
|
|
||||||
#include "protocol_examples_common.h"
|
|
||||||
#include "esp_event.h"
|
|
||||||
#include "nvs_flash.h"
|
|
||||||
|
|
||||||
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);
|
|
||||||
|
|
||||||
|
|
||||||
extern "C" void app_main(void)
|
|
||||||
{
|
|
||||||
ESP_ERROR_CHECK(nvs_flash_init());
|
|
||||||
esp_netif_init();
|
|
||||||
ESP_ERROR_CHECK(esp_event_loop_create_default());
|
|
||||||
|
|
||||||
/* This helper function configures Wi-Fi or Ethernet, as selected in menuconfig.
|
|
||||||
* Read "Establishing Wi-Fi or Ethernet Connection" section in
|
|
||||||
* examples/protocols/README.md for more information about this function.
|
|
||||||
*/
|
|
||||||
ESP_ERROR_CHECK(example_connect());
|
|
||||||
|
|
||||||
/* This helper function configures blocking UART I/O */
|
|
||||||
ESP_ERROR_CHECK(example_configure_stdin_stdout());
|
|
||||||
|
|
||||||
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") {
|
|
||||||
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();
|
|
||||||
|
|
||||||
ESP_ERROR_CHECK(example_disconnect());
|
|
||||||
}
|
|
@ -1,7 +0,0 @@
|
|||||||
CONFIG_ESP_MAIN_TASK_STACK_SIZE=8192
|
|
||||||
|
|
||||||
#
|
|
||||||
# Partition Table
|
|
||||||
#
|
|
||||||
# Leave some room for larger apps without needing to reduce other features
|
|
||||||
CONFIG_PARTITION_TABLE_SINGLE_APP_LARGE=y
|
|
@ -1,10 +0,0 @@
|
|||||||
# The following lines of boilerplate have to be in your project's CMakeLists
|
|
||||||
# in this exact order for cmake to work correctly
|
|
||||||
cmake_minimum_required(VERSION 3.5)
|
|
||||||
|
|
||||||
# (Not part of the boilerplate)
|
|
||||||
# This example uses an extra component for common functions such as Wi-Fi and Ethernet connection.
|
|
||||||
set(EXTRA_COMPONENT_DIRS $ENV{IDF_PATH}/examples/common_components/protocol_examples_common)
|
|
||||||
|
|
||||||
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
|
||||||
project(asio_chat_server)
|
|
@ -1,23 +0,0 @@
|
|||||||
# Asio chat server example
|
|
||||||
|
|
||||||
Simple Asio chat server using WiFi STA or Ethernet.
|
|
||||||
|
|
||||||
## Example workflow
|
|
||||||
|
|
||||||
- Wi-Fi or Ethernet connection is established, and IP address is obtained.
|
|
||||||
- Asio chat server is started on port number defined through the project configuration.
|
|
||||||
- Chat server echoes a message (received from any client) to all connected clients.
|
|
||||||
|
|
||||||
## Running the example
|
|
||||||
|
|
||||||
- Open project configuration menu (`idf.py menuconfig`) to configure Wi-Fi or Ethernet. See "Establishing Wi-Fi or Ethernet Connection" section in [examples/protocols/README.md](../../README.md) for more details.
|
|
||||||
- Set server port number in menuconfig, "Example configuration".
|
|
||||||
- Run `idf.py -p PORT flash monitor` to build and upload the example to your board and connect to it's serial terminal.
|
|
||||||
- Wait for the board to connect to WiFi or Ethernet (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.
|
|
@ -1,44 +0,0 @@
|
|||||||
import os
|
|
||||||
import re
|
|
||||||
import socket
|
|
||||||
|
|
||||||
import ttfw_idf
|
|
||||||
|
|
||||||
|
|
||||||
@ttfw_idf.idf_example_test(env_tag='Example_WIFI_Protocols')
|
|
||||||
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 = b' 4ABC\n'
|
|
||||||
dut1 = env.get_dut('chat_server', 'examples/protocols/asio/chat_server', dut_class=ttfw_idf.ESP32DUT)
|
|
||||||
# check and log bin size
|
|
||||||
binary_file = os.path.join(dut1.app.binary_path, 'asio_chat_server.bin')
|
|
||||||
bin_size = os.path.getsize(binary_file)
|
|
||||||
ttfw_idf.log_performance('asio_chat_server_bin_size', '{}KB'.format(bin_size // 1024))
|
|
||||||
# 1. start test
|
|
||||||
dut1.start_app()
|
|
||||||
# 2. get the server IP address
|
|
||||||
data = dut1.expect(re.compile(r' IPv4 address: ([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)'), timeout=30)
|
|
||||||
# 3. create tcp client and connect to server
|
|
||||||
dut1.expect('ASIO engine is up and running', timeout=1)
|
|
||||||
cli = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
|
||||||
cli.settimeout(30)
|
|
||||||
cli.connect((data[0], 2222))
|
|
||||||
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()
|
|
@ -1,2 +0,0 @@
|
|||||||
idf_component_register(SRCS "chat_server.cpp"
|
|
||||||
INCLUDE_DIRS ".")
|
|
@ -1,9 +0,0 @@
|
|||||||
menu "Example Configuration"
|
|
||||||
|
|
||||||
config EXAMPLE_PORT
|
|
||||||
string "Asio example server port number"
|
|
||||||
default "2222"
|
|
||||||
help
|
|
||||||
Port number used by Asio example
|
|
||||||
|
|
||||||
endmenu
|
|
@ -1,91 +0,0 @@
|
|||||||
//
|
|
||||||
// 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
|
|
@ -1,8 +0,0 @@
|
|||||||
#
|
|
||||||
# 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.
|
|
||||||
#
|
|
@ -1,7 +0,0 @@
|
|||||||
CONFIG_ESP_MAIN_TASK_STACK_SIZE=8192
|
|
||||||
|
|
||||||
#
|
|
||||||
# Partition Table
|
|
||||||
#
|
|
||||||
# Leave some room for larger apps without needing to reduce other features
|
|
||||||
CONFIG_PARTITION_TABLE_SINGLE_APP_LARGE=y
|
|
Reference in New Issue
Block a user