examples: generic cmake support examples

This commit is contained in:
Renz Christian Bagaporo 2018-11-11 15:36:24 +08:00
parent 0908fba1a3
commit 90f5432f2a
17 changed files with 303 additions and 3 deletions

5
.gitmodules vendored
View File

@ -61,6 +61,11 @@
[submodule "components/protobuf-c/protobuf-c"]
path = components/protobuf-c/protobuf-c
url = https://github.com/protobuf-c/protobuf-c
[submodule "components/unity/unity"]
path = components/unity/unity
url = https://github.com/ThrowTheSwitch/Unity
[submodule "examples/build_system/cmake/import_lib/main/lib/tinyxml2"]
path = examples/build_system/cmake/import_lib/main/lib/tinyxml2
url = https://github.com/leethomason/tinyxml2

View File

@ -15,6 +15,7 @@ The examples are grouped into subdirectories by category. Each category director
* `storage` contains examples showing data storage methods using SPI flash or external storage like the SD/MMC interface.
* `system` contains examples which demonstrate some internal chip features, or debugging & development tools.
* `wifi` contains examples of advanced Wi-Fi features. (For network protocol examples, see `protocols` instead.)
* `build_system` contains examples of build system features
# Using Examples

View File

@ -0,0 +1,24 @@
cmake_minimum_required(VERSION 3.5)
project(idf_as_lib C)
# The source file main.c contains app_main() definition
add_executable(${CMAKE_PROJECT_NAME}.elf main.c)
# Provides idf_import_components() and idf_link_components()
include($ENV{IDF_PATH}/tools/cmake/idf_functions.cmake)
# Create artifacts used for flashing the project to target chip
set(IDF_BUILD_ARTIFACTS ON)
set(IDF_PROJECT_EXECUTABLE ${CMAKE_PROJECT_NAME}.elf)
set(IDF_BUILD_ARTIFACTS_DIR ${CMAKE_BINARY_DIR})
# Trim down components included in the build. Although freertos and spi_flash are the ones needed by the application
# itself, the bootloader and esptool_py components are also needed in order to create the artifacts to be used
# for flashing to the target chip
set(IDF_COMPONENTS freertos spi_flash bootloader esptool_py)
# Wraps add_subdirectory() to create library targets for components, and then return them using the specified variable
idf_import_components(components $ENV{IDF_PATH} esp-idf)
# Wraps target_link_libraries() to link processed components by idf_import_components to target
idf_link_components(${CMAKE_PROJECT_NAME}.elf "${components}")

View File

@ -0,0 +1,69 @@
# Using ESP-IDF in Custom CMake Projects
This example illustrates using ESP-IDF components as libraries in custom CMake projects. This builds
an equivalent application to the `hello_world` example under `examples/get-started/hello_world`.
## Example Flow
Users looking at this example should focus on the [top-level CMakeLists.txt file](./CMakeLists.txt). This builds an
application that can run on targets without relying on the typical ESP-IDF application template. The application itself
follows a similar code flow to the aforementioned `hello_world` example.
### Output
```
Hello world!
This is ESP32 chip with 2 CPU cores, WiFi/BT/BLE, silicon revision 0, 4MB external flash
Restarting in 10 seconds...
Restarting in 9 seconds...
Restarting in 8 seconds...
Restarting in 7 seconds...
Restarting in 6 seconds...
Restarting in 5 seconds...
Restarting in 4 seconds...
Restarting in 3 seconds...
Restarting in 2 seconds...
Restarting in 1 seconds...
Restarting in 0 seconds...
```
## Building this Example
To build this example, run the following commands from this directory:
```bash
# Create a build directory, and change location to that directory.
mkdir build; cd build
# Invoke CMake, specifying the top-level CMakeLists.txt directory and toolchain file to use. This will generate
# the build system files.
cmake .. -DCMAKE_TOOLCHAIN_FILE=$IDF_PATH/tools/cmake/toolchain-esp32.cmake -DIDF_TARGET=esp32
# Build using the generated build system files.
cmake --build .
```
Or, execute `build.sh` script, which contains the same commands mentioned above.
## Flashing and Running this Example
To flash this example, we will have to invoke `esptool.py` and `idf_monitor.py` manually. While still in the build directory:
### Flashing to target
```bash
# Write project binaries to flash.
esptool.py --port /dev/ttyUSB0 write_flash @flash_project_args
```
### Running on target
```bash
# Monitor the output of the flashed firmware.
idf_monitor.py --port /dev/ttyUSB0 idf_as_lib.elf
```
Of course, you should replace the specified ports in the commands specified above to the proper one where your device
is connected.
---
There is a discussion on using ESP-IDF in custom CMake projects in the programming guide under `API Guides` -> `Build System (CMake)` -> `Using ESP-IDF in Custom CMake Projects`

View File

@ -0,0 +1,8 @@
#!/bin/bash
#
# Build this example, which does not use that standard IDF app template. See README.md for
# more information about the build and how to run this example on the target once built.
mkdir build; cd build
cmake .. -DCMAKE_TOOLCHAIN_FILE=$IDF_PATH/tools/cmake/toolchain-esp32.cmake -DIDF_TARGET=esp32
cmake --build .

View File

@ -0,0 +1,39 @@
/* Hello World 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 <stdio.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_system.h"
#include "esp_spi_flash.h"
void app_main()
{
printf("Hello world!\n");
/* Print chip information */
esp_chip_info_t chip_info;
esp_chip_info(&chip_info);
printf("This is ESP32 chip with %d CPU cores, WiFi%s%s, ",
chip_info.cores,
(chip_info.features & CHIP_FEATURE_BT) ? "/BT" : "",
(chip_info.features & CHIP_FEATURE_BLE) ? "/BLE" : "");
printf("silicon revision %d, ", chip_info.revision);
printf("%dMB %s flash\n", spi_flash_get_chip_size() / (1024 * 1024),
(chip_info.features & CHIP_FEATURE_EMB_FLASH) ? "embedded" : "external");
for (int i = 10; i >= 0; i--) {
printf("Restarting in %d seconds...\n", i);
vTaskDelay(1000 / portTICK_PERIOD_MS);
}
printf("Restarting now.\n");
fflush(stdout);
esp_restart();
}

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

View File

@ -0,0 +1,36 @@
# Import Third-Party CMake Library Example
This example demonstrates how to import third-party CMake libraries.
## Example Flow
[tinyxml2](https://github.com/leethomason/tinyxml2) is a
a small C++ XML parser. It is imported, without modification, for use in the project's `main` component (see the `main` component's [CMakeLists.txt](main/CMakeLists.txt)). To demonstrate the library being used, a sample XML is embedded into the project.
This sample XML is then read and parsed later on using `tinyxml2`.
### Output
```
I (317) example: Setting up...
I (317) example: Copying sample XML to filesystem...
I (647) example: Reading XML file
I (657) example: Read XML data:
<?xml version="1.0" encoding="UTF-8"?>
<note>
<to>Tove</to>
<from>Jani</from>
<heading>Reminder</heading>
<body>Don't forget me this weekend!</body>
</note>
I (667) example: Parsed XML data:
To: Tove
From: Jani
Heading: Reminder
Body: Don't forget me this weekend!
I (677) example: Example end
```
---
There is a discussion on importing third-party CMake libraries in the programming guide under `API Guides` -> `Build System (CMake)` -> `Using Third-Party CMake Projects with Components`

View File

@ -0,0 +1,21 @@
set(COMPONENT_SRCS "main.cpp")
set(COMPONENT_ADD_INCLUDEDIRS ".")
set(COMPONENT_EMBED_TXTFILES "sample.xml")
register_component()
# Build static library, do not build test executables
option(BUILD_SHARED_LIBS OFF)
option(BUILD_TESTING OFF)
# Import tinyxml2 targets
add_subdirectory(lib/tinyxml2)
# Propagate compile settings to tinyxml2
target_include_directories(tinyxml2 PRIVATE ${IDF_INCLUDE_DIRECTORIES})
target_compile_options(tinyxml2 PRIVATE "${IDF_COMPILE_OPTIONS}")
target_compile_options(tinyxml2 PRIVATE "${IDF_CXX_COMPILE_OPTIONS}")
# Link tinyxml2 to main component
target_link_libraries(${COMPONENT_TARGET} tinyxml2)

@ -0,0 +1 @@
Subproject commit 7e8e249990ec491ec15990cf95b6d871a66cf64a

View File

@ -0,0 +1,72 @@
#include <stdio.h>
#include <string.h>
#include <sys/unistd.h>
#include <sys/stat.h>
#include <stdlib.h>
#include <string.h>
#include "esp_err.h"
#include "esp_log.h"
#include "esp_vfs_fat.h"
#include "lib/tinyxml2/tinyxml2.h"
using namespace tinyxml2;
static const char *TAG = "example";
// Handle of the wear levelling library instance
static wl_handle_t s_wl_handle = WL_INVALID_HANDLE;
// Mount path for the partition
const char *base_path = "/spiflash";
extern "C" void app_main(void)
{
// Do example setup
ESP_LOGI(TAG, "Setting up...");
esp_vfs_fat_mount_config_t mount_config;
mount_config.max_files = 4;
mount_config.format_if_mount_failed = true;
mount_config.allocation_unit_size = CONFIG_WL_SECTOR_SIZE;
esp_err_t err = esp_vfs_fat_spiflash_mount(base_path, "storage", &mount_config, &s_wl_handle);
if (err != ESP_OK) {
ESP_LOGE(TAG, "Failed to mount FATFS (%s)", esp_err_to_name(err));
return;
}
// The sample XML is embedded binary data. Create a file first containing the embedded
// so it can be accessed.
ESP_LOGI(TAG, "Copying sample XML to filesystem...");
extern const char data_start[] asm("_binary_sample_xml_start");
extern const char data_end[] asm("_binary_sample_xml_end");
FILE *f = fopen("/spiflash/sample.xml", "wb");
if (f == NULL) {
ESP_LOGE(TAG, "Failed to open file for writing");
return;
}
fwrite(data_start, sizeof(char), data_end - data_start + 1, f);
fclose(f);
// Now that the file is created, load it using tinyxml2 and parse
ESP_LOGI(TAG, "Reading XML file");
XMLDocument data;
data.LoadFile("/spiflash/sample.xml");
XMLPrinter printer;
data.Print(&printer);
ESP_LOGI(TAG, "Read XML data:\n%s", printer.CStr());
const char* to_data = data.FirstChildElement("note")->FirstChildElement("to")->GetText();
const char* from_data = data.FirstChildElement("note")->FirstChildElement("from")->GetText();
const char* heading_data = data.FirstChildElement("note")->FirstChildElement("heading")->GetText();
const char* body_data = data.FirstChildElement("note")->FirstChildElement("body")->GetText();
ESP_LOGI(TAG, "Parsed XML data:\n\nTo: %s\nFrom: %s\nHeading: %s\nBody: %s",
to_data, from_data, heading_data, body_data);
ESP_LOGI(TAG, "Example end");
}

View File

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<note>
<to>Tove</to>
<from>Jani</from>
<heading>Reminder</heading>
<body>Don't forget me this weekend!</body>
</note>

View File

@ -0,0 +1,6 @@
# Name, Type, SubType, Offset, Size, Flags
# Note: if you change the phy_init or app partition offset, make sure to change the offset in Kconfig.projbuild
nvs, data, nvs, 0x9000, 0x6000,
phy_init, data, phy, 0xf000, 0x1000,
factory, app, factory, 0x10000, 1M,
storage, data, fat, , 528K,
1 # Name, Type, SubType, Offset, Size, Flags
2 # Note: if you change the phy_init or app partition offset, make sure to change the offset in Kconfig.projbuild
3 nvs, data, nvs, 0x9000, 0x6000,
4 phy_init, data, phy, 0xf000, 0x1000,
5 factory, app, factory, 0x10000, 1M,
6 storage, data, fat, , 528K,

View File

@ -0,0 +1,5 @@
CONFIG_PARTITION_TABLE_CUSTOM=y
CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions_example.csv"
CONFIG_PARTITION_TABLE_CUSTOM_APP_BIN_OFFSET=0x10000
CONFIG_PARTITION_TABLE_FILENAME="partitions_example.csv"
CONFIG_APP_OFFSET=0x10000

View File

@ -3,4 +3,4 @@
cmake_minimum_required(VERSION 3.5)
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
project(hello-world)
project(hello-world)

View File

@ -2,6 +2,6 @@ set(COMPONENT_SRCS "native_ota_example.c")
set(COMPONENT_ADD_INCLUDEDIRS ".")
# Embed the server root certificate into the final binary
set(COMPONENT_EMBED_TXTFILES ${PROJECT_PATH}/server_certs/ca_cert.pem)
set(COMPONENT_EMBED_TXTFILES ${IDF_PROJECT_PATH}/server_certs/ca_cert.pem)
register_component()

View File

@ -3,6 +3,6 @@ set(COMPONENT_ADD_INCLUDEDIRS ".")
# Embed the server root certificate into the final binary
set(COMPONENT_EMBED_TXTFILES ${PROJECT_PATH}/server_certs/ca_cert.pem)
set(COMPONENT_EMBED_TXTFILES ${IDF_PROJECT_PATH}/server_certs/ca_cert.pem)
register_component()