diff --git a/README.md b/README.md index ac91af0a1..ee302edbb 100644 --- a/README.md +++ b/README.md @@ -47,6 +47,7 @@ We welcome and encourage the community to submit patches directly to the eRPC pr - [Examples](#examples) - [References](#references) - [Directories](#directories) + - [RT-Thread integration](#rt-thread-integration) - [Building and installing](#building-and-installing) - [Requirements](#requirements) - [Windows](#windows) @@ -297,10 +298,18 @@ This section provides links to interesting erpc-based projects, articles, blogs [mk](/mk) - Contains common makefiles for building eRPC components. +[rtthread](/rtthread) - Contains RT-Thread Kconfig, SCons integration, and usage notes. + [test](/test) - Client/server tests. These tests verify the entire communications path from client to server and back. [utilities](/utilities) - Holds utilities which bring additional benefit to eRPC apps developers. +## RT-Thread integration + +The eRPC C runtime provides an RT-Thread threading backend and an RT-Thread UART transport. +RT-Thread package integration files are provided under [rtthread](/rtthread). +See [rtthread/README.md](/rtthread/README.md) for `menuconfig` and SCons integration steps. + ## Building and installing These build instructions apply to host PCs and embedded Linux. For bare metal or RTOS embedded environments, you should copy the [erpc_c](/erpc_c) directory into your application sources. diff --git a/erpc_c/config/erpc_config.h b/erpc_c/config/erpc_config.h index 279665f3e..24e529a20 100644 --- a/erpc_c/config/erpc_config.h +++ b/erpc_c/config/erpc_config.h @@ -33,6 +33,7 @@ #define ERPC_THREADS_MBED (4U) //!< Mbed OS #define ERPC_THREADS_WIN32 (5U) //!< WIN32 #define ERPC_THREADS_THREADX (6U) //!< THREADX +#define ERPC_THREADS_RTTHREAD (7U) //!< RT-Thread. #define ERPC_NOEXCEPT_DISABLED (0U) //!< Disabling noexcept feature. #define ERPC_NOEXCEPT_ENABLED (1U) //!< Enabling noexcept feature. diff --git a/erpc_c/port/erpc_config_internal.h b/erpc_c/port/erpc_config_internal.h index f5209c65e..f8e8b03c8 100644 --- a/erpc_c/port/erpc_config_internal.h +++ b/erpc_c/port/erpc_config_internal.h @@ -210,6 +210,9 @@ #elif defined(ERPC_THREADS) && (ERPC_THREADS == ERPC_THREADS_MBED) #include "platform/mbed_assert.h" #define erpc_assert(condition) MBED_ASSERT(condition) + #elif defined(ERPC_THREADS) && (ERPC_THREADS == ERPC_THREADS_RTTHREAD) + #include + #define erpc_assert(condition) RT_ASSERT(condition) #else #ifdef __cplusplus #include diff --git a/erpc_c/port/erpc_port_rtthread.cpp b/erpc_c/port/erpc_port_rtthread.cpp new file mode 100644 index 000000000..9f30a17ba --- /dev/null +++ b/erpc_c/port/erpc_port_rtthread.cpp @@ -0,0 +1,17 @@ +/* + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include "erpc_port.h" + +#include + +void *erpc_malloc(size_t size) +{ + return rt_malloc(size); +} + +void erpc_free(void *ptr) +{ + rt_free(ptr); +} diff --git a/erpc_c/port/erpc_threading.h b/erpc_c/port/erpc_threading.h index f28257147..443e73c5e 100644 --- a/erpc_c/port/erpc_threading.h +++ b/erpc_c/port/erpc_threading.h @@ -36,6 +36,8 @@ #include "windows.h" #elif ERPC_THREADS_IS(THREADX) #include "tx_api.h" +#elif ERPC_THREADS_IS(RTTHREAD) +#include #endif // ERPC_THREADS @@ -164,6 +166,8 @@ class Thread return reinterpret_cast(m_thread); #elif ERPC_THREADS_IS(THREADX) return reinterpret_cast(m_thread.tx_thread_id); +#elif ERPC_THREADS_IS(RTTHREAD) + return reinterpret_cast(m_thread); #endif } @@ -186,6 +190,8 @@ class Thread return reinterpret_cast(GetCurrentThread()); #elif ERPC_THREADS_IS(THREADX) return reinterpret_cast(tx_thread_identify()); +#elif ERPC_THREADS_IS(RTTHREAD) + return reinterpret_cast(rt_thread_self()); #endif } @@ -232,9 +238,9 @@ class Thread static pthread_key_t s_threadObjectKey; /*!< Thread key. */ pthread_t m_thread; /*!< Current thread. */ #elif ERPC_THREADS_IS(FREERTOS) - TaskHandle_t m_task; /*!< Current task. */ - Thread *m_next; /*!< Pointer to next Thread. */ - static Thread *s_first; /*!< Pointer to first Thread. */ + TaskHandle_t m_task; /*!< Current task. */ + Thread *m_next; /*!< Pointer to next Thread. */ + static Thread *s_first; /*!< Pointer to first Thread. */ #if ERPC_ALLOCATION_POLICY == ERPC_ALLOCATION_POLICY_STATIC StaticTask_t m_staticTask; /*!< Hold static task data. */ #endif @@ -257,6 +263,8 @@ class Thread TX_THREAD m_thread; /*!< Underlying Thread instance */ Thread *m_next; /*!< Pointer to next Thread. */ static Thread *s_first; /*!< Pointer to first Thread. */ +#elif ERPC_THREADS_IS(RTTHREAD) + rt_thread_t m_thread; /*!< Current thread. */ #endif #if ERPC_THREADS_IS(PTHREADS) @@ -312,6 +320,14 @@ class Thread * @param[in] arg Thread to execute. */ static void threadEntryPointStub(ULONG arg); +#elif ERPC_THREADS_IS(RTTHREAD) + + /*! + * @brief This function execute threadEntryPoint function. + * + * @param[in] arg Thread to execute. + */ + static void threadEntryPointStub(void *arg); #endif private: @@ -413,11 +429,13 @@ class Mutex #elif ERPC_THREADS_IS(ZEPHYR) struct k_mutex m_mutex; /*!< Mutex.*/ #elif ERPC_THREADS_IS(MBED) - rtos::Mutex *m_mutex; /*!< Mutex. */ + rtos::Mutex *m_mutex; /*!< Mutex. */ #elif ERPC_THREADS_IS(WIN32) HANDLE m_mutex; #elif ERPC_THREADS_IS(THREADX) TX_MUTEX m_mutex; +#elif ERPC_THREADS_IS(RTTHREAD) + struct rt_mutex m_mutex; /*!< Mutex. */ #endif private: @@ -499,7 +517,7 @@ class Semaphore SemaphoreHandle_t m_sem; /*!< Semaphore. */ StaticSemaphore_t m_staticQueue; /*!< Static queue. */ #elif ERPC_THREADS_IS(ZEPHYR) - struct k_sem m_sem; /*!< Semaphore. */ + struct k_sem m_sem; /*!< Semaphore. */ #elif ERPC_THREADS_IS(MBED) rtos::Semaphore *m_sem; /*!< Semaphore. */ int m_count; /*!< Semaphore count number. */ @@ -509,6 +527,8 @@ class Semaphore HANDLE m_sem; #elif ERPC_THREADS_IS(THREADX) TX_SEMAPHORE m_sem; /*!< Semaphore. */ +#elif ERPC_THREADS_IS(RTTHREAD) + struct rt_semaphore m_sem; /*!< Semaphore. */ #endif private: diff --git a/erpc_c/port/erpc_threading_rtthread.cpp b/erpc_c/port/erpc_threading_rtthread.cpp new file mode 100644 index 000000000..83a4921ab --- /dev/null +++ b/erpc_c/port/erpc_threading_rtthread.cpp @@ -0,0 +1,263 @@ +/* + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include "erpc_threading.h" + +#if ERPC_THREADS_IS(RTTHREAD) + +using namespace erpc; + +//////////////////////////////////////////////////////////////////////////////// +// Definitions +//////////////////////////////////////////////////////////////////////////////// + +#ifndef ERPC_RTTHREAD_THREAD_STACK_SIZE +#define ERPC_RTTHREAD_THREAD_STACK_SIZE (2048U) +#endif + +#ifndef ERPC_RTTHREAD_THREAD_PRIORITY +#define ERPC_RTTHREAD_THREAD_PRIORITY (20U) +#endif + +#ifndef ERPC_RTTHREAD_THREAD_TIMESLICE +#define ERPC_RTTHREAD_THREAD_TIMESLICE (10U) +#endif + +//////////////////////////////////////////////////////////////////////////////// +// Code +//////////////////////////////////////////////////////////////////////////////// + +static rt_tick_t usecsToTicks(uint32_t usecs) +{ + rt_int32_t ms; + rt_tick_t ticks; + + if (usecs == 0U) + { + return 0; + } + + ms = (rt_int32_t)(((uint64_t)usecs + 999ULL) / 1000ULL); + ticks = (rt_tick_t)rt_tick_from_millisecond(ms); + if (ticks == 0U) + { + ticks = 1U; + } + + return ticks; +} + +static rt_int32_t usecsToWaitTicks(uint32_t timeoutUsecs) +{ + if (timeoutUsecs == Semaphore::kWaitForever) + { + return RT_WAITING_FOREVER; + } + + if (timeoutUsecs == 0U) + { + return RT_WAITING_NO; + } + + return (rt_int32_t)usecsToTicks(timeoutUsecs); +} + +static rt_uint8_t getThreadPriority(uint32_t priority) +{ + uint32_t rtPriority = (priority == 0U) ? ERPC_RTTHREAD_THREAD_PRIORITY : priority; + + if ((priority == 0U) && (rtPriority >= RT_THREAD_PRIORITY_MAX)) + { + rtPriority = RT_THREAD_PRIORITY_MAX - 1U; + } + + erpc_assert((rtPriority < RT_THREAD_PRIORITY_MAX) && ("RT-Thread priority out of range." != NULL)); + return (rt_uint8_t)rtPriority; +} + +static rt_uint32_t getThreadStackSize(uint32_t stackSize) +{ + return (stackSize == 0U) ? ERPC_RTTHREAD_THREAD_STACK_SIZE : stackSize; +} + +Thread::Thread(const char *name) : +m_name(name), m_entry(NULL), m_arg(NULL), m_stackSize(0), m_priority(0), m_stackPtr(NULL), m_thread(RT_NULL) +{ +} + +Thread::Thread(thread_entry_t entry, uint32_t priority, uint32_t stackSize, const char *name, + thread_stack_pointer stackPtr) : +m_name(name), m_entry(entry), m_arg(NULL), m_stackSize(stackSize), m_priority(priority), m_stackPtr(stackPtr), m_thread(RT_NULL) +{ +} + +Thread::~Thread(void) +{ + if ((m_thread != RT_NULL) && (m_thread->user_data == static_cast(reinterpret_cast(this)))) + { + m_thread->user_data = 0U; + } +} + +void Thread::init(thread_entry_t entry, uint32_t priority, uint32_t stackSize, thread_stack_pointer stackPtr) +{ + m_entry = entry; + m_stackSize = stackSize; + m_priority = priority; + m_stackPtr = stackPtr; +} + +void Thread::start(void *arg) +{ + const char *threadName = (m_name != NULL) ? m_name : "erpc"; + rt_uint8_t priority = getThreadPriority(m_priority); + rt_uint32_t stackSize = getThreadStackSize(m_stackSize); + + if (m_stackPtr != NULL) + { + erpc_assert((m_stackPtr == NULL) && ("RT-Thread backend uses rt_thread_create()." != NULL)); + return; + } + + m_arg = arg; + + m_thread = rt_thread_create(threadName, threadEntryPointStub, this, stackSize, priority, ERPC_RTTHREAD_THREAD_TIMESLICE); + erpc_assert(m_thread != RT_NULL); + if (m_thread != RT_NULL) + { + rt_err_t err; + + m_thread->user_data = static_cast(reinterpret_cast(this)); + err = rt_thread_startup(m_thread); + erpc_assert(err == RT_EOK); + } +} + +bool Thread::operator==(Thread &o) +{ + return m_thread == o.m_thread; +} + +Thread *Thread::getCurrentThread(void) +{ + rt_thread_t thread = rt_thread_self(); + + if ((thread == RT_NULL) || (thread->user_data == 0U)) + { + return NULL; + } + + return reinterpret_cast(static_cast(thread->user_data)); +} + +void Thread::sleep(uint32_t usecs) +{ + rt_tick_t ticks = usecsToTicks(usecs); + + if (ticks == 0U) + { + (void)rt_thread_yield(); + } + else + { + (void)rt_thread_delay(ticks); + } +} + +void Thread::threadEntryPoint(void) +{ + if (m_entry != NULL) + { + m_entry(m_arg); + } +} + +void Thread::threadEntryPointStub(void *arg) +{ + Thread *_this = reinterpret_cast(arg); + rt_thread_t current = rt_thread_self(); + + erpc_assert((_this != NULL) && ("Reinterpreting 'void *arg' to 'Thread *' failed." != NULL)); + if (current != RT_NULL) + { + current->user_data = static_cast(reinterpret_cast(_this)); + } + + _this->threadEntryPoint(); + + if ((current != RT_NULL) && (current->user_data == static_cast(reinterpret_cast(_this)))) + { + current->user_data = 0U; + } + _this->m_thread = RT_NULL; +} + +Mutex::Mutex(void) : m_mutex() +{ + rt_err_t err = rt_mutex_init(&m_mutex, "erpc_m", RT_IPC_FLAG_PRIO); + erpc_assert(err == RT_EOK); +} + +Mutex::~Mutex(void) +{ + (void)rt_mutex_detach(&m_mutex); +} + +bool Mutex::tryLock(void) +{ + return (rt_mutex_take(&m_mutex, RT_WAITING_NO) == RT_EOK); +} + +bool Mutex::lock(void) +{ + return (rt_mutex_take(&m_mutex, RT_WAITING_FOREVER) == RT_EOK); +} + +bool Mutex::unlock(void) +{ + return (rt_mutex_release(&m_mutex) == RT_EOK); +} + +Semaphore::Semaphore(int count) : m_sem() +{ + rt_err_t err; + + erpc_assert((count >= 0) && (count <= 0xFFFF)); + err = rt_sem_init(&m_sem, "erpc_s", (rt_uint32_t)count, RT_IPC_FLAG_PRIO); + erpc_assert(err == RT_EOK); +} + +Semaphore::~Semaphore(void) +{ + (void)rt_sem_detach(&m_sem); +} + +void Semaphore::put(void) +{ + (void)rt_sem_release(&m_sem); +} + +bool Semaphore::get(uint32_t timeoutUsecs) +{ + return (rt_sem_take(&m_sem, usecsToWaitTicks(timeoutUsecs)) == RT_EOK); +} + +int Semaphore::getCount(void) const +{ + rt_base_t level; + rt_uint16_t value; + rt_sem_t sem = const_cast(&m_sem); + + level = rt_spin_lock_irqsave(&(sem->spinlock)); + value = sem->value; + rt_spin_unlock_irqrestore(&(sem->spinlock), level); + + return (int)value; +} + +#endif /* ERPC_THREADS_IS(RTTHREAD) */ + +//////////////////////////////////////////////////////////////////////////////// +// EOF +//////////////////////////////////////////////////////////////////////////////// diff --git a/erpc_c/port/rtthread/erpc_config.h b/erpc_c/port/rtthread/erpc_config.h new file mode 100644 index 000000000..0ee62b0b7 --- /dev/null +++ b/erpc_c/port/rtthread/erpc_config.h @@ -0,0 +1,212 @@ +/* + * RT-Thread platform configuration for eRPC. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef _ERPC_CONFIG_H_ +#define _ERPC_CONFIG_H_ + +#include "rtconfig.h" + +/*! + * @addtogroup config + * @{ + * @file + */ + +//! @name Configuration value constants +//@{ +#define ERPC_ALLOCATION_POLICY_DYNAMIC (0U) //!< Dynamic allocation policy. +#define ERPC_ALLOCATION_POLICY_STATIC (1U) //!< Static allocation policy. + +#define ERPC_THREADS_NONE (0U) //!< No threads. +#define ERPC_THREADS_PTHREADS (1U) //!< POSIX pthreads. +#define ERPC_THREADS_FREERTOS (2U) //!< FreeRTOS. +#define ERPC_THREADS_ZEPHYR (3U) //!< Zephyr. +#define ERPC_THREADS_MBED (4U) //!< Mbed OS. +#define ERPC_THREADS_WIN32 (5U) //!< Win32. +#define ERPC_THREADS_THREADX (6U) //!< ThreadX. +#define ERPC_THREADS_RTTHREAD (7U) //!< RT-Thread. + +#define ERPC_NOEXCEPT_DISABLED (0U) //!< Disable noexcept support. +#define ERPC_NOEXCEPT_ENABLED (1U) //!< Enable noexcept support. + +#define ERPC_NESTED_CALLS_DISABLED (0U) //!< Disable nested call support. +#define ERPC_NESTED_CALLS_ENABLED (1U) //!< Enable nested call support. +#define ERPC_NESTED_CALLS_DETECTION_DISABLED (0U) //!< Disable nested call detection. +#define ERPC_NESTED_CALLS_DETECTION_ENABLED (1U) //!< Enable nested call detection. + +#define ERPC_MESSAGE_LOGGING_DISABLED (0U) //!< Disable message logging. +#define ERPC_MESSAGE_LOGGING_ENABLED (1U) //!< Enable message logging. + +#define ERPC_TRANSPORT_MU_USE_MCMGR_DISABLED (0U) //!< Do not use MCMGR for MU ISR management. +#define ERPC_TRANSPORT_MU_USE_MCMGR_ENABLED (1U) //!< Use MCMGR for MU ISR management. + +#define ERPC_PRE_POST_ACTION_DISABLED (0U) //!< Disable pre/post shim callbacks. +#define ERPC_PRE_POST_ACTION_ENABLED (1U) //!< Enable pre/post shim callbacks. +#define ERPC_PRE_POST_ACTION_DEFAULT_DISABLED (0U) //!< Disable default pre/post callbacks. +#define ERPC_PRE_POST_ACTION_DEFAULT_ENABLED (1U) //!< Enable default pre/post callbacks. +//@} + +//! @name RT-Thread platform defaults +//@{ + +/** + * @brief Disable POSIX auto-detection for RT-Thread package builds. + * + * RT-Thread MCU builds must not select pthreads just because the host compiler + * or toolchain exposes POSIX macros. + */ +#define ERPC_HAS_POSIX (0) + +/** + * @brief Disable Win32 auto-detection for RT-Thread package builds. + * + * This package does not build the Win32 port, so Win32 detection is disabled + * unconditionally for the RT-Thread configuration entry. + */ +#define ERPC_HAS_WIN32 (0) + +/** @brief Force eRPC to use the native RT-Thread threading backend. */ +#define ERPC_THREADS (ERPC_THREADS_RTTHREAD) + +/** @brief Force eRPC to use dynamic allocation through the RT-Thread heap port. */ +#define ERPC_ALLOCATION_POLICY (ERPC_ALLOCATION_POLICY_DYNAMIC) + +#ifndef PKG_ERPC_RTTHREAD_THREAD_STACK_SIZE +#define PKG_ERPC_RTTHREAD_THREAD_STACK_SIZE (2048U) +#endif /* PKG_ERPC_RTTHREAD_THREAD_STACK_SIZE */ + +#ifndef PKG_ERPC_RTTHREAD_THREAD_PRIORITY +#define PKG_ERPC_RTTHREAD_THREAD_PRIORITY (20U) +#endif /* PKG_ERPC_RTTHREAD_THREAD_PRIORITY */ + +#ifndef PKG_ERPC_RTTHREAD_THREAD_TIMESLICE +#define PKG_ERPC_RTTHREAD_THREAD_TIMESLICE (10U) +#endif /* PKG_ERPC_RTTHREAD_THREAD_TIMESLICE */ + +#ifndef PKG_ERPC_RTTHREAD_UART_TRANSPORT_COUNT +#define PKG_ERPC_RTTHREAD_UART_TRANSPORT_COUNT (1U) +#endif /* PKG_ERPC_RTTHREAD_UART_TRANSPORT_COUNT */ + +/** @brief Default stack size for eRPC threads created by the RT-Thread backend. */ +#define ERPC_RTTHREAD_THREAD_STACK_SIZE (PKG_ERPC_RTTHREAD_THREAD_STACK_SIZE) + +/** @brief Default native priority for eRPC threads created with priority 0. */ +#define ERPC_RTTHREAD_THREAD_PRIORITY (PKG_ERPC_RTTHREAD_THREAD_PRIORITY) + +/** @brief Default timeslice for eRPC threads created by the RT-Thread backend. */ +#define ERPC_RTTHREAD_THREAD_TIMESLICE (PKG_ERPC_RTTHREAD_THREAD_TIMESLICE) + +/** @brief Maximum number of simultaneously active RT-Thread UART transports. */ +#define ERPC_RTTHREAD_UART_TRANSPORT_COUNT (PKG_ERPC_RTTHREAD_UART_TRANSPORT_COUNT) +//@} + +//! @name Message buffer settings +//@{ +#ifndef PKG_ERPC_DEFAULT_BUFFER_SIZE +#define PKG_ERPC_DEFAULT_BUFFER_SIZE (256U) +#endif /* PKG_ERPC_DEFAULT_BUFFER_SIZE */ + +#ifndef PKG_ERPC_DEFAULT_BUFFERS_COUNT +#define PKG_ERPC_DEFAULT_BUFFERS_COUNT (2U) +#endif /* PKG_ERPC_DEFAULT_BUFFERS_COUNT */ + +/** @brief eRPC message buffer size in bytes. */ +#define ERPC_DEFAULT_BUFFER_SIZE (PKG_ERPC_DEFAULT_BUFFER_SIZE) + +/** @brief Number of buffers owned by the static message buffer factory. */ +#define ERPC_DEFAULT_BUFFERS_COUNT (PKG_ERPC_DEFAULT_BUFFERS_COUNT) +//@} + +//! @name eRPC feature settings +//@{ +/** @brief Configure eRPC noexcept support. */ +#if defined(PKG_ERPC_NOEXCEPT) +#define ERPC_NOEXCEPT (ERPC_NOEXCEPT_ENABLED) +#else +#define ERPC_NOEXCEPT (ERPC_NOEXCEPT_DISABLED) +#endif /* PKG_ERPC_NOEXCEPT */ + +/** @brief Configure nested call support. */ +#if defined(PKG_ERPC_NESTED_CALLS) +#define ERPC_NESTED_CALLS (ERPC_NESTED_CALLS_ENABLED) +#else +#define ERPC_NESTED_CALLS (ERPC_NESTED_CALLS_DISABLED) +#endif /* PKG_ERPC_NESTED_CALLS */ + +/** @brief Configure nested call detection. */ +#if defined(PKG_ERPC_NESTED_CALLS_DETECTION) +#define ERPC_NESTED_CALLS_DETECTION (ERPC_NESTED_CALLS_DETECTION_ENABLED) +#else +#define ERPC_NESTED_CALLS_DETECTION (ERPC_NESTED_CALLS_DETECTION_DISABLED) +#endif /* PKG_ERPC_NESTED_CALLS_DETECTION */ + +/** @brief Configure eRPC message logging support. */ +#if defined(PKG_ERPC_MESSAGE_LOGGING) +#define ERPC_MESSAGE_LOGGING (ERPC_MESSAGE_LOGGING_ENABLED) +#else +#define ERPC_MESSAGE_LOGGING (ERPC_MESSAGE_LOGGING_DISABLED) +#endif /* PKG_ERPC_MESSAGE_LOGGING */ + +/** @brief Configure MCMGR usage in the MU transport. */ +#if defined(PKG_ERPC_TRANSPORT_MU_USE_MCMGR) +#define ERPC_TRANSPORT_MU_USE_MCMGR (ERPC_TRANSPORT_MU_USE_MCMGR_ENABLED) +#else +#define ERPC_TRANSPORT_MU_USE_MCMGR (ERPC_TRANSPORT_MU_USE_MCMGR_DISABLED) +#endif /* PKG_ERPC_TRANSPORT_MU_USE_MCMGR */ + +/** @brief Configure eRPC pre/post action shim support. */ +#if defined(PKG_ERPC_PRE_POST_ACTION) +#define ERPC_PRE_POST_ACTION (ERPC_PRE_POST_ACTION_ENABLED) +#else +#define ERPC_PRE_POST_ACTION (ERPC_PRE_POST_ACTION_DISABLED) +#endif /* PKG_ERPC_PRE_POST_ACTION */ + +/** @brief Configure default eRPC pre/post action callback support. */ +#if defined(PKG_ERPC_PRE_POST_ACTION_DEFAULT) +#define ERPC_PRE_POST_ACTION_DEFAULT (ERPC_PRE_POST_ACTION_DEFAULT_ENABLED) +#else +#define ERPC_PRE_POST_ACTION_DEFAULT (ERPC_PRE_POST_ACTION_DEFAULT_DISABLED) +#endif /* PKG_ERPC_PRE_POST_ACTION_DEFAULT */ +//@} + +//! @name eRPC endianness helper settings +//@{ +#ifndef PKG_ERPC_ENDIANNESS_HEADER +#define PKG_ERPC_ENDIANNESS_HEADER "erpc_endianness_agnostic_example.h" +#endif /* PKG_ERPC_ENDIANNESS_HEADER */ + +#define ENDIANNESS_HEADER PKG_ERPC_ENDIANNESS_HEADER + +#if defined(PKG_ERPC_PROCESSOR_ENDIANNESS_BIG) +#define ERPC_PROCESSOR_ENDIANNESS_LITTLE (0) +#else +#define ERPC_PROCESSOR_ENDIANNESS_LITTLE (1) +#endif /* PKG_ERPC_PROCESSOR_ENDIANNESS_BIG */ + +#if defined(PKG_ERPC_COMMUNICATION_BIG) +#define ERPC_COMMUNICATION_LITTLE (0) +#else +#define ERPC_COMMUNICATION_LITTLE (1) +#endif /* PKG_ERPC_COMMUNICATION_BIG */ + +#if defined(PKG_ERPC_POINTER_SIZE_16) +#define ERPC_POINTER_SIZE_16 (1) +#define ERPC_POINTER_SIZE_32 (0) +#define ERPC_POINTER_SIZE_64 (0) +#elif defined(PKG_ERPC_POINTER_SIZE_64) +#define ERPC_POINTER_SIZE_16 (0) +#define ERPC_POINTER_SIZE_32 (0) +#define ERPC_POINTER_SIZE_64 (1) +#else +#define ERPC_POINTER_SIZE_16 (0) +#define ERPC_POINTER_SIZE_32 (1) +#define ERPC_POINTER_SIZE_64 (0) +#endif /* PKG_ERPC_POINTER_SIZE_16 */ +//@} + +/*! @} */ + +#endif /* _ERPC_CONFIG_H_ */ diff --git a/erpc_c/setup/erpc_setup_uart_rtthread.cpp b/erpc_c/setup/erpc_setup_uart_rtthread.cpp new file mode 100644 index 000000000..d7a1309a6 --- /dev/null +++ b/erpc_c/setup/erpc_setup_uart_rtthread.cpp @@ -0,0 +1,40 @@ +/* + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include "erpc_transport_setup.h" +#include "erpc_uart_rtthread_transport.hpp" + +using namespace erpc; + +//////////////////////////////////////////////////////////////////////////////// +// Code +//////////////////////////////////////////////////////////////////////////////// + +erpc_transport_t erpc_transport_rtthread_uart_init(const char *devName, uint32_t baudRate) +{ + erpc_transport_t transport; + RtThreadUartTransport *uartTransport = new RtThreadUartTransport(devName, baudRate); + + transport = reinterpret_cast(uartTransport); + + if (uartTransport != NULL) + { + if (uartTransport->init() != kErpcStatus_Success) + { + erpc_transport_rtthread_uart_deinit(transport); + transport = NULL; + } + } + + return transport; +} + +void erpc_transport_rtthread_uart_deinit(erpc_transport_t transport) +{ + erpc_assert(transport != NULL); + + RtThreadUartTransport *uartTransport = reinterpret_cast(transport); + + delete uartTransport; +} diff --git a/erpc_c/setup/erpc_transport_setup.h b/erpc_c/setup/erpc_transport_setup.h index d18ac20f0..9eb7cd172 100644 --- a/erpc_c/setup/erpc_transport_setup.h +++ b/erpc_c/setup/erpc_transport_setup.h @@ -485,6 +485,32 @@ void erpc_transport_tcp_deinit(erpc_transport_t transport); //@} + +//! @name RT-Thread UART transport setup +//@{ + +/*! + * @brief Create an RT-Thread UART transport. + * + * Create an RT-Thread UART transport instance, to be used on both the server + * and the client side. + * + * @param[in] devName RT-Thread UART device name, for example "uart2". + * @param[in] baudRate UART baud rate. + * + * @return Return NULL or erpc_transport_t instance pointer. + */ +erpc_transport_t erpc_transport_rtthread_uart_init(const char *devName, uint32_t baudRate); + +/*! + * @brief Deinitialize RT-Thread UART transport. + * + * @param[in] transport Transport which was initialized with init function. + */ +void erpc_transport_rtthread_uart_deinit(erpc_transport_t transport); + +//@} + //! @name CMSIS UART transport setup //@{ diff --git a/erpc_c/transports/erpc_uart_rtthread_transport.cpp b/erpc_c/transports/erpc_uart_rtthread_transport.cpp new file mode 100644 index 000000000..1bba794f4 --- /dev/null +++ b/erpc_c/transports/erpc_uart_rtthread_transport.cpp @@ -0,0 +1,242 @@ +/* + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include "erpc_uart_rtthread_transport.hpp" + +using namespace erpc; + +//////////////////////////////////////////////////////////////////////////////// +// Variables +//////////////////////////////////////////////////////////////////////////////// + +RtThreadUartTransport::RegistryEntry RtThreadUartTransport::s_registry[ERPC_RTTHREAD_UART_TRANSPORT_COUNT] = {}; + +//////////////////////////////////////////////////////////////////////////////// +// Code +//////////////////////////////////////////////////////////////////////////////// + +RtThreadUartTransport::RtThreadUartTransport(const char *devName, uint32_t baudRate) : +m_devName(devName), m_baudRate(baudRate), m_dev(RT_NULL), m_rxSemaphore(), m_isOpen(false), m_isSemInitialized(false), +m_isRxIndicateSet(false), m_isRegistered(false) +{ +} + +RtThreadUartTransport::~RtThreadUartTransport(void) +{ + if ((m_dev != RT_NULL) && m_isRxIndicateSet) + { + (void)rt_device_set_rx_indicate(m_dev, RT_NULL); + m_isRxIndicateSet = false; + } + + unregisterTransport(); + + if ((m_dev != RT_NULL) && m_isOpen) + { + (void)rt_device_close(m_dev); + m_isOpen = false; + } + + if (m_isSemInitialized) + { + (void)rt_sem_detach(&m_rxSemaphore); + m_isSemInitialized = false; + } + + m_dev = RT_NULL; +} + +erpc_status_t RtThreadUartTransport::init(void) +{ + erpc_status_t status = kErpcStatus_InitFailed; + rt_err_t err; + //serial v2 + struct serial_configure config = RT_SERIAL_CONFIG_DEFAULT; + + if (m_devName == NULL) + { + return status; + } + + m_dev = rt_device_find(m_devName); + if (m_dev == RT_NULL) + { + return status; + } + + config.rx_bufsz = ERPC_DEFAULT_BUFFER_SIZE; + config.tx_bufsz = ERPC_DEFAULT_BUFFER_SIZE; + config.dma_ping_bufsz = ERPC_DEFAULT_BUFFER_SIZE; + config.baud_rate = m_baudRate; + err = rt_device_control(m_dev, RT_DEVICE_CTRL_CONFIG, &config); + if (err != RT_EOK) + { + return status; + } + + if (rt_device_open(m_dev, RT_DEVICE_FLAG_RX_NON_BLOCKING | RT_DEVICE_FLAG_TX_NON_BLOCKING) != RT_EOK) + { + return status; + } + m_isOpen = true; + + if (!registerTransport()) + { + return status; + } + + err = rt_device_set_rx_indicate(m_dev, rxIndicate); + if (err != RT_EOK) + { + return status; + } + m_isRxIndicateSet = true; + + err = rt_sem_init(&m_rxSemaphore, "erpc_rx", 0, RT_IPC_FLAG_PRIO); + if (err != RT_EOK) + { + return status; + } + m_isSemInitialized = true; + + status = kErpcStatus_Success; + return status; +} + +erpc_status_t RtThreadUartTransport::underlyingReceive(uint8_t *data, uint32_t size) +{ + uint32_t received = 0; + + if ((m_dev == RT_NULL) || ((data == NULL) && (size > 0U))) + { + return kErpcStatus_ReceiveFailed; + } + + while (received < size) + { + rt_size_t readSize = rt_device_read(m_dev, -1, &data[received], size - received); + + if (readSize > 0U) + { + received += readSize; + continue; + } + + if (rt_sem_take(&m_rxSemaphore, RT_WAITING_FOREVER) != RT_EOK) + { + return kErpcStatus_ReceiveFailed; + } + } + + return kErpcStatus_Success; +} + +erpc_status_t RtThreadUartTransport::underlyingSend(const uint8_t *data, uint32_t size) +{ + uint32_t sent = 0; + + if ((m_dev == RT_NULL) || ((data == NULL) && (size > 0U))) + { + return kErpcStatus_SendFailed; + } + + while (sent < size) + { + rt_size_t writeSize = rt_device_write(m_dev, 0, &data[sent], size - sent); + + if (writeSize == 0U) + { + return kErpcStatus_SendFailed; + } + + sent += writeSize; + } + + return kErpcStatus_Success; +} + +rt_err_t RtThreadUartTransport::rxIndicate(rt_device_t dev, rt_size_t size) +{ + RtThreadUartTransport *transport; + + (void)size; + + transport = findByDevice(dev); + if (transport != NULL) + { + (void)rt_sem_release(&transport->m_rxSemaphore); + } + + return RT_EOK; +} + +bool RtThreadUartTransport::registerTransport(void) +{ + bool registered = false; + int emptySlot; + + if ((m_dev == RT_NULL) || m_isRegistered) + { + return false; + } + + if (findByDevice(m_dev) == NULL) + { + emptySlot = findEmptySlot(); + if (emptySlot >= 0) + { + s_registry[emptySlot].transport = this; + s_registry[emptySlot].dev = m_dev; + m_isRegistered = true; + registered = true; + } + } + + return registered; +} + +void RtThreadUartTransport::unregisterTransport(void) +{ + if (!m_isRegistered) + { + return; + } + + for (uint32_t i = 0U; i < ERPC_RTTHREAD_UART_TRANSPORT_COUNT; ++i) + { + if (s_registry[i].transport == this) + { + s_registry[i].dev = RT_NULL; + s_registry[i].transport = NULL; + m_isRegistered = false; + break; + } + } +} + +RtThreadUartTransport *RtThreadUartTransport::findByDevice(rt_device_t dev) +{ + for (uint32_t i = 0U; i < ERPC_RTTHREAD_UART_TRANSPORT_COUNT; ++i) + { + if (s_registry[i].dev == dev) + { + return s_registry[i].transport; + } + } + + return NULL; +} + +int RtThreadUartTransport::findEmptySlot(void) +{ + for (uint32_t i = 0U; i < ERPC_RTTHREAD_UART_TRANSPORT_COUNT; ++i) + { + if (s_registry[i].dev == RT_NULL) + { + return (int)i; + } + } + + return -1; +} diff --git a/erpc_c/transports/erpc_uart_rtthread_transport.hpp b/erpc_c/transports/erpc_uart_rtthread_transport.hpp new file mode 100644 index 000000000..d48de9604 --- /dev/null +++ b/erpc_c/transports/erpc_uart_rtthread_transport.hpp @@ -0,0 +1,159 @@ +/* + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef _EMBEDDED_RPC_RTTHREAD_UART_TRANSPORT_H_ +#define _EMBEDDED_RPC_RTTHREAD_UART_TRANSPORT_H_ + +#include "erpc_config_internal.h" +#include "erpc_framed_transport.hpp" + +#include +#include + +#ifndef ERPC_RTTHREAD_UART_TRANSPORT_COUNT +#define ERPC_RTTHREAD_UART_TRANSPORT_COUNT (1U) +#endif /* ERPC_RTTHREAD_UART_TRANSPORT_COUNT */ + +/*! + * @addtogroup uart_transport + * @{ + * @file + */ + +//////////////////////////////////////////////////////////////////////////////// +// Classes +//////////////////////////////////////////////////////////////////////////////// + +namespace erpc { +/*! + * @brief Transport to send and receive eRPC framed messages over an RT-Thread UART device. + * + * @ingroup uart_transport + * + * @note This transport owns the UART receive callback while active. Applications should not set another + * rx_indicate callback on the same UART device during the transport lifetime. + * + * @note The UART transport registry is updated only during init/deinit. Runtime RX callbacks read the registry + * without locking. Applications must not deinitialize a transport while it is being used by an eRPC client/server + * or while another thread may access the same transport. + */ +class RtThreadUartTransport : public FramedTransport +{ +public: + /*! + * @brief Constructor. + * + * @param[in] devName RT-Thread UART device name, for example "uart2". + * @param[in] baudRate UART baud rate. + */ + RtThreadUartTransport(const char *devName, uint32_t baudRate); + + /*! + * @brief Destructor. + */ + virtual ~RtThreadUartTransport(void); + + /*! + * @brief Initialize the RT-Thread UART device. + * + * @retval kErpcStatus_InitFailed UART device initialization failed. + * @retval kErpcStatus_Success UART device initialization succeeded. + */ + virtual erpc_status_t init(void); + +private: + using FramedTransport::underlyingReceive; + using FramedTransport::underlyingSend; + + /*! + * @brief Receive bytes from the UART device. + * + * @param[out] data Preallocated buffer for receiving data. + * @param[in] size Number of bytes to receive. + * + * @retval kErpcStatus_ReceiveFailed UART read failed. + * @retval kErpcStatus_Success All requested bytes were received. + */ + virtual erpc_status_t underlyingReceive(uint8_t *data, uint32_t size) override; + + /*! + * @brief Write bytes to the UART device. + * + * @param[in] data Buffer to send. + * @param[in] size Number of bytes to send. + * + * @retval kErpcStatus_SendFailed UART write failed. + * @retval kErpcStatus_Success All requested bytes were sent. + */ + virtual erpc_status_t underlyingSend(const uint8_t *data, uint32_t size) override; + + /*! + * @brief RT-Thread UART receive notification callback. + * + * @param[in] dev UART device that received data. + * @param[in] size Number of received bytes reported by the driver. + * + * @return RT_EOK. + */ + static rt_err_t rxIndicate(rt_device_t dev, rt_size_t size); + + /*! + * @brief Register this transport in the fixed device-to-transport registry. + * + * @return true when the transport was registered successfully. + */ + bool registerTransport(void); + + /*! + * @brief Remove this transport from the fixed device-to-transport registry. + */ + void unregisterTransport(void); + + /*! + * @brief Find the transport bound to a UART device. + * + * The registry is updated only during init/deinit. Runtime RX callbacks read it without locking. + * + * @param[in] dev RT-Thread UART device handle. + * + * @return Matching transport or NULL. + */ + static RtThreadUartTransport *findByDevice(rt_device_t dev); + + /*! + * @brief Find an empty fixed registry slot. + * + * The registry is updated only during init/deinit. This helper is not thread-safe. + * + * @return Slot index or -1 when the registry is full. + */ + static int findEmptySlot(void); + +private: + const char *m_devName; /*!< RT-Thread UART device name. */ + uint32_t m_baudRate; /*!< UART baud rate. */ + rt_device_t m_dev; /*!< RT-Thread UART device handle. */ + struct rt_semaphore m_rxSemaphore; /*!< Semaphore released by the UART RX callback. */ + bool m_isOpen; /*!< Whether the UART device has been opened by this transport. */ + bool m_isSemInitialized; /*!< Whether m_rxSemaphore has been initialized. */ + bool m_isRxIndicateSet; /*!< Whether this transport has installed the UART RX callback. */ + bool m_isRegistered; /*!< Whether this transport is in the fixed device registry. */ + + /*! + * @brief Fixed registry entry that maps one UART device to one transport. + */ + struct RegistryEntry + { + rt_device_t dev; /*!< Registered RT-Thread UART device. */ + RtThreadUartTransport *transport; /*!< Transport bound to the UART device. */ + }; + + static RegistryEntry s_registry[ERPC_RTTHREAD_UART_TRANSPORT_COUNT]; /*!< Fixed device-to-transport registry. */ +}; + +} // namespace erpc + +/*! @} */ + +#endif /* _EMBEDDED_RPC_RTTHREAD_UART_TRANSPORT_H_ */ diff --git a/rtthread/Kconfig b/rtthread/Kconfig new file mode 100644 index 000000000..4a2366bd5 --- /dev/null +++ b/rtthread/Kconfig @@ -0,0 +1,447 @@ +# +# RT-Thread package configuration for eRPC. +# +# SPDX-License-Identifier: BSD-3-Clause +# + +menuconfig PKG_USING_ERPC + bool "eRPC: Embedded RPC framework" + default n + select RT_USING_CPLUSPLUS + select RT_USING_HEAP + select RT_USING_MUTEX + select RT_USING_SEMAPHORE + help + Enable the Embedded RPC runtime as an RT-Thread package. This package + builds the eRPC C/C++ runtime sources used by generated client and + server stubs. The host-side erpcgen tool is not built for the MCU + target by this package. + +if PKG_USING_ERPC + +menu "eRPC RT-Thread runtime configuration" + +config PKG_ERPC_HAS_THREADING_BACKEND + bool + default y + +config PKG_ERPC_RTTHREAD_THREAD_STACK_SIZE + int "Default eRPC thread stack size" + default 2048 + range 512 65535 + help + Default stack size in bytes for eRPC threads created without an + explicit stack size. + +config PKG_ERPC_RTTHREAD_THREAD_PRIORITY + int "Default eRPC thread priority" + default 20 + range 0 255 + help + Default RT-Thread native priority used when the eRPC thread priority is + 0. Non-zero eRPC priorities are passed through as native RT-Thread + priorities. + +config PKG_ERPC_RTTHREAD_THREAD_TIMESLICE + int "Default eRPC thread timeslice" + default 10 + range 1 65535 + help + Default RT-Thread timeslice used for eRPC threads. + +endmenu + +menu "eRPC core components" + +config PKG_ERPC_USING_CLIENT + bool "Enable client runtime" + default n + help + Build the eRPC client manager and client setup helper. Enable this when + generated client stubs will issue RPC requests from the RT-Thread + target. + +config PKG_ERPC_USING_SERVER + bool "Enable server runtime" + default y + help + Build the eRPC server core and simple server setup helper. This is the + default package role for an MCU board that exposes services over a + transport such as UART. + +config PKG_ERPC_USING_TRANSPORT_ARBITRATOR + bool "Enable transport arbitrator runtime" + default n + depends on PKG_ERPC_USING_CLIENT + help + Build erpc_transport_arbitrator.cpp. This component multiplexes replies + and incoming invocations over a shared transport. It requires a valid + eRPC threading backend, which is fixed to RT-Thread native APIs in this package. + +config PKG_ERPC_USING_ARBITRATED_CLIENT + bool "Enable arbitrated client setup" + default n + depends on PKG_ERPC_USING_CLIENT && PKG_ERPC_USING_TRANSPORT_ARBITRATOR + help + Build the arbitrated client manager and setup helper. This is used when + a client shares a transport with a server and replies must be routed to + pending client requests. + +endmenu + +menu "eRPC message buffer factory" + +choice + prompt "Message buffer factory setup helper" + default PKG_ERPC_USING_MBF_DYNAMIC + help + Select exactly one setup helper for creating an eRPC message buffer + factory. Applications that create their own factory manually can still + ignore the selected setup API. + +config PKG_ERPC_USING_MBF_DYNAMIC + bool "Dynamic message buffer factory setup" + help + Build erpc_mbf_dynamic_init(). The factory allocates each message + buffer dynamically with ERPC_DEFAULT_BUFFER_SIZE bytes. + +config PKG_ERPC_USING_MBF_STATIC + bool "Static message buffer factory setup" + help + Build erpc_mbf_static_init(). The factory owns a fixed pool of + ERPC_DEFAULT_BUFFERS_COUNT buffers, each sized by + ERPC_DEFAULT_BUFFER_SIZE. + +endchoice + +config PKG_ERPC_DEFAULT_BUFFER_SIZE + int "eRPC message buffer size" + default 256 + range 1 65535 + help + Size in bytes for message buffers created by eRPC setup helpers. For + RPMsg transports this value must follow the eRPC transport requirement, + normally 2^n - 16. + +config PKG_ERPC_DEFAULT_BUFFERS_COUNT + int "Static message buffer count" + default 2 + range 1 255 + depends on PKG_ERPC_USING_MBF_STATIC + help + Number of buffers owned by the static message buffer factory. + +endmenu + +menu "eRPC feature macros" + +config PKG_ERPC_NOEXCEPT + bool "Enable noexcept support" + default n + help + Define ERPC_NOEXCEPT as ERPC_NOEXCEPT_ENABLED. The disabled state + defines ERPC_NOEXCEPT as ERPC_NOEXCEPT_DISABLED. + +config PKG_ERPC_NESTED_CALLS + bool "Enable nested calls" + default n + help + Define ERPC_NESTED_CALLS as ERPC_NESTED_CALLS_ENABLED. Nested calls + require a working eRPC threading backend. + +config PKG_ERPC_NESTED_CALLS_DETECTION + bool "Enable nested-call detection" + default y if !PKG_ERPC_NESTED_CALLS + default n + help + Define ERPC_NESTED_CALLS_DETECTION as + ERPC_NESTED_CALLS_DETECTION_ENABLED. This is mainly useful while + debugging unmarked nested calls. + +config PKG_ERPC_MESSAGE_LOGGING + bool "Enable message logging" + default n + help + Define ERPC_MESSAGE_LOGGING as ERPC_MESSAGE_LOGGING_ENABLED and compile + the message logger runtime source. + +config PKG_ERPC_PRE_POST_ACTION + bool "Enable pre/post action hooks" + default n + help + Define ERPC_PRE_POST_ACTION as ERPC_PRE_POST_ACTION_ENABLED. This + controls whether pre/post action callback hooks are enabled in eRPC + runtime code. + +config PKG_ERPC_PRE_POST_ACTION_DEFAULT + bool "Enable default pre/post callbacks" + default n + depends on PKG_ERPC_PRE_POST_ACTION + help + Define ERPC_PRE_POST_ACTION_DEFAULT as + ERPC_PRE_POST_ACTION_DEFAULT_ENABLED. This option affects default + pre/post callbacks only; it does not replace the need to enable + ERPC_PRE_POST_ACTION itself. + +endmenu + +menu "eRPC endianness configuration" + +config PKG_ERPC_ENDIANNESS_HEADER + string "ENDIANNESS_HEADER value" + default "erpc_endianness_agnostic_example.h" + help + Header name assigned to ENDIANNESS_HEADER. The selected header must be + reachable from the eRPC include path. + +choice + prompt "Processor endianness" + default PKG_ERPC_PROCESSOR_ENDIANNESS_LITTLE + help + Select the byte order of the current MCU processor for the selected + eRPC endianness helper. + +config PKG_ERPC_PROCESSOR_ENDIANNESS_LITTLE + bool "Processor is little endian" + help + Define ERPC_PROCESSOR_ENDIANNESS_LITTLE as 1. + +config PKG_ERPC_PROCESSOR_ENDIANNESS_BIG + bool "Processor is big endian" + help + Define ERPC_PROCESSOR_ENDIANNESS_LITTLE as 0. + +endchoice + +choice + prompt "Communication endianness" + default PKG_ERPC_COMMUNICATION_LITTLE + help + Select the byte order used on the eRPC wire format for the selected + endianness helper. + +config PKG_ERPC_COMMUNICATION_LITTLE + bool "Communication is little endian" + help + Define ERPC_COMMUNICATION_LITTLE as 1. + +config PKG_ERPC_COMMUNICATION_BIG + bool "Communication is big endian" + help + Define ERPC_COMMUNICATION_LITTLE as 0. + +endchoice + +choice + prompt "Pointer size for endianness helper" + default PKG_ERPC_POINTER_SIZE_32 + help + Select the pointer width reported to the selected endianness helper. + +config PKG_ERPC_POINTER_SIZE_16 + bool "16-bit pointer" + help + Define ERPC_POINTER_SIZE_16 as enabled and the other pointer-size macros + as disabled. + +config PKG_ERPC_POINTER_SIZE_32 + bool "32-bit pointer" + help + Define ERPC_POINTER_SIZE_32 as enabled and the other pointer-size macros + as disabled. + +config PKG_ERPC_POINTER_SIZE_64 + bool "64-bit pointer" + help + Define ERPC_POINTER_SIZE_64 as enabled and the other pointer-size macros + as disabled. + +endchoice + +endmenu + +menu "eRPC transport components" + +config PKG_ERPC_USING_TRANSPORT_INTER_THREAD_BUFFER + bool "Inter-thread buffer transport" + default n + depends on PKG_ERPC_USING_CLIENT && PKG_ERPC_USING_SERVER + help + Build erpc_inter_thread_buffer_transport.cpp. This transport connects a + local client and server inside the same process and does not depend on a + hardware device driver. + +config PKG_ERPC_USING_TRANSPORT_RTTHREAD_UART + bool "RT-Thread UART transport" + default n + depends on RT_USING_DEVICE && RT_USING_SERIAL + help + Build the native RT-Thread UART transport. The transport uses the + RT-Thread device API and supports multiple UART device instances. Each + active transport owns the receive callback of its UART device. + +config PKG_ERPC_RTTHREAD_UART_TRANSPORT_COUNT + int "Maximum active RT-Thread UART transports" + default 1 + range 1 16 + depends on PKG_ERPC_USING_TRANSPORT_RTTHREAD_UART + help + Maximum number of simultaneously registered RT-Thread UART transports. + The native UART transport uses a fixed registry and does not allocate + registry nodes dynamically. + +menuconfig PKG_ERPC_HAS_CMSIS_DRIVER_USART + bool "CMSIS Driver_USART transport support" + default n + help + Enable this when the BSP provides the CMSIS Driver_USART interface used + by erpc_uart_cmsis_transport.cpp. + +if PKG_ERPC_HAS_CMSIS_DRIVER_USART + +config PKG_ERPC_USING_TRANSPORT_UART_CMSIS + bool "CMSIS UART transport" + default n + help + Build erpc_uart_cmsis_transport.cpp and its setup helper. The BSP must + provide the CMSIS Driver_USART API. + +endif + +menuconfig PKG_ERPC_HAS_NXP_SERIAL_MANAGER + bool "NXP serial manager transport support" + default n + help + Enable this when the BSP provides fsl_component_serial_manager.h for the + USB CDC transport implementation. + +if PKG_ERPC_HAS_NXP_SERIAL_MANAGER + +config PKG_ERPC_USING_TRANSPORT_USB_CDC + bool "USB CDC transport" + default n + depends on RT_USING_USB_DEVICE + help + Build erpc_usb_cdc_transport.cpp and its setup helper. The BSP must + provide RT-Thread USB device support and the NXP serial manager header. + +endif + +menuconfig PKG_ERPC_HAS_MCUX_SDK + bool "NXP MCUX SDK transport support" + default n + help + Enable this when the BSP provides board.h and the NXP fsl_* driver + headers required by the MCUX SPI, I2C, and MU transport sources. + +if PKG_ERPC_HAS_MCUX_SDK + +config PKG_ERPC_USING_TRANSPORT_SPI_MASTER + bool "MCUX SPI master transport" + default n + depends on RT_USING_SPI + help + Build erpc_spi_master_transport.cpp and its setup helper. The source + uses board.h, fsl_spi.h, fsl_gpio.h, and fsl_port.h. + +config PKG_ERPC_USING_TRANSPORT_SPI_SLAVE + bool "MCUX SPI slave transport" + default n + depends on RT_USING_SPI + help + Build erpc_spi_slave_transport.cpp and its setup helper. The source uses + board.h, fsl_spi.h, and fsl_gpio.h. + +config PKG_ERPC_USING_TRANSPORT_DSPI_MASTER + bool "MCUX DSPI master transport" + default n + depends on RT_USING_SPI + help + Build erpc_dspi_master_transport.cpp and its setup helper. The source + uses board.h, fsl_dspi.h, fsl_gpio.h, and fsl_port.h. + +config PKG_ERPC_USING_TRANSPORT_DSPI_SLAVE + bool "MCUX DSPI slave transport" + default n + depends on RT_USING_SPI + help + Build erpc_dspi_slave_transport.cpp and its setup helper. The source + uses board.h, fsl_dspi.h, and fsl_gpio.h. + +config PKG_ERPC_USING_TRANSPORT_LPSPI_SLAVE + bool "MCUX LPSPI slave transport" + default n + depends on RT_USING_SPI + help + Build erpc_lpspi_slave_transport.cpp and its setup helper. The source + uses board.h, fsl_lpspi.h, and fsl_gpio.h. + +config PKG_ERPC_USING_TRANSPORT_I2C_SLAVE + bool "MCUX I2C slave transport" + default n + depends on RT_USING_I2C + help + Build erpc_i2c_slave_transport.cpp and its setup helper. The source uses + board.h, fsl_i2c.h, and fsl_gpio.h. + +config PKG_ERPC_USING_TRANSPORT_LPI2C_SLAVE + bool "MCUX LPI2C slave transport" + default n + depends on RT_USING_I2C + help + Build erpc_lpi2c_slave_transport.cpp and its setup helper. The source + uses board.h, fsl_lpi2c.h, and fsl_gpio.h. + +config PKG_ERPC_USING_TRANSPORT_MU + bool "MCUX MU transport" + default n + help + Build erpc_mu_transport.cpp and its setup helper. This transport uses + NXP MU hardware support from the MCUX SDK. + +config PKG_ERPC_TRANSPORT_MU_USE_MCMGR + bool "Use MCMGR for MU interrupt management" + default n + depends on PKG_ERPC_USING_TRANSPORT_MU + help + Define ERPC_TRANSPORT_MU_USE_MCMGR as + ERPC_TRANSPORT_MU_USE_MCMGR_ENABLED. When disabled, the macro is defined + as ERPC_TRANSPORT_MU_USE_MCMGR_DISABLED. + +endif + +menuconfig PKG_ERPC_HAS_RPMSG_LITE + bool "RPMsg-Lite transport support" + default n + help + Enable this when rpmsg_lite.h, rpmsg_ns.h, and the related RPMsg-Lite + headers are available in the BSP include path. + +if PKG_ERPC_HAS_RPMSG_LITE + +config PKG_ERPC_USING_TRANSPORT_RPMSG_LITE + bool "RPMsg-Lite bare-metal transport" + default n + help + Build the RPMsg-Lite transport, RPMsg message buffer setup helper, and + master/remote setup helpers. + +config PKG_ERPC_USING_TRANSPORT_RPMSG_LITE_RTOS + bool "RPMsg-Lite RTOS transport" + default n + help + Build the RPMsg-Lite RTOS transport, RPMsg message buffer setup helper, + and RTOS master/remote setup helpers. + +config PKG_ERPC_USING_TRANSPORT_RPMSG_TTY_RTOS + bool "RPMsg TTY RTOS transport" + default n + help + Build erpc_rpmsg_tty_rtos_transport.cpp and the RPMsg TTY remote setup + helper. + +endif + +endmenu + +endif diff --git a/rtthread/README.md b/rtthread/README.md new file mode 100644 index 000000000..b07a38e82 --- /dev/null +++ b/rtthread/README.md @@ -0,0 +1,118 @@ +# eRPC RT-Thread integration + +This directory provides RT-Thread integration files for the eRPC C runtime. + +## Files + +- `Kconfig`: RT-Thread `menuconfig` options for selecting eRPC runtime components. +- `SConscript`: RT-Thread SCons build script for compiling the selected eRPC sources. + +The eRPC generic CMake source list is not changed by this integration. RT-Thread builds use the files in this directory through RT-Thread `menuconfig` and SCons. + +## Required RT-Thread features + +The package configuration selects the following RT-Thread features when `PKG_USING_ERPC` is enabled: + +- `RT_USING_CPLUSPLUS` +- `RT_USING_HEAP` +- `RT_USING_MUTEX` +- `RT_USING_SEMAPHORE` + +For the RT-Thread UART transport, the BSP must also provide device and serial support: + +- `RT_USING_DEVICE` +- `RT_USING_SERIAL` + +## Kconfig entry + +Add the eRPC RT-Thread Kconfig file to the RT-Thread package or project Kconfig entry used by your BSP. + +For example, when eRPC is placed under a package directory that is reachable from the BSP Kconfig, add a `source` line similar to: + +```text +source "$PKGS_DIR/erpc/rtthread/Kconfig" +``` + +Adjust the path to match the package layout used by your RT-Thread project. + +## Configure with menuconfig + +Open RT-Thread configuration from the BSP root directory: + +```sh +scons --menuconfig +``` + +Then enable: + +```text +eRPC: Embedded RPC framework +``` + +Select at least one runtime role: + +- `Enable client runtime`, if generated client stubs run on the RT-Thread target. +- `Enable server runtime`, if generated server stubs run on the RT-Thread target. + +For UART transport, enable: + +```text +RT-Thread UART transport +``` + +The UART transport option depends on RT-Thread device and serial support. + +## SCons entry + +This integration keeps the RT-Thread build logic in `rtthread/SConscript` and does not require the eRPC repository to carry a root-level `SConscript` file. + +If your RT-Thread package flow expects a `SConscript` file at the eRPC repository root, create a small root-level shim in your local package copy: + +```python +# +# RT-Thread package entry for eRPC. +# +# SPDX-License-Identifier: BSD-3-Clause +# + +from building import * +import os + +cwd = GetCurrentDir() +group = SConscript(os.path.join(cwd, 'rtthread', 'SConscript')) + +Return('group') +``` + +The shim only forwards the build to `rtthread/SConscript`. The actual source selection remains controlled by RT-Thread `menuconfig` options. + +## Configuration header + +The RT-Thread SCons integration adds this include path before the generic eRPC configuration directory: + +```text +erpc_c/port/rtthread +``` + +This makes `erpc_c/port/rtthread/erpc_config.h` the eRPC configuration header for RT-Thread package builds. + +The RT-Thread configuration header includes `rtconfig.h`, disables host POSIX/Win32 auto-detection for the RT-Thread package build, and selects the native RT-Thread backend: + +```c +#define ERPC_THREADS (ERPC_THREADS_RTTHREAD) +#define ERPC_ALLOCATION_POLICY (ERPC_ALLOCATION_POLICY_DYNAMIC) +``` + +Thread defaults and UART transport registry size are controlled by the `PKG_ERPC_*` options selected in `menuconfig`. + +## UART transport usage + +The RT-Thread UART transport uses the RT-Thread device API. The device name must match the BSP UART device name, for example: + +```c +erpc_transport_t transport = erpc_transport_rtthread_uart_init("uart2", 115200); +``` + +The UART transport owns the RT-Thread `rx_indicate` callback while active. Applications should not install another receive callback on the same UART device during the transport lifetime. + +The transport registry is updated during init/deinit. Do not deinitialize a transport while it is being used by an eRPC client/server or while another thread may access the same transport. diff --git a/rtthread/SConscript b/rtthread/SConscript new file mode 100644 index 000000000..f361eb753 --- /dev/null +++ b/rtthread/SConscript @@ -0,0 +1,180 @@ +# +# RT-Thread SCons build script for eRPC. +# +# SPDX-License-Identifier: BSD-3-Clause +# + +from building import * +import os + +cwd = GetCurrentDir() +REPO_ROOT = os.path.abspath(os.path.join(cwd, '..')) +ERPC_C = os.path.join(REPO_ROOT, 'erpc_c') +RTTHREAD_DIR = cwd +RTTHREAD_CONFIG_DIR = os.path.join(ERPC_C, 'port', 'rtthread') + + +def _is_enabled(name): + try: + return GetDepend(name) + except Exception: + return False + + +def _add_existing(src, paths): + for path in paths: + full_path = os.path.join(REPO_ROOT, path) + if os.path.exists(full_path): + src.append(os.path.relpath(full_path, cwd)) + + +src = [] + +_add_existing(src, [ + 'erpc_c/infra/erpc_basic_codec.cpp', + 'erpc_c/infra/erpc_crc16.cpp', + 'erpc_c/infra/erpc_framed_transport.cpp', + 'erpc_c/infra/erpc_message_buffer.cpp', + 'erpc_c/infra/erpc_pre_post_action.cpp', + 'erpc_c/infra/erpc_utils.cpp', + 'erpc_c/port/erpc_port_rtthread.cpp', + 'erpc_c/port/erpc_threading_rtthread.cpp', +]) + +if _is_enabled('PKG_ERPC_USING_CLIENT'): + _add_existing(src, [ + 'erpc_c/infra/erpc_client_manager.cpp', + 'erpc_c/setup/erpc_client_setup.cpp', + ]) + +if _is_enabled('PKG_ERPC_USING_SERVER'): + _add_existing(src, [ + 'erpc_c/infra/erpc_server.cpp', + 'erpc_c/infra/erpc_simple_server.cpp', + 'erpc_c/setup/erpc_server_setup.cpp', + ]) + +if _is_enabled('PKG_ERPC_USING_TRANSPORT_ARBITRATOR'): + _add_existing(src, ['erpc_c/infra/erpc_transport_arbitrator.cpp']) + +if _is_enabled('PKG_ERPC_USING_ARBITRATED_CLIENT'): + _add_existing(src, [ + 'erpc_c/infra/erpc_arbitrated_client_manager.cpp', + 'erpc_c/setup/erpc_arbitrated_client_setup.cpp', + ]) + +if _is_enabled('PKG_ERPC_USING_MBF_DYNAMIC'): + _add_existing(src, ['erpc_c/setup/erpc_setup_mbf_dynamic.cpp']) + +if _is_enabled('PKG_ERPC_USING_MBF_STATIC'): + _add_existing(src, ['erpc_c/setup/erpc_setup_mbf_static.cpp']) + +if _is_enabled('PKG_ERPC_MESSAGE_LOGGING'): + _add_existing(src, ['erpc_c/infra/erpc_message_loggers.cpp']) + +if _is_enabled('PKG_ERPC_USING_TRANSPORT_INTER_THREAD_BUFFER'): + _add_existing(src, ['erpc_c/transports/erpc_inter_thread_buffer_transport.cpp']) + +if _is_enabled('PKG_ERPC_USING_TRANSPORT_RTTHREAD_UART'): + _add_existing(src, [ + 'erpc_c/transports/erpc_uart_rtthread_transport.cpp', + 'erpc_c/setup/erpc_setup_uart_rtthread.cpp', + ]) + +if _is_enabled('PKG_ERPC_USING_TRANSPORT_UART_CMSIS'): + _add_existing(src, [ + 'erpc_c/transports/erpc_uart_cmsis_transport.cpp', + 'erpc_c/setup/erpc_setup_uart_cmsis.cpp', + ]) + +if _is_enabled('PKG_ERPC_USING_TRANSPORT_USB_CDC'): + _add_existing(src, [ + 'erpc_c/transports/erpc_usb_cdc_transport.cpp', + 'erpc_c/setup/erpc_setup_usb_cdc.cpp', + ]) + +if _is_enabled('PKG_ERPC_USING_TRANSPORT_SPI_MASTER'): + _add_existing(src, [ + 'erpc_c/transports/erpc_spi_master_transport.cpp', + 'erpc_c/setup/erpc_setup_spi_master.cpp', + ]) + +if _is_enabled('PKG_ERPC_USING_TRANSPORT_SPI_SLAVE'): + _add_existing(src, [ + 'erpc_c/transports/erpc_spi_slave_transport.cpp', + 'erpc_c/setup/erpc_setup_spi_slave.cpp', + ]) + +if _is_enabled('PKG_ERPC_USING_TRANSPORT_DSPI_MASTER'): + _add_existing(src, [ + 'erpc_c/transports/erpc_dspi_master_transport.cpp', + 'erpc_c/setup/erpc_setup_dspi_master.cpp', + ]) + +if _is_enabled('PKG_ERPC_USING_TRANSPORT_DSPI_SLAVE'): + _add_existing(src, [ + 'erpc_c/transports/erpc_dspi_slave_transport.cpp', + 'erpc_c/setup/erpc_setup_dspi_slave.cpp', + ]) + +if _is_enabled('PKG_ERPC_USING_TRANSPORT_LPSPI_SLAVE'): + _add_existing(src, [ + 'erpc_c/transports/erpc_lpspi_slave_transport.cpp', + 'erpc_c/setup/erpc_setup_lpspi_slave.cpp', + ]) + +if _is_enabled('PKG_ERPC_USING_TRANSPORT_I2C_SLAVE'): + _add_existing(src, [ + 'erpc_c/transports/erpc_i2c_slave_transport.cpp', + 'erpc_c/setup/erpc_setup_i2c_slave.cpp', + ]) + +if _is_enabled('PKG_ERPC_USING_TRANSPORT_LPI2C_SLAVE'): + _add_existing(src, [ + 'erpc_c/transports/erpc_lpi2c_slave_transport.cpp', + 'erpc_c/setup/erpc_setup_lpi2c_slave.cpp', + ]) + +if _is_enabled('PKG_ERPC_USING_TRANSPORT_MU'): + _add_existing(src, [ + 'erpc_c/transports/erpc_mu_transport.cpp', + 'erpc_c/setup/erpc_setup_mu.cpp', + ]) + +if _is_enabled('PKG_ERPC_USING_TRANSPORT_RPMSG_LITE'): + _add_existing(src, [ + 'erpc_c/transports/erpc_rpmsg_lite_transport.cpp', + 'erpc_c/setup/erpc_setup_mbf_rpmsg.cpp', + 'erpc_c/setup/erpc_setup_rpmsg_lite_master.cpp', + 'erpc_c/setup/erpc_setup_rpmsg_lite_remote.cpp', + ]) + +if _is_enabled('PKG_ERPC_USING_TRANSPORT_RPMSG_LITE_RTOS'): + _add_existing(src, [ + 'erpc_c/transports/erpc_rpmsg_lite_rtos_transport.cpp', + 'erpc_c/setup/erpc_setup_mbf_rpmsg.cpp', + 'erpc_c/setup/erpc_setup_rpmsg_lite_rtos_master.cpp', + 'erpc_c/setup/erpc_setup_rpmsg_lite_rtos_remote.cpp', + ]) + +if _is_enabled('PKG_ERPC_USING_TRANSPORT_RPMSG_TTY_RTOS'): + _add_existing(src, [ + 'erpc_c/transports/erpc_rpmsg_tty_rtos_transport.cpp', + 'erpc_c/setup/erpc_setup_rpmsg_tty_rtos_remote.cpp', + ]) + +CPPPATH = [ + RTTHREAD_CONFIG_DIR, + RTTHREAD_DIR, + os.path.join(ERPC_C, 'infra'), + os.path.join(ERPC_C, 'port'), + os.path.join(ERPC_C, 'service'), + os.path.join(ERPC_C, 'setup'), + os.path.join(ERPC_C, 'transports'), +] + +src = list(dict.fromkeys(src)) + +group = DefineGroup('eRPC', src, depend=['PKG_USING_ERPC'], CPPPATH=CPPPATH) + +Return('group')