mirror of
https://gitee.com/beecue/fastbee.git
synced 2025-12-19 09:25:54 +08:00
添加智能灯固件代码
This commit is contained in:
@@ -0,0 +1,6 @@
|
||||
# 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)
|
||||
|
||||
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||
project(cpp_exceptions_example)
|
||||
@@ -0,0 +1,9 @@
|
||||
#
|
||||
# This is a project Makefile. It is assumed the directory this Makefile resides in is a
|
||||
# project subdirectory.
|
||||
#
|
||||
|
||||
PROJECT_NAME := cpp_exceptions_example
|
||||
|
||||
include $(IDF_PATH)/make/project.mk
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
# Example: C++ exception handling
|
||||
|
||||
(See the README.md file in the upper level 'examples' directory for more information about examples.)
|
||||
|
||||
This example demonstrates usage of C++ exceptions in ESP-IDF.
|
||||
|
||||
By default, C++ exceptions support is disabled in ESP-IDF. It can be enabled using `CONFIG_COMPILER_CXX_EXCEPTIONS` configuration option.
|
||||
|
||||
In this example, the `sdkconfig.defaults` file sets the `CONFIG_COMPILER_CXX_EXCEPTIONS` option. This enables both compile time support (`-fexceptions` compiler flag) and run-time support for C++ exception handling.
|
||||
|
||||
The example source code declares a class which can throw exception from the constructor if the argument provided is equal to `0`. This is used to demonstrate that exceptions can be thrown and caught using standard C++ facilities.
|
||||
|
||||
**Note: Due to the use of the C++ exceptions, this example is written in C++ instead of C.**
|
||||
|
||||
## How to use example
|
||||
|
||||
### Hardware Required
|
||||
|
||||
This example should be able to run on any commonly available ESP32 development board.
|
||||
|
||||
### Configure the project
|
||||
|
||||
```
|
||||
idf.py menuconfig
|
||||
```
|
||||
|
||||
### Build and Flash
|
||||
|
||||
```
|
||||
idf.py -p PORT flash monitor
|
||||
```
|
||||
|
||||
(Replace PORT with the name of the serial port.)
|
||||
|
||||
(To exit the serial monitor, type ``Ctrl-]``.)
|
||||
|
||||
See the Getting Started Guide for full steps to configure and use ESP-IDF to build projects.
|
||||
|
||||
## Example Output
|
||||
|
||||
```
|
||||
app_main starting
|
||||
In constructor, arg=42
|
||||
In constructor, arg=0
|
||||
In destructor, m_arg=42
|
||||
Exception caught: Exception in constructor
|
||||
app_main done
|
||||
```
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
from __future__ import print_function
|
||||
|
||||
import ttfw_idf
|
||||
|
||||
|
||||
@ttfw_idf.idf_example_test(env_tag='Example_GENERIC')
|
||||
def test_examples_system_cpp_exceptions(env, extra_data):
|
||||
dut = env.get_dut('cpp_exceptions_example', 'examples/cxx/exceptions', dut_class=ttfw_idf.ESP32DUT)
|
||||
# start test
|
||||
dut.start_app()
|
||||
lines = ['app_main starting',
|
||||
'In constructor, arg=42',
|
||||
'In constructor, arg=0',
|
||||
'In destructor, m_arg=42',
|
||||
'Exception caught: Exception in constructor',
|
||||
'app_main done'
|
||||
]
|
||||
for line in lines:
|
||||
dut.expect(line, timeout=2)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
test_examples_system_cpp_exceptions()
|
||||
@@ -0,0 +1,2 @@
|
||||
idf_component_register(SRCS "exception_example_main.cpp"
|
||||
INCLUDE_DIRS ".")
|
||||
@@ -0,0 +1,4 @@
|
||||
#
|
||||
# "main" pseudo-component makefile.
|
||||
#
|
||||
# (Uses default behaviour of compiling all source files in directory, adding 'include' to include path.)
|
||||
@@ -0,0 +1,56 @@
|
||||
/* C++ exception handling 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 <iostream>
|
||||
|
||||
using std::cout;
|
||||
using std::endl;
|
||||
using std::runtime_error;
|
||||
|
||||
/* A simple class which may throw an exception from constructor */
|
||||
class Throwing
|
||||
{
|
||||
public:
|
||||
Throwing(int arg)
|
||||
: m_arg(arg)
|
||||
{
|
||||
cout << "In constructor, arg=" << arg << endl;
|
||||
if (arg == 0) {
|
||||
throw runtime_error("Exception in constructor");
|
||||
}
|
||||
}
|
||||
|
||||
~Throwing()
|
||||
{
|
||||
cout << "In destructor, m_arg=" << m_arg << endl;
|
||||
}
|
||||
|
||||
protected:
|
||||
int m_arg;
|
||||
};
|
||||
|
||||
/* Inside .cpp file, app_main function must be declared with C linkage */
|
||||
extern "C" void app_main(void)
|
||||
{
|
||||
cout << "app_main starting" << endl;
|
||||
|
||||
try {
|
||||
/* This will succeed */
|
||||
Throwing obj1(42);
|
||||
|
||||
/* This will throw an exception */
|
||||
Throwing obj2(0);
|
||||
|
||||
cout << "This will not be printed" << endl;
|
||||
} catch (const runtime_error &e) {
|
||||
cout << "Exception caught: " << e.what() << endl;
|
||||
}
|
||||
|
||||
cout << "app_main done" << endl;
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
# Enable C++ exceptions and set emergency pool size for exception objects
|
||||
CONFIG_COMPILER_CXX_EXCEPTIONS=y
|
||||
CONFIG_COMPILER_CXX_EXCEPTIONS_EMG_POOL_SIZE=1024
|
||||
@@ -0,0 +1,2 @@
|
||||
idf_component_register(SRCS "esp_exception.cpp"
|
||||
INCLUDE_DIRS "include")
|
||||
@@ -0,0 +1,20 @@
|
||||
# Experimental C++ Component
|
||||
|
||||
*Warning:* This component is subject to change without notice. Don't consider it as a stable API.
|
||||
It proposes future C++ interfaces of IDF components.
|
||||
|
||||
# Usage/Build
|
||||
To use and build this component, add it as an extra component in your project's cmake file:
|
||||
```cmake
|
||||
set(EXTRA_COMPONENT_DIRS $ENV{IDF_PATH}/examples/cxx/experimental/experimental_cpp_component)
|
||||
```
|
||||
|
||||
# Tests
|
||||
To build the tests, first add them to the unit test's CMakeLists.txt:
|
||||
```cmake
|
||||
set(EXTRA_COMPONENT_DIRS "$ENV{IDF_PATH}/examples/cxx/experimental/experimental_cpp_component/")
|
||||
```
|
||||
Then go to the unit test app's directory and run:
|
||||
```bash
|
||||
idf.py -T experimental_cpp_component build
|
||||
```
|
||||
@@ -0,0 +1,11 @@
|
||||
#ifdef __cpp_exceptions
|
||||
|
||||
#include "esp_exception.hpp"
|
||||
|
||||
namespace idf {
|
||||
|
||||
ESPException::ESPException(esp_err_t error) : error(error) { }
|
||||
|
||||
} // namespace idf
|
||||
|
||||
#endif // __cpp_exceptions
|
||||
@@ -0,0 +1,44 @@
|
||||
// Copyright 2019 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_HPP_
|
||||
#define ESP_EXCEPTION_HPP_
|
||||
|
||||
#ifdef __cpp_exceptions
|
||||
|
||||
#include "esp_err.h"
|
||||
#include <exception>
|
||||
|
||||
namespace idf {
|
||||
|
||||
/**
|
||||
* General exception class for exceptions on the ESP chips.
|
||||
* All throwing code in IDF should use either this exception directly or a sub-classes.
|
||||
*/
|
||||
struct ESPException : public std::exception {
|
||||
ESPException(esp_err_t error);
|
||||
|
||||
esp_err_t error;
|
||||
};
|
||||
|
||||
/**
|
||||
* Convenience macro to help converting IDF error codes into ESPException.
|
||||
*/
|
||||
#define CHECK_THROW(error_) if (error_ != ESP_OK) throw idf::ESPException(error_);
|
||||
|
||||
} // namespace idf
|
||||
|
||||
#endif // __cpp_exceptions
|
||||
|
||||
#endif // ESP_EXCEPTION_HPP_
|
||||
@@ -0,0 +1,3 @@
|
||||
idf_component_register(SRC_DIRS "."
|
||||
PRIV_INCLUDE_DIRS .
|
||||
PRIV_REQUIRES unity test_utils experimental_cpp_component)
|
||||
@@ -0,0 +1,7 @@
|
||||
#
|
||||
#Component Makefile
|
||||
#
|
||||
|
||||
COMPONENT_SRCDIRS := .
|
||||
|
||||
COMPONENT_ADD_LDFLAGS = -Wl,--whole-archive -l$(COMPONENT_NAME) -Wl,--no-whole-archive
|
||||
@@ -0,0 +1,44 @@
|
||||
#include <stdio.h>
|
||||
#include "unity.h"
|
||||
|
||||
#include "unity_cxx.hpp"
|
||||
#include "esp_exception.hpp"
|
||||
|
||||
#ifdef __cpp_exceptions
|
||||
|
||||
using namespace std;
|
||||
using namespace idf;
|
||||
|
||||
#define TAG "CXX Exception Test"
|
||||
|
||||
TEST_CASE("TEST_THROW catches exception", "[cxx exception]")
|
||||
{
|
||||
TEST_THROW(throw ESPException(ESP_FAIL);, ESPException);
|
||||
}
|
||||
|
||||
/* The following two test cases are expected to fail */
|
||||
|
||||
TEST_CASE("TEST_THROW asserts catching different exception", "[cxx exception][ignore]")
|
||||
{
|
||||
TEST_THROW(throw std::exception();, ESPException);
|
||||
}
|
||||
|
||||
TEST_CASE("TEST_THROW asserts not catching any exception", "[cxx exception][ignore]")
|
||||
{
|
||||
TEST_THROW(printf(" ");, ESPException); // need statement with effect
|
||||
}
|
||||
|
||||
TEST_CASE("CHECK_THROW continues on ESP_OK", "[cxx exception]")
|
||||
{
|
||||
esp_err_t error = ESP_OK;
|
||||
CHECK_THROW(error);
|
||||
}
|
||||
|
||||
TEST_CASE("CHECK_THROW throws", "[cxx exception]")
|
||||
{
|
||||
esp_err_t error = ESP_FAIL;
|
||||
TEST_THROW(CHECK_THROW(error), ESPException);
|
||||
}
|
||||
|
||||
#endif // __cpp_exceptions
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
#ifndef UNITY_CXX_H_
|
||||
#define UNITY_CXX_H_
|
||||
|
||||
#include "unity.h"
|
||||
|
||||
#define STR(x) #x
|
||||
|
||||
/**
|
||||
* Very simple helper macro to catch exceptions.
|
||||
*
|
||||
* @note
|
||||
* * If there is any exception which not a child of std::exception, it will terminate the program!
|
||||
* * If there is no exception, it will jump from the current frame without de-initializing
|
||||
* destructors!
|
||||
*/
|
||||
#define TEST_THROW(expr_, exception_) \
|
||||
do { \
|
||||
bool caught = false; \
|
||||
bool caught_different = false; \
|
||||
try { \
|
||||
expr_; \
|
||||
} catch ( exception_ &e) { \
|
||||
caught = true; \
|
||||
} catch ( std::exception &e) { \
|
||||
caught_different = true; \
|
||||
} \
|
||||
TEST_ASSERT_FALSE_MESSAGE(caught_different, "ERROR: Expected " STR(exception_) \
|
||||
", but caught different exception."); \
|
||||
TEST_ASSERT_TRUE_MESSAGE(caught, "ERROR: Expected " STR(exception_) \
|
||||
", but no exception thrown."); \
|
||||
} \
|
||||
while (0)
|
||||
|
||||
|
||||
#endif // UNITY_CXX_H_
|
||||
@@ -0,0 +1,6 @@
|
||||
# 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)
|
||||
|
||||
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||
project(cpp_pthread)
|
||||
@@ -0,0 +1,9 @@
|
||||
#
|
||||
# This is a project Makefile. It is assumed the directory this Makefile resides in is a
|
||||
# project subdirectory.
|
||||
#
|
||||
|
||||
PROJECT_NAME := cpp_pthread
|
||||
|
||||
include $(IDF_PATH)/make/project.mk
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
# C++ pthread Example
|
||||
|
||||
(See the README.md file in the upper level 'examples' directory for more information about examples.)
|
||||
|
||||
Support for the [C++ threads](http://www.cplusplus.com/reference/thread/thread/) in ESP-IDF is implemented on top of the [ESP-pthread](https://docs.espressif.com/projects/esp-idf/en/latest/api-reference/system/esp_pthread.html#overview) component. Thus, C++ threads created using the standard thread class constructor will automatically inherit the current ESP-pthread configuration. This example demonstrates how to leverage the thread configuration functions provided by ESP-pthread (e.g., `esp_pthread_get_default_config()` and `esp_pthread_set_cfg()`) to modify the stack sizes, priorities, names, and core affinities of the C++ threads.
|
||||
|
||||
**Note: Due to the use of the C++ threads, this example is written in C++ instead of C.**
|
||||
|
||||
## How to use example
|
||||
|
||||
### Hardware Required
|
||||
|
||||
This example should be able to run on any commonly available ESP32 development board.
|
||||
|
||||
### Configure the project
|
||||
|
||||
```
|
||||
idf.py menuconfig
|
||||
```
|
||||
|
||||
* The default ESP-pthread configuration may also be modified under `Component config > PThreads`
|
||||
|
||||
### Build and Flash
|
||||
|
||||
Build the project and flash it to the board, then run monitor tool to view serial output:
|
||||
|
||||
```
|
||||
idf.py -p PORT flash monitor
|
||||
```
|
||||
|
||||
(Replace PORT with the name of the serial port to use.)
|
||||
|
||||
(To exit the serial monitor, type ``Ctrl-]``.)
|
||||
|
||||
See the Getting Started Guide for full steps to configure and use ESP-IDF to build projects.
|
||||
|
||||
## Example Output
|
||||
|
||||
The following log output should appear when the example runs (note that the bootloader log has been omitted).
|
||||
|
||||
```
|
||||
...
|
||||
I (380) Thread 1: Core id: 0, prio: 5, minimum free stack: 2068 bytes.
|
||||
I (0) pthread: This thread (with the default name) may run on any core.Core id: 1, prio: 5, minimum free stack: 2056 bytes.
|
||||
I (390) Thread 1: This is the INHERITING thread with the same parameters as our parent, including name. Core id: 0, prio: 5, minimum free stack: 2092 bytes.
|
||||
I (410) Thread 2: Core id: 1, prio: 5, minimum free stack: 2088 bytes.
|
||||
I (410) main: core id: 0, prio: 1, minimum free stack: 2928 bytes.
|
||||
```
|
||||
@@ -0,0 +1,21 @@
|
||||
from __future__ import unicode_literals
|
||||
import re
|
||||
import ttfw_idf
|
||||
|
||||
|
||||
@ttfw_idf.idf_example_test(env_tag='Example_GENERIC')
|
||||
def test_examples_cpp_pthread(env, extra_data):
|
||||
|
||||
dut = env.get_dut('cpp_pthread', 'examples/cxx/pthread')
|
||||
dut.start_app()
|
||||
|
||||
dut.expect_all(re.compile(r'pthread: This thread \(with the default name\) may run on any core.'
|
||||
r'Core id: [01], prio: 5, minimum free stack: \d+ bytes.'),
|
||||
re.compile(r'Thread [12]: Core id: [01], prio: 5, minimum free stack: \d+ bytes.'),
|
||||
re.compile(r'Thread [12]: This is the INHERITING thread with the same parameters as our parent, '
|
||||
r'including name. Core id: [01], prio: 5, minimum free stack: \d+ bytes.'),
|
||||
re.compile(r'Thread [12]: Core id: [01], prio: 5, minimum free stack: \d+ bytes'))
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
test_examples_cpp_pthread()
|
||||
@@ -0,0 +1,2 @@
|
||||
idf_component_register(SRCS "cpp_pthread.cpp"
|
||||
INCLUDE_DIRS ".")
|
||||
@@ -0,0 +1,3 @@
|
||||
#
|
||||
# Main Makefile. This is basically the same as a component makefile.
|
||||
#
|
||||
@@ -0,0 +1,112 @@
|
||||
/* pthread/std::thread 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 <iostream>
|
||||
#include <thread>
|
||||
#include <chrono>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
#include <esp_pthread.h>
|
||||
#include <freertos/FreeRTOS.h>
|
||||
#include <freertos/task.h>
|
||||
#include <esp_log.h>
|
||||
|
||||
using namespace std::chrono;
|
||||
|
||||
const auto sleep_time = seconds
|
||||
{
|
||||
5
|
||||
};
|
||||
|
||||
void print_thread_info(const char *extra = nullptr)
|
||||
{
|
||||
std::stringstream ss;
|
||||
if (extra) {
|
||||
ss << extra;
|
||||
}
|
||||
ss << "Core id: " << xPortGetCoreID()
|
||||
<< ", prio: " << uxTaskPriorityGet(nullptr)
|
||||
<< ", minimum free stack: " << uxTaskGetStackHighWaterMark(nullptr) << " bytes.";
|
||||
ESP_LOGI(pcTaskGetTaskName(nullptr), "%s", ss.str().c_str());
|
||||
}
|
||||
|
||||
void thread_func_inherited()
|
||||
{
|
||||
while (true) {
|
||||
print_thread_info("This is the INHERITING thread with the same parameters as our parent, including name. ");
|
||||
std::this_thread::sleep_for(sleep_time);
|
||||
}
|
||||
}
|
||||
|
||||
void spawn_another_thread()
|
||||
{
|
||||
// Create a new thread, it will inherit our configuration
|
||||
std::thread inherits(thread_func_inherited);
|
||||
|
||||
while (true) {
|
||||
print_thread_info();
|
||||
std::this_thread::sleep_for(sleep_time);
|
||||
}
|
||||
}
|
||||
|
||||
void thread_func_any_core()
|
||||
{
|
||||
while (true) {
|
||||
print_thread_info("This thread (with the default name) may run on any core.");
|
||||
std::this_thread::sleep_for(sleep_time);
|
||||
}
|
||||
}
|
||||
|
||||
void thread_func()
|
||||
{
|
||||
while (true) {
|
||||
print_thread_info();
|
||||
std::this_thread::sleep_for(sleep_time);
|
||||
}
|
||||
}
|
||||
|
||||
esp_pthread_cfg_t create_config(const char *name, int core_id, int stack, int prio)
|
||||
{
|
||||
auto cfg = esp_pthread_get_default_config();
|
||||
cfg.thread_name = name;
|
||||
cfg.pin_to_core = core_id;
|
||||
cfg.stack_size = stack;
|
||||
cfg.prio = prio;
|
||||
return cfg;
|
||||
}
|
||||
|
||||
extern "C" void app_main(void)
|
||||
{
|
||||
// Create a thread using deafult values that can run on any core
|
||||
auto cfg = esp_pthread_get_default_config();
|
||||
esp_pthread_set_cfg(&cfg);
|
||||
std::thread any_core(thread_func_any_core);
|
||||
|
||||
// Create a thread on core 0 that spawns another thread, they will both have the same name etc.
|
||||
cfg = create_config("Thread 1", 0, 3 * 1024, 5);
|
||||
cfg.inherit_cfg = true;
|
||||
esp_pthread_set_cfg(&cfg);
|
||||
std::thread thread_1(spawn_another_thread);
|
||||
|
||||
// Create a thread on core 1.
|
||||
cfg = create_config("Thread 2", 1, 3 * 1024, 5);
|
||||
esp_pthread_set_cfg(&cfg);
|
||||
std::thread thread_2(thread_func);
|
||||
|
||||
// Let the main task do something too
|
||||
while (true) {
|
||||
std::stringstream ss;
|
||||
ss << "core id: " << xPortGetCoreID()
|
||||
<< ", prio: " << uxTaskPriorityGet(nullptr)
|
||||
<< ", minimum free stack: " << uxTaskGetStackHighWaterMark(nullptr) << " bytes.";
|
||||
ESP_LOGI(pcTaskGetTaskName(nullptr), "%s", ss.str().c_str());
|
||||
std::this_thread::sleep_for(sleep_time);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
# 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)
|
||||
|
||||
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||
project(cpp_rtti)
|
||||
@@ -0,0 +1,9 @@
|
||||
#
|
||||
# This is a project Makefile. It is assumed the directory this Makefile resides in is a
|
||||
# project subdirectory.
|
||||
#
|
||||
|
||||
PROJECT_NAME := cpp_rtti
|
||||
|
||||
include $(IDF_PATH)/make/project.mk
|
||||
|
||||
@@ -0,0 +1,69 @@
|
||||
# Example: C++ run-time type info (RTTI)
|
||||
|
||||
(See the README.md file in the upper level 'examples' directory for more information about examples.)
|
||||
|
||||
This example demonstrates usage of the RTTI feature in ESP-IDF.
|
||||
|
||||
By default, RTTI support is disabled in ESP-IDF. It can be enabled using `CONFIG_COMPILER_CXX_RTTI` configuration option.
|
||||
|
||||
In this example, `sdkconfig.defaults` file sets `CONFIG_COMPILER_CXX_RTTI` option. This enables compile time support for RTTI (`-frtti` compiler flag).
|
||||
|
||||
The example prints demangled type names of a few objects and functions, obtained from `typeinfo().name`. The example also generates several objects of two classes, derived from a common base class. For each object, it is demonstrated that `dynamic_cast` behaves as expected, returning non-NULL when casting to the real object type, and NULL when casting to a different type.
|
||||
|
||||
## How to use example
|
||||
|
||||
### Configure the project
|
||||
|
||||
To run this example, no additional configuration is necessary.
|
||||
|
||||
### Build and Flash
|
||||
|
||||
Build the project and flash it to the board, then run monitor tool to view serial output:
|
||||
|
||||
```
|
||||
idf.py -p PORT flash monitor
|
||||
```
|
||||
|
||||
(Replace PORT with the name of the serial port to use.)
|
||||
|
||||
(To exit the serial monitor, type ``Ctrl-]``.)
|
||||
|
||||
See the Getting Started Guide for full steps to configure and use ESP-IDF to build projects.
|
||||
|
||||
## Example Output
|
||||
|
||||
```
|
||||
Type names of a few objects:
|
||||
Type name of std::cout is: std::ostream
|
||||
Type name of std::cin is: std::istream
|
||||
Type of app_main is: void ()
|
||||
Type name of a lambda function is: app_main::{lambda(int, int)#1}
|
||||
|
||||
Generating 5 random objects and printing their types:
|
||||
obj->name() is: DerivedB
|
||||
typeid(*obj).name() is: DerivedB
|
||||
dynamic_cast<DerivedA*>(obj)=0
|
||||
dynamic_cast<DerivedB*>(obj)=0x3ffb7e88
|
||||
|
||||
obj->name() is: DerivedB
|
||||
typeid(*obj).name() is: DerivedB
|
||||
dynamic_cast<DerivedA*>(obj)=0
|
||||
dynamic_cast<DerivedB*>(obj)=0x3ffb7e9c
|
||||
|
||||
obj->name() is: DerivedA
|
||||
typeid(*obj).name() is: DerivedA
|
||||
dynamic_cast<DerivedA*>(obj)=0x3ffb7eb0
|
||||
dynamic_cast<DerivedB*>(obj)=0
|
||||
|
||||
obj->name() is: DerivedB
|
||||
typeid(*obj).name() is: DerivedB
|
||||
dynamic_cast<DerivedA*>(obj)=0
|
||||
dynamic_cast<DerivedB*>(obj)=0x3ffb7ec4
|
||||
|
||||
obj->name() is: DerivedA
|
||||
typeid(*obj).name() is: DerivedA
|
||||
dynamic_cast<DerivedA*>(obj)=0x3ffb7ed8
|
||||
dynamic_cast<DerivedB*>(obj)=0
|
||||
|
||||
Example finished.
|
||||
```
|
||||
@@ -0,0 +1,25 @@
|
||||
from __future__ import print_function
|
||||
|
||||
import ttfw_idf
|
||||
|
||||
|
||||
@ttfw_idf.idf_example_test(env_tag='Example_GENERIC')
|
||||
def test_cpp_rtti_example(env, extra_data):
|
||||
dut = env.get_dut('cpp_rtti', 'examples/cxx/rtti', dut_class=ttfw_idf.ESP32DUT)
|
||||
dut.start_app()
|
||||
|
||||
dut.expect('Type name of std::cout is: std::ostream')
|
||||
dut.expect('Type name of std::cin is: std::istream')
|
||||
dut.expect('Type of app_main is: void ()')
|
||||
dut.expect('Type name of a lambda function is: app_main::{lambda(int, int)#1}')
|
||||
|
||||
dut.expect('dynamic_cast<DerivedA*>(obj)=0')
|
||||
dut.expect('dynamic_cast<DerivedB*>(obj)=0x')
|
||||
dut.expect('dynamic_cast<DerivedB*>(obj)=0')
|
||||
dut.expect('dynamic_cast<DerivedA*>(obj)=0x')
|
||||
|
||||
dut.expect('Example finished.')
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
test_cpp_rtti_example()
|
||||
@@ -0,0 +1,2 @@
|
||||
idf_component_register(SRCS "rtti_example_main.cpp"
|
||||
INCLUDE_DIRS ".")
|
||||
@@ -0,0 +1,3 @@
|
||||
#
|
||||
# Main Makefile. This is basically the same as a component makefile.
|
||||
#
|
||||
@@ -0,0 +1,100 @@
|
||||
/* C++ run-time type info (RTTI) 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 <iostream>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
#include <cxxabi.h>
|
||||
|
||||
using std::cout;
|
||||
using std::endl;
|
||||
using std::string;
|
||||
using std::shared_ptr;
|
||||
using std::make_shared;
|
||||
|
||||
class Base;
|
||||
class DerivedA;
|
||||
class DerivedB;
|
||||
|
||||
static string demangle(const char* name);
|
||||
|
||||
class Base
|
||||
{
|
||||
public:
|
||||
virtual ~Base() {} ;
|
||||
virtual string name() = 0;
|
||||
static shared_ptr<Base> make_random_derived();
|
||||
};
|
||||
|
||||
class DerivedA : public Base
|
||||
{
|
||||
public:
|
||||
string name() override { return "DerivedA"; }
|
||||
};
|
||||
|
||||
class DerivedB : public Base
|
||||
{
|
||||
public:
|
||||
string name() override { return "DerivedB"; }
|
||||
};
|
||||
|
||||
/* Creates either DerivedA or DerivedB, depending on a random number */
|
||||
shared_ptr<Base> Base::make_random_derived()
|
||||
{
|
||||
if (std::rand() % 2 == 0) {
|
||||
return make_shared<DerivedA>();
|
||||
} else {
|
||||
return make_shared<DerivedB>();
|
||||
}
|
||||
}
|
||||
|
||||
/* Inside a .cpp file, app_main function must be declared with C linkage */
|
||||
extern "C" void app_main()
|
||||
{
|
||||
/* Demonstrate typeid().name() */
|
||||
cout << "Type names of a few objects:" << endl << '\t';
|
||||
cout << "Type name of std::cout is: " << demangle(typeid(std::cout).name()) << endl << '\t';
|
||||
cout << "Type name of std::cin is: " << demangle(typeid(std::cin).name()) << endl << '\t';
|
||||
cout << "Type of app_main is: " << demangle(typeid(app_main).name()) << endl << '\t';
|
||||
auto sum = [](int x, int y) -> int { return x + y; };
|
||||
cout << "Type name of a lambda function is: " << demangle(typeid(sum).name()) << endl << endl;
|
||||
|
||||
/* Demonstrate dynamic_cast */
|
||||
std::vector<shared_ptr<Base>> objects(5);
|
||||
cout << "Generating " << objects.size() << " random objects and printing their types:" << endl;
|
||||
std::generate(objects.begin(), objects.end(), Base::make_random_derived);
|
||||
for (auto &obj: objects) {
|
||||
cout << "obj->name() is: " << obj->name() << endl << '\t';
|
||||
cout << "typeid(*obj).name() is: " << demangle(typeid(*obj).name()) << endl << '\t';
|
||||
|
||||
const DerivedA* cast_to_derived_a = dynamic_cast<DerivedA*>(obj.get());
|
||||
const DerivedB* cast_to_derived_b = dynamic_cast<DerivedB*>(obj.get());
|
||||
|
||||
cout << "dynamic_cast<DerivedA*>(obj)=" << static_cast<const void*>(cast_to_derived_a) << endl << '\t';
|
||||
cout << "dynamic_cast<DerivedB*>(obj)=" << static_cast<const void*>(cast_to_derived_b) << endl << endl;
|
||||
}
|
||||
|
||||
cout << "Example finished." << endl;
|
||||
}
|
||||
|
||||
/* Helper function which converts typeid().name() to a human-readable type name */
|
||||
static std::string demangle(const char* name)
|
||||
{
|
||||
int status = 0;
|
||||
char* result = abi::__cxa_demangle(name, NULL, NULL, &status);
|
||||
string str_result;
|
||||
if (status == 0) {
|
||||
str_result = result;
|
||||
} else {
|
||||
str_result = name;
|
||||
}
|
||||
free(result);
|
||||
return str_result;
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
CONFIG_COMPILER_CXX_RTTI=y
|
||||
Reference in New Issue
Block a user