/* The Clear BSD License * * Copyright (c) 2025 EdgeImpulse Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted (subject to the limitations in the disclaimer * below) provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * * Neither the name of the copyright holder nor the names of its * contributors may be used to endorse or promote products derived from this * software without specific prior written permission. * * NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED BY * THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #ifndef _EI_CLASSIFIER_PORTING_H_ #define _EI_CLASSIFIER_PORTING_H_ #include #include #include "edge-impulse-sdk/dsp/returntypes.h" #if defined(__cplusplus) && EI_C_LINKAGE == 1 extern "C" { #endif // defined(__cplusplus) /* Private functions ------------------------------------------------------- */ EI_IMPULSE_ERROR ei_run_impulse_check_canceled(); void ei_serial_set_baudrate(int baudrate); /* Public functions -------------------------------------------------------- */ /** * @defgroup ei_user_functions User-defined functions * * These functions are required to be implemented by the user for the target platform. * See [this porting guide](https://docs.edgeimpulse.com/docs/edge-ai-hardware/porting-guide) for more information. They are declared internally in the Edge Impulse * C++ SDK library, and they must be defined by the user. * * **Source**: [porting/ei_classifier_porting.h](https://github.com/edgeimpulse/inferencing-sdk-cpp/blob/master/porting/ei_classifier_porting.h) * * **Examples**: * The following examples demonstrate possible implementations of this function for * various platforms. Note the `__attribute__((weak))` in most of the definitions, which * means that a user could override the implementation elsewhere in the program: * * [Arduino classifier porting](https://github.com/edgeimpulse/inferencing-sdk-cpp/blob/master/porting/arduino/ei_classifier_porting.cpp) * * [mbed classifier porting](https://github.com/edgeimpulse/inferencing-sdk-cpp/blob/master/porting/mbed/ei_classifier_porting.cpp) * * [POSIX classifier porting](https://github.com/edgeimpulse/inferencing-sdk-cpp/blob/master/porting/posix/ei_classifier_porting.cpp) * * [Silicon Labs classifier porting](https://github.com/edgeimpulse/inferencing-sdk-cpp/blob/master/porting/silabs/ei_classifier_porting.cpp) * * [STM32 classifier porting](https://github.com/edgeimpulse/inferencing-sdk-cpp/blob/master/porting/stm32-cubeai/ei_classifier_porting.cpp) * * [TI classifier porting](https://github.com/edgeimpulse/inferencing-sdk-cpp/blob/master/porting/ti/debug_log.cpp) * * [Zephyr classifier porting](https://github.com/edgeimpulse/inferencing-sdk-cpp/blob/master/porting/zephyr/ei_classifier_porting.cpp) * * @addtogroup ei_user_functions * @{ */ /** * Cancelable sleep, can be triggered with signal from other thread */ /** * @brief Cancellable sleep, can be triggered with signal from other thread * * Allow the processor or thread to sleep or block for the given time. * * @param[in] time_ms Time in milliseconds to sleep * * @return `EI_IMPULSE_OK` if successful, error code otherwise */ EI_IMPULSE_ERROR ei_sleep(int32_t time_ms); /** * Read the millisecond timer */ /** * @brief Read the millisecond timer * * This function should return the number of milliseconds that have passed since the * start of the program. If you do not need to determine the run times for DSP and * inference blocks, you can simply return 0 from this function. Your impulse will still * work correctly without timing information. * * @return The number of milliseconds that have passed since the start of the program */ uint64_t ei_read_timer_ms(); /** * @brief Read the microsecond timer * * This function should return the number of milliseconds that have passed since the * start of the program. If you do not need to determine the run times for DSP and * inference blocks, you can simply return 0 from this function. Your impulse will still * work correctly without timing information. * * @return The number of microseconds that have passed since the start of the program */ uint64_t ei_read_timer_us(); /** * @brief Send a single character to the serial port * * @param[in] c The chararater to send */ void ei_putchar(char c); /** * @brief Read a single character from the serial port * * @return The character read from the serial port */ char ei_getchar(void); /** * @brief Print wrapper around printf() * * `ei_printf()` is declared internally to the Edge Impulse SDK library so that debugging * information (e.g. during inference) can be printed out. However, the function must be * defined by the user, as printing methods can change depending on the platform and use * case. For example, you may want to print debugging information to stdout in Linux or * over a UART serial port on a microcontroller. * * @param[in] format Pointer to a character array or string that should be printed * @param[in] ... Other optional arguments may be passed as necessary (e.g. handle to a * UART object). Note that any calls to `ei_printf()` from within the * *edge-impulse-sdk* library do not pass anything other than the `format` argument. */ __attribute__ ((format (printf, 1, 2))) void ei_printf(const char *format, ...); /** * @brief Used to print floating point numbers * * Some platforms cannot handle directly printing floating point numbers (e.g. to a * console or over a serial port). If your platform cannot directly print floats, * provide an implementation of this function to print them as needed (for example, * construct a string containing scientific notation with integers and call * `ei_printf()`). * * If your platform can print floating point values, the easiest implementation of this * function is as follows: * * ``` * __attribute__((weak)) void ei_printf_float(float f) { * printf("%f", f); * } * ``` * * @param[in] f The floating point number to print */ void ei_printf_float(float f); /** * @brief Wrapper around malloc * * This function should allocate `size` bytes and return a pointer to the allocated * memory. In bare-metal implementations, it can simply be a wrapper for `malloc()`. For * example: * * ``` * __attribute__((weak)) void *ei_malloc(size_t size) { * return malloc(size); * } * ``` * * If you intend to run your impulse in a multi-threaded environment, you will need to * ensure that your implementation of `ei_malloc()` is thread-safe. For example, if you * are using FreeRTOS, here is one possible implementation: * * ``` * __attribute__((weak)) void *ei_malloc(size_t size) { * return pvPortMalloc(size); * } * ``` * * @param[in] size The number of bytes to allocate */ void *ei_malloc(size_t size); /** * @brief Wrapper around calloc * * This function should allocate `nitems * size` bytes and initialize all bytes in this * allocated memory to 0. It should return a pointer to the allocated memory. In * bare-metal implementations, it can simply be a wrapper for `calloc()`. For example: * * ``` * __attribute__((weak)) void *ei_calloc(size_t nitems, size_t size) { * return calloc(nitems, size); * } * ``` * * If you intend to run your impulse in a multi-threaded environment, you will need to * ensure that your implementation of `ei_calloc()` is thread-safe. For example, if you * are using FreeRTOS, here is one possible implementation: * * ``` * __attribute__((weak)) void *ei_calloc(size_t nitems, size_t size) { * void *ptr = NULL; * if (size > 0) { * ptr = pvPortMalloc(nitems * size); * if(ptr) * memset(ptr, 0, (nitems * size)); * } * return ptr; * } * ``` * * @param[in] nitems Number of blocks to allocate and clear * @param[in] size Size (in bytes) of each block */ void *ei_calloc(size_t nitems, size_t size); /** * @brief Wrapper around free * * This function should free the memory space pointed to by `ptr`. If `ptr` is `NULL`, * no operation should be performed. In bare-metal implementations, it can simply be a * wrapper for `free()`. For example: * * ``` * __attribute__((weak)) void ei_free(void *ptr) { * free(ptr); * } * ``` * * If you intend to run your impulse in a multi-threaded environment, you will need to * ensure that your implementation of `ei_free()` is thread-safe. For example, if you * are using FreeRTOS, here is one possible implementation: * * ``` * __attribute__((weak)) void ei_free(void *ptr) { * pvPortFree(ptr); * } * ``` * * @param[in] ptr Pointer to the memory to free */ void ei_free(void *ptr); /** @} */ #if defined(__cplusplus) && EI_C_LINKAGE == 1 } #endif // defined(__cplusplus) && EI_C_LINKAGE == 1 // Load porting layer depending on target // First check if any of the general frameworks or operating systems are supported/enabled #ifndef EI_PORTING_ZEPHYR #if defined(__ZEPHYR__) #define EI_PORTING_ZEPHYR 1 #else #define EI_PORTING_ZEPHYR 0 #endif #endif #ifndef EI_PORTING_ARDUINO #ifdef ARDUINO #define EI_PORTING_ARDUINO 1 #else #define EI_PORTING_ARDUINO 0 #endif #endif #ifndef EI_PORTING_ANDROID #ifdef __ANDROID__ #define EI_PORTING_ANDROID 1 #else #define EI_PORTING_ANDROID 0 #endif #endif #ifndef EI_PORTING_MBED #ifdef __MBED__ #define EI_PORTING_MBED 1 #else #define EI_PORTING_MBED 0 #endif #endif // Then check for target spcific build systems #ifndef EI_PORTING_ESPRESSIF #if ((defined(CONFIG_IDF_TARGET_ESP32) || defined(CONFIG_IDF_TARGET_ESP32S3) || defined(CONFIG_IDF_TARGET_ESP32P4)) && EI_PORTING_ZEPHYR == 0) #include "esp_idf_version.h" #if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 0, 0) #define portTICK_RATE_MS portTICK_PERIOD_MS #endif #define EI_PORTING_ESPRESSIF 1 #define EI_PORTING_ARDUINO 0 #else #define EI_PORTING_ESPRESSIF 0 #endif #endif #ifndef EI_PORTING_POSIX #if defined (__unix__) || (defined (__APPLE__) && defined (__MACH__)) #define EI_PORTING_POSIX 1 #else #define EI_PORTING_POSIX 0 #endif #endif #ifndef EI_PORTING_SILABS #if defined(EFR32MG12P332F1024GL125) #define EI_PORTING_SILABS 1 #else #define EI_PORTING_SILABS 0 #endif #endif #ifndef EI_PORTING_RASPBERRY #ifdef PICO_BOARD #define EI_PORTING_RASPBERRY 1 #else #define EI_PORTING_RASPBERRY 0 #endif #endif #ifndef EI_PORTING_STM32_CUBEAI #if defined(USE_HAL_DRIVER) && !defined(__MBED__) && EI_PORTING_ZEPHYR == 0 #define EI_PORTING_STM32_CUBEAI 1 #else #define EI_PORTING_STM32_CUBEAI 0 #endif #endif #ifndef EI_PORTING_HIMAX #ifdef CPU_ARC #define EI_PORTING_HIMAX 1 #else #define EI_PORTING_HIMAX 0 #endif #endif #ifndef EI_PORTING_MINGW32 #ifdef __MINGW32__ #define EI_PORTING_MINGW32 1 #else #define EI_PORTING_MINGW32 0 #endif #endif // End load porting layer depending on target // Additional configuration for specific architecture for Armv8.1-M architecture ie CM55 and CM85 #if defined (__ARM_ARCH ) && (__ARM_ARCH >= 8) #define EI_MAX_OVERFLOW_BUFFER_COUNT 50 #endif #if defined(CONFIG_IDF_TARGET_ESP32S3) #define EI_MAX_OVERFLOW_BUFFER_COUNT 30 #endif // End additional configuration #endif // _EI_CLASSIFIER_PORTING_H_