Support for ESP32 with ESP-IDF
PiperOrigin-RevId: 277408790 Change-Id: Ie1cc9ab7149db89b93508d21e7bfe7be40422433
This commit is contained in:
parent
1cc64d35f0
commit
e9a3aa158a
tensorflow/lite/experimental/micro
examples/hello_world
tools/make
@ -67,6 +67,65 @@ wave graphically. To view it, go to `Tools -> Serial Plotter`. You will see one
|
||||
datapoint being logged for each inference cycle, expressed as a number between 0
|
||||
and 255.
|
||||
|
||||
## Deploy to ESP32
|
||||
|
||||
The following instructions will help you build and deploy this sample
|
||||
to [ESP32](https://www.espressif.com/en/products/hardware/esp32/overview)
|
||||
devices using the [ESP IDF](https://github.com/espressif/esp-idf).
|
||||
|
||||
The sample has been tested on ESP-IDF version 4.0 with the following devices:
|
||||
- [ESP32-DevKitC](http://esp-idf.readthedocs.io/en/latest/get-started/get-started-devkitc.html)
|
||||
- [ESP-EYE](https://github.com/espressif/esp-who/blob/master/docs/en/get-started/ESP-EYE_Getting_Started_Guide.md)
|
||||
|
||||
### Install the ESP IDF
|
||||
|
||||
Follow the instructions of the
|
||||
[ESP-IDF get started guide](https://docs.espressif.com/projects/esp-idf/en/latest/get-started/index.html)
|
||||
to setup the toolchain and the ESP-IDF itself.
|
||||
|
||||
The next steps assume that the
|
||||
[IDF environment variables are set](https://docs.espressif.com/projects/esp-idf/en/latest/get-started/index.html#step-4-set-up-the-environment-variables) :
|
||||
|
||||
* The `IDF_PATH` environment variable is set
|
||||
* `idf.py` and Xtensa-esp32 tools (e.g. `xtensa-esp32-elf-gcc`) are in `$PATH`
|
||||
|
||||
### Generate the examples
|
||||
The example project can be generated with the following command:
|
||||
```
|
||||
make -f tensorflow/lite/experimental/micro/tools/make/Makefile TARGET=esp generate_hello_world_esp_project
|
||||
```
|
||||
|
||||
### Building the example
|
||||
|
||||
Go the the example project directory
|
||||
```
|
||||
cd tensorflow/lite/experimental/micro/tools/make/gen/esp_xtensa-esp32/prj/hello_world/esp-idf
|
||||
```
|
||||
|
||||
Then build with `idf.py`
|
||||
```
|
||||
idf.py build
|
||||
```
|
||||
|
||||
### Load and run the example
|
||||
|
||||
To flash (replace `/dev/ttyUSB0` with the device serial port):
|
||||
```
|
||||
idf.py --port /dev/ttyUSB0 flash
|
||||
```
|
||||
|
||||
Monitor the serial output:
|
||||
```
|
||||
idf.py --port /dev/ttyUSB0 monitor
|
||||
```
|
||||
|
||||
Use `Ctrl+]` to exit.
|
||||
|
||||
The previous two commands can be combined:
|
||||
```
|
||||
idf.py --port /dev/ttyUSB0 flash monitor
|
||||
```
|
||||
|
||||
## Deploy to SparkFun Edge
|
||||
|
||||
The following instructions will help you build and deploy this sample on the
|
||||
|
@ -0,0 +1,23 @@
|
||||
/* Copyright 2019 The TensorFlow Authors. All Rights Reserved.
|
||||
|
||||
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.
|
||||
==============================================================================*/
|
||||
|
||||
#include "tensorflow/lite/experimental/micro/examples/hello_world/main_functions.h"
|
||||
|
||||
extern "C" void app_main(void) {
|
||||
setup();
|
||||
while (true) {
|
||||
loop();
|
||||
}
|
||||
}
|
@ -184,6 +184,12 @@ KEIL_PROJECT_FILES := \
|
||||
ARDUINO_PROJECT_FILES := \
|
||||
library.properties
|
||||
|
||||
ESP_PROJECT_FILES := \
|
||||
README_ESP.md \
|
||||
CMakeLists.txt \
|
||||
main/CMakeLists.txt \
|
||||
components/tfmicro/CMakeLists.txt
|
||||
|
||||
ALL_PROJECT_TARGETS :=
|
||||
|
||||
ARDUINO_LIBRARY_TARGETS :=
|
||||
|
@ -112,33 +112,38 @@ define generate_arduino_project
|
||||
|
||||
$(PRJDIR)$(2)/arduino/examples/%.cpp: tensorflow/lite/experimental/micro/examples/%.cc
|
||||
@mkdir -p $$(dir $$@)
|
||||
@python tensorflow/lite/experimental/micro/tools/make/transform_arduino_source.py \
|
||||
@python tensorflow/lite/experimental/micro/tools/make/transform_source.py \
|
||||
--platform=arduino \
|
||||
--is_example_source \
|
||||
--source_path="$$<" \
|
||||
--third_party_headers="$(4)" < $$< > $$@
|
||||
|
||||
$(PRJDIR)$(2)/arduino/examples/%.h: tensorflow/lite/experimental/micro/examples/%.h
|
||||
@mkdir -p $$(dir $$@)
|
||||
@python tensorflow/lite/experimental/micro/tools/make/transform_arduino_source.py \
|
||||
@python tensorflow/lite/experimental/micro/tools/make/transform_source.py \
|
||||
--platform=arduino \
|
||||
--is_example_source \
|
||||
--source_path="$$<" \
|
||||
--third_party_headers="$(4)" < $$< > $$@
|
||||
|
||||
$(PRJDIR)$(2)/arduino/examples/%/main.ino: tensorflow/lite/experimental/micro/examples/%/main_functions.cc
|
||||
@mkdir -p $$(dir $$@)
|
||||
@python tensorflow/lite/experimental/micro/tools/make/transform_arduino_source.py \
|
||||
@python tensorflow/lite/experimental/micro/tools/make/transform_source.py \
|
||||
--platform=arduino \
|
||||
--is_example_ino \
|
||||
--source_path="$$<" \
|
||||
--third_party_headers="$(4)" < $$< > $$@
|
||||
|
||||
$(PRJDIR)$(2)/arduino/src/%.cpp: %.cc
|
||||
@mkdir -p $$(dir $$@)
|
||||
@python tensorflow/lite/experimental/micro/tools/make/transform_arduino_source.py \
|
||||
@python tensorflow/lite/experimental/micro/tools/make/transform_source.py \
|
||||
--platform=arduino \
|
||||
--third_party_headers="$(4)" < $$< > $$@
|
||||
|
||||
$(PRJDIR)$(2)/arduino/src/%.h: %.h third_party_downloads
|
||||
@mkdir -p $$(dir $$@)
|
||||
@python tensorflow/lite/experimental/micro/tools/make/transform_arduino_source.py \
|
||||
@python tensorflow/lite/experimental/micro/tools/make/transform_source.py \
|
||||
--platform=arduino \
|
||||
--third_party_headers="$(4)" < $$< > $$@
|
||||
|
||||
$(PRJDIR)$(2)/arduino/LICENSE: LICENSE
|
||||
@ -147,28 +152,33 @@ $(PRJDIR)$(2)/arduino/LICENSE: LICENSE
|
||||
|
||||
$(PRJDIR)$(2)/arduino/src/%: % third_party_downloads
|
||||
@mkdir -p $$(dir $$@)
|
||||
@python tensorflow/lite/experimental/micro/tools/make/transform_arduino_source.py \
|
||||
@python tensorflow/lite/experimental/micro/tools/make/transform_source.py \
|
||||
--platform=arduino \
|
||||
--third_party_headers="$(4)" < $$< > $$@
|
||||
|
||||
$(PRJDIR)$(2)/arduino/src/third_party/%: tensorflow/lite/experimental/micro/tools/make/downloads/% third_party_downloads
|
||||
@mkdir -p $$(dir $$@)
|
||||
@python tensorflow/lite/experimental/micro/tools/make/transform_arduino_source.py \
|
||||
@python tensorflow/lite/experimental/micro/tools/make/transform_source.py \
|
||||
--platform=arduino \
|
||||
--third_party_headers="$(4)" < $$< > $$@
|
||||
|
||||
$(PRJDIR)$(2)/arduino/src/third_party/%.cpp: tensorflow/lite/experimental/micro/tools/make/downloads/%.cc third_party_downloads
|
||||
@mkdir -p $$(dir $$@)
|
||||
@python tensorflow/lite/experimental/micro/tools/make/transform_arduino_source.py \
|
||||
@python tensorflow/lite/experimental/micro/tools/make/transform_source.py \
|
||||
--platform=arduino \
|
||||
--third_party_headers="$(4)" < $$< > $$@
|
||||
|
||||
$(PRJDIR)$(2)/arduino/src/third_party/flatbuffers/include/flatbuffers/base.h: tensorflow/lite/experimental/micro/tools/make/downloads/flatbuffers/include/flatbuffers/base.h third_party_downloads
|
||||
@mkdir -p $$(dir $$@)
|
||||
@python tensorflow/lite/experimental/micro/tools/make/transform_arduino_source.py \
|
||||
@python tensorflow/lite/experimental/micro/tools/make/transform_source.py \
|
||||
--platform=arduino \
|
||||
--third_party_headers="$(4)" < $$< | \
|
||||
sed -E 's/utility\.h/utility/g' > $$@
|
||||
|
||||
$(PRJDIR)$(2)/arduino/src/third_party/kissfft/kiss_fft.h: tensorflow/lite/experimental/micro/tools/make/downloads/kissfft/kiss_fft.h third_party_downloads
|
||||
@mkdir -p $$(dir $$@)
|
||||
@python tensorflow/lite/experimental/micro/tools/make/transform_arduino_source.py \
|
||||
@python tensorflow/lite/experimental/micro/tools/make/transform_source.py \
|
||||
--platform=arduino \
|
||||
--third_party_headers="$(4)" < $$< | \
|
||||
sed -E 's@#include <string.h>@//#include <string.h> /* Patched by helper_functions.inc for Arduino compatibility */@g' > $$@
|
||||
|
||||
@ -217,6 +227,67 @@ ALL_PROJECT_TARGETS += $(if $(findstring _test,$(2)),,generate_$(2)_arduino_libr
|
||||
|
||||
endef
|
||||
|
||||
# Creates a set of rules to build a standalone ESP-IDF project for an
|
||||
# executable, including all of the source and header files required in a
|
||||
# separate folder.
|
||||
# Arguments are:
|
||||
# 1 - Project file template names.
|
||||
# 2 - Name of executable.
|
||||
# 3 - List of C/C++ source files needed to build the TF Micro component.
|
||||
# 4 - List of C/C++ header files needed to build the TF Micro component.
|
||||
# 5 - List of C/C++ source files needed to build this particular project.
|
||||
# 6 - List of C/C++ header files needed to build this particular project.
|
||||
# 7 - Linker flags required.
|
||||
# 8 - C++ compilation flags needed.
|
||||
# 9 - C compilation flags needed.
|
||||
# 10 - List of includes.
|
||||
define generate_esp_project
|
||||
$(PRJDIR)$(2)/esp-idf/LICENSE: LICENSE
|
||||
@mkdir -p $$(dir $$@)
|
||||
@cp $$< $$@
|
||||
|
||||
$(PRJDIR)$(2)/esp-idf/main/%.cc: tensorflow/lite/experimental/micro/examples/$(2)/%.cc
|
||||
@mkdir -p $$(dir $$@)
|
||||
@python tensorflow/lite/experimental/micro/tools/make/transform_source.py \
|
||||
--platform=esp \
|
||||
--is_example_source \
|
||||
--source_path="$$<" \
|
||||
< $$< > $$@
|
||||
|
||||
$(PRJDIR)$(2)/esp-idf/main/%: tensorflow/lite/experimental/micro/examples/$(2)/%
|
||||
@mkdir -p $$(dir $$@)
|
||||
@cp $$< $$@
|
||||
|
||||
$(PRJDIR)$(2)/esp-idf/components/tfmicro/%: % third_party_downloads
|
||||
@mkdir -p $$(dir $$@)
|
||||
@cp $$< $$@
|
||||
|
||||
$(PRJDIR)$(2)/esp-idf/components/tfmicro/third_party/%: tensorflow/lite/experimental/micro/tools/make/downloads/% third_party_downloads
|
||||
@mkdir -p $$(dir $$@)
|
||||
@cp $$< $$@
|
||||
|
||||
$(PRJDIR)$(2)/esp-idf/%: tensorflow/lite/experimental/micro/tools/make/templates/esp/%.tpl
|
||||
$(eval MAIN_SRCS_RELATIVE := $(patsubst tensorflow/lite/experimental/micro/examples/$(2)/%,%,$(5)))
|
||||
|
||||
@mkdir -p $$(dir $$@)
|
||||
@sed -E 's#\%\{COMPONENT_SRCS\}\%#$(3)#g' $$< | \
|
||||
sed -E 's#\%\{MAIN_SRCS\}\%#$(MAIN_SRCS_RELATIVE)#g' | \
|
||||
sed -E 's#\%\{EXECUTABLE\}\%#$(2)#g' | \
|
||||
sed -E 's#\%\{COMPONENT_INCLUDES\}\%#$(10)#g' | \
|
||||
sed -E 's#\%\{LINKER_FLAGS\}\%#$(7)#g' | \
|
||||
sed -E 's#\%\{CXX_FLAGS\}\%#$(8)#g' | \
|
||||
sed -E 's#\%\{CC_FLAGS\}\%#$(9)#g' > $$@
|
||||
|
||||
generate_$(2)_esp_project: \
|
||||
$(addprefix $(PRJDIR)$(2)/esp-idf/,\
|
||||
$(patsubst tensorflow/%,components/tfmicro/tensorflow/%,\
|
||||
$(patsubst third_party/%,components/tfmicro/third_party/%,\
|
||||
$(patsubst tensorflow/lite/experimental/micro/examples/$(2)/%,main/%,$(3) $(4) $(5) $(6))))) \
|
||||
$(addprefix $(PRJDIR)$(2)/esp-idf/,$(1))
|
||||
|
||||
ALL_PROJECT_TARGETS += generate_$(2)_esp_project
|
||||
endef
|
||||
|
||||
# Specialized version of generate_project for TF Lite Micro test targets that
|
||||
# automatically includes standard library files, so you just need to pass the
|
||||
# test name and any extra source files required.
|
||||
@ -231,6 +302,7 @@ $(call generate_project,make,$(MAKE_PROJECT_FILES),$(1),$(MICROLITE_CC_SRCS) $(T
|
||||
$(call generate_project,mbed,$(MBED_PROJECT_FILES),$(1),$(MICROLITE_CC_SRCS) $(THIRD_PARTY_CC_SRCS) $(2),$(MICROLITE_CC_HDRS) $(THIRD_PARTY_CC_HDRS) $(MICROLITE_TEST_HDRS) $(3),$(MICROLITE_LIBS),$(CXXFLAGS),$(CCFLAGS))
|
||||
$(call generate_project,keil,$(KEIL_PROJECT_FILES),$(1),$(MICROLITE_CC_SRCS) $(THIRD_PARTY_CC_SRCS) $(2),$(MICROLITE_CC_HDRS) $(THIRD_PARTY_CC_HDRS) $(MICROLITE_TEST_HDRS) $(3),$(MICROLITE_LIBS),$(CXXFLAGS),$(CCFLAGS))
|
||||
$(call generate_arduino_project,$(ARDUINO_PROJECT_FILES),$(1),$(MICROLITE_CC_SRCS) $(THIRD_PARTY_CC_SRCS) $(2),$(MICROLITE_CC_HDRS) $(THIRD_PARTY_CC_HDRS) $(MICROLITE_TEST_HDRS) $(3),$(MICROLITE_LIBS),$(CXXFLAGS),$(CCFLAGS))
|
||||
$(call generate_esp_project,$(ESP_PROJECT_FILES),$(1),$(MICROLITE_CC_SRCS) $(THIRD_PARTY_CC_SRCS),$(MICROLITE_CC_HDRS) $(THIRD_PARTY_CC_HDRS) $(MICROLITE_TEST_HDRS),$(2),$(3),$(MICROLITE_LIBS),$(CXXFLAGS),$(CCFLAGS),$(PROJECT_INCLUDES))
|
||||
endef
|
||||
|
||||
# Handles the details of generating a binary target, including specializing
|
||||
|
@ -0,0 +1,5 @@
|
||||
# Settings for Espressif ESP32
|
||||
|
||||
ifeq ($(TARGET), esp)
|
||||
TARGET_ARCH := xtensa-esp32
|
||||
endif
|
@ -0,0 +1,3 @@
|
||||
cmake_minimum_required(VERSION 3.5)
|
||||
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||
project(%{EXECUTABLE}%)
|
@ -0,0 +1,58 @@
|
||||
# TensorFlow Lite Micro ESP-IDF Project
|
||||
|
||||
This folder has been autogenerated by TensorFlow, and contains source, header,
|
||||
and project files needed to build a single TensorFlow Lite Micro target using
|
||||
Espressif's [ESP-IDF](https://docs.espressif.com/projects/esp-idf/en/latest/).
|
||||
|
||||
## Usage
|
||||
|
||||
### Install the ESP IDF
|
||||
|
||||
Follow the instructions of the
|
||||
[ESP-IDF get started guide](https://docs.espressif.com/projects/esp-idf/en/latest/get-started/index.html)
|
||||
to setup the toolchain and the ESP-IDF itself.
|
||||
|
||||
The next steps assume that the
|
||||
[IDF environment variables are set](https://docs.espressif.com/projects/esp-idf/en/latest/get-started/index.html#step-4-set-up-the-environment-variables) :
|
||||
* The `IDF_PATH` environment variable is set.
|
||||
* `idf.py` and Xtensa-esp32 tools (e.g., `xtensa-esp32-elf-gcc`) are in `$PATH`.
|
||||
|
||||
## Build the example
|
||||
|
||||
To build this, run:
|
||||
|
||||
```
|
||||
idf.py build
|
||||
```
|
||||
|
||||
### Load and run the example
|
||||
|
||||
To flash (replace `/dev/ttyUSB0` with the device serial port):
|
||||
```
|
||||
idf.py --port /dev/ttyUSB0 flash
|
||||
```
|
||||
|
||||
Monitor the serial output:
|
||||
```
|
||||
idf.py --port /dev/ttyUSB0 monitor
|
||||
```
|
||||
|
||||
Use `Ctrl+]` to exit.
|
||||
|
||||
The previous two commands can be combined:
|
||||
```
|
||||
idf.py --port /dev/ttyUSB0 flash monitor
|
||||
```
|
||||
|
||||
## Project Generation
|
||||
|
||||
See
|
||||
[tensorflow/lite/experimental/micro](https://github.com/tensorflow/tensorflow/tree/master/tensorflow/lite/experimental/micro)
|
||||
for details on how projects like this can be generated from the main source
|
||||
tree.
|
||||
|
||||
## License
|
||||
|
||||
TensorFlow's code is covered by the Apache2 License included in the repository,
|
||||
and third party dependencies are covered by their respective licenses, in the
|
||||
third_party folder of this package.
|
@ -0,0 +1,38 @@
|
||||
|
||||
# Copyright 2019 The TensorFlow Authors. All Rights Reserved.
|
||||
#
|
||||
# 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.
|
||||
|
||||
#
|
||||
# This component was generated for the '%{EXECUTABLE}%' TF Micro example.
|
||||
#
|
||||
|
||||
# Make sure that the IDF Path environment variable is defined
|
||||
if(NOT DEFINED ENV{IDF_PATH})
|
||||
message(FATAL_ERROR "The IDF_PATH environment variable must point to the location of the ESP-IDF.")
|
||||
endif()
|
||||
|
||||
idf_component_register(
|
||||
SRCS %{COMPONENT_SRCS}%
|
||||
INCLUDE_DIRS %{COMPONENT_INCLUDES}%)
|
||||
|
||||
# Reduce the level of paranoia to be able to compile TF sources
|
||||
target_compile_options(${COMPONENT_LIB} PRIVATE
|
||||
-Wno-maybe-uninitialized
|
||||
-Wno-missing-field-initializers
|
||||
-Wno-pointer-sign
|
||||
-Wno-type-limits)
|
||||
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} %{CC_FLAGS}%")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} %{CXX_FLAGS}%")
|
||||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} %{LINKER_FLAGS}%")
|
@ -0,0 +1,8 @@
|
||||
|
||||
#
|
||||
# Main component of TF Micro project '%{EXECUTABLE}%'.
|
||||
#
|
||||
|
||||
idf_component_register(
|
||||
SRCS %{MAIN_SRCS}%
|
||||
INCLUDE_DIRS "")
|
@ -37,7 +37,8 @@ EOF
|
||||
OUTPUT_REGULAR_FILE=${TEST_TMPDIR}/output_regular.cc
|
||||
THIRD_PARTY_HEADERS="subdir/foo.h subdir_2/include/bar/fish.h subdir_3/something.h"
|
||||
|
||||
${TEST_SRCDIR}/tensorflow/lite/experimental/micro/tools/make/transform_arduino_source \
|
||||
${TEST_SRCDIR}/tensorflow/lite/experimental/micro/tools/make/transform_source \
|
||||
--platform=arduino \
|
||||
--third_party_headers="${THIRD_PARTY_HEADERS}" \
|
||||
< ${INPUT_REGULAR_FILE} \
|
||||
> ${OUTPUT_REGULAR_FILE}
|
||||
@ -89,7 +90,8 @@ EOF
|
||||
|
||||
OUTPUT_EXAMPLE_INO_FILE=${TEST_TMPDIR}/output_regular.cc
|
||||
|
||||
${TEST_SRCDIR}/tensorflow/lite/experimental/micro/tools/make/transform_arduino_source \
|
||||
${TEST_SRCDIR}/tensorflow/lite/experimental/micro/tools/make/transform_source \
|
||||
--platform=arduino \
|
||||
--third_party_headers="${THIRD_PARTY_HEADERS}" \
|
||||
--is_example_ino \
|
||||
< ${INPUT_EXAMPLE_INO_FILE} \
|
||||
@ -129,7 +131,8 @@ EOF
|
||||
|
||||
OUTPUT_EXAMPLE_SOURCE_FILE=${TEST_TMPDIR}/output_example_source.h
|
||||
|
||||
${TEST_SRCDIR}/tensorflow/lite/experimental/micro/tools/make/transform_arduino_source \
|
||||
${TEST_SRCDIR}/tensorflow/lite/experimental/micro/tools/make/transform_source \
|
||||
--platform=arduino \
|
||||
--third_party_headers="${THIRD_PARTY_HEADERS}" \
|
||||
--is_example_source \
|
||||
--source_path="foo/input_example_source.h" \
|
||||
|
108
tensorflow/lite/experimental/micro/tools/make/transform_esp_source_test.sh
Executable file
108
tensorflow/lite/experimental/micro/tools/make/transform_esp_source_test.sh
Executable file
@ -0,0 +1,108 @@
|
||||
#!/bin/bash
|
||||
# Copyright 2019 The TensorFlow Authors. All Rights Reserved.
|
||||
#
|
||||
# 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.
|
||||
# ==============================================================================
|
||||
#
|
||||
# Bash unit tests for the TensorFlow Lite Micro project generator.
|
||||
|
||||
set -e
|
||||
|
||||
INPUT_EXAMPLE_FILE=${TEST_TMPDIR}/input_example.cc
|
||||
cat << EOF > ${INPUT_EXAMPLE_FILE}
|
||||
#include <stdio.h>
|
||||
#include "baz.h"
|
||||
#include "tensorflow/lite/experimental/micro/examples/something/foo/fish.h"
|
||||
|
||||
main() {
|
||||
fprintf(stderr, "Hello World!\n");
|
||||
return 0;
|
||||
}
|
||||
EOF
|
||||
|
||||
OUTPUT_EXAMPLE_FILE=${TEST_TMPDIR}/output_example.cc
|
||||
|
||||
${TEST_SRCDIR}/tensorflow/lite/experimental/micro/tools/make/transform_source \
|
||||
--platform=esp \
|
||||
--is_example_source \
|
||||
--source_path="tensorflow/lite/experimental/micro/examples/something/input_example.cc" \
|
||||
< ${INPUT_EXAMPLE_FILE} \
|
||||
> ${OUTPUT_EXAMPLE_FILE}
|
||||
|
||||
if ! grep -q '#include <stdio.h>' ${OUTPUT_EXAMPLE_FILE}; then
|
||||
echo "ERROR: No stdio.h include found in output '${OUTPUT_EXAMPLE_FILE}'"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if ! grep -q '#include "baz.h"' ${OUTPUT_EXAMPLE_FILE}; then
|
||||
echo "ERROR: No baz.h include found in output '${OUTPUT_EXAMPLE_FILE}'"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if ! grep -q '#include "foo/fish.h"' ${OUTPUT_EXAMPLE_FILE}; then
|
||||
echo "ERROR: No foo/fish.h include found in output '${OUTPUT_EXAMPLE_FILE}'"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
|
||||
#
|
||||
# Example file in a sub directory.
|
||||
#
|
||||
|
||||
mkdir -p "${TEST_TMPDIR}/subdir"
|
||||
INPUT_EXAMPLE_SUBDIR_FILE=${TEST_TMPDIR}/subdir/input_example.cc
|
||||
cat << EOF > ${INPUT_EXAMPLE_SUBDIR_FILE}
|
||||
#include <stdio.h>
|
||||
#include "baz.h"
|
||||
#include "tensorflow/lite/experimental/micro/examples/something/subdir/input_example.h"
|
||||
#include "tensorflow/lite/experimental/micro/examples/something/bleh.h"
|
||||
#include "tensorflow/lite/experimental/micro/examples/something/foo/fish.h"
|
||||
EOF
|
||||
|
||||
OUTPUT_EXAMPLE_SUBDIR_FILE=${TEST_TMPDIR}/output_example.cc
|
||||
|
||||
${TEST_SRCDIR}/tensorflow/lite/experimental/micro/tools/make/transform_source \
|
||||
--platform=esp \
|
||||
--is_example_source \
|
||||
--source_path="tensorflow/lite/experimental/micro/examples/something/subdir/input_example.cc" \
|
||||
< ${INPUT_EXAMPLE_SUBDIR_FILE} \
|
||||
> ${OUTPUT_EXAMPLE_SUBDIR_FILE}
|
||||
|
||||
if ! grep -q '#include <stdio.h>' ${OUTPUT_EXAMPLE_SUBDIR_FILE}; then
|
||||
echo "ERROR: No stdio.h include found in output '${OUTPUT_EXAMPLE_SUBDIR_FILE}'"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if ! grep -q '#include "baz.h"' ${OUTPUT_EXAMPLE_SUBDIR_FILE}; then
|
||||
echo "ERROR: No baz.h include found in output '${OUTPUT_EXAMPLE_SUBDIR_FILE}'"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if ! grep -q '#include "input_example.h"' ${OUTPUT_EXAMPLE_SUBDIR_FILE}; then
|
||||
echo "ERROR: No input_example.h include found in output '${OUTPUT_EXAMPLE_SUBDIR_FILE}'"
|
||||
cat ${OUTPUT_EXAMPLE_SUBDIR_FILE}
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if ! grep -q '#include "../bleh.h"' ${OUTPUT_EXAMPLE_SUBDIR_FILE}; then
|
||||
echo "ERROR: No ../bleh.h include found in output '${OUTPUT_EXAMPLE_SUBDIR_FILE}'"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if ! grep -q '#include "../foo/fish.h"' ${OUTPUT_EXAMPLE_SUBDIR_FILE}; then
|
||||
echo "ERROR: No ../foo/fish.h include found in output '${OUTPUT_EXAMPLE_SUBDIR_FILE}'"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo
|
||||
echo "SUCCESS: transform_esp_source test PASSED"
|
@ -0,0 +1,204 @@
|
||||
# Lint as: python2, python3
|
||||
# Copyright 2019 The TensorFlow Authors. All Rights Reserved.
|
||||
#
|
||||
# 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.
|
||||
# ==============================================================================
|
||||
"""Resolves non-system C/C++ includes to their full paths.
|
||||
|
||||
Used to generate Arduino and ESP-IDF examples.
|
||||
"""
|
||||
|
||||
from __future__ import absolute_import
|
||||
from __future__ import division
|
||||
from __future__ import print_function
|
||||
|
||||
import argparse
|
||||
import os
|
||||
import re
|
||||
import sys
|
||||
import six
|
||||
|
||||
|
||||
EXAMPLE_DIR_PATH = 'tensorflow/lite/experimental/micro/examples/'
|
||||
|
||||
|
||||
def replace_arduino_includes(line, supplied_headers_list):
|
||||
"""Updates any includes to reference the new Arduino library paths."""
|
||||
include_match = re.match(r'(.*#include.*")(.*)(")', line)
|
||||
if include_match:
|
||||
path = include_match.group(2)
|
||||
for supplied_header in supplied_headers_list:
|
||||
if six.ensure_str(supplied_header).endswith(path):
|
||||
path = supplied_header
|
||||
break
|
||||
line = include_match.group(1) + six.ensure_str(path) + include_match.group(
|
||||
3)
|
||||
return line
|
||||
|
||||
|
||||
def replace_arduino_main(line):
|
||||
"""Updates any occurences of a bare main definition to the Arduino equivalent."""
|
||||
main_match = re.match(r'(.*int )(main)(\(.*)', line)
|
||||
if main_match:
|
||||
line = main_match.group(1) + 'tflite_micro_main' + main_match.group(3)
|
||||
return line
|
||||
|
||||
|
||||
def check_ino_functions(input_text):
|
||||
"""Ensures the required functions exist."""
|
||||
# We're moving to an Arduino-friendly structure for all our examples, so they
|
||||
# have to have a setup() and loop() function, just like their IDE expects.
|
||||
if not re.search(r'void setup\(\) \{', input_text):
|
||||
raise Exception(
|
||||
'All examples must have a setup() function for Arduino compatiblity\n' +
|
||||
input_text)
|
||||
if not re.search(r'void loop\(\) \{', input_text):
|
||||
raise Exception(
|
||||
'All examples must have a loop() function for Arduino compatiblity')
|
||||
return input_text
|
||||
|
||||
|
||||
def add_example_ino_library_include(input_text):
|
||||
"""Makes sure the example includes the header that loads the library."""
|
||||
return re.sub(r'#include ', '#include <TensorFlowLite.h>\n\n#include ',
|
||||
input_text, 1)
|
||||
|
||||
|
||||
def replace_ardunio_example_includes(line, _):
|
||||
"""Updates any includes for local example files."""
|
||||
# Because the export process moves the example source and header files out of
|
||||
# their default locations into the top-level 'examples' folder in the Arduino
|
||||
# library, we have to update any include references to match.
|
||||
dir_path = 'tensorflow/lite/experimental/micro/examples/'
|
||||
include_match = re.match(
|
||||
r'(.*#include.*")' + six.ensure_str(dir_path) + r'([^/]+)/(.*")', line)
|
||||
if include_match:
|
||||
flattened_name = re.sub(r'/', '_', include_match.group(3))
|
||||
line = include_match.group(1) + flattened_name
|
||||
return line
|
||||
|
||||
|
||||
def replace_esp_example_includes(line, source_path):
|
||||
"""Updates any includes for local example files."""
|
||||
# Because the export process moves the example source and header files out of
|
||||
# their default locations into the top-level 'main' folder in the ESP-IDF
|
||||
# project, we have to update any include references to match.
|
||||
include_match = re.match(r'.*#include.*"(' + EXAMPLE_DIR_PATH + r'.*)"', line)
|
||||
|
||||
if include_match:
|
||||
# Compute the target path relative from the source's directory
|
||||
target_path = include_match.group(1)
|
||||
source_dirname = os.path.dirname(source_path)
|
||||
rel_to_target = os.path.relpath(target_path, start=source_dirname)
|
||||
|
||||
line = '#include "%s"' % rel_to_target
|
||||
return line
|
||||
|
||||
|
||||
def transform_arduino_sources(input_lines, flags):
|
||||
"""Transform sources for the Arduino platform.
|
||||
|
||||
Args:
|
||||
input_lines: A sequence of lines from the input file to process.
|
||||
flags: Flags indicating which transformation(s) to apply.
|
||||
|
||||
Returns:
|
||||
The transformed output as a string.
|
||||
"""
|
||||
supplied_headers_list = six.ensure_str(flags.third_party_headers).split(' ')
|
||||
|
||||
output_lines = []
|
||||
for line in input_lines:
|
||||
line = replace_arduino_includes(line, supplied_headers_list)
|
||||
if flags.is_example_ino or flags.is_example_source:
|
||||
line = replace_ardunio_example_includes(line, flags.source_path)
|
||||
else:
|
||||
line = replace_arduino_main(line)
|
||||
output_lines.append(line)
|
||||
output_text = '\n'.join(output_lines)
|
||||
|
||||
if flags.is_example_ino:
|
||||
output_text = check_ino_functions(output_text)
|
||||
output_text = add_example_ino_library_include(output_text)
|
||||
|
||||
return output_text
|
||||
|
||||
|
||||
def transform_esp_sources(input_lines, flags):
|
||||
"""Transform sources for the ESP-IDF platform.
|
||||
|
||||
Args:
|
||||
input_lines: A sequence of lines from the input file to process.
|
||||
flags: Flags indicating which transformation(s) to apply.
|
||||
|
||||
Returns:
|
||||
The transformed output as a string.
|
||||
"""
|
||||
output_lines = []
|
||||
for line in input_lines:
|
||||
if flags.is_example_source:
|
||||
line = replace_esp_example_includes(line, flags.source_path)
|
||||
output_lines.append(line)
|
||||
|
||||
output_text = '\n'.join(output_lines)
|
||||
return output_text
|
||||
|
||||
|
||||
def main(unused_args, flags):
|
||||
"""Transforms the input source file to work when exported as example."""
|
||||
input_file_lines = sys.stdin.read().split('\n')
|
||||
|
||||
output_text = ''
|
||||
if flags.platform == 'arduino':
|
||||
output_text = transform_arduino_sources(input_file_lines, flags)
|
||||
elif flags.platform == 'esp':
|
||||
output_text = transform_esp_sources(input_file_lines, flags)
|
||||
|
||||
sys.stdout.write(output_text)
|
||||
|
||||
|
||||
def parse_args():
|
||||
"""Converts the raw arguments into accessible flags."""
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument(
|
||||
'--platform',
|
||||
choices=['arduino', 'esp'],
|
||||
required=True,
|
||||
help='Target platform.')
|
||||
parser.add_argument(
|
||||
'--third_party_headers',
|
||||
type=str,
|
||||
default='',
|
||||
help='Space-separated list of headers to resolve.')
|
||||
parser.add_argument(
|
||||
'--is_example_ino',
|
||||
dest='is_example_ino',
|
||||
action='store_true',
|
||||
help='Whether the destination is an example main ino.')
|
||||
parser.add_argument(
|
||||
'--is_example_source',
|
||||
dest='is_example_source',
|
||||
action='store_true',
|
||||
help='Whether the destination is an example cpp or header file.')
|
||||
parser.add_argument(
|
||||
'--source_path',
|
||||
type=str,
|
||||
default='',
|
||||
help='The relative path of the source code file.')
|
||||
flags, unparsed = parser.parse_known_args()
|
||||
|
||||
main(unparsed, flags)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
parse_args()
|
Loading…
Reference in New Issue
Block a user