diff --git a/apps/int32_publisher/app.c b/apps/int32_publisher/app.c index 00063062..bfe91a20 100644 --- a/apps/int32_publisher/app.c +++ b/apps/int32_publisher/app.c @@ -1,4 +1,5 @@ #include +#include #include #include @@ -7,6 +8,11 @@ #include #include +#ifdef ESP_PLATFORM +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#endif + #define RCCHECK(fn) { rcl_ret_t temp_rc = fn; if((temp_rc != RCL_RET_OK)){printf("Failed status on line %d: %d. Aborting.\n",__LINE__,(int)temp_rc);vTaskDelete(NULL);}} #define RCSOFTCHECK(fn) { rcl_ret_t temp_rc = fn; if((temp_rc != RCL_RET_OK)){printf("Failed status on line %d: %d. Continuing.\n",__LINE__,(int)temp_rc);}} @@ -70,4 +76,4 @@ void appMain(void * arg) RCCHECK(rcl_node_fini(&node)) vTaskDelete(NULL); -} \ No newline at end of file +} diff --git a/apps/ping_pong/app-colcon.meta b/apps/ping_pong/app-colcon.meta index 9ffed6ba..75cf652d 100644 --- a/apps/ping_pong/app-colcon.meta +++ b/apps/ping_pong/app-colcon.meta @@ -11,4 +11,4 @@ ] } } -} \ No newline at end of file +} diff --git a/apps/ping_pong/app.c b/apps/ping_pong/app.c index 5b2f5721..8580d7ca 100644 --- a/apps/ping_pong/app.c +++ b/apps/ping_pong/app.c @@ -9,6 +9,11 @@ #include #include +#ifdef ESP_PLATFORM +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#endif + #define STRING_BUFFER_LEN 50 #define RCCHECK(fn) { rcl_ret_t temp_rc = fn; if((temp_rc != RCL_RET_OK)){printf("Failed status on line %d: %d. Aborting.\n",__LINE__,(int)temp_rc); vTaskDelete(NULL);}} diff --git a/microros_esp32_extensions/.gitignore b/microros_esp32_extensions/.gitignore new file mode 100644 index 00000000..69272295 --- /dev/null +++ b/microros_esp32_extensions/.gitignore @@ -0,0 +1,4 @@ +build/ +sdkconfig +sdkconfig.old +esp32_toolchain.cmake diff --git a/microros_esp32_extensions/CMakeLists.txt b/microros_esp32_extensions/CMakeLists.txt new file mode 100644 index 00000000..098f5778 --- /dev/null +++ b/microros_esp32_extensions/CMakeLists.txt @@ -0,0 +1,12 @@ +cmake_minimum_required(VERSION 3.5) + +if(NOT DEFINED IDF_PATH) + message(FATAL_ERROR "The CMake varible IDF_PATH was not set!") +endif() + +if(NOT DEFINED UROS_APP) + message(FATAL_ERROR "The CMake varible UROS_APP was not set!") +endif() + +include(${IDF_PATH}/tools/cmake/project.cmake) +project(${UROS_APP}) diff --git a/microros_esp32_extensions/components/libatomic/CMakeLists.txt b/microros_esp32_extensions/components/libatomic/CMakeLists.txt new file mode 100644 index 00000000..47ff8c42 --- /dev/null +++ b/microros_esp32_extensions/components/libatomic/CMakeLists.txt @@ -0,0 +1,3 @@ +file(GLOB SRCS ${CMAKE_CURRENT_LIST_DIR}/*.c*) +idf_component_register(SRCS ${SRCS} + INCLUDE_DIRS ".") diff --git a/microros_esp32_extensions/components/libatomic/libatomic.c b/microros_esp32_extensions/components/libatomic/libatomic.c new file mode 100644 index 00000000..2ca432f1 --- /dev/null +++ b/microros_esp32_extensions/components/libatomic/libatomic.c @@ -0,0 +1,598 @@ +/* Basic implementation of libatomic for GCC. + This basic implementation currently assumes everything is aligned. + + Copyright (C) 2010, 2011 + Free Software Foundation, Inc. + + This file is part of GCC. + + GCC is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation; either version 3, or (at your option) any + later version. + + GCC is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + for more details. + + You should have received a copy of the GNU General Public License + along with GCC; see the file COPYING3. If not see + . */ + + +#include +#include +#include +#include + +/* These defines should be defined based on configuration of what the target + supports. Changing these #defines is all that is required to use this + file. If your target supports unsigned int type of the appropriate + number of bytes, simply define it as 1. Note that for I16 you may + also have to change the type from __int128_t to int128_t if approriate. + + Also note that you can expect to see warning from compiler similar to : +warning: conflicting types for built-in function ‘__atomic_compare_exchange_1’ + This is expected behaviour. */ + + + +#ifndef __LIBATOMIC_SUPPORTS_I1 +#define __LIBATOMIC_SUPPORTS_I1 1 +#endif + +#ifndef __LIBATOMIC_SUPPORTS_I2 +#define __LIBATOMIC_SUPPORTS_I2 1 +#endif + +#ifndef __LIBATOMIC_SUPPORTS_I4 +#define __LIBATOMIC_SUPPORTS_I4 1 +#endif + +/* not sure about 64 bit support, but to be on the safe side... */ + +#ifndef __LIBATOMIC_SUPPORTS_I8 +#define __LIBATOMIC_SUPPORTS_I8 1 +#endif + +#ifndef __LIBATOMIC_SUPPORTS_I16 +#define __LIBATOMIC_SUPPORTS_I16 0 +#endif + +/* Define types for all supported sizes. */ + +#if __LIBATOMIC_SUPPORTS_I1 +typedef uint8_t I1; +#endif +#if __LIBATOMIC_SUPPORTS_I2 +typedef uint16_t I2; +#endif +#if __LIBATOMIC_SUPPORTS_I4 +typedef uint32_t I4; +#endif +#if __LIBATOMIC_SUPPORTS_I8 +typedef uint64_t I8; +#endif +#if __LIBATOMIC_SUPPORTS_I16 +typedef __int128_t I16; +#endif + +/* For testing the locked implementation, define this to make all routines use + locks and run the testsuites. */ + +#if __LIBATOMIC_ALWAYS_LOCKED +#define __atomic_always_lock_free(S,P) false +#endif + +/* This defines the number of unqiue locks which are available for mapping + an address to. */ +#define __LIBATOMIC_N_LOCKS (1 << 4) + + +/* Return a pointer to a boolean test_and_set flag for ADDR. */ + +static bool * +__libatomic_flag_for_address (void *addr) +{ + static bool flag_table[__LIBATOMIC_N_LOCKS] + = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; + uintptr_t p = (uintptr_t)addr; + + p += (p >> 2) + (p << 4); + p += (p >> 7) + (p << 5); + p += (p >> 17) + (p << 13); + if (sizeof(void *) > 4) + p += (p >> 31); + p &= (__LIBATOMIC_N_LOCKS - 1); + return flag_table + p; +} + +/* If the specified memory MODEL can act as a release fence, issue the + appropriate barrier. Specify it such that it is a compile time constant. */ + +static inline void +maybe_release_fence (int model) +{ + switch (model) + { + case __ATOMIC_RELEASE: + __atomic_thread_fence (__ATOMIC_RELEASE); + break; + case __ATOMIC_ACQ_REL: + __atomic_thread_fence (__ATOMIC_ACQ_REL); + break; + case __ATOMIC_SEQ_CST: + __atomic_thread_fence (__ATOMIC_SEQ_CST); + break; + default: + break; + } +} + +/* If the specified memory MODEL can act as an acquire fence, issue the + appropriate barrier. Specify it such that it is a compile time constant. */ + +static inline void +maybe_acquire_fence (int model) +{ + switch (model) + { + case __ATOMIC_ACQUIRE: + __atomic_thread_fence (__ATOMIC_ACQUIRE); + break; + case __ATOMIC_ACQ_REL: + __atomic_thread_fence (__ATOMIC_ACQ_REL); + break; + case __ATOMIC_SEQ_CST: + __atomic_thread_fence (__ATOMIC_SEQ_CST); + break; + default: + break; + } +} + +/* Acquire the spin lock for ADDR, and issue any barrier which might be + required. */ + +static inline void +get_lock (void *addr, int model) +{ + bool *lock_ptr = __libatomic_flag_for_address (addr); + + maybe_release_fence (model); + while (__atomic_test_and_set (lock_ptr, __ATOMIC_ACQUIRE) == 1) + ; +} + +/* Release the spin lock for ADDR, and issue any barrier which might be + required. */ + +static inline void +free_lock (void *addr, int model) +{ + bool *lock_ptr = __libatomic_flag_for_address (addr); + + __atomic_clear (lock_ptr, __ATOMIC_RELEASE); + maybe_acquire_fence (model); +} + + +/* Return whether a size is lock free or not. PTR is currently unused since + we're assuming alignment for the moment. */ + +bool +__atomic_is_lock_free (size_t size, void *ptr __attribute__ ((unused))) +{ + /* __atomic_always_lock_free requires a compile time constant to evalutate + properly, so provide individual cases and simply fill in the constant. */ + switch (size) + { + case 1: + return __atomic_always_lock_free (1, 0); + case 2: + return __atomic_always_lock_free (2, 0); + case 4: + return __atomic_always_lock_free (4, 0); + case 8: + return __atomic_always_lock_free (8, 0); + case 16: + return __atomic_always_lock_free (16, 0); + default: + break; + } + return false; +} + + +/* If SIZE is lockfree, issue a lockfree sequence for the load, otherwise + break from the switch element. */ +#define LOAD(SIZE) \ + if (__atomic_always_lock_free (SIZE, 0)) \ + { \ + I ## SIZE tmp = __atomic_load_ ## SIZE (mem, model); \ + memcpy (ret, &tmp, SIZE); \ + return; \ + } \ + else \ + break; + + +/* Implement a generic atomic load for an object of SIZE, copying the value + from MEM into RET using MODEL. */ + +void +__atomic_load (size_t size, void *mem, void *ret, int model) +{ + switch (size) + { +#if __LIBATOMIC_SUPPORTS_I1 + case 1: + LOAD (1); +#endif +#if __LIBATOMIC_SUPPORTS_I2 + case 2: + LOAD (2); +#endif +#if __LIBATOMIC_SUPPORTS_I4 + case 4: + LOAD (4); +#endif +#if __LIBATOMIC_SUPPORTS_I8 + case 8: + LOAD (8); +#endif +#if __LIBATOMIC_SUPPORTS_I16 + case 16: + LOAD (16); +#endif + default: + break; + } + + /* If control gets here, a lock is needed. */ + get_lock (mem, model); + memcpy (ret, mem, size); + free_lock (mem, model); +} + + +/* If SIZE is lockfree, issue a lockfree sequence for the store, otherwise + break from the switch element. */ +#define STORE(SIZE) \ + if (__atomic_always_lock_free (SIZE, 0)) \ + { \ + I ## SIZE tmp; \ + memcpy (&tmp, val, SIZE); \ + __atomic_store_ ## SIZE (mem, tmp, model); \ + return; \ + } \ + else \ + break; + +/* Perform an atomic store for an object of SIZE. Store VAL into MEM using + MODEL. */ + +void +__atomic_store (size_t size, void *mem, void *val, int model) +{ + switch (size) + { +#if __LIBATOMIC_SUPPORTS_I1 + case 1: + STORE (1); +#endif +#if __LIBATOMIC_SUPPORTS_I2 + case 2: + STORE (2); +#endif +#if __LIBATOMIC_SUPPORTS_I4 + case 4: + STORE (4); +#endif +#if __LIBATOMIC_SUPPORTS_I8 + case 8: + STORE (8); +#endif +#if __LIBATOMIC_SUPPORTS_I16 + case 16: + STORE (16); +#endif + default: + break; + } + + /* If control gets here, a lock is needed. */ + get_lock (mem, model); + memcpy (mem, val, size); + free_lock (mem, model); +} + + +/* If SIZE is lockfree, issue a lockfree sequence for the exchange, otherwise + break from the switch element. */ +#define EXCHANGE(SIZE) \ + if (__atomic_always_lock_free (SIZE, 0)) \ + { \ + I ## SIZE tmp1, tmp2; \ + memcpy (&tmp2, val, SIZE); \ + tmp1 = __atomic_exchange_ ## SIZE (mem, tmp2, model); \ + memcpy (ret, &tmp1, SIZE); \ + return; \ + } \ + else \ + break; + +/* Perform an atomic exchange for an object of SIZE. Store VAL into MEM using + MODEL, and return the previous value of MEM in RET. */ + +void +__atomic_exchange (size_t size, void *mem, void *val, void *ret, int model) +{ + switch (size) + { +#if __LIBATOMIC_SUPPORTS_I1 + case 1: + EXCHANGE (1); +#endif +#if __LIBATOMIC_SUPPORTS_I2 + case 2: + EXCHANGE (2); +#endif +#if __LIBATOMIC_SUPPORTS_I4 + case 4: + EXCHANGE (4); +#endif +#if __LIBATOMIC_SUPPORTS_I8 + case 8: + EXCHANGE (8); +#endif +#if __LIBATOMIC_SUPPORTS_I16 + case 16: + EXCHANGE (16); +#endif + default: + break; + } + + /* If control gets here, a lock is needed. */ + get_lock (mem, model); + memcpy (ret, mem, size); + memcpy (mem, val, size); + free_lock (mem, model); +} + + +/* If SIZE is lockfree, issue a lockfree sequence for the compare_exchange, + otherwise break from the switch element. */ +#define COMPARE_EXCHANGE(SIZE) \ + if (__atomic_always_lock_free (SIZE, 0)) \ + { \ + bool ret; \ + I ## SIZE tmp; \ + memcpy (&tmp, desired, SIZE); \ + ret = __atomic_compare_exchange_ ## SIZE (mem, expect, tmp, 0, \ + success, failure); \ + return ret; \ + } \ + else \ + break; + +/* Perform an atomic compare_exchange for an object of SIZE. If MEM contains + the value in EXPECT, copy DESIRED into MEM utilizing memory model SUCESS and + return true. Otherwise copy the contents of MEM into EXPECT using memory + model FAILURE and return false. */ + +bool +__atomic_compare_exchange (size_t size, void *mem, void *expect, void *desired, int success, int failure) +{ + switch (size) + { +#if __LIBATOMIC_SUPPORTS_I1 + case 1: + COMPARE_EXCHANGE (1); +#endif +#if __LIBATOMIC_SUPPORTS_I2 + case 2: + COMPARE_EXCHANGE (2); +#endif +#if __LIBATOMIC_SUPPORTS_I4 + case 4: + COMPARE_EXCHANGE (4); +#endif +#if __LIBATOMIC_SUPPORTS_I8 + case 8: + COMPARE_EXCHANGE (8); +#endif +#if __LIBATOMIC_SUPPORTS_I16 + case 16: + COMPARE_EXCHANGE (16); +#endif + default: + break; + } + + /* If control gets here, a lock is needed. */ + get_lock (mem, success); + if (memcmp (mem, expect, size) == 0) + { + memcpy (mem, desired, size); + free_lock (mem, success); + return true; + } + memcpy (expect, mem, size); + free_lock (mem, failure); + return false; +} + + +/* Issue a SIZE specific __atomic_load_N function. */ +#define ATOMIC_LOAD(SIZE) I ## SIZE \ +__atomic_load_ ## SIZE (I ## SIZE *mem, int model) \ +{ \ + I ## SIZE ret; \ + if (__atomic_always_lock_free (sizeof (ret), 0)) \ + return __atomic_load_n (mem, model); \ + get_lock (mem, model); \ + ret = *mem; \ + free_lock (mem, model); \ + return ret; \ +} + + +/* Issue a SIZE specific __atomic_store_N function. */ +#define ATOMIC_STORE(SIZE) void \ +__atomic_store_ ## SIZE (I ## SIZE *mem, I ## SIZE val, int model) \ +{ \ + if (__atomic_always_lock_free (sizeof (val), 0)) \ + __atomic_store_n (mem, val, model); \ + else \ + { \ + get_lock (mem, model); \ + *mem = val; \ + free_lock (mem, model); \ + } \ +} + +/*#define ATOMIC_STORE(SIZE) void \ +__atomic_store_ ## SIZE (I ## SIZE *mem, I ## SIZE val, int model) \ +{ \ + if (__atomic_always_lock_free (sizeof (val), 0)) \ + __atomic_store_n (mem, val, model); \ + else \ + { \ + *mem = val; \ + } \ +}*/ + +/* Issue a SIZE specific __atomic_exchange_N function. */ +#define ATOMIC_EXCHANGE(SIZE) I ## SIZE \ +__atomic_exchange_ ## SIZE (I ## SIZE *mem, I ## SIZE val, int model) \ +{ \ + I ## SIZE ret; \ + if (__atomic_always_lock_free (sizeof (ret), 0)) \ + return __atomic_exchange_n (mem, val, model); \ + get_lock (mem, model); \ + ret = *mem; \ + *mem = val; \ + free_lock (mem, model); \ + return ret; \ +} + +/* Issue a SIZE specific __atomic_compare_exchange_N function. + Note the compiler complains when compiling these since these functions + do not have the boolean weak parameter, so the params dont match the + builtin exactly. */ + +#define ATOMIC_COMPARE_EXCHANGE(SIZE) bool \ +__atomic_compare_exchange_ ## SIZE (I ## SIZE *mem, I ## SIZE *expect, I ## SIZE desired, int success, int failure) \ +{ \ + if (__atomic_always_lock_free (sizeof (desired), 0)) \ + return __atomic_compare_exchange_n (mem, expect, desired, 0,\ + success, failure); \ + get_lock (mem, success); \ + if (*mem == *expect) \ + { \ + *mem = desired; \ + free_lock (mem, success); \ + return true; \ + } \ + *expect = *mem; \ + free_lock (mem, failure); \ + return false; \ +} + + +#define ATOMIC_FETCH(SIZE,OP,SYM) I ## SIZE \ +__atomic_fetch_## OP ## SIZE (I ## SIZE *mem, I ## SIZE val, int model) \ +{ \ + I ## SIZE ret; \ + if (__atomic_always_lock_free (sizeof (ret), 0)) \ + return __atomic_fetch_ ## OP ## SIZE (mem, val, model); \ + get_lock (mem, model); \ + ret = *mem; \ + *mem SYM ## = val; \ + free_lock (mem, model); \ + return ret; \ +} + +#define ATOMIC_FETCH_NAND(SIZE) I ## SIZE \ +__atomic_fetch_nand_ ## SIZE (I ## SIZE *mem, I ## SIZE val, int model) \ +{ \ + I ## SIZE ret; \ + if (__atomic_always_lock_free (sizeof (ret), 0)) \ + return __atomic_fetch_nand_ ## SIZE (mem, val, model); \ + get_lock (mem, model); \ + ret = *mem; \ + *mem = ~(*mem & val); \ + free_lock (mem, model); \ + return ret; \ +} + +#if __LIBATOMIC_SUPPORTS_I1 +ATOMIC_LOAD (1) +ATOMIC_STORE (1) +ATOMIC_EXCHANGE (1) +// ATOMIC_COMPARE_EXCHANGE (1) +ATOMIC_FETCH (1, add_, +) +ATOMIC_FETCH (1, sub_, -) +ATOMIC_FETCH (1, and_, &) +ATOMIC_FETCH (1, or_, |) +ATOMIC_FETCH (1, xor_, ^) +ATOMIC_FETCH_NAND (1) +#endif + +#if __LIBATOMIC_SUPPORTS_I2 +ATOMIC_LOAD (2) +ATOMIC_STORE (2) +ATOMIC_EXCHANGE (2) +// ATOMIC_COMPARE_EXCHANGE (2) +ATOMIC_FETCH (2, add_, +) +ATOMIC_FETCH (2, sub_, -) +ATOMIC_FETCH (2, and_, &) +ATOMIC_FETCH (2, or_, |) +ATOMIC_FETCH (2, xor_, ^) +ATOMIC_FETCH_NAND (2) +#endif + + +#if __LIBATOMIC_SUPPORTS_I4 +ATOMIC_LOAD (4) +ATOMIC_STORE (4) +ATOMIC_EXCHANGE (4) +// ATOMIC_COMPARE_EXCHANGE (4) +ATOMIC_FETCH (4, add_, +) +ATOMIC_FETCH (4, sub_, -) +ATOMIC_FETCH (4, and_, &) +ATOMIC_FETCH (4, or_, |) +ATOMIC_FETCH (4, xor_, ^) +ATOMIC_FETCH_NAND (4) +#endif + + +#if __LIBATOMIC_SUPPORTS_I8 +ATOMIC_LOAD (8) +ATOMIC_STORE (8) +ATOMIC_EXCHANGE (8) +// ATOMIC_COMPARE_EXCHANGE (8) +ATOMIC_FETCH (8, add_, +) +ATOMIC_FETCH (8, sub_, -) +ATOMIC_FETCH (8, and_, &) +ATOMIC_FETCH (8, or_, |) +ATOMIC_FETCH (8, xor_, ^) +ATOMIC_FETCH_NAND (8) +#endif + + +#if __LIBATOMIC_SUPPORTS_I16 +ATOMIC_LOAD (16) +ATOMIC_STORE (16) +ATOMIC_EXCHANGE (16) +// ATOMIC_COMPARE_EXCHANGE (16) +ATOMIC_FETCH (16, add_, +) +ATOMIC_FETCH (16, sub_, -) +ATOMIC_FETCH (16, and_, &) +ATOMIC_FETCH (16, or_, |) +ATOMIC_FETCH (16, xor_, ^) +ATOMIC_FETCH_NAND (16) +#endif \ No newline at end of file diff --git a/microros_esp32_extensions/esp32_toolchain.cmake.in b/microros_esp32_extensions/esp32_toolchain.cmake.in new file mode 100644 index 00000000..cd75b072 --- /dev/null +++ b/microros_esp32_extensions/esp32_toolchain.cmake.in @@ -0,0 +1,75 @@ +include(CMakeForceCompiler) + +set(CMAKE_SYSTEM_NAME Generic) +set(CMAKE_SYSTEM_PROCESSOR xtensa) +set(CMAKE_CROSSCOMPILING 1) +set(CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY) +set(PLATFORM_NAME "ESP32") + +set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) +set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) +set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) + +set(CMAKE_C_COMPILER @CMAKE_C_COMPILER@) +set(CMAKE_CXX_COMPILER @CMAKE_CXX_COMPILER@) + +set(CMAKE_C_FLAGS_INIT "@CFLAGS@" CACHE STRING "" FORCE) +set(CMAKE_CXX_FLAGS_INIT "@CXXFLAGS@" CACHE STRING "" FORCE) + +set(idf_path "@IDF_PATH@") + +include_directories( + "@BUILD_CONFIG_DIR@" + ${idf_path}/components/newlib/platform_include + ${idf_path}/components/protocomm/include + ${idf_path}/components/esp_rom/include + ${idf_path}/components/driver/include + ${idf_path}/components/wear_levelling/include + ${idf_path}/components/vfs/include + ${idf_path}/components/log/include + ${idf_path}/components/freertos/include + ${idf_path}/components/wifi_provisioning/include + ${idf_path}/components/pthread/include + ${idf_path}/components/libsodium/libsodium/src/libsodium/include + ${idf_path}/components/coap/port/include + ${idf_path}/components/coap/libcoap/include + ${idf_path}/components/tcp_transport/include + ${idf_path}/components/unity/include + ${idf_path}/components/lwip/port/esp32/include + ${idf_path}/components/lwip/lwip/src/include + ${idf_path}/components/lwip/include + ${idf_path}/components/esp32/include + ${idf_path}/components/asio/port/include + ${idf_path}/components/asio/asio/asio/include + ${idf_path}/components/app_update/include + ${idf_path}/components/esp_ringbuf/include + ${idf_path}/components/soc/esp32/include + ${idf_path}/components/soc/include + ${idf_path}/components/efuse/test/include + ${idf_path}/components/efuse/esp32/include + ${idf_path}/components/efuse/include + ${idf_path}/components/mbedtls/port/include + ${idf_path}/components/mbedtls/mbedtls/include + ${idf_path}/components/xtensa/esp32/include + ${idf_path}/components/xtensa/include + ${idf_path}/components/app_trace/include + ${idf_path}/components/nvs_flash/include + ${idf_path}/components/jsmn/include + ${idf_path}/components/esp_eth/include + ${idf_path}/components/spiffs/include + ${idf_path}/components/ulp/include + ${idf_path}/components/mdns/include + ${idf_path}/components/freemodbus/modbus/include + ${idf_path}/components/freemodbus/common/include + ${idf_path}/components/esp_event/include + ${idf_path}/components/expat/port/include + ${idf_path}/components/bootloader_support/include + ${idf_path}/components/heap/include + ${idf_path}/components/wpa_supplicant/port/include + ${idf_path}/components/wpa_supplicant/include + ${idf_path}/components/tcpip_adapter/include + ${idf_path}/components/openssl/include + ${idf_path}/components/sdmmc/include + ${idf_path}/components/esp_local_ctrl/include + ${idf_path}/components/esp_common/include + ) diff --git a/microros_esp32_extensions/libmicroros.mk b/microros_esp32_extensions/libmicroros.mk new file mode 100644 index 00000000..545ab883 --- /dev/null +++ b/microros_esp32_extensions/libmicroros.mk @@ -0,0 +1,59 @@ +EXTENSIONS_DIR = $(shell pwd) +FW_DIR = $(EXTENSIONS_DIR)/../.. +UROS_DIR = $(FW_DIR)/mcu_ws +BUILD_DIR ?= $(EXTENSIONS_DIR)/build + +DEBUG ?= 1 + +ifeq ($(DEBUG), 1) + BUILD_TYPE = Debug +else + BUILD_TYPE = Release +endif + +CFLAGS_INTERNAL := $(CFLAGS) +CXXFLAGS_INTERNAL := $(CXXFLAGS) + +TOOLCHAIN = $(EXTENSIONS_DIR)/esp32_toolchain.cmake + +all: libmicroros + +esp32_toolchain: $(EXTENSIONS_DIR)/esp32_toolchain.cmake.in + rm -f $(EXTENSIONS_DIR)/esp32_toolchain.cmake; \ + cat $(EXTENSIONS_DIR)/esp32_toolchain.cmake.in | \ + sed "s/@CMAKE_C_COMPILER@/$(subst /,\/,$(CC))/g" | \ + sed "s/@CMAKE_CXX_COMPILER@/$(subst /,\/,$(CXX))/g" | \ + sed "s/@CFLAGS@/$(subst /,\/,$(CFLAGS_INTERNAL))/g" | \ + sed "s/@CXXFLAGS@/$(subst /,\/,$(CXXFLAGS_INTERNAL))/g" | \ + sed "s/@IDF_PATH@/$(subst /,\/,$(IDF_PATH))/g" | \ + sed "s/@BUILD_CONFIG_DIR@/$(subst /,\/,$(BUILD_DIR)/config)/g" \ + > $(EXTENSIONS_DIR)/esp32_toolchain.cmake + +colcon_compile: esp32_toolchain + cd $(UROS_DIR); \ + colcon build \ + --merge-install \ + --packages-ignore-regex=.*_cpp \ + --metas $(UROS_DIR)/colcon.meta $(APP_META) \ + --cmake-args \ + "--no-warn-unused-cli" \ + -DCMAKE_POSITION_INDEPENDENT_CODE:BOOL=OFF \ + -DTHIRDPARTY=ON \ + -DBUILD_SHARED_LIBS=OFF \ + -DBUILD_TESTING=OFF \ + -DCMAKE_BUILD_TYPE=$(BUILD_TYPE) \ + -DCMAKE_TOOLCHAIN_FILE=$(TOOLCHAIN) \ + -DCMAKE_VERBOSE_MAKEFILE=ON; \ + +libmicroros: colcon_compile + mkdir -p $(UROS_DIR)/libmicroros; cd $(UROS_DIR)/libmicroros; \ + for file in $$(find $(UROS_DIR)/install/lib/ -name '*.a'); do \ + folder=$$(echo $$file | sed -E "s/(.+)\/(.+).a/\2/"); \ + mkdir -p $$folder; cd $$folder; $(AR) x $$file; \ + for f in *; do \ + mv $$f ../$$folder-$$f; \ + done; \ + cd ..; rm -rf $$folder; \ + done ; \ + $(AR) rc libmicroros.a *.obj; mkdir -p $(BUILD_DIR); cp libmicroros.a $(BUILD_DIR); ranlib $(BUILD_DIR)/libmicroros.a; \ + cd ..; rm -rf libmicroros; diff --git a/microros_esp32_extensions/main/CMakeLists.txt b/microros_esp32_extensions/main/CMakeLists.txt new file mode 100644 index 00000000..f502da88 --- /dev/null +++ b/microros_esp32_extensions/main/CMakeLists.txt @@ -0,0 +1,51 @@ +file(GLOB SRCS ${UROS_APP_FOLDER}/*.c*) +idf_component_register(SRCS main.c ${SRCS} + INCLUDE_DIRS ".") + +set(EXTENSIONS_DIR ${COMPONENT_DIR}/..) +set(UROS_DIR ${COMPONENT_DIR}/../../../mcu_ws) + +set(MICROROS_INCLUDE_DIR ${UROS_DIR}/install/include) +set(MICROROS_PREFIX ${CMAKE_BINARY_DIR}/libmicroros-prefix) + + +if(CMAKE_GENERATOR STREQUAL "Unix Makefiles") +set(submake "$(MAKE)") +else() +set(submake "make") +endif() + +externalproject_add(libmicroros + PREFIX ${MICROROS_PREFIX} + SOURCE_DIR ${UROS_DIR} + BINARY_DIR ${EXTENSIONS_DIR} + CONFIGURE_COMMAND "" + BUILD_COMMAND + ${submake} -f libmicroros.mk + CC=${CMAKE_C_COMPILER} + AR=${CMAKE_AR} + CFLAGS=${CMAKE_C_FLAGS} + CXX=${CMAKE_CXX_COMPILER} + CXXFLAGS=${CMAKE_CXX_FLAGS} + BUILD_DIR=${CMAKE_BINARY_DIR} + IDF_PATH=${IDF_PATH} + APP_META=${UROS_APP_FOLDER}/app-colcon.meta + INSTALL_COMMAND "" + BUILD_BYPRODUCTS ${CMAKE_BINARY_DIR}/libmicroros.a + ) + +file(MAKE_DIRECTORY ${MICROROS_INCLUDE_DIR}) + +add_library(microros STATIC IMPORTED GLOBAL) +add_dependencies(microros libmicroros idf::libatomic) +target_link_libraries(microros INTERFACE idf::libatomic) + +set_target_properties(microros PROPERTIES IMPORTED_LOCATION ${CMAKE_BINARY_DIR}/libmicroros.a) +set_target_properties(microros PROPERTIES INTERFACE_INCLUDE_DIRECTORIES ${MICROROS_INCLUDE_DIR}) + +set_directory_properties( PROPERTIES ADDITIONAL_MAKE_CLEAN_FILES + "${UROS_DIR}/install;${UROS_DIR}/build;${UROS_DIR}/log" ) + +add_dependencies(${COMPONENT_LIB} microros) +target_include_directories(${COMPONENT_LIB} PUBLIC microros) +target_link_libraries(${COMPONENT_LIB} PUBLIC microros) diff --git a/microros_esp32_extensions/main/Kconfig.projbuild b/microros_esp32_extensions/main/Kconfig.projbuild new file mode 100644 index 00000000..489e64bf --- /dev/null +++ b/microros_esp32_extensions/main/Kconfig.projbuild @@ -0,0 +1,36 @@ +menu "MicroRos Transport Settings" + +menu "UART Settings (for serial transport)" + +config MICROROS_UART_TXD + int "UART TX pin" + range -1 33 + default -1 + help + Select Tx Down pin for uart connection or -1 for no change (Only used if serial transport is used for microros). + +config MICROROS_UART_RXD + int "UART RX pin" + range -1 33 + default -1 + help + Select Rx Down pin for uart connection or -1 for no change (Only used if serial transport is used for microros). + +config MICROROS_UART_RTS + int "UART RTS pin" + range -1 33 + default -1 + help + Select RTS Down pin for uart connection or -1 for no change (Only used if serial transport is used for microros). + +config MICROROS_UART_CTS + int "UART CTS pin" + range -1 33 + default -1 + help + Select CTS Down pin for uart connection or -1 for no change (Only used if serial transport is used for microros). + +endmenu + + +endmenu diff --git a/microros_esp32_extensions/main/app.h b/microros_esp32_extensions/main/app.h new file mode 100644 index 00000000..e1bd7e3f --- /dev/null +++ b/microros_esp32_extensions/main/app.h @@ -0,0 +1,6 @@ +#ifndef _MAIN_H_ +#define _MAIN_H_ + +void appMain(void *argument); + +#endif // _MAIN_H_ diff --git a/microros_esp32_extensions/main/main.c b/microros_esp32_extensions/main/main.c new file mode 100644 index 00000000..5688ab38 --- /dev/null +++ b/microros_esp32_extensions/main/main.c @@ -0,0 +1,14 @@ +#include "app.h" + +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "esp_system.h" + +#include +#include + +void app_main(void) +{ + // start microROS task + xTaskCreate(appMain, "uros_task", 12*2048, NULL, 5, NULL); +} diff --git a/microros_esp32_extensions/sdkconfig.defaults b/microros_esp32_extensions/sdkconfig.defaults new file mode 100644 index 00000000..0dc7d342 --- /dev/null +++ b/microros_esp32_extensions/sdkconfig.defaults @@ -0,0 +1,3 @@ +CONFIG_ESP_MAIN_TASK_STACK_SIZE=25000 +CONFIG_FREERTOS_UNICORE=y +CONFIG_ESP_TASK_WDT=n diff --git a/microros_esp32_extensions/serial_transport_external/esp32_serial_transport.c b/microros_esp32_extensions/serial_transport_external/esp32_serial_transport.c new file mode 100644 index 00000000..2df06151 --- /dev/null +++ b/microros_esp32_extensions/serial_transport_external/esp32_serial_transport.c @@ -0,0 +1,64 @@ +#include + +#include +#include + +#define UART_TXD (CONFIG_MICROROS_UART_TXD) +#define UART_RXD (CONFIG_MICROROS_UART_RXD) +#define UART_RTS (CONFIG_MICROROS_UART_RTS) +#define UART_CTS (CONFIG_MICROROS_UART_CTS) + +#define UART_BUFFER_SIZE (512) + + +bool uxr_init_serial_platform(struct uxrSerialPlatform* platform, int fd, uint8_t remote_addr, uint8_t local_addr) +{ + + if (fd == 0) { + platform->uart_port = UART_NUM_0; + } else if (fd == 1) { + platform->uart_port = UART_NUM_1; + } else if (fd == 2) { + platform->uart_port = UART_NUM_2; + } else { + return false; + } + + uart_config_t uart_config = { + .baud_rate = 115200, + .data_bits = UART_DATA_8_BITS, + .parity = UART_PARITY_DISABLE, + .stop_bits = UART_STOP_BITS_1, + .flow_ctrl = UART_HW_FLOWCTRL_DISABLE, + }; + + if (uart_param_config(platform->uart_port, &uart_config) == ESP_FAIL) { + return false; + } + if (uart_set_pin(platform->uart_port, UART_TXD, UART_RXD, UART_RTS, UART_CTS) == ESP_FAIL) { + return false; + } + if (uart_driver_install(platform->uart_port, UART_BUFFER_SIZE * 2, 0, 0, NULL, 0) == ESP_FAIL) { + return false; + } + + return true; +} + +bool uxr_close_serial_platform(struct uxrSerialPlatform* platform) +{ + return uart_driver_delete(platform->uart_port) == ESP_OK; +} + +size_t uxr_write_serial_data_platform(uxrSerialPlatform* platform, uint8_t* buf, size_t len, uint8_t* errcode) +{ + const int txBytes = uart_write_bytes(platform->uart_port, buf, len); + return txBytes; +} + +size_t uxr_read_serial_data_platform(uxrSerialPlatform* platform, uint8_t* buf, size_t len, int timeout, uint8_t* errcode) +{ + const int rxBytes = uart_read_bytes(platform->uart_port, buf, len, timeout / portTICK_RATE_MS); + return rxBytes; +} + diff --git a/microros_esp32_extensions/serial_transport_external/esp32_serial_transport.h b/microros_esp32_extensions/serial_transport_external/esp32_serial_transport.h new file mode 100644 index 00000000..54340d53 --- /dev/null +++ b/microros_esp32_extensions/serial_transport_external/esp32_serial_transport.h @@ -0,0 +1,22 @@ + +#ifndef _UXR_CLIENT_SERIAL_TRANSPORT_ESP32_H_ +#define _UXR_CLIENT_SERIAL_TRANSPORT_ESP32_H_ + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include + +typedef struct uxrSerialPlatform +{ + uart_port_t uart_port; +} uxrSerialPlatform; + +#ifdef __cplusplus +} +#endif + +#endif //_UXR_CLIENT_SERIAL_TRANSPORT_ESP32_H_ +