提交 fdc88436 编写于 作者: A Advait Jain

Delete (most of the) Arduino-specific code.

Moving forward, TFLM support for Arduino is going to be maintained in a
stand-alone repository at:
https://github.com/tensorflow/tflite-micro-arduino-examples

BUG=http://b/193823889
上级 0b75349b
# YAML schema for GitHub Actions:
# https://help.github.com/en/actions/automating-your-workflow-with-github-actions/workflow-syntax-for-github-actions
#
# Helpful YAML parser to clarify YAML syntax:
# https://yaml-online-parser.appspot.com/
name: Arduino
# https://docs.github.com/en/actions/reference/workflow-syntax-for-github-actions#onschedule
on:
schedule:
# 10am UTC is 3am or 4am PT depending on daylight savings.
- cron: '0 10 * * *'
# Allow manually triggering of the workflow.
workflow_dispatch: {}
jobs:
arduino:
runs-on: ubuntu-latest
if: |
github.event_name == 'workflow_dispatch' ||
(github.event_name == 'schedule' && github.repository == 'tensorflow/tflite-micro')
name: Arduino Continuous Builds
steps:
- uses: actions/checkout@v2
- name: Test
run: |
tensorflow/lite/micro/tools/ci_build/test_arduino.sh
/* Copyright 2020 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.
==============================================================================*/
void* __dso_handle;
/* Copyright 2021 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 file is empty to ensure that a specialized implementation of
// debug_log.h is used (instead of the default implementation from
// tensorflow/lite/micro/debug_log.cc).
//
// The actual target-specific implementation of debug_log.h is in
// system_setup.cc since that allows us to consolidate all the target-specific
// specializations into one source file.
/* Copyright 2021 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/micro/system_setup.h"
#include "Arduino.h"
#include "tensorflow/lite/micro/debug_log.h"
// The Arduino DUE uses a different object for the default serial port shown in
// the monitor than most other models, so make sure we pick the right one. See
// https://github.com/arduino/Arduino/issues/3088#issuecomment-406655244
#if defined(__SAM3X8E__)
#define DEBUG_SERIAL_OBJECT (SerialUSB)
#else
#define DEBUG_SERIAL_OBJECT (Serial)
#endif
extern "C" void DebugLog(const char* s) { DEBUG_SERIAL_OBJECT.print(s); }
namespace tflite {
void InitializeTarget() { DEBUG_SERIAL_OBJECT.begin(9600); }
} // namespace tflite
/* 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/micro/examples/hello_world/constants.h"
// This is tuned so that a full cycle takes ~4 seconds on an Arduino MKRZERO.
const int kInferencesPerCycle = 1000;
/* 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/micro/examples/hello_world/main_functions.h"
// Arduino automatically calls the setup() and loop() functions in a sketch, so
// where other systems need their own main routine in this file, it can be left
// empty.
/* 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/micro/examples/hello_world/output_handler.h"
#include "Arduino.h"
#include "tensorflow/lite/micro/examples/hello_world/constants.h"
// The pin of the Arduino's built-in LED
int led = LED_BUILTIN;
// Track whether the function has run at least once
bool initialized = false;
// Animates a dot across the screen to represent the current x and y values
void HandleOutput(tflite::ErrorReporter* error_reporter, float x_value,
float y_value) {
// Do this only once
if (!initialized) {
// Set the LED pin to output
pinMode(led, OUTPUT);
initialized = true;
}
// Calculate the brightness of the LED such that y=-1 is fully off
// and y=1 is fully on. The LED's brightness can range from 0-255.
int brightness = (int)(127.5f * (y_value + 1));
// Set the brightness of the LED. If the specified pin does not support PWM,
// this will result in the LED being on when y > 127, off otherwise.
analogWrite(led, brightness);
// Log the current brightness value for display in the Arduino plotter
TF_LITE_REPORT_ERROR(error_reporter, "%d\n", brightness);
}
ifeq ($(TARGET),$(filter $(TARGET),arduino))
magic_wand_SRCS += \
tensorflow/lite/micro/examples/magic_wand/sparkfun_edge/accelerometer_handler.cc \
tensorflow/lite/micro/examples/magic_wand/sparkfun_edge/output_handler.cc
endif
/* 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.
==============================================================================*/
#if defined(ARDUINO) && !defined(ARDUINO_ARDUINO_NANO33BLE)
#define ARDUINO_EXCLUDE_CODE
#endif // defined(ARDUINO) && !defined(ARDUINO_ARDUINO_NANO33BLE)
#ifndef ARDUINO_EXCLUDE_CODE
#include "tensorflow/lite/micro/examples/magic_wand/accelerometer_handler.h"
#include <Arduino.h>
#include <Arduino_LSM9DS1.h>
#include "tensorflow/lite/micro/examples/magic_wand/constants.h"
// A buffer holding the last 200 sets of 3-channel values
float save_data[600] = {0.0};
// Most recent position in the save_data buffer
int begin_index = 0;
// True if there is not yet enough data to run inference
bool pending_initial_data = true;
// How often we should save a measurement during downsampling
int sample_every_n;
// The number of measurements since we last saved one
int sample_skip_counter = 1;
TfLiteStatus SetupAccelerometer(tflite::ErrorReporter* error_reporter) {
// Switch on the IMU
if (!IMU.begin()) {
TF_LITE_REPORT_ERROR(error_reporter, "Failed to initialize IMU");
return kTfLiteError;
}
// Make sure we are pulling measurements into a FIFO.
// If you see an error on this line, make sure you have at least v1.1.0 of the
// Arduino_LSM9DS1 library installed.
IMU.setContinuousMode();
// Determine how many measurements to keep in order to
// meet kTargetHz
float sample_rate = IMU.accelerationSampleRate();
sample_every_n = static_cast<int>(roundf(sample_rate / kTargetHz));
TF_LITE_REPORT_ERROR(error_reporter, "Magic starts!");
return kTfLiteOk;
}
bool ReadAccelerometer(tflite::ErrorReporter* error_reporter, float* input,
int length) {
// Keep track of whether we stored any new data
bool new_data = false;
// Loop through new samples and add to buffer
while (IMU.accelerationAvailable()) {
float x, y, z;
// Read each sample, removing it from the device's FIFO buffer
if (!IMU.readAcceleration(x, y, z)) {
TF_LITE_REPORT_ERROR(error_reporter, "Failed to read data");
break;
}
// Throw away this sample unless it's the nth
if (sample_skip_counter != sample_every_n) {
sample_skip_counter += 1;
continue;
}
// Write samples to our buffer, converting to milli-Gs and rotating the axis
// order for compatibility with model (sensor orientation is different on
// Arduino Nano BLE Sense compared with SparkFun Edge).
// The expected orientation of the Arduino on the wand is with the USB port
// facing down the shaft towards the user's hand, with the reset button
// pointing at the user's face:
//
// ____
// | |<- Arduino board
// | |
// | () | <- Reset button
// | |
// -TT- <- USB port
// ||
// ||<- Wand
// ....
// ||
// ||
// ()
//
const float norm_x = -z;
const float norm_y = y;
const float norm_z = x;
save_data[begin_index++] = norm_x * 1000;
save_data[begin_index++] = norm_y * 1000;
save_data[begin_index++] = norm_z * 1000;
// Since we took a sample, reset the skip counter
sample_skip_counter = 1;
// If we reached the end of the circle buffer, reset
if (begin_index >= 600) {
begin_index = 0;
}
new_data = true;
}
// Skip this round if data is not ready yet
if (!new_data) {
return false;
}
// Check if we are ready for prediction or still pending more initial data
if (pending_initial_data && begin_index >= 200) {
pending_initial_data = false;
}
// Return if we don't have enough data
if (pending_initial_data) {
return false;
}
// Copy the requested number of bytes to the provided input tensor
for (int i = 0; i < length; ++i) {
int ring_array_index = begin_index + i - length;
if (ring_array_index < 0) {
ring_array_index += 600;
}
input[i] = save_data[ring_array_index];
}
return true;
}
#endif // ARDUINO_EXCLUDE_CODE
/* 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/micro/examples/hello_world/main_functions.h"
// Arduino automatically calls the setup() and loop() functions in a sketch, so
// where other systems need their own main routine in this file, it can be left
// empty.
/* 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.
==============================================================================*/
#if defined(ARDUINO) && !defined(ARDUINO_ARDUINO_NANO33BLE)
#define ARDUINO_EXCLUDE_CODE
#endif // defined(ARDUINO) && !defined(ARDUINO_ARDUINO_NANO33BLE)
#ifndef ARDUINO_EXCLUDE_CODE
#include "tensorflow/lite/micro/examples/magic_wand/output_handler.h"
#include "Arduino.h"
void HandleOutput(tflite::ErrorReporter* error_reporter, int kind) {
// The first time this method runs, set up our LED
static bool is_initialized = false;
if (!is_initialized) {
pinMode(LED_BUILTIN, OUTPUT);
is_initialized = true;
}
// Print some ASCII art for each gesture and control the LED.
if (kind == 0) {
TF_LITE_REPORT_ERROR(
error_reporter,
"WING:\n\r* * *\n\r * * * "
"*\n\r * * * *\n\r * * * *\n\r * * "
"* *\n\r * *\n\r");
} else if (kind == 1) {
digitalWrite(LED_BUILTIN, HIGH);
TF_LITE_REPORT_ERROR(
error_reporter,
"RING:\n\r *\n\r * *\n\r * *\n\r "
" * *\n\r * *\n\r * *\n\r "
" *\n\r");
} else if (kind == 2) {
digitalWrite(LED_BUILTIN, LOW);
TF_LITE_REPORT_ERROR(
error_reporter,
"SLOPE:\n\r *\n\r *\n\r *\n\r *\n\r "
"*\n\r *\n\r *\n\r * * * * * * * *\n\r");
}
}
#endif // ARDUINO_EXCLUDE_CODE
ifeq ($(TARGET),$(filter $(TARGET),arduino))
MICRO_SPEECH_SRCS += \
tensorflow/lite/micro/examples/micro_speech/sparkfun_edge/audio_provider.cc \
tensorflow/lite/micro/examples/micro_speech/sparkfun_edge/command_responder.cc
endif
/* Copyright 2018 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.
==============================================================================*/
/* Copyright 2018 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.
==============================================================================*/
#if defined(ARDUINO) && !defined(ARDUINO_ARDUINO_NANO33BLE)
#define ARDUINO_EXCLUDE_CODE
#endif // defined(ARDUINO) && !defined(ARDUINO_ARDUINO_NANO33BLE)
#ifndef ARDUINO_EXCLUDE_CODE
#include "tensorflow/lite/micro/examples/micro_speech/audio_provider.h"
#include "PDM.h"
#include "tensorflow/lite/micro/examples/micro_speech/micro_features/micro_model_settings.h"
namespace {
bool g_is_audio_initialized = false;
// An internal buffer able to fit 16x our sample size
constexpr int kAudioCaptureBufferSize = DEFAULT_PDM_BUFFER_SIZE * 16;
int16_t g_audio_capture_buffer[kAudioCaptureBufferSize];
// A buffer that holds our output
int16_t g_audio_output_buffer[kMaxAudioSampleSize];
// Mark as volatile so we can check in a while loop to see if
// any samples have arrived yet.
volatile int32_t g_latest_audio_timestamp = 0;
} // namespace
void CaptureSamples() {
// This is how many bytes of new data we have each time this is called
const int number_of_samples = DEFAULT_PDM_BUFFER_SIZE;
// Calculate what timestamp the last audio sample represents
const int32_t time_in_ms =
g_latest_audio_timestamp +
(number_of_samples / (kAudioSampleFrequency / 1000));
// Determine the index, in the history of all samples, of the last sample
const int32_t start_sample_offset =
g_latest_audio_timestamp * (kAudioSampleFrequency / 1000);
// Determine the index of this sample in our ring buffer
const int capture_index = start_sample_offset % kAudioCaptureBufferSize;
// Read the data to the correct place in our buffer
PDM.read(g_audio_capture_buffer + capture_index, DEFAULT_PDM_BUFFER_SIZE);
// This is how we let the outside world know that new audio data has arrived.
g_latest_audio_timestamp = time_in_ms;
}
TfLiteStatus InitAudioRecording(tflite::ErrorReporter* error_reporter) {
// Hook up the callback that will be called with each sample
PDM.onReceive(CaptureSamples);
// Start listening for audio: MONO @ 16KHz with gain at 20
PDM.begin(1, kAudioSampleFrequency);
PDM.setGain(20);
// Block until we have our first audio sample
while (!g_latest_audio_timestamp) {
}
return kTfLiteOk;
}
TfLiteStatus GetAudioSamples(tflite::ErrorReporter* error_reporter,
int start_ms, int duration_ms,
int* audio_samples_size, int16_t** audio_samples) {
// Set everything up to start receiving audio
if (!g_is_audio_initialized) {
TfLiteStatus init_status = InitAudioRecording(error_reporter);
if (init_status != kTfLiteOk) {
return init_status;
}
g_is_audio_initialized = true;
}
// This next part should only be called when the main thread notices that the
// latest audio sample data timestamp has changed, so that there's new data
// in the capture ring buffer. The ring buffer will eventually wrap around and
// overwrite the data, but the assumption is that the main thread is checking
// often enough and the buffer is large enough that this call will be made
// before that happens.
// Determine the index, in the history of all samples, of the first
// sample we want
const int start_offset = start_ms * (kAudioSampleFrequency / 1000);
// Determine how many samples we want in total
const int duration_sample_count =
duration_ms * (kAudioSampleFrequency / 1000);
for (int i = 0; i < duration_sample_count; ++i) {
// For each sample, transform its index in the history of all samples into
// its index in g_audio_capture_buffer
const int capture_index = (start_offset + i) % kAudioCaptureBufferSize;
// Write the sample to the output buffer
g_audio_output_buffer[i] = g_audio_capture_buffer[capture_index];
}
// Set pointers to provide access to the audio
*audio_samples_size = kMaxAudioSampleSize;
*audio_samples = g_audio_output_buffer;
return kTfLiteOk;
}
int32_t LatestAudioTimestamp() { return g_latest_audio_timestamp; }
#endif // ARDUINO_EXCLUDE_CODE
/* 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.
==============================================================================*/
#if defined(ARDUINO) && !defined(ARDUINO_ARDUINO_NANO33BLE)
#define ARDUINO_EXCLUDE_CODE
#endif // defined(ARDUINO) && !defined(ARDUINO_ARDUINO_NANO33BLE)
#ifndef ARDUINO_EXCLUDE_CODE
#include "tensorflow/lite/micro/examples/micro_speech/command_responder.h"
#include "Arduino.h"
// Toggles the built-in LED every inference, and lights a colored LED depending
// on which word was detected.
void RespondToCommand(tflite::ErrorReporter* error_reporter,
int32_t current_time, const char* found_command,
uint8_t score, bool is_new_command) {
static bool is_initialized = false;
if (!is_initialized) {
pinMode(LED_BUILTIN, OUTPUT);
// Pins for the built-in RGB LEDs on the Arduino Nano 33 BLE Sense
pinMode(LEDR, OUTPUT);
pinMode(LEDG, OUTPUT);
pinMode(LEDB, OUTPUT);
// Ensure the LED is off by default.
// Note: The RGB LEDs on the Arduino Nano 33 BLE
// Sense are on when the pin is LOW, off when HIGH.
digitalWrite(LEDR, HIGH);
digitalWrite(LEDG, HIGH);
digitalWrite(LEDB, HIGH);
is_initialized = true;
}
static int32_t last_command_time = 0;
static int count = 0;
static int certainty = 220;
if (is_new_command) {
TF_LITE_REPORT_ERROR(error_reporter, "Heard %s (%d) @%dms", found_command,
score, current_time);
// If we hear a command, light up the appropriate LED
if (found_command[0] == 'y') {
last_command_time = current_time;
digitalWrite(LEDG, LOW); // Green for yes
}
if (found_command[0] == 'n') {
last_command_time = current_time;
digitalWrite(LEDR, LOW); // Red for no
}
if (found_command[0] == 'u') {
last_command_time = current_time;
digitalWrite(LEDB, LOW); // Blue for unknown
}
}
// If last_command_time is non-zero but was >3 seconds ago, zero it
// and switch off the LED.
if (last_command_time != 0) {
if (last_command_time < (current_time - 3000)) {
last_command_time = 0;
digitalWrite(LED_BUILTIN, LOW);
digitalWrite(LEDR, HIGH);
digitalWrite(LEDG, HIGH);
digitalWrite(LEDB, HIGH);
}
// If it is non-zero but <3 seconds ago, do nothing.
return;
}
// Otherwise, toggle the LED every time an inference is performed.
++count;
if (count & 1) {
digitalWrite(LED_BUILTIN, HIGH);
} else {
digitalWrite(LED_BUILTIN, LOW);
}
}
#endif // ARDUINO_EXCLUDE_CODE
/* 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/micro/examples/micro_speech/main_functions.h"
// Arduino automatically calls the setup() and loop() functions in a sketch, so
// where other systems need their own main routine in this file, it can be left
// empty.
/* 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.
==============================================================================*/
#ifndef TENSORFLOW_LITE_MICRO_EXAMPLES_PERSON_DETECTION_ARDUINO_HM01B0_PLATFORM_H_
#define TENSORFLOW_LITE_MICRO_EXAMPLES_PERSON_DETECTION_ARDUINO_HM01B0_PLATFORM_H_
#if defined(ARDUINO) && defined(ARDUINO_SFE_EDGE)
#include "hm01b0_platform_edge.h"
#define HM01B0_PIN_TRIG 0 // unused
#define HM01B0_PIN_INT 0 // unused
#endif // defined(ARDUINO) && defined(ARDUINO_SFE_EDGE)
#endif // TENSORFLOW_LITE_MICRO_EXAMPLES_PERSON_DETECTION_ARDUINO_HM01B0_PLATFORM_H_
\ No newline at end of file
ifeq ($(TARGET),$(filter $(TARGET),arduino))
person_detection_SRCS += \
tensorflow/lite/micro/examples/person_detection/sparkfun_edge/image_provider.cc \
tensorflow/lite/micro/examples/person_detection/sparkfun_edge/detection_responder.cc \
tensorflow/lite/micro/examples/person_detection/himax_driver/HM01B0_debug.c \
tensorflow/lite/micro/examples/person_detection/himax_driver/HM01B0_optimized.c \
tensorflow/lite/micro/examples/person_detection/himax_driver/HM01B0.c
person_detection_HDRS += \
tensorflow/lite/micro/examples/person_detection/himax_driver/HM01B0_debug.h \
tensorflow/lite/micro/examples/person_detection/himax_driver/HM01B0_optimized.h \
tensorflow/lite/micro/examples/person_detection/himax_driver/HM01B0_RAW8_QVGA_8bits_lsb_5fps.h \
tensorflow/lite/micro/examples/person_detection/himax_driver/HM01B0_Walking1s_01.h \
tensorflow/lite/micro/examples/person_detection/himax_driver/HM01B0.h \
tensorflow/lite/micro/examples/person_detection/arduino/HM01B0_platform.h
endif
/* 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.
==============================================================================*/
#if defined(ARDUINO) && !defined(ARDUINO_ARDUINO_NANO33BLE)
#define ARDUINO_EXCLUDE_CODE
#endif // defined(ARDUINO) && !defined(ARDUINO_ARDUINO_NANO33BLE)
#ifndef ARDUINO_EXCLUDE_CODE
#include "tensorflow/lite/micro/examples/person_detection/detection_responder.h"
#include "Arduino.h"
// Flash the blue LED after each inference
void RespondToDetection(tflite::ErrorReporter* error_reporter,
int8_t person_score, int8_t no_person_score) {
static bool is_initialized = false;
if (!is_initialized) {
// Pins for the built-in RGB LEDs on the Arduino Nano 33 BLE Sense
pinMode(LEDR, OUTPUT);
pinMode(LEDG, OUTPUT);
pinMode(LEDB, OUTPUT);
is_initialized = true;
}
// Note: The RGB LEDs on the Arduino Nano 33 BLE
// Sense are on when the pin is LOW, off when HIGH.
// Switch the person/not person LEDs off
digitalWrite(LEDG, HIGH);
digitalWrite(LEDR, HIGH);
// Flash the blue LED after every inference.
digitalWrite(LEDB, LOW);
delay(100);
digitalWrite(LEDB, HIGH);
// Switch on the green LED when a person is detected,
// the red when no person is detected
if (person_score > no_person_score) {
digitalWrite(LEDG, LOW);
digitalWrite(LEDR, HIGH);
} else {
digitalWrite(LEDG, HIGH);
digitalWrite(LEDR, LOW);
}
TF_LITE_REPORT_ERROR(error_reporter, "Person score: %d No person score: %d",
person_score, no_person_score);
}
#endif // ARDUINO_EXCLUDE_CODE
/* 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/micro/examples/person_detection/image_provider.h"
/*
* The sample requires the following third-party libraries to be installed and
* configured:
*
* Arducam
* -------
* 1. Download https://github.com/ArduCAM/Arduino and copy its `ArduCAM`
* subdirectory into `Arduino/libraries`. Commit #e216049 has been tested
* with this code.
* 2. Edit `Arduino/libraries/ArduCAM/memorysaver.h` and ensure that
* "#define OV2640_MINI_2MP_PLUS" is not commented out. Ensure all other
* defines in the same section are commented out.
*
* JPEGDecoder
* -----------
* 1. Install "JPEGDecoder" 1.8.0 from the Arduino library manager.
* 2. Edit "Arduino/Libraries/JPEGDecoder/src/User_Config.h" and comment out
* "#define LOAD_SD_LIBRARY" and "#define LOAD_SDFAT_LIBRARY".
*/
#if defined(ARDUINO) && !defined(ARDUINO_ARDUINO_NANO33BLE)
#define ARDUINO_EXCLUDE_CODE
#endif // defined(ARDUINO) && !defined(ARDUINO_ARDUINO_NANO33BLE)
#ifndef ARDUINO_EXCLUDE_CODE
// Required by Arducam library
#include <SPI.h>
#include <Wire.h>
#include <memorysaver.h>
// Arducam library
#include <ArduCAM.h>
// JPEGDecoder library
#include <JPEGDecoder.h>
// Checks that the Arducam library has been correctly configured
#if !(defined OV2640_MINI_2MP_PLUS)
#error Please select the hardware platform and camera module in the Arduino/libraries/ArduCAM/memorysaver.h
#endif
// The size of our temporary buffer for holding
// JPEG data received from the Arducam module
#define MAX_JPEG_BYTES 4096
// The pin connected to the Arducam Chip Select
#define CS 7
// Camera library instance
ArduCAM myCAM(OV2640, CS);
// Temporary buffer for holding JPEG data from camera
uint8_t jpeg_buffer[MAX_JPEG_BYTES] = {0};
// Length of the JPEG data currently in the buffer
uint32_t jpeg_length = 0;
// Get the camera module ready
TfLiteStatus InitCamera(tflite::ErrorReporter* error_reporter) {
TF_LITE_REPORT_ERROR(error_reporter, "Attempting to start Arducam");
// Enable the Wire library
Wire.begin();
// Configure the CS pin
pinMode(CS, OUTPUT);
digitalWrite(CS, HIGH);
// initialize SPI
SPI.begin();
// Reset the CPLD
myCAM.write_reg(0x07, 0x80);
delay(100);
myCAM.write_reg(0x07, 0x00);
delay(100);
// Test whether we can communicate with Arducam via SPI
myCAM.write_reg(ARDUCHIP_TEST1, 0x55);
uint8_t test;
test = myCAM.read_reg(ARDUCHIP_TEST1);
if (test != 0x55) {
TF_LITE_REPORT_ERROR(error_reporter, "Can't communicate with Arducam");
delay(1000);
return kTfLiteError;
}
// Use JPEG capture mode, since it allows us to specify
// a resolution smaller than the full sensor frame
myCAM.set_format(JPEG);
myCAM.InitCAM();
// Specify the smallest possible resolution
myCAM.OV2640_set_JPEG_size(OV2640_160x120);
delay(100);
return kTfLiteOk;
}
// Begin the capture and wait for it to finish
TfLiteStatus PerformCapture(tflite::ErrorReporter* error_reporter) {
TF_LITE_REPORT_ERROR(error_reporter, "Starting capture");
// Make sure the buffer is emptied before each capture
myCAM.flush_fifo();
myCAM.clear_fifo_flag();
// Start capture
myCAM.start_capture();
// Wait for indication that it is done
while (!myCAM.get_bit(ARDUCHIP_TRIG, CAP_DONE_MASK)) {
}
TF_LITE_REPORT_ERROR(error_reporter, "Image captured");
delay(50);
// Clear the capture done flag
myCAM.clear_fifo_flag();
return kTfLiteOk;
}
// Read data from the camera module into a local buffer
TfLiteStatus ReadData(tflite::ErrorReporter* error_reporter) {
// This represents the total length of the JPEG data
jpeg_length = myCAM.read_fifo_length();
TF_LITE_REPORT_ERROR(error_reporter, "Reading %d bytes from Arducam",
jpeg_length);
// Ensure there's not too much data for our buffer
if (jpeg_length > MAX_JPEG_BYTES) {
TF_LITE_REPORT_ERROR(error_reporter, "Too many bytes in FIFO buffer (%d)",
MAX_JPEG_BYTES);
return kTfLiteError;
}
if (jpeg_length == 0) {
TF_LITE_REPORT_ERROR(error_reporter, "No data in Arducam FIFO buffer");
return kTfLiteError;
}
myCAM.CS_LOW();
myCAM.set_fifo_burst();
for (int index = 0; index < jpeg_length; index++) {
jpeg_buffer[index] = SPI.transfer(0x00);
}
delayMicroseconds(15);
TF_LITE_REPORT_ERROR(error_reporter, "Finished reading");
myCAM.CS_HIGH();
return kTfLiteOk;
}
// Decode the JPEG image, crop it, and convert it to greyscale
TfLiteStatus DecodeAndProcessImage(tflite::ErrorReporter* error_reporter,
int image_width, int image_height,
int8_t* image_data) {
TF_LITE_REPORT_ERROR(error_reporter,
"Decoding JPEG and converting to greyscale");
// Parse the JPEG headers. The image will be decoded as a sequence of Minimum
// Coded Units (MCUs), which are 16x8 blocks of pixels.
JpegDec.decodeArray(jpeg_buffer, jpeg_length);
// Crop the image by keeping a certain number of MCUs in each dimension
const int keep_x_mcus = image_width / JpegDec.MCUWidth;
const int keep_y_mcus = image_height / JpegDec.MCUHeight;
// Calculate how many MCUs we will throw away on the x axis
const int skip_x_mcus = JpegDec.MCUSPerRow - keep_x_mcus;
// Roughly center the crop by skipping half the throwaway MCUs at the
// beginning of each row
const int skip_start_x_mcus = skip_x_mcus / 2;
// Index where we will start throwing away MCUs after the data
const int skip_end_x_mcu_index = skip_start_x_mcus + keep_x_mcus;
// Same approach for the columns
const int skip_y_mcus = JpegDec.MCUSPerCol - keep_y_mcus;
const int skip_start_y_mcus = skip_y_mcus / 2;
const int skip_end_y_mcu_index = skip_start_y_mcus + keep_y_mcus;
// Pointer to the current pixel
uint16_t* pImg;
// Color of the current pixel
uint16_t color;
// Loop over the MCUs
while (JpegDec.read()) {
// Skip over the initial set of rows
if (JpegDec.MCUy < skip_start_y_mcus) {
continue;
}
// Skip if we're on a column that we don't want
if (JpegDec.MCUx < skip_start_x_mcus ||
JpegDec.MCUx >= skip_end_x_mcu_index) {
continue;
}
// Skip if we've got all the rows we want
if (JpegDec.MCUy >= skip_end_y_mcu_index) {
continue;
}
// Pointer to the current pixel
pImg = JpegDec.pImage;
// The x and y indexes of the current MCU, ignoring the MCUs we skip
int relative_mcu_x = JpegDec.MCUx - skip_start_x_mcus;
int relative_mcu_y = JpegDec.MCUy - skip_start_y_mcus;
// The coordinates of the top left of this MCU when applied to the output
// image
int x_origin = relative_mcu_x * JpegDec.MCUWidth;
int y_origin = relative_mcu_y * JpegDec.MCUHeight;
// Loop through the MCU's rows and columns
for (int mcu_row = 0; mcu_row < JpegDec.MCUHeight; mcu_row++) {
// The y coordinate of this pixel in the output index
int current_y = y_origin + mcu_row;
for (int mcu_col = 0; mcu_col < JpegDec.MCUWidth; mcu_col++) {
// Read the color of the pixel as 16-bit integer
color = *pImg++;
// Extract the color values (5 red bits, 6 green, 5 blue)
uint8_t r, g, b;
r = ((color & 0xF800) >> 11) * 8;
g = ((color & 0x07E0) >> 5) * 4;
b = ((color & 0x001F) >> 0) * 8;
// Convert to grayscale by calculating luminance
// See https://en.wikipedia.org/wiki/Grayscale for magic numbers
float gray_value = (0.2126 * r) + (0.7152 * g) + (0.0722 * b);
// Convert to signed 8-bit integer by subtracting 128.
gray_value -= 128;
// The x coordinate of this pixel in the output image
int current_x = x_origin + mcu_col;
// The index of this pixel in our flat output buffer
int index = (current_y * image_width) + current_x;
image_data[index] = static_cast<int8_t>(gray_value);
}
}
}
TF_LITE_REPORT_ERROR(error_reporter, "Image decoded and processed");
return kTfLiteOk;
}
// Get an image from the camera module
TfLiteStatus GetImage(tflite::ErrorReporter* error_reporter, int image_width,
int image_height, int channels, int8_t* image_data) {
static bool g_is_camera_initialized = false;
if (!g_is_camera_initialized) {
TfLiteStatus init_status = InitCamera(error_reporter);
if (init_status != kTfLiteOk) {
TF_LITE_REPORT_ERROR(error_reporter, "InitCamera failed");
return init_status;
}
g_is_camera_initialized = true;
}
TfLiteStatus capture_status = PerformCapture(error_reporter);
if (capture_status != kTfLiteOk) {
TF_LITE_REPORT_ERROR(error_reporter, "PerformCapture failed");
return capture_status;
}
TfLiteStatus read_data_status = ReadData(error_reporter);
if (read_data_status != kTfLiteOk) {
TF_LITE_REPORT_ERROR(error_reporter, "ReadData failed");
return read_data_status;
}
TfLiteStatus decode_status = DecodeAndProcessImage(
error_reporter, image_width, image_height, image_data);
if (decode_status != kTfLiteOk) {
TF_LITE_REPORT_ERROR(error_reporter, "DecodeAndProcessImage failed");
return decode_status;
}
return kTfLiteOk;
}
#endif // ARDUINO_EXCLUDE_CODE
/* 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/micro/examples/person_detection/main_functions.h"
// Arduino automatically calls the setup() and loop() functions in a sketch, so
// where other systems need their own main routine in this file, it can be left
// empty.
#!/usr/bin/env 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.
# ==============================================================================
#
# Installs the latest arduino-cli tool in /tmp/arduino-cli
set -e
cd /tmp
rm -rf arduino-cli*
curl -L -O "https://github.com/arduino/arduino-cli/releases/download/0.4.0/arduino-cli_0.4.0_Linux_64bit.tar.gz"
tar xzf arduino-cli_0.4.0_Linux_64bit.tar.gz
# To use with MacOS, replace the previous two lines with:
# curl -L -O "https://github.com/arduino/arduino-cli/releases/download/0.4.0/arduino-cli_0.4.0_MacOS_64bit.tar.gz"
# tar xzf arduino-cli_0.4.0_MacOS_64bit.tar.gz
/tmp/arduino-cli core update-index
/tmp/arduino-cli core install arduino:mbed
#!/usr/bin/env bash
# Copyright 2019 The TensorFlow Authors. All Rights Reserved.
# Copyright 2021 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.
......@@ -110,9 +110,6 @@ tensorflow/lite/micro/tools/ci_build/test_sparkfun.sh
echo "Running stm32f4 tests at `date`"
tensorflow/lite/micro/tools/ci_build/test_stm32f4.sh PRESUBMIT
echo "Running Arduino tests at `date`"
tensorflow/lite/micro/tools/ci_build/test_arduino.sh
echo "Running cortex_m_generic tests at `date`"
tensorflow/lite/micro/tools/ci_build/test_cortex_m_generic.sh
......
#!/usr/bin/env 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.
# ==============================================================================
#
# Creates the project file distributions for the TensorFlow Lite Micro test and
# example targets aimed at embedded platforms.
set -e
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
ROOT_DIR=${SCRIPT_DIR}/../../../../..
cd "${ROOT_DIR}"
source tensorflow/lite/micro/tools/ci_build/helper_functions.sh
readable_run make -f tensorflow/lite/micro/tools/make/Makefile clean
TARGET=arduino
OPTIMIZED_KERNEL_DIR=cmsis_nn
# TODO(b/143715361): parallel builds do not work with generated files right now.
readable_run make -f tensorflow/lite/micro/tools/make/Makefile \
TARGET=${TARGET} \
OPTIMIZED_KERNEL_DIR=${OPTIMIZED_KERNEL_DIR} \
generate_arduino_zip
readable_run tensorflow/lite/micro/tools/ci_build/install_arduino_cli.sh
readable_run tensorflow/lite/micro/tools/ci_build/test_arduino_library.sh \
tensorflow/lite/micro/tools/make/gen/arduino_x86_64_default/prj/tensorflow_lite.zip
#!/usr/bin/env 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.
# ==============================================================================
#
# Tests an individual Arduino library. Because libraries need to be installed
# globally, this can cause problems with previously-installed modules, so we
# recommend that you only run this within a VM.
set -e
ARDUINO_HOME_DIR=${HOME}/Arduino
ARDUINO_LIBRARIES_DIR=${ARDUINO_HOME_DIR}/libraries
ARDUINO_CLI_TOOL=/tmp/arduino-cli
# Necessary due to bug in arduino-cli that allows it to build files in pwd
TEMP_BUILD_DIR=/tmp/tflite-arduino-build
LIBRARY_ZIP=${1}
rm -rf ${TEMP_BUILD_DIR}
mkdir -p "${ARDUINO_HOME_DIR}/libraries"
mkdir -p ${TEMP_BUILD_DIR}
unzip -o -q ${LIBRARY_ZIP} -d "${ARDUINO_LIBRARIES_DIR}"
# Installs all dependencies for Arduino
InstallLibraryDependencies () {
# Required by magic_wand
${ARDUINO_CLI_TOOL} lib install Arduino_LSM9DS1@1.1.0
# Required by person_detection
${ARDUINO_CLI_TOOL} lib install JPEGDecoder@1.8.0
# Patch to ensure works with nano33ble. This hack (deleting the entire
# contents of the file) works with 1.8.0. If we bump the version, may need a
# different patch.
> ${ARDUINO_LIBRARIES_DIR}/JPEGDecoder/src/User_Config.h
# Arducam, not available through Arduino library manager. This specific
# commit is tested to work; if we bump the commit, we need to ensure that
# the defines in ArduCAM/memorysaver.h are correct.
wget -O /tmp/arducam-master.zip https://github.com/ArduCAM/Arduino/archive/e216049ba304048ec9bb29adfc2cc24c16f589b1/master.zip
unzip -o /tmp/arducam-master.zip -d /tmp
cp -r /tmp/Arduino-e216049ba304048ec9bb29adfc2cc24c16f589b1/ArduCAM "${ARDUINO_LIBRARIES_DIR}"
}
InstallLibraryDependencies
for f in ${ARDUINO_LIBRARIES_DIR}/tensorflow_lite/examples/*/*.ino; do
${ARDUINO_CLI_TOOL} compile --build-cache-path ${TEMP_BUILD_DIR} --build-path ${TEMP_BUILD_DIR} --fqbn arduino:mbed:nano33ble $f
done
rm -rf ${ARDUINO_LIBRARIES_DIR}
rm -rf ${TEMP_BUILD_DIR}
......@@ -386,9 +386,7 @@ MICROLITE_CC_SRCS := $(filter-out $(MICROLITE_BENCHMARK_SRCS), $(MICROLITE_CC_SR
# For project generation v1, the headers that are common to all targets need to
# have a third_party prefix. Other third_party headers (e.g. CMSIS) do not have
# this requirement and are added to THIRD_PARTY_CC_HDRS with full path from the
# tensorflow root. This inconsistency may also be the reason why (for
# example) these different third party libraries are fund in different paths in
# the Arduino output tree.
# tensorflow root.
#
# The convention with the (under development) project generation v2 is for all
# third party paths to be relative to the root of the git repository. We are
......@@ -429,9 +427,6 @@ KEIL_PROJECT_FILES := \
README_KEIL.md \
keil_project.uvprojx
ARDUINO_PROJECT_FILES := \
library.properties
ESP_PROJECT_FILES := \
README_ESP.md \
CMakeLists.txt \
......@@ -440,9 +435,6 @@ ESP_PROJECT_FILES := \
ALL_PROJECT_TARGETS :=
ARDUINO_LIBRARY_TARGETS :=
ARDUINO_LIBRARY_ZIPS :=
# For some invocations of the makefile, it is useful to avoid downloads. This
# can be achieved by explicitly passing in DISABLE_DOWNLOADS=true on the command
# line. Note that for target-specific downloads (e.g. CMSIS) there will need to
......@@ -481,13 +473,8 @@ endif
# The target-specific makefile must have a name that is exactly
# TARGET_makefile.inc and is only needed for cross-compilation (i.e. when TARGET
# is different from the HOST_OS).
# There are also some other targets like arduino and CHRE that are also special
# in that they do no have a <target>_makefile but are still used to create a
# directory for the generated artifacts. We are using a workaround right now and
# will be separating the project generation from the Makefile in the future.
TARGETS_WITHOUT_MAKEFILES := \
$(HOST_OS) \
arduino
$(HOST_OS)
# This specific string needs to be outputted for a test to be recognized as
# having passed.
......@@ -718,11 +705,6 @@ build: $(MICROLITE_BUILD_TARGETS)
generate_projects: $(ALL_PROJECT_TARGETS)
ARDUINO_PROJECT_TARGETS := $(foreach TARGET,$(ALL_PROJECT_TARGETS),$(if $(findstring _arduino,$(TARGET)),$(TARGET),))
generate_arduino_zip: $(ARDUINO_PROJECT_TARGETS) $(ARDUINO_LIBRARY_ZIPS)
python tensorflow/lite/micro/tools/make/merge_arduino_zips.py $(PRJDIR)/tensorflow_lite.zip $(ARDUINO_LIBRARY_ZIPS)
list_library_sources:
@echo $(MICROLITE_CC_SRCS) $(MICROLITE_CC_KERNEL_SRCS)
......
# 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.
# ==============================================================================
"""Moves source files to match Arduino library conventions."""
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
import argparse
import glob
import os
import six
def rename_example_subfolder_files(library_dir):
"""Moves source files in example subfolders to equivalents at root."""
patterns = ['*.h', '*.cpp', '*.c']
for pattern in patterns:
search_path = os.path.join(library_dir, 'examples/*/*', pattern)
for source_file_path in glob.glob(search_path):
source_file_dir = os.path.dirname(source_file_path)
source_file_base = os.path.basename(source_file_path)
new_source_file_path = source_file_dir + '_' + source_file_base
os.rename(source_file_path, new_source_file_path)
def move_person_data(library_dir):
"""Moves the downloaded person model into the examples folder."""
old_person_data_path = os.path.join(
library_dir, 'src/tensorflow/lite/micro/tools/make/downloads/' +
'person_model_int8/person_detect_model_data.cpp')
new_person_data_path = os.path.join(
library_dir, 'examples/person_detection/person_detect_model_data.cpp')
if os.path.exists(old_person_data_path):
os.rename(old_person_data_path, new_person_data_path)
# Update include.
with open(new_person_data_path, 'r') as source_file:
file_contents = source_file.read()
file_contents = file_contents.replace(
six.ensure_str('#include "tensorflow/lite/micro/examples/' +
'person_detection/person_detect_model_data.h"'),
'#include "person_detect_model_data.h"')
with open(new_person_data_path, 'w') as source_file:
source_file.write(file_contents)
def rename_example_main_inos(library_dir):
"""Makes sure the .ino sketch files match the example name."""
search_path = os.path.join(library_dir, 'examples/*', 'main.ino')
for ino_path in glob.glob(search_path):
example_path = os.path.dirname(ino_path)
example_name = os.path.basename(example_path)
new_ino_path = os.path.join(example_path, example_name + '.ino')
os.rename(ino_path, new_ino_path)
def main(unparsed_args):
"""Control the rewriting of source files."""
library_dir = unparsed_args[0]
rename_example_subfolder_files(library_dir)
rename_example_main_inos(library_dir)
move_person_data(library_dir)
def parse_args():
"""Converts the raw arguments into accessible flags."""
parser = argparse.ArgumentParser()
_, unparsed_args = parser.parse_known_args()
main(unparsed_args)
if __name__ == '__main__':
parse_args()
#!/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
LIBRARY_DIR=${TEST_TMPDIR}/library
mkdir -p ${LIBRARY_DIR}
EXAMPLES_SUBDIR_CPP=${LIBRARY_DIR}/examples/something/foo/fish.cpp
mkdir -p `dirname ${EXAMPLES_SUBDIR_CPP}`
touch ${EXAMPLES_SUBDIR_CPP}
EXAMPLES_SUBDIR_HEADER=${LIBRARY_DIR}/examples/something/foo/fish.h
mkdir -p `dirname ${EXAMPLES_SUBDIR_HEADER}`
touch ${EXAMPLES_SUBDIR_HEADER}
TENSORFLOW_SRC_DIR=${LIBRARY_DIR}/src/
PERSON_DATA_FILE=${TENSORFLOW_SRC_DIR}tensorflow/lite/micro/tools/make/downloads/person_model_int8/person_detect_model_data.cpp
mkdir -p `dirname ${PERSON_DATA_FILE}`
echo '#include "tensorflow/lite/micro/examples/person_detection/person_detect_model_data.h"' > ${PERSON_DATA_FILE}
mkdir -p ${LIBRARY_DIR}/examples/person_detection
EXAMPLE_INO_FILE=${LIBRARY_DIR}/examples/something/main.ino
mkdir -p `dirname ${EXAMPLE_INO_FILE}`
touch ${EXAMPLE_INO_FILE}
${TEST_SRCDIR}/tensorflow/lite/micro/tools/make/fix_arduino_subfolders \
${LIBRARY_DIR}
EXPECTED_EXAMPLES_SUBDIR_CPP=${LIBRARY_DIR}/examples/something/foo_fish.cpp
if [[ ! -f ${EXPECTED_EXAMPLES_SUBDIR_CPP} ]]; then
echo "${EXPECTED_EXAMPLES_SUBDIR_CPP} wasn't created."
exit 1
fi
EXPECTED_EXAMPLES_SUBDIR_HEADER=${LIBRARY_DIR}/examples/something/foo_fish.h
if [[ ! -f ${EXPECTED_EXAMPLES_SUBDIR_HEADER} ]]; then
echo "${EXPECTED_EXAMPLES_SUBDIR_HEADER} wasn't created."
exit 1
fi
EXPECTED_PERSON_DATA_FILE=${LIBRARY_DIR}/examples/person_detection/person_detect_model_data.cpp
if [[ ! -f ${EXPECTED_PERSON_DATA_FILE} ]]; then
echo "${EXPECTED_PERSON_DATA_FILE} wasn't created."
exit 1
fi
if ! grep -q '#include "person_detect_model_data.h"' ${EXPECTED_PERSON_DATA_FILE}; then
echo "ERROR: No person_detect_model_data.h include found in output '${EXPECTED_PERSON_DATA_FILE}'"
exit 1
fi
EXPECTED_EXAMPLE_INO_FILE=${LIBRARY_DIR}/examples/something/something.ino
if [[ ! -f ${EXPECTED_EXAMPLE_INO_FILE} ]]; then
echo "${EXPECTED_EXAMPLE_INO_FILE} wasn't created."
exit 1
fi
echo
echo "SUCCESS: fix_arduino_subfolders test PASSED"
......@@ -220,150 +220,6 @@ endif
endif
endef
# Creates a set of rules to build a standalone Arduino project for an
# executable, including all of the source and header files required in a
# separate folder and a simple makefile.
# Arguments are:
# 1 - Project file template names.
# 2 - Name of executable.
# 3 - List of C/C++ source files needed to build the target.
# 4 - List of C/C++ header files needed to build the target.
# 5 - Linker flags required.
# 6 - C++ compilation flags needed.
# 7 - C compilation flags needed.
# Calling eval on the output will create a <Name>_makefile target that you
# can invoke to create the standalone project.
define generate_arduino_project
$(PRJDIR)$(2)/arduino/examples/%.c: tensorflow/lite/micro/examples/%.c
@mkdir -p $$(dir $$@)
@python tensorflow/lite/micro/tools/make/transform_source.py \
--platform=arduino \
--is_example_source \
--source_path="$$<" \
--third_party_headers="$(4)" < $$< > $$@
$(PRJDIR)$(2)/arduino/examples/%.cpp: tensorflow/lite/micro/examples/%.cc
@mkdir -p $$(dir $$@)
@python tensorflow/lite/micro/tools/make/transform_source.py \
--platform=arduino \
--is_example_source \
--source_path="$$<" \
--third_party_headers="$(4)" < $$< > $$@
$(PRJDIR)$(2)/arduino/examples/%.h: tensorflow/lite/micro/examples/%.h
@mkdir -p $$(dir $$@)
@python tensorflow/lite/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/micro/examples/%/main_functions.cc
@mkdir -p $$(dir $$@)
@python tensorflow/lite/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/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/micro/tools/make/transform_source.py \
--platform=arduino \
--third_party_headers="$(4)" < $$< > $$@
$(PRJDIR)$(2)/arduino/LICENSE: LICENSE
@mkdir -p $$(dir $$@)
@cp $$< $$@
$(PRJDIR)$(2)/arduino/src/%: % third_party_downloads
@mkdir -p $$(dir $$@)
@python tensorflow/lite/micro/tools/make/transform_source.py \
--platform=arduino \
--third_party_headers="$(4)" < $$< > $$@
$(PRJDIR)$(2)/arduino/src/third_party/%: tensorflow/lite/micro/tools/make/downloads/% third_party_downloads
@mkdir -p $$(dir $$@)
@python tensorflow/lite/micro/tools/make/transform_source.py \
--platform=arduino \
--third_party_headers="$(4)" < $$< > $$@
$(PRJDIR)$(2)/arduino/src/third_party/%.cpp: tensorflow/lite/micro/tools/make/downloads/%.cc third_party_downloads
@mkdir -p $$(dir $$@)
@python tensorflow/lite/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/micro/tools/make/downloads/flatbuffers/include/flatbuffers/base.h third_party_downloads
@mkdir -p $$(dir $$@)
@python tensorflow/lite/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/micro/tools/make/downloads/kissfft/kiss_fft.h third_party_downloads
@mkdir -p $$(dir $$@)
@python tensorflow/lite/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' > $$@
$(PRJDIR)$(2)/arduino/%: tensorflow/lite/micro/tools/make/templates/%
@mkdir -p $$(dir $$@)
@sed -E 's#\%\{SRCS\}\%#$(3)#g' $$< | \
sed -E 's#\%\{EXECUTABLE\}\%#$(2)#g' | \
sed -E 's#\%\{LINKER_FLAGS\}\%#$(5)#g' | \
sed -E 's#\%\{CXX_FLAGS\}\%#$(6)#g' | \
sed -E 's#\%\{CC_FLAGS\}\%#$(7)#g' > $$@
$(PRJDIR)$(2)/arduino/examples/$(2)/$(2).ino: tensorflow/lite/micro/tools/make/templates/arduino_example.ino
@mkdir -p $$(dir $$@)
@cp $$< $$@
$(PRJDIR)$(2)/arduino/src/TensorFlowLite.h: tensorflow/lite/micro/tools/make/templates/TensorFlowLite.h
@mkdir -p $$(dir $$@)
@cp $$< $$@
# This would be cleaner if we broke up the list of dependencies into variables,
# but these get hard to define with the evaluation approach used to define make
# functions.
generate_$(2)_arduino_project: \
$(addprefix $(PRJDIR)$(2)/arduino/, \
$(patsubst tensorflow/%,src/tensorflow/%,\
$(patsubst examples/%/main_functions.cpp,examples/%/main.ino,\
$(patsubst examples/%_test.cpp,examples/%_test.ino,\
$(patsubst tensorflow/lite/micro/examples/%,examples/%,\
$(patsubst third_party/%,src/third_party/%,\
$(patsubst %.cc,%.cpp,$(3)))))))) \
$(addprefix $(PRJDIR)$(2)/arduino/, \
$(patsubst tensorflow/%,src/tensorflow/%,\
$(patsubst tensorflow/lite/micro/examples/%,examples/%,\
$(patsubst third_party/%,src/third_party/%,$(4))))) \
$(addprefix $(PRJDIR)$(2)/arduino/,$(1)) \
$(PRJDIR)$(2)/arduino/src/TensorFlowLite.h
generate_$(2)_arduino_library_zip: generate_$(2)_arduino_project
cp -r $(PRJDIR)$(2)/arduino $(PRJDIR)$(2)/tensorflow_lite
python tensorflow/lite/micro/tools/make/fix_arduino_subfolders.py $(PRJDIR)$(2)/tensorflow_lite
@cd $(PRJDIR)$(2) && zip -q -r tensorflow_lite.zip tensorflow_lite
ALL_PROJECT_TARGETS += $(if $(findstring _test,$(2)),,generate_$(2)_arduino_library_zip)
ARDUINO_LIBRARY_ZIPS += $(if $(findstring _mock,$(2)),,$(if $(findstring _test,$(2)),,$(PRJDIR)$(2)/tensorflow_lite.zip))
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.
......@@ -462,9 +318,6 @@ $(call generate_ceva_bx1_project,make,$(MAKE_PROJECT_FILES) $($(1)_MAKE_PROJECT_
$(call generate_ceva_sp500_project,make,$(MAKE_PROJECT_FILES) $($(1)_MAKE_PROJECT_FILES),$(1),$(MICROLITE_CC_SRCS) $(THIRD_PARTY_CC_SRCS) $(MICROLITE_CC_KERNEL_SRCS) $(2),$(MICROLITE_CC_HDRS) $(THIRD_PARTY_CC_HDRS) $(MICROLITE_TEST_HDRS) $(3),$(LDFLAGS) $(GENERATED_PROJECT_LIBS),$(CXXFLAGS) $(GENERATED_PROJECT_INCLUDES), $(CCFLAGS) $(GENERATED_PROJECT_INCLUDES))
$(call generate_project,mbed,$(MBED_PROJECT_FILES) $($(1)_MBED_PROJECT_FILES),$(1),$(MICROLITE_CC_SRCS) $(THIRD_PARTY_CC_SRCS) $(MICROLITE_CC_KERNEL_SRCS) $(2),$(MICROLITE_CC_HDRS) $(THIRD_PARTY_CC_HDRS) $(MICROLITE_TEST_HDRS) $(3),$(MICROLITE_LIBS),$(CXXFLAGS),$(CCFLAGS),$(TARGET_TOOLCHAIN_ROOT),$(TARGET_TOOLCHAIN_PREFIX))
$(call generate_project,keil,$(KEIL_PROJECT_FILES) $($(1)_KEIL_PROJECT_FILES),$(1),$(MICROLITE_CC_SRCS) $(THIRD_PARTY_CC_SRCS) $(MICROLITE_CC_KERNEL_SRCS) $(2),$(MICROLITE_CC_HDRS) $(THIRD_PARTY_CC_HDRS) $(MICROLITE_TEST_HDRS) $(3),$(MICROLITE_LIBS),$(CXXFLAGS),$(CCFLAGS),$(TARGET_TOOLCHAIN_ROOT),$(TARGET_TOOLCHAIN_PREFIX))
ifeq (,$(findstring _benchmark,$(1)))
$(call generate_arduino_project,$(ARDUINO_PROJECT_FILES) $($(1)_ARDUINO_PROJECT_FILES),$(1),$(MICROLITE_CC_SRCS) $(THIRD_PARTY_CC_SRCS) $(MICROLITE_CC_KERNEL_SRCS) $(2),$(MICROLITE_CC_HDRS) $(THIRD_PARTY_CC_HDRS) $(MICROLITE_TEST_HDRS) $(3),$(MICROLITE_LIBS),$(CXXFLAGS),$(CCFLAGS))
endif
$(call generate_esp_project,$(ESP_PROJECT_FILES) $($(1)_ESP_PROJECT_FILES),$(1),$(MICROLITE_CC_SRCS) $(THIRD_PARTY_CC_SRCS) $(MICROLITE_CC_KERNEL_SRCS),$(MICROLITE_CC_HDRS) $(THIRD_PARTY_CC_HDRS) $(MICROLITE_TEST_HDRS),$(2),$(3),$(MICROLITE_LIBS),$(CXXFLAGS),$(CCFLAGS),$(PROJECT_INCLUDES))
endef
......
# 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 to help Arduino."""
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
import argparse
import shutil
import tempfile
import zipfile
def main(unparsed_args):
"""Merges multiple Arduino zipfiles into a single result."""
output_zip_path = unparsed_args[0]
input_zip_paths = unparsed_args[1::]
working_dir = tempfile.mkdtemp()
for input_zip_path in input_zip_paths:
with zipfile.ZipFile(input_zip_path, 'r') as input_zip:
input_zip.extractall(path=working_dir)
output_path_without_zip = output_zip_path.replace('.zip', '')
shutil.make_archive(output_path_without_zip, 'zip', working_dir)
def parse_args():
"""Converts the raw arguments into accessible flags."""
parser = argparse.ArgumentParser()
_, unparsed_args = parser.parse_known_args()
main(unparsed_args)
if __name__ == '__main__':
parse_args()
#!/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
INPUT1_DIR=${TEST_TMPDIR}/input1
mkdir -p ${INPUT1_DIR}
touch ${INPUT1_DIR}/a.txt
touch ${INPUT1_DIR}/b.txt
mkdir ${INPUT1_DIR}/sub1/
touch ${INPUT1_DIR}/sub1/c.txt
mkdir ${INPUT1_DIR}/sub2/
touch ${INPUT1_DIR}/sub2/d.txt
INPUT1_ZIP=${TEST_TMPDIR}/input1.zip
pushd ${INPUT1_DIR}
zip -q -r ${INPUT1_ZIP} *
popd
INPUT2_DIR=${TEST_TMPDIR}/input2
mkdir -p ${INPUT2_DIR}
touch ${INPUT2_DIR}/a.txt
touch ${INPUT2_DIR}/e.txt
mkdir ${INPUT2_DIR}/sub1/
touch ${INPUT2_DIR}/sub1/f.txt
mkdir ${INPUT2_DIR}/sub3/
touch ${INPUT2_DIR}/sub3/g.txt
INPUT2_ZIP=${TEST_TMPDIR}/input2.zip
pushd ${INPUT2_DIR}
zip -q -r ${INPUT2_ZIP} *
popd
OUTPUT_DIR=${TEST_TMPDIR}/output/
OUTPUT_ZIP=${OUTPUT_DIR}/output.zip
${TEST_SRCDIR}/tensorflow/lite/micro/tools/make/merge_arduino_zips \
${OUTPUT_ZIP} ${INPUT1_ZIP} ${INPUT2_ZIP}
if [[ ! -f ${OUTPUT_ZIP} ]]; then
echo "${OUTPUT_ZIP} wasn't created."
fi
pushd ${OUTPUT_DIR}
unzip -q ${OUTPUT_ZIP}
popd
for EXPECTED_FILE in a.txt b.txt sub1/c.txt sub2/d.txt e.txt sub1/f.txt sub3/g.txt
do
if [[ ! -f ${OUTPUT_DIR}/${EXPECTED_FILE} ]]; then
echo "${OUTPUT_DIR}/${EXPECTED_FILE} wasn't created."
exit 1
fi
done
echo
echo "SUCCESS: merge_arduino_zips test PASSED"
/* 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.
==============================================================================*/
#ifndef TENSORFLOW_LITE_MICRO_TOOLS_MAKE_TEMPLATES_TENSORFLOWLITE_H_
#define TENSORFLOW_LITE_MICRO_TOOLS_MAKE_TEMPLATES_TENSORFLOWLITE_H_
// This header is deliberately empty, and is only present because including it
// in a .ino sketch forces the Arduino toolchain to build the rest of the
// library.
#endif // TENSORFLOW_LITE_MICRO_TOOLS_MAKE_TEMPLATES_TENSORFLOWLITE_H_
/* 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.
==============================================================================*/
// Template sketch that calls into the detailed TensorFlow Lite example code.
// Include an empty header so that Arduino knows to build the TF Lite library.
#include <TensorFlowLite.h>
// TensorFlow Lite defines its own main function
extern int tflite_micro_main(int argc, char* argv[]);
// So the example works with or without a serial connection,
// wait to see one for 5 seconds before giving up.
void waitForSerial() {
int start = millis();
while(!Serial) {
int diff = millis() - start;
if (diff > 5000) break;
}
}
// Runs once when the program starts
void setup() {
waitForSerial();
tflite_micro_main(0, NULL);
}
// Leave the loop unused
void loop() {
}
\ No newline at end of file
name=Arduino_TensorFlowLite
version=2.4.0-ALPHA
author=TensorFlow Authors
maintainer=Pete Warden <petewarden@google.com>
sentence=Allows you to run machine learning models locally on your device.
paragraph=This library runs TensorFlow machine learning models on microcontrollers, allowing you to build AI/ML applications powered by deep learning and neural networks. With the included examples, you can recognize speech, detect people using a camera, and recognise "magic wand" gestures using an accelerometer. The examples work best with the Arduino Nano 33 BLE Sense board, which has a microphone and accelerometer.
category=Data Processing
url=https://www.tensorflow.org/lite/microcontrollers/overview
ldflags=-lm
includes=TensorFlowLite.h
precompiled=full
# 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 to help Arduino."""
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
import argparse
import re
import sys
import six
def replace_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_main(line):
"""Updates any occurrences 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 compatibility\n'
+ input_text)
if not re.search(r'void loop\(\) \{', input_text):
raise Exception(
'All examples must have a loop() function for Arduino compatibility')
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_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/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 main(unused_args, flags):
"""Transforms the input source file to work when exported to Arduino."""
input_file_lines = sys.stdin.read().split('\n')
supplied_headers_list = six.ensure_str(flags.third_party_headers).split(' ')
output_lines = []
for line in input_file_lines:
line = replace_includes(line, supplied_headers_list)
if flags.is_example_ino or flags.is_example_source:
line = replace_example_includes(line, flags.source_path)
else:
line = replace_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)
sys.stdout.write(output_text)
def parse_args():
"""Converts the raw arguments into accessible flags."""
parser = argparse.ArgumentParser()
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()
#!/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_REGULAR_FILE=${TEST_TMPDIR}/input_regular.cc
cat << EOF > ${INPUT_REGULAR_FILE}
#include <stdio.h>
#include "foo.h"
#include "bar/fish.h"
#include "baz.h"
#ifndef __ANDROID__
#include "something.h"
#endif // __ANDROID__
int main(int argc, char** argv) {
fprintf(stderr, "Hello World!\n");
return 0;
}
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/micro/tools/make/transform_source \
--platform=arduino \
--third_party_headers="${THIRD_PARTY_HEADERS}" \
< ${INPUT_REGULAR_FILE} \
> ${OUTPUT_REGULAR_FILE}
if ! grep -q '#include <stdio.h>' ${OUTPUT_REGULAR_FILE}; then
echo "ERROR: No stdio.h include found in output '${OUTPUT_REGULAR_FILE}'"
exit 1
fi
if ! grep -q '#include "subdir/foo.h"' ${OUTPUT_REGULAR_FILE}; then
echo "ERROR: No subdir/foo.h include found in output '${OUTPUT_REGULAR_FILE}'"
exit 1
fi
if ! grep -q '#include "subdir_2/include/bar/fish.h"' ${OUTPUT_REGULAR_FILE}; then
echo "ERROR: No subdir_2/include/bar/fish.h include found in output '${OUTPUT_REGULAR_FILE}'"
exit 1
fi
if ! grep -q '#include "baz.h"' ${OUTPUT_REGULAR_FILE}; then
echo "ERROR: No baz.h include found in output '${OUTPUT_REGULAR_FILE}'"
exit 1
fi
if ! grep -q '#include "subdir_3/something.h"' ${OUTPUT_REGULAR_FILE}; then
echo "ERROR: No subdir_3/something.h include found in output '${OUTPUT_REGULAR_FILE}'"
exit 1
fi
if ! grep -q 'int tflite_micro_main(' ${OUTPUT_REGULAR_FILE}; then
echo "ERROR: No int tflite_micro_main() definition found in output '${OUTPUT_REGULAR_FILE}'"
exit 1
fi
INPUT_EXAMPLE_INO_FILE=${TEST_TMPDIR}/input_example_ino.cc
cat << EOF > ${INPUT_EXAMPLE_INO_FILE}
#include <stdio.h>
#include "foo.h"
#include "tensorflow/lite/micro/examples/something/foo/fish.h"
#include "baz.h"
void setup() {
}
void loop() {
}
EOF
OUTPUT_EXAMPLE_INO_FILE=${TEST_TMPDIR}/output_regular.cc
${TEST_SRCDIR}/tensorflow/lite/micro/tools/make/transform_source \
--platform=arduino \
--third_party_headers="${THIRD_PARTY_HEADERS}" \
--is_example_ino \
< ${INPUT_EXAMPLE_INO_FILE} \
> ${OUTPUT_EXAMPLE_INO_FILE}
if ! grep -q '#include <TensorFlowLite.h>' ${OUTPUT_EXAMPLE_INO_FILE}; then
echo "ERROR: No TensorFlowLite.h include found in output '${OUTPUT_EXAMPLE_INO_FILE}'"
exit 1
fi
if ! grep -q '#include "foo_fish.h"' ${OUTPUT_EXAMPLE_INO_FILE}; then
echo "ERROR: No foo/fish.h include found in output '${OUTPUT_EXAMPLE_INO_FILE}'"
exit 1
fi
INPUT_EXAMPLE_SOURCE_FILE=${TEST_TMPDIR}/input_example_source.h
cat << EOF > ${INPUT_EXAMPLE_SOURCE_FILE}
#include <stdio.h>
#include "foo.h"
#include "foo/fish.h"
#include "baz.h"
#include "tensorflow/lite/micro/examples/something/cube/tri.h"
void setup() {
}
void loop() {
}
int main(int argc, char* argv[]) {
setup();
while (true) {
loop();
}
}
EOF
OUTPUT_EXAMPLE_SOURCE_FILE=${TEST_TMPDIR}/output_example_source.h
${TEST_SRCDIR}/tensorflow/lite/micro/tools/make/transform_source \
--platform=arduino \
--third_party_headers="${THIRD_PARTY_HEADERS}" \
--is_example_source \
--source_path="foo/input_example_source.h" \
< ${INPUT_EXAMPLE_SOURCE_FILE} \
> ${OUTPUT_EXAMPLE_SOURCE_FILE}
if ! grep -q '#include "foo/fish.h"' ${OUTPUT_EXAMPLE_SOURCE_FILE}; then
echo "ERROR: No foo/fish.h include found in output '${OUTPUT_EXAMPLE_SOURCE_FILE}'"
exit 1
fi
if ! grep -q '#include "cube_tri.h"' ${OUTPUT_EXAMPLE_SOURCE_FILE}; then
echo "ERROR: No cube_tri.h include found in output '${OUTPUT_EXAMPLE_SOURCE_FILE}'"
exit 1
fi
echo
echo "SUCCESS: transform_arduino_source test PASSED"
# Lint as: python2, python3
# Copyright 2019 The TensorFlow Authors. All Rights Reserved.
# Copyright 2021 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.
......@@ -15,7 +15,7 @@
# ==============================================================================
"""Resolves non-system C/C++ includes to their full paths.
Used to generate Arduino and ESP-IDF examples.
Used to generate ESP-IDF examples.
"""
from __future__ import absolute_import
......@@ -32,62 +32,6 @@ import six
EXAMPLE_DIR_PATH = 'tensorflow/lite/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 occurrences 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 compatibility\n'
+ input_text)
if not re.search(r'void loop\(\) \{', input_text):
raise Exception(
'All examples must have a loop() function for Arduino compatibility')
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_arduino_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/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
......@@ -106,35 +50,6 @@ def replace_esp_example_includes(line, source_path):
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_arduino_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.
......@@ -160,9 +75,7 @@ def main(unused_args, flags):
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':
if flags.platform == 'esp':
output_text = transform_esp_sources(input_file_lines, flags)
sys.stdout.write(output_text)
......@@ -172,7 +85,7 @@ def parse_args():
"""Converts the raw arguments into accessible flags."""
parser = argparse.ArgumentParser()
parser.add_argument('--platform',
choices=['arduino', 'esp'],
choices=['esp'],
required=True,
help='Target platform.')
parser.add_argument('--third_party_headers',
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册