添加智能灯固件代码

This commit is contained in:
kerwincui
2021-07-13 17:14:51 +08:00
parent 332f74dd17
commit ecc0b91b8b
2568 changed files with 229441 additions and 0 deletions

View File

@@ -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)

View File

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

View File

@@ -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
```

View File

@@ -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()

View File

@@ -0,0 +1,2 @@
idf_component_register(SRCS "exception_example_main.cpp"
INCLUDE_DIRS ".")

View File

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

View File

@@ -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;
}

View File

@@ -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

View File

@@ -0,0 +1,2 @@
idf_component_register(SRCS "esp_exception.cpp"
INCLUDE_DIRS "include")

View File

@@ -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
```

View File

@@ -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

View File

@@ -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_

View File

@@ -0,0 +1,3 @@
idf_component_register(SRC_DIRS "."
PRIV_INCLUDE_DIRS .
PRIV_REQUIRES unity test_utils experimental_cpp_component)

View File

@@ -0,0 +1,7 @@
#
#Component Makefile
#
COMPONENT_SRCDIRS := .
COMPONENT_ADD_LDFLAGS = -Wl,--whole-archive -l$(COMPONENT_NAME) -Wl,--no-whole-archive

View File

@@ -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

View File

@@ -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_

View File

@@ -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)

View File

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

View File

@@ -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.
```

View File

@@ -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()

View File

@@ -0,0 +1,2 @@
idf_component_register(SRCS "cpp_pthread.cpp"
INCLUDE_DIRS ".")

View File

@@ -0,0 +1,3 @@
#
# Main Makefile. This is basically the same as a component makefile.
#

View File

@@ -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);
}
}

View File

@@ -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)

View File

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

View File

@@ -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.
```

View File

@@ -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()

View File

@@ -0,0 +1,2 @@
idf_component_register(SRCS "rtti_example_main.cpp"
INCLUDE_DIRS ".")

View File

@@ -0,0 +1,3 @@
#
# Main Makefile. This is basically the same as a component makefile.
#

View File

@@ -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;
}

View File

@@ -0,0 +1 @@
CONFIG_COMPILER_CXX_RTTI=y