mirror of
https://gitee.com/beecue/fastbee.git
synced 2025-12-20 01:45:55 +08:00
添加智能灯固件代码
This commit is contained in:
@@ -0,0 +1,10 @@
|
||||
# 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)
|
||||
@@ -0,0 +1,9 @@
|
||||
#
|
||||
# This is a project Makefile. It is assumed the directory this Makefile resides in is a
|
||||
# project subdirectory.
|
||||
#
|
||||
PROJECT_NAME := asio_chat_server
|
||||
|
||||
EXTRA_COMPONENT_DIRS = $(IDF_PATH)/examples/common_components/protocol_examples_common
|
||||
|
||||
include $(IDF_PATH)/make/project.mk
|
||||
@@ -0,0 +1,23 @@
|
||||
# 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.
|
||||
@@ -0,0 +1,44 @@
|
||||
import re
|
||||
import os
|
||||
import socket
|
||||
|
||||
import ttfw_idf
|
||||
|
||||
|
||||
@ttfw_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 = 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))
|
||||
ttfw_idf.check_performance("asio_chat_server_size", bin_size // 1024, dut1.TARGET)
|
||||
# 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
|
||||
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()
|
||||
@@ -0,0 +1,2 @@
|
||||
idf_component_register(SRCS "chat_server.cpp"
|
||||
INCLUDE_DIRS ".")
|
||||
@@ -0,0 +1,9 @@
|
||||
menu "Example Configuration"
|
||||
|
||||
config EXAMPLE_PORT
|
||||
string "Asio example server port number"
|
||||
default "2222"
|
||||
help
|
||||
Port number used by Asio example
|
||||
|
||||
endmenu
|
||||
@@ -0,0 +1,91 @@
|
||||
//
|
||||
// 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
|
||||
@@ -0,0 +1,229 @@
|
||||
//
|
||||
// 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"
|
||||
#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_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_;
|
||||
};
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
io_context.run();
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
@@ -0,0 +1 @@
|
||||
CONFIG_ESP_MAIN_TASK_STACK_SIZE=8192
|
||||
Reference in New Issue
Block a user