From 7201e34ee916a908a38252369b5f9dbfd4965141 Mon Sep 17 00:00:00 2001 From: Chris Ring Date: Mon, 15 Apr 2019 10:43:03 -0700 Subject: [PATCH 01/96] Remove whitespace from C common header template Removes whitespace from the C common header template. This whitespace separates the template's doxygen-style comment and the user's (optional) trailing interface comment. This helps remove undesirable trailing whitespace for the (many) users that don't use trailing interface comments. Signed-off-by: Chris Ring --- erpcgen/src/templates/c_common_header.template | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erpcgen/src/templates/c_common_header.template b/erpcgen/src/templates/c_common_header.template index 0e93542af..4af36e21c 100644 --- a/erpcgen/src/templates/c_common_header.template +++ b/erpcgen/src/templates/c_common_header.template @@ -129,7 +129,7 @@ extern "C" { {$> fn.mlComment} {$fn.prototype};{$fn.ilComment}{$loop.addNewLineIfNotLast} {% endfor -- functions %} -//@} {$iface.ilComment} +//@}{$iface.ilComment} {% endfor -- iface %} #if defined(__cplusplus) From dbc27bc2bfaa02de122dac8a010d802543980017 Mon Sep 17 00:00:00 2001 From: Dusan Cervenka Date: Mon, 21 Oct 2019 14:56:59 +0200 Subject: [PATCH 02/96] Added deinit function for RPMSG tty --- .../erpc_setup_rpmsg_tty_rtos_remote.cpp | 5 ++++ erpc_c/setup/erpc_transport_setup.h | 25 ++++++++++++------- .../erpc_rpmsg_tty_rtos_transport.cpp | 4 +++ 3 files changed, 25 insertions(+), 9 deletions(-) diff --git a/erpc_c/setup/erpc_setup_rpmsg_tty_rtos_remote.cpp b/erpc_c/setup/erpc_setup_rpmsg_tty_rtos_remote.cpp index 3f3b048a0..db20f8f75 100644 --- a/erpc_c/setup/erpc_setup_rpmsg_tty_rtos_remote.cpp +++ b/erpc_c/setup/erpc_setup_rpmsg_tty_rtos_remote.cpp @@ -35,3 +35,8 @@ erpc_transport_t erpc_transport_rpmsg_lite_tty_rtos_remote_init(unsigned long sr } return NULL; } + +void erpc_transport_rpmsg_lite_tty_rtos_deinit() +{ + s_transport.destroy(); +} diff --git a/erpc_c/setup/erpc_transport_setup.h b/erpc_c/setup/erpc_transport_setup.h index c845ec737..33b59fdf3 100644 --- a/erpc_c/setup/erpc_transport_setup.h +++ b/erpc_c/setup/erpc_transport_setup.h @@ -44,8 +44,8 @@ extern "C" { /*! * @brief Create a CMSIS UART transport. * - * Create a CMSIS UART transport instance, to be used on both the server - * and the client side. + * Create a CMSIS UART transport instance, to be used on both the server + * and the client side. * * @param[in] uartDrv CMSIS USART driver structure address (Driver Control Block). * @@ -60,7 +60,7 @@ erpc_transport_t erpc_transport_cmsis_uart_init(void *uartDrv); /*! * @brief Create a host PC serial port transport. * - * Create a host PC serial port transport instance. + * Create a host PC serial port transport instance. * * @param[in] portName Port name. * @param[in] baudRate Baud rate. @@ -76,7 +76,7 @@ erpc_transport_t erpc_transport_serial_init(const char *portName, long baudRate) /*! * @brief Create a SPI master transport. * - * Create SPI master transport instance, to be used at master core. + * Create SPI master transport instance, to be used at master core. * * @param[in] baseAddr Base address of SPI peripheral used in this transport layer. * @param[in] baudRate SPI baud rate. @@ -89,7 +89,7 @@ erpc_transport_t erpc_transport_spi_master_init(void *baseAddr, uint32_t baudRat /*! * @brief Create a SPI slave transport. * - * Create SPI slave transport instance, to be used at slave core. + * Create SPI slave transport instance, to be used at slave core. * * @param[in] baseAddr Base address of SPI peripheral used in this transport layer. * @param[in] baudRate SPI baud rate. @@ -106,7 +106,7 @@ erpc_transport_t erpc_transport_spi_slave_init(void *baseAddr, uint32_t baudRate /*! * @brief Create a DSPI master transport. * - * Create DSPI master transport instance, to be used at master core. + * Create DSPI master transport instance, to be used at master core. * * @param[in] baseAddr Base address of DSPI peripheral used in this transport layer. * @param[in] baudRate DSPI baud rate. @@ -119,7 +119,7 @@ erpc_transport_t erpc_transport_dspi_master_init(void *baseAddr, uint32_t baudRa /*! * @brief Create a DSPI slave transport. * - * Create DSPI slave transport instance, to be used at slave core. + * Create DSPI slave transport instance, to be used at slave core. * * @param[in] baseAddr Base address of DSPI peripheral used in this transport layer. * @param[in] baudRate DSPI baud rate. @@ -136,8 +136,8 @@ erpc_transport_t erpc_transport_dspi_slave_init(void *baseAddr, uint32_t baudRat /*! * @brief Create an MU transport. * - * Create Messaging Unit (MU) transport instance, to be used on both the server - * and the client side. Base address of the MU peripheral needs to be passed. + * Create Messaging Unit (MU) transport instance, to be used on both the server + * and the client side. Base address of the MU peripheral needs to be passed. * * @param[in] baseAddr Base address of MU peripheral. * @@ -246,6 +246,13 @@ erpc_transport_t erpc_transport_rpmsg_lite_rtos_remote_init(unsigned long src_ad erpc_transport_t erpc_transport_rpmsg_lite_tty_rtos_remote_init(unsigned long src_addr, unsigned long dst_addr, void *start_address, int rpmsg_link_id, rpmsg_ready_cb ready, char *nameservice_name); + +/*! + * @brief Deinitialize an RPMSG lite tty rtos transport. + * + * This function deinitializes the RPMSG lite tty rtos transport. + */ +void erpc_transport_rpmsg_lite_tty_rtos_deinit(void); //@} //! @name Linux RPMSG endpoint setup diff --git a/erpc_c/transports/erpc_rpmsg_tty_rtos_transport.cpp b/erpc_c/transports/erpc_rpmsg_tty_rtos_transport.cpp index 755cfff23..2aebf2a87 100644 --- a/erpc_c/transports/erpc_rpmsg_tty_rtos_transport.cpp +++ b/erpc_c/transports/erpc_rpmsg_tty_rtos_transport.cpp @@ -37,6 +37,10 @@ RPMsgTTYRTOSTransport::RPMsgTTYRTOSTransport(void) RPMsgTTYRTOSTransport::~RPMsgTTYRTOSTransport(void) { + if (m_rpmsg_ept != RL_NULL) + { + rpmsg_queue_destroy(s_rpmsg, m_rpmsg_ept) + } rpmsg_lite_deinit(s_rpmsg); s_initialized = 0; } From 96199e4faabb1e61236ee1dd94def9dd6381b77e Mon Sep 17 00:00:00 2001 From: Dusan Cervenka Date: Mon, 21 Oct 2019 15:18:56 +0200 Subject: [PATCH 03/96] Fixed deinitialization of RPMSG lite tty transport --- .../erpc_rpmsg_tty_rtos_transport.cpp | 27 ++++++++++++++++--- 1 file changed, 23 insertions(+), 4 deletions(-) diff --git a/erpc_c/transports/erpc_rpmsg_tty_rtos_transport.cpp b/erpc_c/transports/erpc_rpmsg_tty_rtos_transport.cpp index 2aebf2a87..6dbc2d091 100644 --- a/erpc_c/transports/erpc_rpmsg_tty_rtos_transport.cpp +++ b/erpc_c/transports/erpc_rpmsg_tty_rtos_transport.cpp @@ -37,12 +37,31 @@ RPMsgTTYRTOSTransport::RPMsgTTYRTOSTransport(void) RPMsgTTYRTOSTransport::~RPMsgTTYRTOSTransport(void) { - if (m_rpmsg_ept != RL_NULL) + if (s_rpmsg != NULL) { - rpmsg_queue_destroy(s_rpmsg, m_rpmsg_ept) + if (m_rpmsg_ept != RL_NULL) + { + if (RL_SUCCESS != rpmsg_lite_destroy_ept(s_rpmsg, m_rpmsg_ept)) + { + return; + } + } + + if (m_rpmsg_queue != RL_NULL) + { + if (RL_SUCCESS != rpmsg_queue_destroy(s_rpmsg, m_rpmsg_queue)) + { + return; + } + } + + if (RL_SUCCESS != rpmsg_lite_deinit(s_rpmsg)) + { + return; + } + + s_initialized = 0; } - rpmsg_lite_deinit(s_rpmsg); - s_initialized = 0; } void RPMsgTTYRTOSTransport::setCrc16(Crc16 *crcImpl) From f7481518801e5f0d9f3a903807de080cd7102b94 Mon Sep 17 00:00:00 2001 From: "Michal Princ (nxa17570)" Date: Tue, 17 Dec 2019 10:53:36 +0100 Subject: [PATCH 04/96] eRPC updates 12/2019 -- improved the test_callbacks logic to be more understandable and to allow requested callback execution on the server side -- transportArbitrator::prepareClientReceive modified to avoid incorrect return value type -- the ClientManager and the ArbitratedClientManager updated to avoid performing client requests when the previous serialization phase fails -- generate the shim code for destroy of statically allocated services -- documentation update for v1.7.3 --- README.md | 6 +- doxygen/Doxyfile.erpc | 2 +- doxygen/Doxyfile.erpcgen | 2 +- erpc_c/config/erpc_config.h | 6 +- .../infra/erpc_arbitrated_client_manager.cpp | 25 ++- erpc_c/infra/erpc_arbitrated_client_manager.h | 2 +- erpc_c/infra/erpc_client_manager.cpp | 50 ++++-- erpc_c/infra/erpc_client_manager.h | 6 +- erpc_c/infra/erpc_server.cpp | 20 +++ erpc_c/infra/erpc_server.h | 7 + erpc_c/infra/erpc_simple_server.cpp | 10 -- erpc_c/infra/erpc_simple_server.h | 5 - erpc_c/infra/erpc_transport_arbitrator.cpp | 7 +- erpc_c/infra/erpc_version.h | 6 +- erpc_c/port/erpc_config_internal.h | 2 +- erpc_c/port/erpc_threading_freertos.cpp | 22 ++- erpc_c/setup/erpc_server_setup.cpp | 8 + erpc_c/setup/erpc_server_setup.h | 7 + erpc_c/setup/erpc_setup_mbf_rpmsg.cpp | 4 +- erpc_c/setup/erpc_setup_mbf_rpmsg_tty.cpp | 4 +- erpc_c/setup/erpc_setup_rpmsg_lite_master.cpp | 3 +- erpc_c/setup/erpc_setup_rpmsg_lite_remote.cpp | 4 +- .../erpc_setup_rpmsg_lite_rtos_master.cpp | 3 +- .../erpc_setup_rpmsg_lite_rtos_remote.cpp | 6 +- .../erpc_setup_rpmsg_tty_rtos_remote.cpp | 6 +- erpc_c/setup/erpc_transport_setup.h | 23 ++- .../erpc_rpmsg_lite_rtos_transport.cpp | 14 +- .../erpc_rpmsg_lite_rtos_transport.h | 8 +- .../transports/erpc_rpmsg_lite_transport.cpp | 13 +- erpc_c/transports/erpc_rpmsg_lite_transport.h | 10 +- .../erpc_rpmsg_tty_rtos_transport.cpp | 16 +- .../erpc_rpmsg_tty_rtos_transport.h | 8 +- erpc_python/README.rst | 24 --- erpc_python/README_Pypi.md | 23 +++ erpc_python/erpc/erpc_version.py | 4 +- erpc_python/setup.cfg | 10 +- erpc_python/setup.py | 7 +- .../src/templates/c_common_header.template | 2 +- .../src/templates/c_server_header.template | 6 + .../src/templates/c_server_source.template | 13 ++ .../service/__init__.py | 2 +- .../service/erpc_matrix_multiply/__init__.py | 6 +- .../service/erpc_matrix_multiply/client.py | 2 +- .../service/erpc_matrix_multiply/common.py | 2 +- .../service/erpc_matrix_multiply/interface.py | 2 +- .../service/erpc_matrix_multiply/server.py | 2 +- test/common/gtest/gtest.h | 2 +- test/common/retarget_cpp_streamed_io.c | 168 ++++++++---------- test/common/unit_test_client.cpp | 22 +-- test/common/unit_test_server.cpp | 20 +-- test/test_callbacks/callbacks1.h | 4 +- test/test_callbacks/callbacks2.h | 2 +- test/test_callbacks/test_callbacks.erpc | 10 +- .../test_callbacks_client_impl.cpp | 24 ++- .../test_callbacks_server_impl.cpp | 45 ++--- 55 files changed, 389 insertions(+), 328 deletions(-) delete mode 100644 erpc_python/README.rst create mode 100644 erpc_python/README_Pypi.md diff --git a/README.md b/README.md index fb243b6ad..6dc3ad2a3 100644 --- a/README.md +++ b/README.md @@ -26,7 +26,7 @@ Client side usage: void example_client(void) { // Initialize client running over UART. erpc_client_init( - erpc_transport_cmsis_uart_init(UART0_NonBlocking_Driver); + erpc_transport_cmsis_uart_init(Driver_USART0); // Now we can call the remote function to turn on the green LED. set_led(kGreen, true); @@ -43,7 +43,7 @@ void set_led(LEDName whichLed, bool onOrOff) { void example_server(void) { // Initialize server running over UART. erpc_server_init( - erpc_transport_uart_init(UART0_NonBlocking_Driver); + erpc_transport_cmsis_uart_init(Driver_USART0); // Add the IO service. erpc_add_service_to_server(create_IO_service()); @@ -71,7 +71,7 @@ eRPC is available with an unrestrictive BSD 3-clause license. See the LICENSE fi ## Documentation -[Documentation](https://github.com/EmbeddedRPC/erpc/wiki) is in the `wiki` section. Commit sha in wiki repository: 7199a9c00fef4b952a6b05a8e3b0257f788e4eeb. +[Documentation](https://github.com/EmbeddedRPC/erpc/wiki) is in the `wiki` section. Commit sha in wiki repository: 431cba8. [Example IDL](examples/README.md) is available in the `examples/` folder. diff --git a/doxygen/Doxyfile.erpc b/doxygen/Doxyfile.erpc index a76e2af5c..dae9cb25b 100644 --- a/doxygen/Doxyfile.erpc +++ b/doxygen/Doxyfile.erpc @@ -38,7 +38,7 @@ PROJECT_NAME = "eRPC API Reference" # could be handy for archiving the generated documentation or if some version # control system is used. -PROJECT_NUMBER = "Rev. 1.7.2" +PROJECT_NUMBER = "Rev. 1.7.3" # Using the PROJECT_BRIEF tag one can provide an optional one line description # for a project that appears at the top of each page and should give viewer a diff --git a/doxygen/Doxyfile.erpcgen b/doxygen/Doxyfile.erpcgen index c83ed08a9..1771189b5 100644 --- a/doxygen/Doxyfile.erpcgen +++ b/doxygen/Doxyfile.erpcgen @@ -38,7 +38,7 @@ PROJECT_NAME = "eRPC Generator (erpcgen)" # could be handy for archiving the generated documentation or if some version # control system is used. -PROJECT_NUMBER = "Rev. 1.7.2" +PROJECT_NUMBER = "Rev. 1.7.3" # Using the PROJECT_BRIEF tag one can provide an optional one line description # for a project that appears at the top of each page and should give viewer a diff --git a/erpc_c/config/erpc_config.h b/erpc_c/config/erpc_config.h index a8a1b84a0..6e2e73538 100644 --- a/erpc_c/config/erpc_config.h +++ b/erpc_c/config/erpc_config.h @@ -1,6 +1,6 @@ /* * Copyright (c) 2016, Freescale Semiconductor, Inc. - * Copyright 2016-2018 NXP + * Copyright 2016-2019 NXP * All rights reserved. * * @@ -94,7 +94,7 @@ //! @def ERPC_MESSAGE_LOGGING //! -//! Enable eRPC message logging code through the eRPC. Take look into "message_logging.h". Can be used for base printing +//! Enable eRPC message logging code through the eRPC. Take look into "erpc_message_loggers.h". Can be used for base printing //! messages, or sending data to another system for data analysis. Default set to ERPC_MESSAGE_LOGGING_DISABLED. //! //! Uncomment for using logging feature. @@ -112,7 +112,7 @@ //! is part of the project, otherwise the ERPC_TRANSPORT_MU_USE_MCMGR_DISABLED option is used. This settings can be //! overwritten from the erpc_config.h by uncommenting the ERPC_TRANSPORT_MU_USE_MCMGR macro definition. Do not forget //! to add the MCMGR library into your project when ERPC_TRANSPORT_MU_USE_MCMGR_ENABLED option is used! See the -//! mu_transport.h for additional MU settings. +//! erpc_mu_transport.h for additional MU settings. //#define ERPC_TRANSPORT_MU_USE_MCMGR ERPC_TRANSPORT_MU_USE_MCMGR_DISABLED //@} diff --git a/erpc_c/infra/erpc_arbitrated_client_manager.cpp b/erpc_c/infra/erpc_arbitrated_client_manager.cpp index 50c204636..a68661649 100644 --- a/erpc_c/infra/erpc_arbitrated_client_manager.cpp +++ b/erpc_c/infra/erpc_arbitrated_client_manager.cpp @@ -29,7 +29,7 @@ void ArbitratedClientManager::setArbitrator(TransportArbitrator *arbitrator) m_transport = arbitrator; } -erpc_status_t ArbitratedClientManager::performClientRequest(RequestContext &request) +void ArbitratedClientManager::performClientRequest(RequestContext &request) { assert(m_arbitrator && "arbitrator not set"); @@ -42,13 +42,15 @@ erpc_status_t ArbitratedClientManager::performClientRequest(RequestContext &requ #if ERPC_NESTED_CALLS_DETECTION if (nestingDetection) { - return kErpcStatus_NestedCallFailure; + request.getCodec()->updateStatus(kErpcStatus_NestedCallFailure); + return; } #endif token = m_arbitrator->prepareClientReceive(request); if (!token) { - return kErpcStatus_Fail; + request.getCodec()->updateStatus(kErpcStatus_Fail); + return; } } @@ -58,7 +60,8 @@ erpc_status_t ArbitratedClientManager::performClientRequest(RequestContext &requ err = logMessage(request.getCodec()->getBuffer()); if (err) { - return err; + request.getCodec()->updateStatus(err); + return; } #endif @@ -66,7 +69,8 @@ erpc_status_t ArbitratedClientManager::performClientRequest(RequestContext &requ err = m_arbitrator->send(request.getCodec()->getBuffer()); if (err) { - return err; + request.getCodec()->updateStatus(err); + return; } if (!request.isOneway()) @@ -75,14 +79,16 @@ erpc_status_t ArbitratedClientManager::performClientRequest(RequestContext &requ err = m_arbitrator->clientReceive(token); if (err) { - return err; + request.getCodec()->updateStatus(err); + return; } #if ERPC_MESSAGE_LOGGING err = logMessage(request.getCodec()->getBuffer()); if (err) { - return err; + request.getCodec()->updateStatus(err); + return; } #endif @@ -90,9 +96,10 @@ erpc_status_t ArbitratedClientManager::performClientRequest(RequestContext &requ err = verifyReply(request); if (err) { - return err; + request.getCodec()->updateStatus(err); + return; } } - return kErpcStatus_Success; + return; } diff --git a/erpc_c/infra/erpc_arbitrated_client_manager.h b/erpc_c/infra/erpc_arbitrated_client_manager.h index 194dad061..d6bf0922a 100644 --- a/erpc_c/infra/erpc_arbitrated_client_manager.h +++ b/erpc_c/infra/erpc_arbitrated_client_manager.h @@ -69,7 +69,7 @@ class ArbitratedClientManager : public ClientManager * * @param[in] request Request context to perform. */ - virtual erpc_status_t performClientRequest(RequestContext &request); + virtual void performClientRequest(RequestContext &request); //! @brief This method is not used with this class. void setTransport(Transport *transport) {} diff --git a/erpc_c/infra/erpc_client_manager.cpp b/erpc_c/infra/erpc_client_manager.cpp index f5d38c3a1..2a4e025c6 100644 --- a/erpc_c/infra/erpc_client_manager.cpp +++ b/erpc_c/infra/erpc_client_manager.cpp @@ -35,8 +35,15 @@ RequestContext ClientManager::createRequest(bool isOneway) return RequestContext(++m_sequence, codec, isOneway); } -erpc_status_t ClientManager::performRequest(RequestContext &request) +void ClientManager::performRequest(RequestContext &request) { + // Check the codec status + if (kErpcStatus_Success != (request.getCodec()->getStatus())) + { + // Do not perform the request + return; + } + #if ERPC_NESTED_CALLS assert(m_serverThreadId && "server thread id was not set"); if (Thread::getCurrentThreadId() == m_serverThreadId) @@ -47,12 +54,13 @@ erpc_status_t ClientManager::performRequest(RequestContext &request) return performClientRequest(request); } -erpc_status_t ClientManager::performClientRequest(RequestContext &request) +void ClientManager::performClientRequest(RequestContext &request) { #if ERPC_NESTED_CALLS_DETECTION if (!request.isOneway() && nestingDetection) { - return kErpcStatus_NestedCallFailure; + request.getCodec()->updateStatus(kErpcStatus_NestedCallFailure); + return; } #endif @@ -62,7 +70,8 @@ erpc_status_t ClientManager::performClientRequest(RequestContext &request) err = logMessage(request.getCodec()->getBuffer()); if (err) { - return err; + request.getCodec()->updateStatus(err); + return; } #endif @@ -70,7 +79,8 @@ erpc_status_t ClientManager::performClientRequest(RequestContext &request) err = m_transport->send(request.getCodec()->getBuffer()); if (err) { - return err; + request.getCodec()->updateStatus(err); + return; } // If the request is oneway, then there is nothing more to do. @@ -80,14 +90,16 @@ erpc_status_t ClientManager::performClientRequest(RequestContext &request) err = m_transport->receive(request.getCodec()->getBuffer()); if (err) { - return err; + request.getCodec()->updateStatus(err); + return; } #if ERPC_MESSAGE_LOGGING err = logMessage(request.getCodec()->getBuffer()); if (err) { - return err; + request.getCodec()->updateStatus(err); + return; } #endif @@ -95,15 +107,16 @@ erpc_status_t ClientManager::performClientRequest(RequestContext &request) err = verifyReply(request); if (err) { - return err; + request.getCodec()->updateStatus(err); + return; } } - return kErpcStatus_Success; + return; } #if ERPC_NESTED_CALLS -erpc_status_t ClientManager::performNestedClientRequest(RequestContext &request) +void ClientManager::performNestedClientRequest(RequestContext &request) { assert(m_transport && "transport/arbitrator not set"); @@ -113,7 +126,8 @@ erpc_status_t ClientManager::performNestedClientRequest(RequestContext &request) err = logMessage(request.getCodec()->getBuffer()); if (err) { - return err; + request.getCodec()->updateStatus(err); + return; } #endif @@ -121,7 +135,8 @@ erpc_status_t ClientManager::performNestedClientRequest(RequestContext &request) err = m_transport->send(request.getCodec()->getBuffer()); if (err) { - return err; + request.getCodec()->updateStatus(err); + return; } // If the request is oneway, then there is nothing more to do. @@ -132,14 +147,16 @@ erpc_status_t ClientManager::performNestedClientRequest(RequestContext &request) err = m_server->run(request); if (err) { - return err; + request.getCodec()->updateStatus(err); + return; } #if ERPC_MESSAGE_LOGGING err = logMessage(request.getCodec()->getBuffer()); if (err) { - return err; + request.getCodec()->updateStatus(err); + return; } #endif @@ -147,11 +164,10 @@ erpc_status_t ClientManager::performNestedClientRequest(RequestContext &request) err = verifyReply(request); if (err) { - return err; + request.getCodec()->updateStatus(err); + return; } } - - return kErpcStatus_Success; } #endif diff --git a/erpc_c/infra/erpc_client_manager.h b/erpc_c/infra/erpc_client_manager.h index cc4f825ac..9bef6d23c 100644 --- a/erpc_c/infra/erpc_client_manager.h +++ b/erpc_c/infra/erpc_client_manager.h @@ -119,7 +119,7 @@ class ClientManager * * @param[in] request Request context to perform. */ - virtual erpc_status_t performRequest(RequestContext &request); + virtual void performRequest(RequestContext &request); /*! * @brief This function releases request context. @@ -180,7 +180,7 @@ class ClientManager * * @param[in] request Request context to perform. */ - virtual erpc_status_t performClientRequest(RequestContext &request); + virtual void performClientRequest(RequestContext &request); #if ERPC_NESTED_CALLS /*! @@ -190,7 +190,7 @@ class ClientManager * * @param[in] request Request context to perform. */ - virtual erpc_status_t performNestedClientRequest(RequestContext &request); + virtual void performNestedClientRequest(RequestContext &request); #endif //! @brief Validate that an incoming message is a reply. diff --git a/erpc_c/infra/erpc_server.cpp b/erpc_c/infra/erpc_server.cpp index 5e3b98a97..08bade9ea 100644 --- a/erpc_c/infra/erpc_server.cpp +++ b/erpc_c/infra/erpc_server.cpp @@ -42,6 +42,26 @@ void Server::addService(Service *service) link->setNext(service); } +void Server::removeService(Service *service) +{ + Service *link = m_firstService; + + if (link == service) + { + m_firstService = link->getNext(); + return; + } + while (link != NULL) + { + if (link->getNext() == service) + { + link->setNext(link->getNext()->getNext()); + return; + } + link = link->getNext(); + } +} + erpc_status_t Server::readHeadOfMessage(Codec *codec, message_type_t &msgType, uint32_t &serviceId, uint32_t &methodId, uint32_t &sequence) { diff --git a/erpc_c/infra/erpc_server.h b/erpc_c/infra/erpc_server.h index c9c8c2220..7e32f2c9b 100644 --- a/erpc_c/infra/erpc_server.h +++ b/erpc_c/infra/erpc_server.h @@ -159,6 +159,13 @@ class Server */ void addService(Service *service); + /*! + * @brief Remove service. + * + * @param[in] service Service to remove. + */ + void removeService(Service *service); + /*! * @brief This function runs the server. */ diff --git a/erpc_c/infra/erpc_simple_server.cpp b/erpc_c/infra/erpc_simple_server.cpp index bb70639ae..7777c3e5f 100644 --- a/erpc_c/infra/erpc_simple_server.cpp +++ b/erpc_c/infra/erpc_simple_server.cpp @@ -15,16 +15,6 @@ using namespace erpc; // Code //////////////////////////////////////////////////////////////////////////////// -SimpleServer::~SimpleServer(void) -{ - while (m_firstService != NULL) - { - Service *firstService = m_firstService; - m_firstService = m_firstService->getNext(); - delete firstService; - } -} - void SimpleServer::disposeBufferAndCodec(Codec *codec) { if (codec) diff --git a/erpc_c/infra/erpc_simple_server.h b/erpc_c/infra/erpc_simple_server.h index 01942e2d9..2326f0fff 100644 --- a/erpc_c/infra/erpc_simple_server.h +++ b/erpc_c/infra/erpc_simple_server.h @@ -41,11 +41,6 @@ class SimpleServer : public Server { } - /*! - * @brief SimpleServer destructor - */ - virtual ~SimpleServer(void); - /*! * @brief Run server in infinite loop. * diff --git a/erpc_c/infra/erpc_transport_arbitrator.cpp b/erpc_c/infra/erpc_transport_arbitrator.cpp index 846a5645a..d004af3a1 100644 --- a/erpc_c/infra/erpc_transport_arbitrator.cpp +++ b/erpc_c/infra/erpc_transport_arbitrator.cpp @@ -115,12 +115,11 @@ erpc_status_t TransportArbitrator::send(MessageBuffer *message) TransportArbitrator::client_token_t TransportArbitrator::prepareClientReceive(RequestContext &request) { PendingClientInfo *info = addPendingClient(); - if (!info) + if (NULL != info) { - return kErpcStatus_Fail; + info->m_request = &request; + info->m_isValid = true; } - info->m_request = &request; - info->m_isValid = true; return reinterpret_cast(info); } diff --git a/erpc_c/infra/erpc_version.h b/erpc_c/infra/erpc_version.h index 94964efc1..653b1cb12 100644 --- a/erpc_c/infra/erpc_version.h +++ b/erpc_c/infra/erpc_version.h @@ -1,6 +1,6 @@ /* * Copyright (c) 2016, Freescale Semiconductor, Inc. - * Copyright 2016-2017 NXP + * Copyright 2016-2019 NXP * All rights reserved. * * @@ -20,9 +20,9 @@ //////////////////////////////////////////////////////////////////////////////// //! @brief String version of eRPC. -#define ERPC_VERSION "1.7.2" +#define ERPC_VERSION "1.7.3" //! @brief Integer version of eRPC. -#define ERPC_VERSION_NUMBER 10702 +#define ERPC_VERSION_NUMBER 10703 /*! @} */ diff --git a/erpc_c/port/erpc_config_internal.h b/erpc_c/port/erpc_config_internal.h index 7f3a83bfc..d9bca3a03 100644 --- a/erpc_c/port/erpc_config_internal.h +++ b/erpc_c/port/erpc_config_internal.h @@ -106,7 +106,7 @@ #define ERPC_MESSAGE_LOGGING (ERPC_MESSAGE_LOGGING_DISABLED) #endif -#if defined(__CC_ARM) /* Keil MDK */ +#if defined(__CC_ARM) || defined(__ARMCC_VERSION) /* Keil MDK */ #define THROW_BADALLOC throw(std::bad_alloc) #define THROW throw() #else diff --git a/erpc_c/port/erpc_threading_freertos.cpp b/erpc_c/port/erpc_threading_freertos.cpp index ac2a86179..748e55cb4 100644 --- a/erpc_c/port/erpc_threading_freertos.cpp +++ b/erpc_c/port/erpc_threading_freertos.cpp @@ -66,16 +66,17 @@ void Thread::start(void *arg) // which will scan the linked list. taskENTER_CRITICAL(); - (void)xTaskCreate(threadEntryPointStub, (m_name ? m_name : "task"), - ((m_stackSize + sizeof(uint32_t) - 1) / sizeof(uint32_t)), // Round up number of words. - this, m_priority, &m_task); - - // Link in this thread to the list. - if (s_first) + if (pdPASS == xTaskCreate(threadEntryPointStub, (m_name ? m_name : "task"), + ((m_stackSize + sizeof(uint32_t) - 1) / sizeof(uint32_t)), // Round up number of words. + this, m_priority, &m_task)) { - m_next = s_first; + // Link in this thread to the list. + if (NULL != s_first) + { + m_next = s_first; + } + s_first = this; } - s_first = this; taskEXIT_CRITICAL(); } @@ -234,7 +235,10 @@ bool Semaphore::get(uint32_t timeout) timeout = portMAX_DELAY - 1; } #endif - (void)xSemaphoreTake(m_sem, timeout / 1000 / portTICK_PERIOD_MS); + if (pdTRUE != xSemaphoreTake(m_sem, timeout / 1000 / portTICK_PERIOD_MS)) + { + return false; + } return true; } diff --git a/erpc_c/setup/erpc_server_setup.cpp b/erpc_c/setup/erpc_server_setup.cpp index ac9984150..5bf370574 100644 --- a/erpc_c/setup/erpc_server_setup.cpp +++ b/erpc_c/setup/erpc_server_setup.cpp @@ -67,6 +67,14 @@ void erpc_add_service_to_server(void *service) } } +void erpc_remove_service_from_server(void *service) +{ + if (g_server != NULL && service != NULL) + { + g_server->removeService(static_cast(service)); + } +} + void erpc_server_set_crc(uint32_t crcStart) { s_crc16->setCrcStart(crcStart); diff --git a/erpc_c/setup/erpc_server_setup.h b/erpc_c/setup/erpc_server_setup.h index a91dda711..dd6d42f34 100644 --- a/erpc_c/setup/erpc_server_setup.h +++ b/erpc_c/setup/erpc_server_setup.h @@ -63,6 +63,13 @@ void erpc_server_deinit(void); */ void erpc_add_service_to_server(void *service); +/*! + * @brief This function removes service from server. + * + * @param[in] service Service which contains implementations of functions called from client to server. + */ +void erpc_remove_service_from_server(void *service); + /*! * @brief Can be used to set own crcStart number. * diff --git a/erpc_c/setup/erpc_setup_mbf_rpmsg.cpp b/erpc_c/setup/erpc_setup_mbf_rpmsg.cpp index 37c8a257d..9b1bb0407 100644 --- a/erpc_c/setup/erpc_setup_mbf_rpmsg.cpp +++ b/erpc_c/setup/erpc_setup_mbf_rpmsg.cpp @@ -47,7 +47,7 @@ class RPMsgMessageBufferFactory : public MessageBufferFactory virtual MessageBuffer create(void) { void *buf = NULL; - unsigned long size = 0; + uint32_t size = 0; buf = rpmsg_lite_alloc_tx_buffer(m_rpmsg, &size, RL_BLOCK); assert(NULL != buf); @@ -65,7 +65,7 @@ class RPMsgMessageBufferFactory : public MessageBufferFactory void *tmp = (void *)buf->get(); if (tmp) { - int ret; + int32_t ret; ret = rpmsg_lite_release_rx_buffer(m_rpmsg, tmp); if (ret != RL_SUCCESS) { diff --git a/erpc_c/setup/erpc_setup_mbf_rpmsg_tty.cpp b/erpc_c/setup/erpc_setup_mbf_rpmsg_tty.cpp index beef233c4..56752976c 100644 --- a/erpc_c/setup/erpc_setup_mbf_rpmsg_tty.cpp +++ b/erpc_c/setup/erpc_setup_mbf_rpmsg_tty.cpp @@ -50,7 +50,7 @@ class RPMsgTTYMessageBufferFactory : public MessageBufferFactory virtual MessageBuffer create(void) { void *buf = NULL; - unsigned long size = 0; + uint32_t size = 0; buf = rpmsg_lite_alloc_tx_buffer(m_rpmsg, &size, TIMEOUT_MS); assert(NULL != buf); @@ -69,7 +69,7 @@ class RPMsgTTYMessageBufferFactory : public MessageBufferFactory void *tmp = (void *)buf->get(); if (tmp) { - int ret; + int32_t ret; ret = rpmsg_lite_release_rx_buffer(m_rpmsg, (void *)(((uint8_t *)tmp) - sizeof(FramedTransport::Header))); if (ret != RL_SUCCESS) { diff --git a/erpc_c/setup/erpc_setup_rpmsg_lite_master.cpp b/erpc_c/setup/erpc_setup_rpmsg_lite_master.cpp index a4401cbec..4cb00af8e 100644 --- a/erpc_c/setup/erpc_setup_rpmsg_lite_master.cpp +++ b/erpc_c/setup/erpc_setup_rpmsg_lite_master.cpp @@ -38,8 +38,7 @@ static ManuallyConstructed s_transport; // Code //////////////////////////////////////////////////////////////////////////////// -erpc_transport_t erpc_transport_rpmsg_lite_master_init(unsigned long src_addr, unsigned long dst_addr, - int rpmsg_link_id) +erpc_transport_t erpc_transport_rpmsg_lite_master_init(uint32_t src_addr, uint32_t dst_addr, int32_t rpmsg_link_id) { s_transport.construct(); if (s_transport->init(src_addr, dst_addr, rpmsg_lite_base, SH_MEM_TOTAL_SIZE, rpmsg_link_id) == kErpcStatus_Success) diff --git a/erpc_c/setup/erpc_setup_rpmsg_lite_remote.cpp b/erpc_c/setup/erpc_setup_rpmsg_lite_remote.cpp index a2813d8e6..900646532 100644 --- a/erpc_c/setup/erpc_setup_rpmsg_lite_remote.cpp +++ b/erpc_c/setup/erpc_setup_rpmsg_lite_remote.cpp @@ -23,8 +23,8 @@ static ManuallyConstructed s_transport; // Code //////////////////////////////////////////////////////////////////////////////// -erpc_transport_t erpc_transport_rpmsg_lite_remote_init(unsigned long src_addr, unsigned long dst_addr, - void *start_address, int rpmsg_link_id, rpmsg_ready_cb ready, +erpc_transport_t erpc_transport_rpmsg_lite_remote_init(uint32_t src_addr, uint32_t dst_addr, void *start_address, + int32_t rpmsg_link_id, rpmsg_ready_cb ready, char *nameservice_name) { s_transport.construct(); diff --git a/erpc_c/setup/erpc_setup_rpmsg_lite_rtos_master.cpp b/erpc_c/setup/erpc_setup_rpmsg_lite_rtos_master.cpp index a5f076672..1d20569c1 100644 --- a/erpc_c/setup/erpc_setup_rpmsg_lite_rtos_master.cpp +++ b/erpc_c/setup/erpc_setup_rpmsg_lite_rtos_master.cpp @@ -37,8 +37,7 @@ static ManuallyConstructed s_transport; // Code //////////////////////////////////////////////////////////////////////////////// -erpc_transport_t erpc_transport_rpmsg_lite_rtos_master_init(unsigned long src_addr, unsigned long dst_addr, - int rpmsg_link_id) +erpc_transport_t erpc_transport_rpmsg_lite_rtos_master_init(uint32_t src_addr, uint32_t dst_addr, int32_t rpmsg_link_id) { s_transport.construct(); if (s_transport->init(src_addr, dst_addr, rpmsg_lite_base, SH_MEM_TOTAL_SIZE, rpmsg_link_id) == kErpcStatus_Success) diff --git a/erpc_c/setup/erpc_setup_rpmsg_lite_rtos_remote.cpp b/erpc_c/setup/erpc_setup_rpmsg_lite_rtos_remote.cpp index 0b2bf7e6f..35fe535d8 100644 --- a/erpc_c/setup/erpc_setup_rpmsg_lite_rtos_remote.cpp +++ b/erpc_c/setup/erpc_setup_rpmsg_lite_rtos_remote.cpp @@ -23,9 +23,9 @@ static ManuallyConstructed s_transport; // Code //////////////////////////////////////////////////////////////////////////////// -erpc_transport_t erpc_transport_rpmsg_lite_rtos_remote_init(unsigned long src_addr, unsigned long dst_addr, - void *start_address, int rpmsg_link_id, - rpmsg_ready_cb ready, char *nameservice_name) +erpc_transport_t erpc_transport_rpmsg_lite_rtos_remote_init(uint32_t src_addr, uint32_t dst_addr, void *start_address, + int32_t rpmsg_link_id, rpmsg_ready_cb ready, + char *nameservice_name) { s_transport.construct(); if (s_transport->init(src_addr, dst_addr, start_address, rpmsg_link_id, ready, nameservice_name) == diff --git a/erpc_c/setup/erpc_setup_rpmsg_tty_rtos_remote.cpp b/erpc_c/setup/erpc_setup_rpmsg_tty_rtos_remote.cpp index db20f8f75..bfdfd52ac 100644 --- a/erpc_c/setup/erpc_setup_rpmsg_tty_rtos_remote.cpp +++ b/erpc_c/setup/erpc_setup_rpmsg_tty_rtos_remote.cpp @@ -1,6 +1,6 @@ /* * Copyright (c) 2016, Freescale Semiconductor, Inc. - * Copyright 2016-2017 NXP + * Copyright 2016-2019 NXP * All rights reserved. * * @@ -23,8 +23,8 @@ static ManuallyConstructed s_transport; // Code //////////////////////////////////////////////////////////////////////////////// -erpc_transport_t erpc_transport_rpmsg_lite_tty_rtos_remote_init(unsigned long src_addr, unsigned long dst_addr, - void *start_address, int rpmsg_link_id, +erpc_transport_t erpc_transport_rpmsg_lite_tty_rtos_remote_init(uint32_t src_addr, uint32_t dst_addr, + void *start_address, int32_t rpmsg_link_id, rpmsg_ready_cb ready, char *nameservice_name) { s_transport.construct(); diff --git a/erpc_c/setup/erpc_transport_setup.h b/erpc_c/setup/erpc_transport_setup.h index 33b59fdf3..1caf46668 100644 --- a/erpc_c/setup/erpc_transport_setup.h +++ b/erpc_c/setup/erpc_transport_setup.h @@ -1,6 +1,6 @@ /* * Copyright (c) 2014-2016, Freescale Semiconductor, Inc. - * Copyright 2016-2017 NXP + * Copyright 2016-2019 NXP * All rights reserved. * * @@ -161,8 +161,7 @@ erpc_transport_t erpc_transport_mu_init(void *baseAddr); * * @return Return NULL or erpc_transport_t instance pointer. */ -erpc_transport_t erpc_transport_rpmsg_lite_master_init(unsigned long src_addr, unsigned long dst_addr, - int rpmsg_link_id); +erpc_transport_t erpc_transport_rpmsg_lite_master_init(uint32_t src_addr, uint32_t dst_addr, int32_t rpmsg_link_id); /*! * @brief Create an RPMsg-Lite transport. @@ -183,8 +182,8 @@ erpc_transport_t erpc_transport_rpmsg_lite_master_init(unsigned long src_addr, u * * @return Return NULL or erpc_transport_t instance pointer. */ -erpc_transport_t erpc_transport_rpmsg_lite_remote_init(unsigned long src_addr, unsigned long dst_addr, - void *start_address, int rpmsg_link_id, rpmsg_ready_cb ready, +erpc_transport_t erpc_transport_rpmsg_lite_remote_init(uint32_t src_addr, uint32_t dst_addr, void *start_address, + int32_t rpmsg_link_id, rpmsg_ready_cb ready, char *nameservice_name); /*! @@ -199,8 +198,8 @@ erpc_transport_t erpc_transport_rpmsg_lite_remote_init(unsigned long src_addr, u * * @return Return NULL or erpc_transport_t instance pointer. */ -erpc_transport_t erpc_transport_rpmsg_lite_rtos_master_init(unsigned long src_addr, unsigned long dst_addr, - int rpmsg_link_id); +erpc_transport_t erpc_transport_rpmsg_lite_rtos_master_init(uint32_t src_addr, uint32_t dst_addr, + int32_t rpmsg_link_id); /*! * @brief Create an RPMsg-Lite RTOS transport. @@ -220,9 +219,9 @@ erpc_transport_t erpc_transport_rpmsg_lite_rtos_master_init(unsigned long src_ad * * @return Return NULL or erpc_transport_t instance pointer. */ -erpc_transport_t erpc_transport_rpmsg_lite_rtos_remote_init(unsigned long src_addr, unsigned long dst_addr, - void *start_address, int rpmsg_link_id, - rpmsg_ready_cb ready, char *nameservice_name); +erpc_transport_t erpc_transport_rpmsg_lite_rtos_remote_init(uint32_t src_addr, uint32_t dst_addr, void *start_address, + int32_t rpmsg_link_id, rpmsg_ready_cb ready, + char *nameservice_name); /*! * @brief Create an RPMsg-Lite TTY transport. @@ -243,8 +242,8 @@ erpc_transport_t erpc_transport_rpmsg_lite_rtos_remote_init(unsigned long src_ad * * @return Return NULL or erpc_transport_t instance pointer. */ -erpc_transport_t erpc_transport_rpmsg_lite_tty_rtos_remote_init(unsigned long src_addr, unsigned long dst_addr, - void *start_address, int rpmsg_link_id, +erpc_transport_t erpc_transport_rpmsg_lite_tty_rtos_remote_init(uint32_t src_addr, uint32_t dst_addr, + void *start_address, int32_t rpmsg_link_id, rpmsg_ready_cb ready, char *nameservice_name); /*! diff --git a/erpc_c/transports/erpc_rpmsg_lite_rtos_transport.cpp b/erpc_c/transports/erpc_rpmsg_lite_rtos_transport.cpp index 2f2e1b758..c48eb0901 100644 --- a/erpc_c/transports/erpc_rpmsg_lite_rtos_transport.cpp +++ b/erpc_c/transports/erpc_rpmsg_lite_rtos_transport.cpp @@ -40,8 +40,8 @@ RPMsgRTOSTransport::~RPMsgRTOSTransport(void) s_initialized = 0; } -erpc_status_t RPMsgRTOSTransport::init(unsigned long src_addr, unsigned long dst_addr, void *base_address, - unsigned long length, int rpmsg_link_id) +erpc_status_t RPMsgRTOSTransport::init(uint32_t src_addr, uint32_t dst_addr, void *base_address, uint32_t length, + int32_t rpmsg_link_id) { if (!s_initialized) { @@ -65,8 +65,8 @@ erpc_status_t RPMsgRTOSTransport::init(unsigned long src_addr, unsigned long dst return m_rpmsg_ept == RL_NULL ? kErpcStatus_InitFailed : kErpcStatus_Success; } -erpc_status_t RPMsgRTOSTransport::init(unsigned long src_addr, unsigned long dst_addr, void *base_address, - int rpmsg_link_id, void (*ready_cb)(void), char *nameservice_name) +erpc_status_t RPMsgRTOSTransport::init(uint32_t src_addr, uint32_t dst_addr, void *base_address, int32_t rpmsg_link_id, + void (*ready_cb)(void), char *nameservice_name) { if (!s_initialized) { @@ -111,8 +111,8 @@ erpc_status_t RPMsgRTOSTransport::init(unsigned long src_addr, unsigned long dst erpc_status_t RPMsgRTOSTransport::receive(MessageBuffer *message) { char *buf = NULL; - int length = 0; - int ret_val = rpmsg_queue_recv_nocopy(s_rpmsg, m_rpmsg_queue, &m_dst_addr, &buf, &length, RL_BLOCK); + uint32_t length = 0; + int32_t ret_val = rpmsg_queue_recv_nocopy(s_rpmsg, m_rpmsg_queue, &m_dst_addr, &buf, &length, RL_BLOCK); assert(buf); message->set((uint8_t *)buf, length); message->setUsed(length); @@ -125,7 +125,7 @@ erpc_status_t RPMsgRTOSTransport::send(MessageBuffer *message) uint32_t length = message->getLength(); uint32_t used = message->getUsed(); message->set(NULL, 0); - int ret_val = rpmsg_lite_send_nocopy(s_rpmsg, m_rpmsg_ept, m_dst_addr, buf, used); + int32_t ret_val = rpmsg_lite_send_nocopy(s_rpmsg, m_rpmsg_ept, m_dst_addr, buf, used); if (ret_val == RL_SUCCESS) { return kErpcStatus_Success; diff --git a/erpc_c/transports/erpc_rpmsg_lite_rtos_transport.h b/erpc_c/transports/erpc_rpmsg_lite_rtos_transport.h index 6995d59e6..3a07d9016 100644 --- a/erpc_c/transports/erpc_rpmsg_lite_rtos_transport.h +++ b/erpc_c/transports/erpc_rpmsg_lite_rtos_transport.h @@ -62,8 +62,8 @@ class RPMsgRTOSTransport : public RPMsgBaseTransport * @retval kErpcStatus_Success When rpmsg init function was executed successfully. * @retval kErpcStatus_InitFailed When rpmsg init function wasn't executed successfully. */ - virtual erpc_status_t init(unsigned long src_addr, unsigned long dst_addr, void *base_address, unsigned long length, - int rpmsg_link_id); + virtual erpc_status_t init(uint32_t src_addr, uint32_t dst_addr, void *base_address, uint32_t length, + int32_t rpmsg_link_id); /*! * @brief This function call RPMsg rtos init function - as RPMsg remote @@ -79,7 +79,7 @@ class RPMsgRTOSTransport : public RPMsgBaseTransport * @retval kErpcStatus_Success When rpmsg init function was executed successfully. * @retval kErpcStatus_InitFailed When rpmsg init function wasn't executed successfully. */ - virtual erpc_status_t init(unsigned long src_addr, unsigned long dst_addr, void *base_address, int rpmsg_link_id, + virtual erpc_status_t init(uint32_t src_addr, uint32_t dst_addr, void *base_address, int32_t rpmsg_link_id, void (*ready_cb)(void), char *nameservice_name); /*! @@ -117,7 +117,7 @@ class RPMsgRTOSTransport : public RPMsgBaseTransport /* Remote device */ struct remote_device *m_rdev; /*!< Device which represent the second core. */ struct rpmsg_channel *m_app_rp_chnl; /*!< Represent connection between two device (two cores). */ - unsigned long m_dst_addr; /*!< Destination address used by rpmsg. */ + uint32_t m_dst_addr; /*!< Destination address used by rpmsg. */ rpmsg_queue_handle m_rpmsg_queue; /*!< Handle of RPMsg queue. */ struct rpmsg_lite_endpoint *m_rpmsg_ept; /*!< Pointer to RPMsg Lite Endpoint structure. */ }; diff --git a/erpc_c/transports/erpc_rpmsg_lite_transport.cpp b/erpc_c/transports/erpc_rpmsg_lite_transport.cpp index b255d6c5e..8202f879d 100644 --- a/erpc_c/transports/erpc_rpmsg_lite_transport.cpp +++ b/erpc_c/transports/erpc_rpmsg_lite_transport.cpp @@ -23,7 +23,7 @@ struct rpmsg_lite_instance *RPMsgBaseTransport::s_rpmsg = NULL; // Code //////////////////////////////////////////////////////////////////////////////// -int RPMsgTransport::rpmsg_read_cb(void *payload, int payload_len, unsigned long src, void *priv) +int32_t RPMsgTransport::rpmsg_read_cb(void *payload, uint32_t payload_len, uint32_t src, void *priv) { RPMsgTransport *transport = (RPMsgTransport *)priv; if (payload_len <= ERPC_DEFAULT_BUFFER_SIZE) @@ -45,8 +45,8 @@ RPMsgTransport::RPMsgTransport(void) RPMsgTransport::~RPMsgTransport(void) {} -erpc_status_t RPMsgTransport::init(unsigned long src_addr, unsigned long dst_addr, void *base_address, - unsigned long length, int rpmsg_link_id) +erpc_status_t RPMsgTransport::init(uint32_t src_addr, uint32_t dst_addr, void *base_address, uint32_t length, + int32_t rpmsg_link_id) { if (!s_initialized) { @@ -61,8 +61,8 @@ erpc_status_t RPMsgTransport::init(unsigned long src_addr, unsigned long dst_add return m_rpmsg_ept == RL_NULL ? kErpcStatus_InitFailed : kErpcStatus_Success; } -erpc_status_t RPMsgTransport::init(unsigned long src_addr, unsigned long dst_addr, void *base_address, - int rpmsg_link_id, void (*ready_cb)(void), char *nameservice_name) +erpc_status_t RPMsgTransport::init(uint32_t src_addr, uint32_t dst_addr, void *base_address, int32_t rpmsg_link_id, + void (*ready_cb)(void), char *nameservice_name) { if (!s_initialized) { @@ -107,7 +107,8 @@ erpc_status_t RPMsgTransport::receive(MessageBuffer *message) erpc_status_t RPMsgTransport::send(MessageBuffer *message) { - int ret_val = rpmsg_lite_send_nocopy(s_rpmsg, m_rpmsg_ept, m_dst_addr, (char *)message->get(), message->getUsed()); + int32_t ret_val = + rpmsg_lite_send_nocopy(s_rpmsg, m_rpmsg_ept, m_dst_addr, (char *)message->get(), message->getUsed()); message->set(NULL, 0); return ret_val != RL_SUCCESS ? kErpcStatus_SendFailed : kErpcStatus_Success; } diff --git a/erpc_c/transports/erpc_rpmsg_lite_transport.h b/erpc_c/transports/erpc_rpmsg_lite_transport.h index 622bf1198..201bbcd57 100644 --- a/erpc_c/transports/erpc_rpmsg_lite_transport.h +++ b/erpc_c/transports/erpc_rpmsg_lite_transport.h @@ -65,8 +65,8 @@ class RPMsgTransport : public RPMsgBaseTransport * @retval kErpcStatus_Success When rpmsg init function was executed successfully. * @retval kErpcStatus_InitFailed When rpmsg init function wasn't executed successfully. */ - virtual erpc_status_t init(unsigned long src_addr, unsigned long dst_addr, void *base_address, unsigned long length, - int rpmsg_link_id); + virtual erpc_status_t init(uint32_t src_addr, uint32_t dst_addr, void *base_address, uint32_t length, + int32_t rpmsg_link_id); /*! * @brief Initialization of RPMsgTransport layer - as RPMsg remote @@ -84,7 +84,7 @@ class RPMsgTransport : public RPMsgBaseTransport * @retval kErpcStatus_Success When rpmsg init function was executed successfully. * @retval kErpcStatus_InitFailed When rpmsg init function wasn't executed successfully. */ - virtual erpc_status_t init(unsigned long src_addr, unsigned long dst_addr, void *base_address, int rpmsg_link_id, + virtual erpc_status_t init(uint32_t src_addr, uint32_t dst_addr, void *base_address, int32_t rpmsg_link_id, void (*ready_cb)(void), char *nameservice_name); /*! @@ -131,12 +131,12 @@ class RPMsgTransport : public RPMsgBaseTransport * * @return */ - static int rpmsg_read_cb(void *payload, int payload_len, unsigned long src, void *priv); + static int32_t rpmsg_read_cb(void *payload, uint32_t payload_len, uint32_t src, void *priv); StaticQueue m_messageQueue; /*!< Received messages. Queue of messages with buffers filled in rpmsg callback. */ - unsigned long m_dst_addr; /*!< Destination address used by rpmsg. */ + uint32_t m_dst_addr; /*!< Destination address used by rpmsg. */ struct rpmsg_lite_ept_static_context m_rpmsg_ept_context; /*!< RPMsg Lite Endpoint static context. */ struct rpmsg_lite_endpoint *m_rpmsg_ept; /*!< Pointer to RPMsg Lite Endpoint structure. */ diff --git a/erpc_c/transports/erpc_rpmsg_tty_rtos_transport.cpp b/erpc_c/transports/erpc_rpmsg_tty_rtos_transport.cpp index 6dbc2d091..983ecd1b5 100644 --- a/erpc_c/transports/erpc_rpmsg_tty_rtos_transport.cpp +++ b/erpc_c/transports/erpc_rpmsg_tty_rtos_transport.cpp @@ -1,6 +1,6 @@ /* * Copyright (c) 2016, Freescale Semiconductor, Inc. - * Copyright 2017 NXP + * Copyright 2017-2019 NXP * All rights reserved. * * @@ -70,8 +70,8 @@ void RPMsgTTYRTOSTransport::setCrc16(Crc16 *crcImpl) m_crcImpl = crcImpl; } -erpc_status_t RPMsgTTYRTOSTransport::init(unsigned long src_addr, unsigned long dst_addr, void *base_address, - unsigned long length, int rpmsg_link_id) +erpc_status_t RPMsgTTYRTOSTransport::init(uint32_t src_addr, uint32_t dst_addr, void *base_address, uint32_t length, + int32_t rpmsg_link_id) { if (!s_initialized) { @@ -95,8 +95,8 @@ erpc_status_t RPMsgTTYRTOSTransport::init(unsigned long src_addr, unsigned long return m_rpmsg_ept == RL_NULL ? kErpcStatus_InitFailed : kErpcStatus_Success; } -erpc_status_t RPMsgTTYRTOSTransport::init(unsigned long src_addr, unsigned long dst_addr, void *base_address, - int rpmsg_link_id, void (*ready_cb)(void), char *nameservice_name) +erpc_status_t RPMsgTTYRTOSTransport::init(uint32_t src_addr, uint32_t dst_addr, void *base_address, + int32_t rpmsg_link_id, void (*ready_cb)(void), char *nameservice_name) { if (!s_initialized) { @@ -143,9 +143,9 @@ erpc_status_t RPMsgTTYRTOSTransport::receive(MessageBuffer *message) assert(m_crcImpl && "Uninitialized Crc16 object."); FramedTransport::Header h; char *buf = NULL; - int length = 0; + uint32_t length = 0; - int ret_val = rpmsg_queue_recv_nocopy(s_rpmsg, m_rpmsg_queue, &m_dst_addr, &buf, &length, RL_BLOCK); + int32_t ret_val = rpmsg_queue_recv_nocopy(s_rpmsg, m_rpmsg_queue, &m_dst_addr, &buf, &length, RL_BLOCK); assert(buf); memcpy((uint8_t *)&h, buf, sizeof(h)); @@ -177,7 +177,7 @@ erpc_status_t RPMsgTTYRTOSTransport::send(MessageBuffer *message) memcpy(buf - sizeof(h), (uint8_t *)&h, sizeof(h)); - int ret_val = rpmsg_lite_send_nocopy(s_rpmsg, m_rpmsg_ept, m_dst_addr, buf - sizeof(h), used + sizeof(h)); + int32_t ret_val = rpmsg_lite_send_nocopy(s_rpmsg, m_rpmsg_ept, m_dst_addr, buf - sizeof(h), used + sizeof(h)); if (ret_val == RL_SUCCESS) { return kErpcStatus_Success; diff --git a/erpc_c/transports/erpc_rpmsg_tty_rtos_transport.h b/erpc_c/transports/erpc_rpmsg_tty_rtos_transport.h index c7918b1ce..70c9a3d16 100644 --- a/erpc_c/transports/erpc_rpmsg_tty_rtos_transport.h +++ b/erpc_c/transports/erpc_rpmsg_tty_rtos_transport.h @@ -67,8 +67,8 @@ class RPMsgTTYRTOSTransport : public RPMsgBaseTransport * @retval kErpcStatus_InitFailed When rpmsg init function wasn't executed * successfully. */ - virtual erpc_status_t init(unsigned long src_addr, unsigned long dst_addr, void *base_address, unsigned long length, - int rpmsg_link_id); + virtual erpc_status_t init(uint32_t src_addr, uint32_t dst_addr, void *base_address, uint32_t length, + int32_t rpmsg_link_id); /*! * @brief This function call RPMsg rtos init function - as RPMsg remote @@ -88,7 +88,7 @@ class RPMsgTTYRTOSTransport : public RPMsgBaseTransport * @retval kErpcStatus_InitFailed When rpmsg init function wasn't executed * successfully. */ - virtual erpc_status_t init(unsigned long src_addr, unsigned long dst_addr, void *base_address, int rpmsg_link_id, + virtual erpc_status_t init(uint32_t src_addr, uint32_t dst_addr, void *base_address, int32_t rpmsg_link_id, void (*ready_cb)(void), char *nameservice_name); /*! @@ -122,7 +122,7 @@ class RPMsgTTYRTOSTransport : public RPMsgBaseTransport virtual void setCrc16(Crc16 *crcImpl); protected: - unsigned long m_dst_addr; /*!< Destination address used by rpmsg. */ + uint32_t m_dst_addr; /*!< Destination address used by rpmsg. */ rpmsg_queue_handle m_rpmsg_queue; /*!< Handle of RPMsg queue. */ struct rpmsg_lite_endpoint *m_rpmsg_ept; /*!< Pointer to RPMsg Lite Endpoint structure. */ Crc16 *m_crcImpl; //!< CRC object. diff --git a/erpc_python/README.rst b/erpc_python/README.rst deleted file mode 100644 index 822acf464..000000000 --- a/erpc_python/README.rst +++ /dev/null @@ -1,24 +0,0 @@ -| eRPC Python Infrastructure -| ========================== -| -| This folder contains the Python implementation of the eRPC infrastructure. -| -| The eRPC project is stored on Github_. -.. _Github: https://github.com/EmbeddedRPC/erpc -| -| The Python implementation of eRPC is fully compatible with the C/C++ implementation at the -| protocol level. Also, the classes mirror those in the C++ infrastructure. -| -| Installation: -| -| To install the eRPC Python infrastructure, run the setup.py script like this: -| -| pip install erpc -| -| -| Once installed, you can access the infrastructure via a standard import statement. -| -| import erpc -| xport = erpc.transport.SerialTransport("/dev/ttyS1", 115200) -| client = erpc.client.ClientManager(xport, erpc.basic_codec.BasicCodec) - diff --git a/erpc_python/README_Pypi.md b/erpc_python/README_Pypi.md new file mode 100644 index 000000000..7b48e33b7 --- /dev/null +++ b/erpc_python/README_Pypi.md @@ -0,0 +1,23 @@ +eRPC Python Infrastructure +========================== + +This folder contains the Python implementation of the eRPC infrastructure. + +The eRPC project is stored on Github: https://github.com/EmbeddedRPC/erpc + +The Python implementation of eRPC is fully compatible with the C/C++ implementation at the +protocol level. Also, the classes mirror those in the C++ infrastructure. + +Installation: + + To install the eRPC Python infrastructure, run the setup.py script like this: + + pip install erpc + + + Once installed, you can access the infrastructure via a standard import statement. + + import erpc + xport = erpc.transport.SerialTransport("/dev/ttyS1", 115200) + client = erpc.client.ClientManager(xport, erpc.basic_codec.BasicCodec) + diff --git a/erpc_python/erpc/erpc_version.py b/erpc_python/erpc/erpc_version.py index 5d09d9924..d669c1a17 100644 --- a/erpc_python/erpc/erpc_version.py +++ b/erpc_python/erpc/erpc_version.py @@ -1,9 +1,9 @@ #!/usr/bin/env python -# Copyright 2017 NXP +# Copyright 2017-2019 NXP # All rights reserved. # # SPDX-License-Identifier: BSD-3-Clause #Should be same as in erpc_version.h -ERPC_VERSION = "1.7.2" +ERPC_VERSION = "1.7.3" diff --git a/erpc_python/setup.cfg b/erpc_python/setup.cfg index c34b498b2..adf5ed72a 100644 --- a/erpc_python/setup.cfg +++ b/erpc_python/setup.cfg @@ -1,5 +1,7 @@ [bdist_wheel] -# This flag says that the code is written to work on both Python 2 and Python -# 3. If at all possible, it is good practice to do this. If you cannot, you -# will need to generate wheels for each Python version that you support. -universal=1 \ No newline at end of file +universal = 1 + +[egg_info] +tag_build = +tag_date = 0 + diff --git a/erpc_python/setup.py b/erpc_python/setup.py index 565c1f4e6..98e860211 100644 --- a/erpc_python/setup.py +++ b/erpc_python/setup.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # Copyright (c) 2016 Freescale Semiconductor, Inc. -# Copyright 2016 NXP +# Copyright 2016-2019 NXP # All rights reserved. # # SPDX-License-Identifier: BSD-3-Clause @@ -13,7 +13,7 @@ here = path.abspath(path.dirname(__file__)) -with open(path.join(here, 'README.rst'), encoding='utf-8') as f: +with open(path.join(here, 'README_Pypi.md'), encoding='utf-8') as f: long_description = f.read() #steps: https://packaging.python.org/distributing/ @@ -26,6 +26,7 @@ version=erpc_version.ERPC_VERSION, description="eRPC Python infrastructure", long_description=long_description, + long_description_content_type="text/markdown", author="NXP", url='https://github.com/embeddedrpc/erpc', license="BSD 3-Clause", @@ -41,7 +42,7 @@ "Operating System :: Microsoft :: Windows", "Operating System :: POSIX :: Linux", ], - keywords='rpc rpc-framework embedded multicore multiprocessor amp', + keywords='rpc rpc-framework embedded multicore multiprocessor amp rpmsg_lite', use_2to3=True, packages=['erpc'], ) diff --git a/erpcgen/src/templates/c_common_header.template b/erpcgen/src/templates/c_common_header.template index 0e93542af..bb8fbdf53 100644 --- a/erpcgen/src/templates/c_common_header.template +++ b/erpcgen/src/templates/c_common_header.template @@ -8,7 +8,7 @@ #define {$commonGuardMacro} {% if usedUnionType %} -#if defined(__CC_ARM) +#if defined(__CC_ARM) || defined(__ARMCC_VERSION) #pragma anon_unions #endif {% endif -- usedUnionType %} diff --git a/erpcgen/src/templates/c_server_header.template b/erpcgen/src/templates/c_server_header.template index 71098a496..52e2aba24 100644 --- a/erpcgen/src/templates/c_server_header.template +++ b/erpcgen/src/templates/c_server_header.template @@ -50,6 +50,12 @@ typedef void * erpc_service_t; {% for iface in group.interfaces %} erpc_service_t create_{$iface.serviceClassName}(void); +{% if dynamicServices == true %} +void destroy_{$iface.serviceClassName}(erpc_service_t *service); +{% else --dynamicServices == true %} +void destroy_{$iface.serviceClassName}(void); +{% endif --dynamicServices == true %} + {% endfor -- iface %} #ifdef __cplusplus } diff --git a/erpcgen/src/templates/c_server_source.template b/erpcgen/src/templates/c_server_source.template index 68d842c30..a7b427ce3 100644 --- a/erpcgen/src/templates/c_server_source.template +++ b/erpcgen/src/templates/c_server_source.template @@ -240,11 +240,24 @@ erpc_service_t create_{$iface.serviceClassName}() { return new (nothrow) {$iface.serviceClassName}(); } + +void destroy_{$iface.serviceClassName}(erpc_service_t *service) +{ + if (*service) + { + delete service; + } +} {% else --dynamicServices == true %} erpc_service_t create_{$iface.serviceClassName}() { s_{$iface.serviceClassName}.construct(); return s_{$iface.serviceClassName}.get(); } + +void destroy_{$iface.serviceClassName}() +{ + s_{$iface.serviceClassName}.destroy(); +} {% endif --dynamicServices == true %} {% endfor -- iface %} diff --git a/examples/matrix_multiply_tcp_python/service/__init__.py b/examples/matrix_multiply_tcp_python/service/__init__.py index 4de10adea..f6d859d0b 100644 --- a/examples/matrix_multiply_tcp_python/service/__init__.py +++ b/examples/matrix_multiply_tcp_python/service/__init__.py @@ -5,7 +5,7 @@ # SPDX-License-Identifier: BSD-3-Clause # -# Generated by erpcgen 1.7.2 on Fri Mar 15 10:14:52 2019. +# Generated by erpcgen 1.7.3 on Mon Sep 23 13:00:45 2019. # # AUTOGENERATED - DO NOT EDIT # diff --git a/examples/matrix_multiply_tcp_python/service/erpc_matrix_multiply/__init__.py b/examples/matrix_multiply_tcp_python/service/erpc_matrix_multiply/__init__.py index 18eb5d0fe..5ecf43d93 100644 --- a/examples/matrix_multiply_tcp_python/service/erpc_matrix_multiply/__init__.py +++ b/examples/matrix_multiply_tcp_python/service/erpc_matrix_multiply/__init__.py @@ -5,7 +5,7 @@ # SPDX-License-Identifier: BSD-3-Clause # -# Generated by erpcgen 1.7.2 on Fri Mar 15 10:14:52 2019. +# Generated by erpcgen 1.7.3 on Mon Sep 23 13:00:45 2019. # # AUTOGENERATED - DO NOT EDIT # @@ -15,8 +15,8 @@ version = erpc_version.ERPC_VERSION except ImportError: version = "unknown" -if version != "1.7.2": - raise ValueError("The generated shim code version (1.7.2) is different to the rest of eRPC code (%s). \ +if version != "1.7.3": + raise ValueError("The generated shim code version (1.7.3) is different to the rest of eRPC code (%s). \ Install newer version by running \"python setup.py install\" in folder erpc/erpc_python/." % repr(version)) from . import common diff --git a/examples/matrix_multiply_tcp_python/service/erpc_matrix_multiply/client.py b/examples/matrix_multiply_tcp_python/service/erpc_matrix_multiply/client.py index 41fdc87d3..834b30c68 100644 --- a/examples/matrix_multiply_tcp_python/service/erpc_matrix_multiply/client.py +++ b/examples/matrix_multiply_tcp_python/service/erpc_matrix_multiply/client.py @@ -5,7 +5,7 @@ # SPDX-License-Identifier: BSD-3-Clause # -# Generated by erpcgen 1.7.2 on Fri Mar 15 10:14:52 2019. +# Generated by erpcgen 1.7.3 on Mon Sep 23 13:00:45 2019. # # AUTOGENERATED - DO NOT EDIT # diff --git a/examples/matrix_multiply_tcp_python/service/erpc_matrix_multiply/common.py b/examples/matrix_multiply_tcp_python/service/erpc_matrix_multiply/common.py index cf21b35be..1e1264d1a 100644 --- a/examples/matrix_multiply_tcp_python/service/erpc_matrix_multiply/common.py +++ b/examples/matrix_multiply_tcp_python/service/erpc_matrix_multiply/common.py @@ -5,7 +5,7 @@ # SPDX-License-Identifier: BSD-3-Clause # -# Generated by erpcgen 1.7.2 on Fri Mar 15 10:14:52 2019. +# Generated by erpcgen 1.7.3 on Mon Sep 23 13:00:45 2019. # # AUTOGENERATED - DO NOT EDIT # diff --git a/examples/matrix_multiply_tcp_python/service/erpc_matrix_multiply/interface.py b/examples/matrix_multiply_tcp_python/service/erpc_matrix_multiply/interface.py index e35618083..6f3fe7733 100644 --- a/examples/matrix_multiply_tcp_python/service/erpc_matrix_multiply/interface.py +++ b/examples/matrix_multiply_tcp_python/service/erpc_matrix_multiply/interface.py @@ -5,7 +5,7 @@ # SPDX-License-Identifier: BSD-3-Clause # -# Generated by erpcgen 1.7.2 on Fri Mar 15 10:14:52 2019. +# Generated by erpcgen 1.7.3 on Mon Sep 23 13:00:45 2019. # # AUTOGENERATED - DO NOT EDIT # diff --git a/examples/matrix_multiply_tcp_python/service/erpc_matrix_multiply/server.py b/examples/matrix_multiply_tcp_python/service/erpc_matrix_multiply/server.py index f2750aa5d..6bbc32ee5 100644 --- a/examples/matrix_multiply_tcp_python/service/erpc_matrix_multiply/server.py +++ b/examples/matrix_multiply_tcp_python/service/erpc_matrix_multiply/server.py @@ -5,7 +5,7 @@ # SPDX-License-Identifier: BSD-3-Clause # -# Generated by erpcgen 1.7.2 on Fri Mar 15 10:14:52 2019. +# Generated by erpcgen 1.7.3 on Mon Sep 23 13:00:45 2019. # # AUTOGENERATED - DO NOT EDIT # diff --git a/test/common/gtest/gtest.h b/test/common/gtest/gtest.h index eb28fadcd..ca8f6926d 100644 --- a/test/common/gtest/gtest.h +++ b/test/common/gtest/gtest.h @@ -2091,7 +2091,7 @@ using ::std::tuple_size; #endif // _LIBCPP_VERSION is defined by the libc++ library from the LLVM project. -#if defined(__GLIBCXX__) || defined(_LIBCPP_VERSION) +#if ((defined(__GLIBCXX__) || defined(_LIBCPP_VERSION)) && (!defined(__ARMCC_VERSION))) # define GTEST_HAS_CXXABI_H_ 1 #else # define GTEST_HAS_CXXABI_H_ 0 diff --git a/test/common/retarget_cpp_streamed_io.c b/test/common/retarget_cpp_streamed_io.c index 9048d55c2..273180d04 100644 --- a/test/common/retarget_cpp_streamed_io.c +++ b/test/common/retarget_cpp_streamed_io.c @@ -26,18 +26,17 @@ #if defined(__CC_ARM) || defined(__ARMCC_VERSION) -#include "fsl_log.h" +//#include "fsl_log.h" +#include "fsl_debug_console.h" //#pragma import(__use_no_semihosting_swi) #include #define DEFAULT_HANDLE 0x100; -char *_sys_command_string(char *cmd, int len) -{ - return (cmd); -} - +#if 0 //already defined in fsl_debug_console.c +char *_sys_command_string(char *cmd, int len) { return (cmd); } +#endif /* * These names are special strings which will be recognized by * _sys_open and will cause it to return the standard I/O handles, instead @@ -51,18 +50,14 @@ const char __stderr_name[] = "STDERR"; * Open a file. May return -1 if the file failed to open. We do not require * this function to do anything. Simply return a dummy handle. */ -FILEHANDLE _sys_open(const char *name, int openmode) -{ - return DEFAULT_HANDLE; -} +FILEHANDLE _sys_open(const char *name, int openmode) { return DEFAULT_HANDLE; } /* * Close a file. Should return 0 on success or a negative value on error. * Not required in this implementation. Always return success. */ -int _sys_close(FILEHANDLE fh) -{ - return 0; // return success +int _sys_close(FILEHANDLE fh) { + return 0; // return success } /* @@ -70,16 +65,18 @@ int _sys_close(FILEHANDLE fh) * of characters _not_ written on partial success. This implementation sends * a buffer of size 'len' to the UART. */ -int _sys_write(FILEHANDLE fh, const unsigned char *buf, unsigned len, int mode) -{ - int i; - for (i = 0; i < len; i++) - { - // UART_write(buf[i]); - LOG_Push((uint8_t *)(&buf[i]), 1); - } - - return 0; +int _sys_write(FILEHANDLE fh, const unsigned char *buf, unsigned len, + int mode) { + // int i; + // for (i = 0; i < len; i++) + //{ + // // UART_write(buf[i]); + // LOG_Push((uint8_t *)(&buf[i]), 1); + //} + + DbgConsole_SendData((uint8_t *)buf, len); + + return 0; } /* @@ -93,66 +90,65 @@ int _sys_write(FILEHANDLE fh, const unsigned char *buf, unsigned len, int mode) * if required (backspace) and then echo the character to the Terminal * Emulator, printing the correct sequence after successive keystrokes. */ -int _sys_read(FILEHANDLE fh, unsigned char *buf, unsigned len, int mode) -{ - int pos = 0; - - do - { - - // buf[pos]=UART_read(); - LOG_ReadCharacter((uint8_t *)&buf[pos]); - - // Advance position in buffer - pos++; - - // Handle backspace - if (buf[pos - 1] == '\b') - { - // More than 1 char in buffer - if (pos > 1) - { - // Delete character on terminal - // UART_write('\b'); - // UART_write(' '); - // UART_write('\b'); - - // Update position in buffer - pos -= 2; - } - else if (pos > 0) - pos--; // Backspace pressed, empty buffer - } - // else UART_write(buf[pos-1]); // Echo normal char to terminal - else - LOG_Push((uint8_t *)(&buf[pos - 1]), 1); // Echo normal char to terminal - - } while (buf[pos - 1] != '\r'); - - buf[pos] = '\0'; // Ensure Null termination - - return 0; +int _sys_read(FILEHANDLE fh, unsigned char *buf, unsigned len, int mode) { + int pos = 0; + + do { + + // buf[pos]=UART_read(); + // LOG_ReadCharacter((uint8_t *)&buf[pos]); + DbgConsole_ReadCharacter((uint8_t *)&buf[pos]); + + // Advance position in buffer + pos++; + + // Handle backspace + if (buf[pos - 1] == '\b') { + // More than 1 char in buffer + if (pos > 1) { + // Delete character on terminal + // UART_write('\b'); + // UART_write(' '); + // UART_write('\b'); + + // Update position in buffer + pos -= 2; + } else if (pos > 0) + pos--; // Backspace pressed, empty buffer + } + // else UART_write(buf[pos-1]); // Echo normal char to terminal + else + // LOG_Push((uint8_t *)(&buf[pos - 1]), 1); // Echo normal char to + // terminal + DbgConsole_SendData((uint8_t *)(&buf[pos - 1]), + 1); // Echo normal char to terminal + + } while (buf[pos - 1] != '\r'); + + buf[pos] = '\0'; // Ensure Null termination + + return 0; } +#if 0 //already defined in fsl_debug_console.c /* * Writes a character to the output channel. This function is used * for last-resort error message output. */ -void _ttywrch(int ch) -{ - // Convert correctly for endianness change - char ench = ch; +void _ttywrch(int ch) { + // Convert correctly for endianness change + char ench = ch; - // UART_write(ench); - LOG_Push((uint8_t *)(&ench), 1); + // UART_write(ench); + // LOG_Push((uint8_t *)(&ench), 1); + DbgConsole_SendData((uint8_t *)(&ench), 1); } - +#endif /* * Return non-zero if the argument file is connected to a terminal. */ -int _sys_istty(FILEHANDLE fh) -{ - return 1; // no interactive device present +int _sys_istty(FILEHANDLE fh) { + return 1; // no interactive device present } /* @@ -160,9 +156,8 @@ int _sys_istty(FILEHANDLE fh) * Returns >=0 on success, <0 on failure. Seeking is not supported for the * UART. */ -int _sys_seek(FILEHANDLE fh, long pos) -{ - return -1; // error +int _sys_seek(FILEHANDLE fh, long pos) { + return -1; // error } /* @@ -170,9 +165,8 @@ int _sys_seek(FILEHANDLE fh, long pos) * is up to date on disk. Result is >=0 if OK, negative for an * error. */ -int _sys_ensure(FILEHANDLE fh) -{ - return 0; // success +int _sys_ensure(FILEHANDLE fh) { + return 0; // success } /* @@ -182,29 +176,23 @@ int _sys_ensure(FILEHANDLE fh) * called when processing SEEK_END relative fseeks, and therefore a * call to _sys_flen is always followed by a call to _sys_seek. */ -long _sys_flen(FILEHANDLE fh) -{ - return 0; -} +long _sys_flen(FILEHANDLE fh) { return 0; } /* * Return the name for temporary file number sig in the buffer * name. Returns 0 on failure. maxlen is the maximum name length * allowed. */ -int _sys_tmpnam(char *name, int sig, unsigned maxlen) -{ - return 0; // fail, not supported +int _sys_tmpnam(char *name, int sig, unsigned maxlen) { + return 0; // fail, not supported } +#if 0 //already defined in fsl_debug_console.c /* * Terminate the program, passing a return code back to the user. * This function may not return. */ -void _sys_exit(int returncode) -{ - while (1) - { - }; +void _sys_exit(int returncode) { while (1) { }; } +#endif #endif /* __CC_ARM */ diff --git a/test/common/unit_test_client.cpp b/test/common/unit_test_client.cpp index 7f5b5b617..b83b22070 100644 --- a/test/common/unit_test_client.cpp +++ b/test/common/unit_test_client.cpp @@ -14,7 +14,7 @@ #include "myAlloc.h" #include "test_unit_test_common.h" -#if (defined(RPMSG) || defined(UART) || defined(LPUART)) +#if (defined(RPMSG) || defined(UART)) extern "C" { #include "app_core0.h" #include "board.h" @@ -22,6 +22,8 @@ extern "C" { #include "mcmgr.h" #if defined(RPMSG) #include "rpmsg_lite.h" +#elif defined(UART) +#include "fsl_usart_cmsis.h" #endif } @@ -79,6 +81,9 @@ volatile uint16_t eRPCReadyEventData = 0; //////////////////////////////////////////////////////////////////////////////// // Code //////////////////////////////////////////////////////////////////////////////// +#ifdef __cplusplus +extern "C" { +#endif #if defined(RPMSG) /*! * @brief eRPC server side ready event handler @@ -101,9 +106,6 @@ void SystemInitHook(void) } #endif -#ifdef __cplusplus -extern "C" { -#endif int main(int argc, char **argv) { ::testing::InitGoogleTest(&argc, argv); @@ -111,7 +113,7 @@ int main(int argc, char **argv) ::testing::TestEventListeners &listeners = ::testing::UnitTest::GetInstance()->listeners(); listeners.Append(new LeakChecker); -#if (defined(RPMSG) || defined(UART) || defined(LPUART)) +#if (defined(RPMSG) || defined(UART)) delete listeners.Release(listeners.default_result_printer()); listeners.Append(new MinimalistPrinter); #ifdef UNITY_DUMP_RESULTS @@ -158,14 +160,8 @@ int main(int argc, char **argv) #if defined(RPMSG) transport = erpc_transport_rpmsg_lite_master_init(100, 101, ERPC_TRANSPORT_RPMSG_LITE_LINK_ID); message_buffer_factory = erpc_mbf_rpmsg_init(transport); -#else -#if defined(UART) - transport = erpc_transport_uart_init(ERPC_BOARD_UART_BASEADDR, ERPC_BOARD_UART_BAUDRATE, - CLOCK_GetFreq(ERPC_BOARD_UART_CLKSRC); -#elif defined(LPUART) - transport = erpc_transport_lpuart_init(ERPC_BOARD_UART_BASEADDR, ERPC_BOARD_UART_BAUDRATE, - CLOCK_GetFreq(ERPC_BOARD_UART_CLKSRC); -#endif +#elif defined(UART) + transport = erpc_transport_cmsis_uart_init((void *)&Driver_USART0); message_buffer_factory = erpc_mbf_dynamic_init(); #endif diff --git a/test/common/unit_test_server.cpp b/test/common/unit_test_server.cpp index d5a1779b2..370af62d7 100644 --- a/test/common/unit_test_server.cpp +++ b/test/common/unit_test_server.cpp @@ -14,13 +14,15 @@ #include "test_unit_test_common_server.h" #include "unit_test_wrapped.h" -#if (defined(RPMSG) || defined(UART) || defined(LPUART)) +#if (defined(RPMSG) || defined(UART)) extern "C" { #include "app_core1.h" #if defined(RPMSG) #define APP_ERPC_READY_EVENT_DATA (1) #include "mcmgr.h" #include "rpmsg_lite.h" +#elif defined(UART) +#include "fsl_usart_cmsis.h" #endif } #endif @@ -34,6 +36,9 @@ int MyAlloc::allocated_ = 0; //////////////////////////////////////////////////////////////////////////////// // Code //////////////////////////////////////////////////////////////////////////////// +#ifdef __cplusplus +extern "C" { +#endif #if defined(RPMSG) static void SignalReady(void) { @@ -53,9 +58,6 @@ void SystemInitHook(void) } #endif -#ifdef __cplusplus -extern "C" { -#endif int main(int argc, const char *argv[]) { #if defined(RPMSG) @@ -77,14 +79,8 @@ int main(int argc, const char *argv[]) transport = erpc_transport_rpmsg_lite_remote_init(101, 100, (void *)startupData, ERPC_TRANSPORT_RPMSG_LITE_LINK_ID, SignalReady, NULL); message_buffer_factory = erpc_mbf_rpmsg_init(transport); -#else -#if defined(UART) - transport = erpc_transport_uart_init(ERPC_BOARD_UART_BASEADDR, ERPC_BOARD_UART_BAUDRATE, - CLOCK_GetFreq(ERPC_BOARD_UART_CLKSRC); -#elif defined(LPUART) - transport = erpc_transport_lpuart_init(ERPC_BOARD_UART_BASEADDR, ERPC_BOARD_UART_BAUDRATE, - CLOCK_GetFreq(ERPC_BOARD_UART_CLKSRC); -#endif +#elif defined(UART) + transport = erpc_transport_cmsis_uart_init((void *)&Driver_USART0); message_buffer_factory = erpc_mbf_dynamic_init(); #endif diff --git a/test/test_callbacks/callbacks1.h b/test/test_callbacks/callbacks1.h index 57ef3c6ed..b1d511c73 100644 --- a/test/test_callbacks/callbacks1.h +++ b/test/test_callbacks/callbacks1.h @@ -6,6 +6,6 @@ * SPDX-License-Identifier: BSD-3-Clause */ -void callback1(int32_t a, int32_t b); +void callback1a(int32_t a, int32_t b); -void callback2(int32_t param1, int32_t param2); +void callback1b(int32_t param1, int32_t param2); diff --git a/test/test_callbacks/callbacks2.h b/test/test_callbacks/callbacks2.h index 3208ecead..f3f4120c8 100644 --- a/test/test_callbacks/callbacks2.h +++ b/test/test_callbacks/callbacks2.h @@ -6,4 +6,4 @@ * SPDX-License-Identifier: BSD-3-Clause */ -void callback3(int32_t param1, int32_t param2); +void callback2(int32_t param1, int32_t param2); diff --git a/test/test_callbacks/test_callbacks.erpc b/test/test_callbacks/test_callbacks.erpc index 45ae4da77..031cdf9ce 100644 --- a/test/test_callbacks/test_callbacks.erpc +++ b/test/test_callbacks/test_callbacks.erpc @@ -17,20 +17,20 @@ oneway callback2_t(int32, int32) @group("core0") interface ClientCore0Services { - myFun(in callback1_t pCallback1_t, out callback1_t pCallback2_t) -> void + myFun(in callback1_t pCallback1_in, out callback1_t pCallback1_out) -> void - myFun2(callback2_t pCallback1_t, out callback2_t pCallback2_t) -> void + myFun2(callback2_t pCallback2_in, out callback2_t pCallback2_out) -> void @include("callbacks1.h") - callback1_t callback1; + callback1_t callback1a; @include("callbacks1.h") - callback1_t callback2(param1, param2); + callback1_t callback1b(param1, param2); } @group("core1") interface ClientCore1Services { @include("callbacks2.h") - callback2_t callback3(param1, param2); + callback2_t callback2(param1, param2); } \ No newline at end of file diff --git a/test/test_callbacks/test_callbacks_client_impl.cpp b/test/test_callbacks/test_callbacks_client_impl.cpp index 11bb1291f..4d812e6ca 100644 --- a/test/test_callbacks/test_callbacks_client_impl.cpp +++ b/test/test_callbacks/test_callbacks_client_impl.cpp @@ -9,24 +9,32 @@ #include "test_core0.h" #include "test_core1_server.h" -void callback3(int32_t param1, int32_t param2) {} +void callback2(int32_t param1, int32_t param2) {} //////////////////////////////////////////////////////////////////////////////// // Unit test Implementation code //////////////////////////////////////////////////////////////////////////////// -TEST(test_callbacks, In_Out_table) +TEST(test_callbacks, In_Out_table_1) { - callback1_t pCallback2_t = NULL; - myFun(callback1, &pCallback2_t); + callback1_t pCallback1_out = NULL; + myFun(callback1a, &pCallback1_out); - EXPECT_TRUE(callback1 == *pCallback2_t); + EXPECT_TRUE(callback1a == *pCallback1_out); +} + +TEST(test_callbacks, In_Out_table_2) +{ + callback1_t pCallback1_out = NULL; + myFun(callback1b, &pCallback1_out); + + EXPECT_TRUE(callback1b == *pCallback1_out); } TEST(test_callbacks, In_Out_withoutTable) { - callback2_t pCallback2_t = NULL; - myFun2(callback3, &pCallback2_t); + callback2_t pCallback2_out = NULL; + myFun2(callback2, &pCallback2_out); - EXPECT_TRUE(callback3 == *pCallback2_t); + EXPECT_TRUE(callback2 == *pCallback2_out); } diff --git a/test/test_callbacks/test_callbacks_server_impl.cpp b/test/test_callbacks/test_callbacks_server_impl.cpp index 69bae214a..1d76d7ee7 100644 --- a/test/test_callbacks/test_callbacks_server_impl.cpp +++ b/test/test_callbacks/test_callbacks_server_impl.cpp @@ -16,37 +16,38 @@ // Implementation of function code //////////////////////////////////////////////////////////////////////////////// -void myFun(const callback1_t pCallback1_t, callback1_t *pCallback2_t) +callback1_t *cb1 = NULL; +callback2_t *cb2 = NULL; + +void myFun(const callback1_t pCallback1_in, callback1_t *pCallback1_out) { - if (pCallback1_t == callback1) - { - *pCallback2_t = pCallback1_t; - } - else - { - *pCallback2_t = callback2; - } + cb1 = NULL; + pCallback1_in(1, 2); + *pCallback1_out = (callback1_t)cb1; } -void myFun2(const callback2_t pCallback1_t, callback2_t *pCallback2_t) +void myFun2(const callback2_t pCallback2_in, callback2_t *pCallback2_out) { - - if (pCallback1_t == callback3) - { - *pCallback2_t = pCallback1_t; - } - else - { - *pCallback2_t = NULL; - } + cb2 = NULL; + pCallback2_in(1, 2); + *pCallback2_out = (callback2_t)cb2; } -void callback1(int32_t a, int32_t b) {} +void callback1a(int32_t a, int32_t b) +{ + cb1 = (callback1_t *)callback1a; +} -void callback2(int32_t param1, int32_t param2) {} +void callback1b(int32_t param1, int32_t param2) +{ + cb1 = (callback1_t *)callback1b; +} /* will be shim code in real use case */ -void callback3(int32_t param1, int32_t param2) {} +void callback2(int32_t param1, int32_t param2) +{ + cb2 = (callback2_t *)callback2; +} //////////////////////////////////////////////////////////////////////////////// // Add service to server code From 6a0f2a6afdee636310f4093774d2deef617f15d3 Mon Sep 17 00:00:00 2001 From: zuzy Date: Wed, 25 Dec 2019 16:46:34 +0800 Subject: [PATCH 05/96] Fixed extra return in client.cpp, when generages callbacks with return value. Enriched test_callbacks demo with some new callbacks. --- .../src/templates/c_client_source.template | 2 -- test/test_callbacks/test_callbacks.erpc | 9 ++++++ .../test_callbacks_client_impl.cpp | 15 ++++++++++ .../test_callbacks_server_impl.cpp | 28 +++++++++++++++++++ 4 files changed, 52 insertions(+), 2 deletions(-) diff --git a/erpcgen/src/templates/c_client_source.template b/erpcgen/src/templates/c_client_source.template index 050cedd1b..10711d7c9 100644 --- a/erpcgen/src/templates/c_client_source.template +++ b/erpcgen/src/templates/c_client_source.template @@ -164,8 +164,6 @@ static {$callbackType.prototype} { {% if fn.isCallback %} {% if fn.returnValue.type.isNotVoid %}return {% endif %}{$fn.callbackFName}(k{$iface.name}_service_id, k{$iface.name}_{$fn.name}_id{% for param in fn.parameters %}, {$param.name}{% endfor %}); -{% if fn.returnValue.type.isNotVoid %}return; -{% endif %} {% else -- fn.isCallback >%} {$ clientShimCode(fn, "k"& iface.name & "_service_id", "k" & iface.name & "_" & fn.name & "_id") >} {% endif -- fn.isCallback >%} diff --git a/test/test_callbacks/test_callbacks.erpc b/test/test_callbacks/test_callbacks.erpc index 031cdf9ce..3c3aff2ec 100644 --- a/test/test_callbacks/test_callbacks.erpc +++ b/test/test_callbacks/test_callbacks.erpc @@ -12,6 +12,7 @@ import "../common/unit_test_common.erpc" oneway callback1_t(int32 a, int32 b) oneway callback2_t(int32, int32) +callback3_t(int32 arg1, int32 arg2) -> int32 @include("test_core1.h") @group("core0") @@ -21,9 +22,17 @@ interface ClientCore0Services myFun2(callback2_t pCallback2_in, out callback2_t pCallback2_out) -> void + myFun3(callback3_t callback, in int32 arg1, in int32 arg2) -> int32 + + callback3_t my_add; + callback3_t my_sub; + callback3_t my_mul; + callback3_t my_div; + @include("callbacks1.h") callback1_t callback1a; + @include("callbacks1.h") callback1_t callback1b(param1, param2); } diff --git a/test/test_callbacks/test_callbacks_client_impl.cpp b/test/test_callbacks/test_callbacks_client_impl.cpp index 4d812e6ca..7b21043df 100644 --- a/test/test_callbacks/test_callbacks_client_impl.cpp +++ b/test/test_callbacks/test_callbacks_client_impl.cpp @@ -38,3 +38,18 @@ TEST(test_callbacks, In_Out_withoutTable) EXPECT_TRUE(callback2 == *pCallback2_out); } + +TEST(test_callbacks, Common_Callback) +{ + callback3_t callback = my_add; + EXPECT_TRUE(12 == myFun3(callback, 9, 3)); + + callback = my_sub; + EXPECT_TRUE(6 == myFun3(callback, 9, 3)); + + callback = my_mul; + EXPECT_TRUE(27 == myFun3(callback, 9, 3)); + + callback = my_div; + EXPECT_TRUE(3 == myFun3(callback, 9, 3)); +} \ No newline at end of file diff --git a/test/test_callbacks/test_callbacks_server_impl.cpp b/test/test_callbacks/test_callbacks_server_impl.cpp index 1d76d7ee7..c96c0c07c 100644 --- a/test/test_callbacks/test_callbacks_server_impl.cpp +++ b/test/test_callbacks/test_callbacks_server_impl.cpp @@ -49,6 +49,34 @@ void callback2(int32_t param1, int32_t param2) cb2 = (callback2_t *)callback2; } +int32_t myFun3(const callback3_t callback, int32_t arg1, int32_t arg2) +{ + return callback(arg1, arg2); +} + +int32_t my_add(int32_t arg1, int32_t arg2) +{ + return arg1 + arg2; +} + +int32_t my_sub(int32_t arg1, int32_t arg2) +{ + return arg1 - arg2; +} + +int32_t my_mul(int32_t arg1, int32_t arg2) +{ + return arg1 * arg2; +} + +int32_t my_div(int32_t arg1, int32_t arg2) +{ + if(arg2) { + return arg1 / arg2; + } + return 0; +} + //////////////////////////////////////////////////////////////////////////////// // Add service to server code //////////////////////////////////////////////////////////////////////////////// From 2141c21b1128ace3ef35d09f335ebc3c9dd086c5 Mon Sep 17 00:00:00 2001 From: "Michal Princ (nxa17570)" Date: Tue, 14 Jan 2020 08:41:25 +0100 Subject: [PATCH 06/96] Copyright year update --- LICENSE | 4 ++-- README.md | 5 +++-- erpcgen/src/erpcgen.cpp | 2 +- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/LICENSE b/LICENSE index b6b0efa9a..a05f102ec 100644 --- a/LICENSE +++ b/LICENSE @@ -1,5 +1,5 @@ -Copyright (c) 2014-2016 Freescale Semiconductor, Inc. -Copyright 2016-2018 NXP +Copyright 2014-2016 Freescale Semiconductor, Inc. +Copyright 2016-2020 NXP All rights reserved. SPDX-License-Identifier: BSD-3-Clause diff --git a/README.md b/README.md index 6dc3ad2a3..e054932b1 100644 --- a/README.md +++ b/README.md @@ -170,5 +170,6 @@ After installation, the `erpc` package is available via normal import statements Repository on Github contains two main branches. __Master__ and __develop__. Code is developed on __develop__ branch. Release version is created via merging __develop__ branch into __master__ branch. --- -Copyright © 2014-2016 Freescale Semiconductor, Inc. -Copyright © 2016-2017 NXP +Copyright 2014-2016 Freescale Semiconductor, Inc. + +Copyright 2016-2020 NXP diff --git a/erpcgen/src/erpcgen.cpp b/erpcgen/src/erpcgen.cpp index 326d4ee86..b698bdb61 100644 --- a/erpcgen/src/erpcgen.cpp +++ b/erpcgen/src/erpcgen.cpp @@ -40,7 +40,7 @@ const char k_toolName[] = "erpcgen"; const char k_version[] = ERPC_VERSION; /*! Copyright string. */ -const char k_copyright[] = "Copyright 2016-2018 NXP. All rights reserved."; +const char k_copyright[] = "Copyright 2016-2020 NXP. All rights reserved."; static const char *k_optionsDefinition[] = { "?|help", "V|version", From 7d993085d8ec90893647e085e1006ce628ddd269 Mon Sep 17 00:00:00 2001 From: George Beckstein Date: Wed, 4 Dec 2019 17:08:35 -0500 Subject: [PATCH 07/96] Implemented support for mbed-os --- erpc_c/config/erpc_config.h | 1 + erpc_c/port/erpc_port_mbed.cpp | 227 +++++++++++++++++++++++++++++++++ erpc_c/port/erpc_threading.h | 29 +++++ 3 files changed, 257 insertions(+) create mode 100644 erpc_c/port/erpc_port_mbed.cpp diff --git a/erpc_c/config/erpc_config.h b/erpc_c/config/erpc_config.h index 6e2e73538..547550d98 100644 --- a/erpc_c/config/erpc_config.h +++ b/erpc_c/config/erpc_config.h @@ -26,6 +26,7 @@ #define ERPC_THREADS_PTHREADS (1) //!< POSIX pthreads. #define ERPC_THREADS_FREERTOS (2) //!< FreeRTOS. #define ERPC_THREADS_ZEPHYR (3) //!< ZEPHYR. +#define ERPC_THREADS_MBED (4) //!< Mbed OS #define ERPC_NOEXCEPT_DISABLED (0) //!< Disabling noexcept feature. #define ERPC_NOEXCEPT_ENABLED (1) //!< Enabling noexcept feature. diff --git a/erpc_c/port/erpc_port_mbed.cpp b/erpc_c/port/erpc_port_mbed.cpp new file mode 100644 index 000000000..8a97864b7 --- /dev/null +++ b/erpc_c/port/erpc_port_mbed.cpp @@ -0,0 +1,227 @@ +/* + * Copyright (c) 2019, Embedded Planet, Inc + * All rights reserved. + * + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include "erpc_threading.h" + +#include "platform/CriticalSectionLock.h" +#include "platform/mbed_assert.h" + +#if ERPC_THREADS_IS(MBED) + +namespace erpc +{ + + //////////////////////////////////////////////////////////////////////////////// + // Variables + //////////////////////////////////////////////////////////////////////////////// + + Thread *Thread::s_first = NULL; + + //////////////////////////////////////////////////////////////////////////////// + // Code + //////////////////////////////////////////////////////////////////////////////// + + Thread::Thread(const char *name) + : m_name(name) + , m_entry(0) + , m_arg(0) + , m_stackSize(0) + , m_priority(0) + , m_thread(NULL) + , m_next(NULL) + { + } + + Thread::Thread(thread_entry_t entry, uint32_t priority, uint32_t stackSize, const char *name) + : m_name(name) + , m_entry(entry) + , m_arg(0) + , m_stackSize(stackSize) + , m_priority(priority) + , m_thread(NULL) + , m_next(NULL) + { + } + + Thread::~Thread(void) { + if(m_thread != NULL) { + delete m_thread; + m_thread = NULL; + } + } + + void Thread::init(thread_entry_t entry, uint32_t priority, uint32_t stackSize) + { + m_entry = entry; + m_stackSize = stackSize; + m_priority = priority; + m_thread = new rtos::Thread(osPriorityNormal, // Ignore priority because erpc does not map their priority to anything + ((m_stackSize + sizeof(uint32_t) - 1) / sizeof(uint32_t)), // Round up number of words + NULL, m_name); + } + + void Thread::start(void *arg) + { + m_arg = arg; + + // Enter a critical section to disable preemptive scheduling until we add the newly + // created thread to the linked list. This prevents a race condition if the new thread is + // higher priority than the current thread, and the new thread calls getCurrenThread(), + // which will scan the linked list. + mbed::CriticalSectionLock::enable(); + + if(s_first) + { + m_next = s_first; + } + s_first = this; + + // Start the thread + m_thread->start(mbed::callback(&erpc::Thread::threadEntryPointStub, this)); + + mbed::CriticalSectionLock::disable(); + } + + bool Thread::operator==(Thread &o) + { + return (this->getThreadId() == o.getThreadId()); + } + + Thread *Thread::getCurrentThread() + { + osThreadId_t currentThreadId = rtos::ThisThread::get_id(); + + // Walk the threads list to find the Thread object for the current task. + mbed::CriticalSectionLock::enable(); + Thread *it = s_first; + while (it) + { + if (it->getThreadId() == currentThreadId) + { + break; + } + it = it->m_next; + } + mbed::CriticalSectionLock::disable(); + return it; + } + + void Thread::sleep(uint32_t usecs) + { + rtos::ThisThread::sleep_for(usecs/1000); + } + + void Thread::threadEntryPoint(void) + { + if (m_entry) + { + m_entry(m_arg); + } + } + + void Thread::threadEntryPointStub(void *arg) + { + Thread *_this = reinterpret_cast(arg); + MBED_ASSERT(_this); // Reinterpreting 'void *arg' to 'Thread *' failed. + _this->threadEntryPoint(); + + // Remove this thread from the linked list. + mbed::CriticalSectionLock::enable(); + Thread *it = s_first; + Thread *prev = NULL; + while (it) + { + if (it == _this) + { + if (it == s_first) + { + s_first = _this->m_next; + } + else if (prev) + { + prev->m_next = _this->m_next; + } + _this->m_next = NULL; + + break; + } + prev = it; + it = it->m_next; + } + mbed::CriticalSectionLock::disable(); + } + + Mutex::Mutex(void) + { + // Having a member variable mutex + // was causing memory alignment issues... + m_mutex = new rtos::Mutex(); + } + + Mutex::~Mutex(void) + { + if(m_mutex != NULL) { + delete m_mutex; + m_mutex = NULL; + } + } + + bool Mutex::tryLock(void) + { + // Pass a zero timeout to poll the mutex. + return m_mutex->trylock(); + } + + bool Mutex::lock(void) + { + return m_mutex->lock(); + } + + bool Mutex::unlock(void) + { + return m_mutex->unlock(); + } + + Semaphore::Semaphore(int count) + : m_count(count) + { + m_sem = new rtos::Semaphore(m_count); + } + + Semaphore::~Semaphore(void) + { + if(m_sem != NULL) { + delete m_sem; + m_sem = NULL; + } + } + + void Semaphore::put(void) + { + m_sem->release(); + } + + bool Semaphore::get(uint32_t timeout) + { + m_count = m_sem->wait(timeout); + if(m_count < 0) { + return true; + } + else { + return false; + } + } + + int Semaphore::getCount(void) const + { + return m_count; + } + +} + +#endif diff --git a/erpc_c/port/erpc_threading.h b/erpc_c/port/erpc_threading.h index c932f0f0a..4c2913377 100644 --- a/erpc_c/port/erpc_threading.h +++ b/erpc_c/port/erpc_threading.h @@ -24,6 +24,12 @@ #include "task.h" #elif ERPC_THREADS_IS(ZEPHYR) #include "kernel.h" +#elif ERPC_THREADS_IS(MBED) +#if MBED_CONF_RTOS_PRESENT +#include "rtos.h" +#else +#warning mbed-rpc: Threading is enabled but Mbed RTOS is not present! +#endif #endif // ERPC_THREADS_IS /*! @@ -136,6 +142,8 @@ class Thread return reinterpret_cast(m_task); #elif ERPC_THREADS_IS(ZEPHYR) return reinterpret_cast(m_thread); +#elif ERPC_THREADS_IS(MBED) + return reinterpret_cast(m_thread->get_id()); #endif } @@ -152,6 +160,8 @@ class Thread return reinterpret_cast(xTaskGetCurrentTaskHandle()); #elif ERPC_THREADS_IS(ZEPHYR) return reinterpret_cast(k_current_get()); +#elif ERPC_THREADS_IS(MBED) + return reinterpret_cast(rtos::ThisThread::get_id()); #endif } @@ -203,6 +213,10 @@ class Thread #elif ERPC_THREADS_IS(ZEPHYR) struct k_thread m_thread; /*!< Current thread. */ k_thread_stack_t *m_stack; /*!< Pointer to stack. */ +#elif ERPC_THREADS_IS(MBED) + rtos::Thread* m_thread; /*!< Underlying Thread instance */ + Thread *m_next; /*!< Pointer to next Thread. */ + static Thread *s_first; /*!< Pointer to first Thread. */ #endif #if ERPC_THREADS_IS(PTHREADS) @@ -231,6 +245,16 @@ class Thread * @param[in] arg3 */ static void *threadEntryPointStub(void *arg1, void *arg2, void *arg3); + +#elif ERPC_THREADS_IS(MBED) + + /*! + * @brief This function execute threadEntryPoint function. + * + * @param[in] arg Thread to execute. + */ + static void threadEntryPointStub(void *arg); + #endif private: @@ -334,6 +358,8 @@ class Mutex SemaphoreHandle_t m_mutex; /*!< Mutex.*/ #elif ERPC_THREADS_IS(ZEPHYR) struct k_mutex m_mutex; /*!< Mutex.*/ +#elif ERPC_THREADS_IS(MBED) + rtos::Mutex* m_mutex; /*!< Mutex. */ #endif private: @@ -415,6 +441,9 @@ class Semaphore SemaphoreHandle_t m_sem; /*!< Semaphore. */ #elif ERPC_THREADS_IS(ZEPHYR) struct k_sem m_sem; /*!< Semaphore. */ +#elif ERPC_THREADS_IS(MBED) + rtos::Semaphore* m_sem; /*!< Semaphore. */ + int m_count; /*!< Semaphore count number. */ #endif private: From 5313853674f1afa61772f47a1d2b2bd666f51e62 Mon Sep 17 00:00:00 2001 From: George Beckstein Date: Wed, 4 Dec 2019 19:50:23 -0500 Subject: [PATCH 08/96] Add link to supporting library and examples --- erpc_c/config/erpc_config.h | 2 +- erpc_c/port/erpc_port_mbed.cpp | 412 +++++++++++++++++---------------- erpc_c/port/erpc_threading.h | 14 +- 3 files changed, 215 insertions(+), 213 deletions(-) diff --git a/erpc_c/config/erpc_config.h b/erpc_c/config/erpc_config.h index 547550d98..d3e0b8181 100644 --- a/erpc_c/config/erpc_config.h +++ b/erpc_c/config/erpc_config.h @@ -26,7 +26,7 @@ #define ERPC_THREADS_PTHREADS (1) //!< POSIX pthreads. #define ERPC_THREADS_FREERTOS (2) //!< FreeRTOS. #define ERPC_THREADS_ZEPHYR (3) //!< ZEPHYR. -#define ERPC_THREADS_MBED (4) //!< Mbed OS +#define ERPC_THREADS_MBED (4) //!< Mbed OS #define ERPC_NOEXCEPT_DISABLED (0) //!< Disabling noexcept feature. #define ERPC_NOEXCEPT_ENABLED (1) //!< Enabling noexcept feature. diff --git a/erpc_c/port/erpc_port_mbed.cpp b/erpc_c/port/erpc_port_mbed.cpp index 8a97864b7..bdd254f1c 100644 --- a/erpc_c/port/erpc_port_mbed.cpp +++ b/erpc_c/port/erpc_port_mbed.cpp @@ -2,6 +2,8 @@ * Copyright (c) 2019, Embedded Planet, Inc * All rights reserved. * + * For supporting transports and examples see: + * https://github.com/EmbeddedPlanet/mbed-rpc * * SPDX-License-Identifier: BSD-3-Clause */ @@ -16,211 +18,211 @@ namespace erpc { - //////////////////////////////////////////////////////////////////////////////// - // Variables - //////////////////////////////////////////////////////////////////////////////// - - Thread *Thread::s_first = NULL; - - //////////////////////////////////////////////////////////////////////////////// - // Code - //////////////////////////////////////////////////////////////////////////////// - - Thread::Thread(const char *name) - : m_name(name) - , m_entry(0) - , m_arg(0) - , m_stackSize(0) - , m_priority(0) - , m_thread(NULL) - , m_next(NULL) - { - } - - Thread::Thread(thread_entry_t entry, uint32_t priority, uint32_t stackSize, const char *name) - : m_name(name) - , m_entry(entry) - , m_arg(0) - , m_stackSize(stackSize) - , m_priority(priority) - , m_thread(NULL) - , m_next(NULL) - { - } - - Thread::~Thread(void) { - if(m_thread != NULL) { - delete m_thread; - m_thread = NULL; - } - } - - void Thread::init(thread_entry_t entry, uint32_t priority, uint32_t stackSize) - { - m_entry = entry; - m_stackSize = stackSize; - m_priority = priority; - m_thread = new rtos::Thread(osPriorityNormal, // Ignore priority because erpc does not map their priority to anything - ((m_stackSize + sizeof(uint32_t) - 1) / sizeof(uint32_t)), // Round up number of words - NULL, m_name); - } - - void Thread::start(void *arg) - { - m_arg = arg; - - // Enter a critical section to disable preemptive scheduling until we add the newly - // created thread to the linked list. This prevents a race condition if the new thread is - // higher priority than the current thread, and the new thread calls getCurrenThread(), - // which will scan the linked list. - mbed::CriticalSectionLock::enable(); - - if(s_first) - { - m_next = s_first; - } - s_first = this; - - // Start the thread - m_thread->start(mbed::callback(&erpc::Thread::threadEntryPointStub, this)); - - mbed::CriticalSectionLock::disable(); - } - - bool Thread::operator==(Thread &o) - { - return (this->getThreadId() == o.getThreadId()); - } - - Thread *Thread::getCurrentThread() - { - osThreadId_t currentThreadId = rtos::ThisThread::get_id(); - - // Walk the threads list to find the Thread object for the current task. - mbed::CriticalSectionLock::enable(); - Thread *it = s_first; - while (it) - { - if (it->getThreadId() == currentThreadId) - { - break; - } - it = it->m_next; - } - mbed::CriticalSectionLock::disable(); - return it; - } - - void Thread::sleep(uint32_t usecs) - { - rtos::ThisThread::sleep_for(usecs/1000); - } - - void Thread::threadEntryPoint(void) - { - if (m_entry) - { - m_entry(m_arg); - } - } - - void Thread::threadEntryPointStub(void *arg) - { - Thread *_this = reinterpret_cast(arg); - MBED_ASSERT(_this); // Reinterpreting 'void *arg' to 'Thread *' failed. - _this->threadEntryPoint(); - - // Remove this thread from the linked list. - mbed::CriticalSectionLock::enable(); - Thread *it = s_first; - Thread *prev = NULL; - while (it) - { - if (it == _this) - { - if (it == s_first) - { - s_first = _this->m_next; - } - else if (prev) - { - prev->m_next = _this->m_next; - } - _this->m_next = NULL; - - break; - } - prev = it; - it = it->m_next; - } - mbed::CriticalSectionLock::disable(); - } - - Mutex::Mutex(void) - { - // Having a member variable mutex - // was causing memory alignment issues... - m_mutex = new rtos::Mutex(); - } - - Mutex::~Mutex(void) - { - if(m_mutex != NULL) { - delete m_mutex; - m_mutex = NULL; - } - } - - bool Mutex::tryLock(void) - { - // Pass a zero timeout to poll the mutex. - return m_mutex->trylock(); - } - - bool Mutex::lock(void) - { - return m_mutex->lock(); - } - - bool Mutex::unlock(void) - { - return m_mutex->unlock(); - } - - Semaphore::Semaphore(int count) - : m_count(count) - { - m_sem = new rtos::Semaphore(m_count); - } - - Semaphore::~Semaphore(void) - { - if(m_sem != NULL) { - delete m_sem; - m_sem = NULL; - } - } - - void Semaphore::put(void) - { - m_sem->release(); - } - - bool Semaphore::get(uint32_t timeout) - { - m_count = m_sem->wait(timeout); - if(m_count < 0) { - return true; - } - else { - return false; - } - } - - int Semaphore::getCount(void) const - { - return m_count; - } +//////////////////////////////////////////////////////////////////////////////// +// Variables +//////////////////////////////////////////////////////////////////////////////// + + Thread *Thread::s_first = NULL; + +//////////////////////////////////////////////////////////////////////////////// +// Code +//////////////////////////////////////////////////////////////////////////////// + + Thread::Thread(const char *name) + : m_name(name) + , m_entry(0) + , m_arg(0) + , m_stackSize(0) + , m_priority(0) + , m_thread(NULL) + , m_next(NULL) + { + } + + Thread::Thread(thread_entry_t entry, uint32_t priority, uint32_t stackSize, const char *name) + : m_name(name) + , m_entry(entry) + , m_arg(0) + , m_stackSize(stackSize) + , m_priority(priority) + , m_thread(NULL) + , m_next(NULL) + { + } + + Thread::~Thread(void) { + if(m_thread != NULL) { + delete m_thread; + m_thread = NULL; + } + } + + void Thread::init(thread_entry_t entry, uint32_t priority, uint32_t stackSize) + { + m_entry = entry; + m_stackSize = stackSize; + m_priority = priority; + m_thread = new rtos::Thread(osPriorityNormal, // Ignore priority because erpc does not map their priority to anything + ((m_stackSize + sizeof(uint32_t) - 1) / sizeof(uint32_t)),// Round up number of words + NULL, m_name); + } + + void Thread::start(void *arg) + { + m_arg = arg; + + // Enter a critical section to disable preemptive scheduling until we add the newly + // created thread to the linked list. This prevents a race condition if the new thread is + // higher priority than the current thread, and the new thread calls getCurrenThread(), + // which will scan the linked list. + mbed::CriticalSectionLock::enable(); + + if(s_first) + { + m_next = s_first; + } + s_first = this; + + // Start the thread + m_thread->start(mbed::callback(&erpc::Thread::threadEntryPointStub, this)); + + mbed::CriticalSectionLock::disable(); + } + + bool Thread::operator==(Thread &o) + { + return (this->getThreadId() == o.getThreadId()); + } + + Thread *Thread::getCurrentThread() + { + osThreadId_t currentThreadId = rtos::ThisThread::get_id(); + +// Walk the threads list to find the Thread object for the current task. + mbed::CriticalSectionLock::enable(); + Thread *it = s_first; + while (it) + { + if (it->getThreadId() == currentThreadId) + { + break; + } + it = it->m_next; + } + mbed::CriticalSectionLock::disable(); + return it; + } + + void Thread::sleep(uint32_t usecs) + { + rtos::ThisThread::sleep_for(usecs/1000); + } + + void Thread::threadEntryPoint(void) + { + if (m_entry) + { + m_entry(m_arg); + } + } + + void Thread::threadEntryPointStub(void *arg) + { + Thread *_this = reinterpret_cast(arg); + MBED_ASSERT(_this); // Reinterpreting 'void *arg' to 'Thread *' failed. + _this->threadEntryPoint(); + + // Remove this thread from the linked list. + mbed::CriticalSectionLock::enable(); + Thread *it = s_first; + Thread *prev = NULL; + while (it) + { + if (it == _this) + { + if (it == s_first) + { + s_first = _this->m_next; + } + else if (prev) + { + prev->m_next = _this->m_next; + } + _this->m_next = NULL; + + break; + } + prev = it; + it = it->m_next; + } + mbed::CriticalSectionLock::disable(); + } + + Mutex::Mutex(void) + { + // Having a member variable mutex + // was causing memory alignment issues... + m_mutex = new rtos::Mutex(); + } + + Mutex::~Mutex(void) + { + if(m_mutex != NULL) { + delete m_mutex; + m_mutex = NULL; + } + } + + bool Mutex::tryLock(void) + { + // Pass a zero timeout to poll the mutex. + return m_mutex->trylock(); + } + + bool Mutex::lock(void) + { + return m_mutex->lock(); + } + + bool Mutex::unlock(void) + { + return m_mutex->unlock(); + } + + Semaphore::Semaphore(int count) + : m_count(count) + { + m_sem = new rtos::Semaphore(m_count); + } + + Semaphore::~Semaphore(void) + { + if(m_sem != NULL) { + delete m_sem; + m_sem = NULL; + } + } + + void Semaphore::put(void) + { + m_sem->release(); + } + + bool Semaphore::get(uint32_t timeout) + { + m_count = m_sem->wait(timeout); + if(m_count < 0) { + return true; + } + else { + return false; + } + } + + int Semaphore::getCount(void) const + { + return m_count; + } } diff --git a/erpc_c/port/erpc_threading.h b/erpc_c/port/erpc_threading.h index 4c2913377..d5806ec33 100644 --- a/erpc_c/port/erpc_threading.h +++ b/erpc_c/port/erpc_threading.h @@ -249,11 +249,11 @@ class Thread #elif ERPC_THREADS_IS(MBED) /*! - * @brief This function execute threadEntryPoint function. - * - * @param[in] arg Thread to execute. - */ - static void threadEntryPointStub(void *arg); + * @brief This function execute threadEntryPoint function. + * + * @param[in] arg Thread to execute. + */ + static void threadEntryPointStub(void *arg); #endif @@ -442,8 +442,8 @@ class Semaphore #elif ERPC_THREADS_IS(ZEPHYR) struct k_sem m_sem; /*!< Semaphore. */ #elif ERPC_THREADS_IS(MBED) - rtos::Semaphore* m_sem; /*!< Semaphore. */ - int m_count; /*!< Semaphore count number. */ + rtos::Semaphore* m_sem; /*!< Semaphore. */ + int m_count; /*!< Semaphore count number. */ #endif private: From af02b3e4c2b37edb3a3e4eb4bc21263a52fc96da Mon Sep 17 00:00:00 2001 From: "Michal Princ (nxa17570)" Date: Fri, 17 Apr 2020 10:11:10 +0200 Subject: [PATCH 09/96] Rename cpp file from pull request #81 to be aligned with other port layer files naming Signed-off-by: Michal Princ (nxa17570) --- erpc_c/port/{erpc_port_mbed.cpp => erpc_threading_mbed.cpp} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename erpc_c/port/{erpc_port_mbed.cpp => erpc_threading_mbed.cpp} (100%) diff --git a/erpc_c/port/erpc_port_mbed.cpp b/erpc_c/port/erpc_threading_mbed.cpp similarity index 100% rename from erpc_c/port/erpc_port_mbed.cpp rename to erpc_c/port/erpc_threading_mbed.cpp From 736c5d3d20395b72faab5d0fdb4162f67df0526e Mon Sep 17 00:00:00 2001 From: Chris Trowbridge Date: Fri, 24 Apr 2020 09:19:09 -0400 Subject: [PATCH 10/96] Add mbed support for malloc() and free() --- erpc_c/port/erpc_port_mbed.cpp | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) create mode 100644 erpc_c/port/erpc_port_mbed.cpp diff --git a/erpc_c/port/erpc_port_mbed.cpp b/erpc_c/port/erpc_port_mbed.cpp new file mode 100644 index 000000000..b8c66dfb9 --- /dev/null +++ b/erpc_c/port/erpc_port_mbed.cpp @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2020, Embedded Planet, Inc + * All rights reserved. + * + * For supporting transports and examples see: + * https://github.com/EmbeddedPlanet/mbed-rpc + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include "erpc_port.h" + +#if ERPC_THREADS_IS(MBED) + +#include + +using namespace std; + +void *erpc_malloc(size_t size) +{ + void *p = malloc(size); + return p; +} + +void erpc_free(void *ptr) +{ + free(ptr); +} +#endif From 439affde13546f200fcb935cf0aeaf2b3d772d61 Mon Sep 17 00:00:00 2001 From: zuzy Date: Wed, 3 Jun 2020 10:14:54 +0800 Subject: [PATCH 11/96] : Fix erpcgen python client inout argument bug : Insert a judge of parameter.direction Issue #98 --- erpcgen/src/templates/py_client.template | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/erpcgen/src/templates/py_client.template b/erpcgen/src/templates/py_client.template index a9bdfd5ee..e9f629e16 100644 --- a/erpcgen/src/templates/py_client.template +++ b/erpcgen/src/templates/py_client.template @@ -61,7 +61,11 @@ class {$iface.name}Client(interface.I{$iface.name}): {% if p.type.type == 'union' %} {$p.name}._write(codec, {$p.discriminator}) {% else%} +{% if p.direction == "inout" %} + {$encodeValue(p.type, p.name & ".value", "codec", " ", 0)} +{% else %} {$encodeValue(p.type, p.name, "codec", " ", 0)} +{% endif -- p.direction %} {% endif -- isUnion %} {% endif -- isNullable %} {% endfor -- inParams %} From 7300793ed19bd8dafaf9ce42c91005130784fb41 Mon Sep 17 00:00:00 2001 From: Ramsey Harris Date: Fri, 22 May 2020 17:10:49 -0700 Subject: [PATCH 12/96] Remove '$' character from generated symbol name in '_$union' suffix When generating the symbol names, don't use the '$' character in the suffix string; this is not a valid Python identifier. The symbol name is used when generating the Python class name; this name is not used when generating the C code. --- erpcgen/src/SymbolScanner.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/erpcgen/src/SymbolScanner.cpp b/erpcgen/src/SymbolScanner.cpp index ccf56b3d6..f88d50149 100644 --- a/erpcgen/src/SymbolScanner.cpp +++ b/erpcgen/src/SymbolScanner.cpp @@ -1,6 +1,7 @@ /* * Copyright (c) 2014-2016, Freescale Semiconductor, Inc. * Copyright 2016-2017 NXP + * Copyright (c) 2020 Texas Instruments Incorporated * All rights reserved. * * @@ -772,7 +773,7 @@ AstNode *SymbolScanner::handleUnion(AstNode *node, top_down) string unionVariableName = node->getParent()->getChild(0)->getToken().getStringValue(); /* Create a new node in the AST for the union's name, and assign it */ - node->appendChild(new AstNode(Token(TOK_IDENT, new StringValue(unionVariableName + "_$union")))); + node->appendChild(new AstNode(Token(TOK_IDENT, new StringValue(unionVariableName + "_union")))); /* union token. */ tok = &node->getChild(3)->getToken(); From 5959ccd31b1d3cb66ab46892783a3f27873c4829 Mon Sep 17 00:00:00 2001 From: "Michal Princ (nxa17570)" Date: Tue, 21 Jul 2020 15:33:35 +0200 Subject: [PATCH 13/96] eRPC updates 07/2020 -- Unit test code updated to handle service add and remove operations -- Several MISRA issues in rpmsg-based transports addressed -- Support MU transport unit testing -- Fixed Linux/TCP acceptance tests in release target -- Minor documentation updates, code formatting --- README.md | 2 +- doxygen/Doxyfile.erpc | 2 +- doxygen/Doxyfile.erpcgen | 2 +- doxygen/html_footer.html | 4 +- erpc_c/config/erpc_config.h | 7 +- .../infra/erpc_arbitrated_client_manager.cpp | 6 +- erpc_c/infra/erpc_transport_arbitrator.cpp | 6 +- erpc_c/infra/erpc_version.h | 6 +- erpc_c/port/erpc_threading.h | 16 +- erpc_c/port/erpc_threading_mbed.cpp | 314 +++++++++--------- erpc_c/setup/erpc_arbitrated_client_setup.cpp | 6 +- erpc_c/setup/erpc_setup_rpmsg_lite_master.cpp | 6 +- erpc_c/setup/erpc_setup_rpmsg_lite_remote.cpp | 4 +- .../erpc_setup_rpmsg_lite_rtos_master.cpp | 5 +- .../erpc_setup_rpmsg_lite_rtos_remote.cpp | 4 +- .../erpc_setup_rpmsg_tty_rtos_remote.cpp | 4 +- erpc_c/setup/erpc_transport_setup.h | 12 +- .../erpc_rpmsg_lite_rtos_transport.cpp | 44 +-- .../erpc_rpmsg_lite_rtos_transport.h | 6 +- .../transports/erpc_rpmsg_lite_transport.cpp | 34 +- erpc_c/transports/erpc_rpmsg_lite_transport.h | 6 +- .../erpc_rpmsg_tty_rtos_transport.cpp | 48 +-- .../erpc_rpmsg_tty_rtos_transport.h | 6 +- erpc_python/erpc/erpc_version.py | 4 +- .../service/__init__.py | 2 +- .../service/erpc_matrix_multiply/__init__.py | 6 +- .../service/erpc_matrix_multiply/client.py | 2 +- .../service/erpc_matrix_multiply/common.py | 2 +- .../service/erpc_matrix_multiply/interface.py | 2 +- .../service/erpc_matrix_multiply/server.py | 2 +- test/common/retarget_cpp_streamed_io.c | 172 +++++----- test/common/unit_test.h | 6 +- test/common/unit_test_arbitrator_app0.cpp | 55 ++- test/common/unit_test_arbitrator_app1.cpp | 36 +- test/common/unit_test_client.cpp | 59 +++- test/common/unit_test_serial_server.cpp | 18 +- test/common/unit_test_server.cpp | 37 ++- .../unit_test_tcp_arbitrator_client.cpp | 4 +- .../unit_test_tcp_arbitrator_server.cpp | 12 +- test/common/unit_test_tcp_server.cpp | 17 +- test/common/unit_test_wrapped.h | 4 +- .../test_annotations_server_impl.cpp | 42 ++- .../test_arbitrator_client_impl.cpp | 24 +- .../test_arbitrator_server_impl.cpp | 22 +- test/test_arrays/test_arrays_server_impl.cpp | 39 ++- test/test_binary/test_binary_server_impl.cpp | 42 ++- .../test_builtin/test_builtin_server_impl.cpp | 39 ++- .../test_callbacks_server_impl.cpp | 39 ++- test/test_const/test_const_server_impl.cpp | 29 +- test/test_enums/test_enums_server_impl.cpp | 39 ++- test/test_lists/test_lists_server_impl.cpp | 39 ++- test/test_shared/test_shared_server_impl.cpp | 39 ++- test/test_struct/test_struct_server_impl.cpp | 50 ++- .../test_typedef/test_typedef_server_impl.cpp | 39 ++- test/test_unions/test_unions_server_impl.cpp | 39 ++- 55 files changed, 1039 insertions(+), 472 deletions(-) diff --git a/README.md b/README.md index e054932b1..298ef96af 100644 --- a/README.md +++ b/README.md @@ -117,7 +117,7 @@ Steps are described in [`erpcgen/VisualStudio_v14/readme_erpcgen.txt`](erpcgen/V Install these packages: * bison: GNU yacc-compatible parser generator * flex: A fast lexical analyzer generator -* libboost-dev, libboost-filesystem-dev, libboost-system-dev: Boost C++ libraries (Linux needs to use libboost version 1.58.0) +* libboost-dev, libboost-filesystem-dev, libboost-system-dev: Boost C++ libraries (Linux needs to use libboost version 1.67.0) * make: the GNU version of the 'make' utility * python: Python language interpreter (either 2.7 or 3.5+ work) * gcc-core: GNU Compiler Collection (C, OpenMP) diff --git a/doxygen/Doxyfile.erpc b/doxygen/Doxyfile.erpc index dae9cb25b..16cd59f72 100644 --- a/doxygen/Doxyfile.erpc +++ b/doxygen/Doxyfile.erpc @@ -38,7 +38,7 @@ PROJECT_NAME = "eRPC API Reference" # could be handy for archiving the generated documentation or if some version # control system is used. -PROJECT_NUMBER = "Rev. 1.7.3" +PROJECT_NUMBER = "Rev. 1.7.4" # Using the PROJECT_BRIEF tag one can provide an optional one line description # for a project that appears at the top of each page and should give viewer a diff --git a/doxygen/Doxyfile.erpcgen b/doxygen/Doxyfile.erpcgen index 1771189b5..8a767aeff 100644 --- a/doxygen/Doxyfile.erpcgen +++ b/doxygen/Doxyfile.erpcgen @@ -38,7 +38,7 @@ PROJECT_NAME = "eRPC Generator (erpcgen)" # could be handy for archiving the generated documentation or if some version # control system is used. -PROJECT_NUMBER = "Rev. 1.7.3" +PROJECT_NUMBER = "Rev. 1.7.4" # Using the PROJECT_BRIEF tag one can provide an optional one line description # for a project that appears at the top of each page and should give viewer a diff --git a/doxygen/html_footer.html b/doxygen/html_footer.html index 99eff856b..dd02cae32 100644 --- a/doxygen/html_footer.html +++ b/doxygen/html_footer.html @@ -3,14 +3,14 @@ diff --git a/erpc_c/config/erpc_config.h b/erpc_c/config/erpc_config.h index d3e0b8181..ad16559f5 100644 --- a/erpc_c/config/erpc_config.h +++ b/erpc_c/config/erpc_config.h @@ -1,6 +1,6 @@ /* * Copyright (c) 2016, Freescale Semiconductor, Inc. - * Copyright 2016-2019 NXP + * Copyright 2016-2020 NXP * All rights reserved. * * @@ -95,8 +95,9 @@ //! @def ERPC_MESSAGE_LOGGING //! -//! Enable eRPC message logging code through the eRPC. Take look into "erpc_message_loggers.h". Can be used for base printing -//! messages, or sending data to another system for data analysis. Default set to ERPC_MESSAGE_LOGGING_DISABLED. +//! Enable eRPC message logging code through the eRPC. Take look into "erpc_message_loggers.h". Can be used for base +//! printing messages, or sending data to another system for data analysis. Default set to +//! ERPC_MESSAGE_LOGGING_DISABLED. //! //! Uncomment for using logging feature. //#define ERPC_MESSAGE_LOGGING (ERPC_MESSAGE_LOGGING_ENABLED) diff --git a/erpc_c/infra/erpc_arbitrated_client_manager.cpp b/erpc_c/infra/erpc_arbitrated_client_manager.cpp index a68661649..15312e3d8 100644 --- a/erpc_c/infra/erpc_arbitrated_client_manager.cpp +++ b/erpc_c/infra/erpc_arbitrated_client_manager.cpp @@ -1,6 +1,6 @@ /* * Copyright (c) 2016, Freescale Semiconductor, Inc. - * Copyright 2016-2017 NXP + * Copyright 2016-2020 NXP * All rights reserved. * * @@ -11,6 +11,10 @@ #include "erpc_transport_arbitrator.h" #include "assert.h" +#if ERPC_THREADS_IS(NONE) +#error "Arbitrator code does not work in no-threading configuration." +#endif + using namespace erpc; //////////////////////////////////////////////////////////////////////////////// diff --git a/erpc_c/infra/erpc_transport_arbitrator.cpp b/erpc_c/infra/erpc_transport_arbitrator.cpp index d004af3a1..158e576c6 100644 --- a/erpc_c/infra/erpc_transport_arbitrator.cpp +++ b/erpc_c/infra/erpc_transport_arbitrator.cpp @@ -1,6 +1,6 @@ /* * Copyright (c) 2016, Freescale Semiconductor, Inc. - * Copyright 2016-2017 NXP + * Copyright 2016-2020 NXP * All rights reserved. * * @@ -12,6 +12,10 @@ #include #include +#if ERPC_THREADS_IS(NONE) +#error "Arbitrator code does not work in no-threading configuration." +#endif + using namespace erpc; //////////////////////////////////////////////////////////////////////////////// diff --git a/erpc_c/infra/erpc_version.h b/erpc_c/infra/erpc_version.h index 653b1cb12..f3d610ff3 100644 --- a/erpc_c/infra/erpc_version.h +++ b/erpc_c/infra/erpc_version.h @@ -1,6 +1,6 @@ /* * Copyright (c) 2016, Freescale Semiconductor, Inc. - * Copyright 2016-2019 NXP + * Copyright 2016-2020 NXP * All rights reserved. * * @@ -20,9 +20,9 @@ //////////////////////////////////////////////////////////////////////////////// //! @brief String version of eRPC. -#define ERPC_VERSION "1.7.3" +#define ERPC_VERSION "1.7.4" //! @brief Integer version of eRPC. -#define ERPC_VERSION_NUMBER 10703 +#define ERPC_VERSION_NUMBER 10704 /*! @} */ diff --git a/erpc_c/port/erpc_threading.h b/erpc_c/port/erpc_threading.h index d5806ec33..fbcc643bc 100644 --- a/erpc_c/port/erpc_threading.h +++ b/erpc_c/port/erpc_threading.h @@ -1,6 +1,6 @@ /* * Copyright (c) 2014-2016, Freescale Semiconductor, Inc. - * Copyright 2016-2017 NXP + * Copyright 2016-2020 NXP * All rights reserved. * * @@ -214,7 +214,7 @@ class Thread struct k_thread m_thread; /*!< Current thread. */ k_thread_stack_t *m_stack; /*!< Pointer to stack. */ #elif ERPC_THREADS_IS(MBED) - rtos::Thread* m_thread; /*!< Underlying Thread instance */ + rtos::Thread *m_thread; /*!< Underlying Thread instance */ Thread *m_next; /*!< Pointer to next Thread. */ static Thread *s_first; /*!< Pointer to first Thread. */ #endif @@ -249,10 +249,10 @@ class Thread #elif ERPC_THREADS_IS(MBED) /*! - * @brief This function execute threadEntryPoint function. - * - * @param[in] arg Thread to execute. - */ + * @brief This function execute threadEntryPoint function. + * + * @param[in] arg Thread to execute. + */ static void threadEntryPointStub(void *arg); #endif @@ -359,7 +359,7 @@ 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. */ #endif private: @@ -442,7 +442,7 @@ class Semaphore #elif ERPC_THREADS_IS(ZEPHYR) struct k_sem m_sem; /*!< Semaphore. */ #elif ERPC_THREADS_IS(MBED) - rtos::Semaphore* m_sem; /*!< Semaphore. */ + rtos::Semaphore *m_sem; /*!< Semaphore. */ int m_count; /*!< Semaphore count number. */ #endif diff --git a/erpc_c/port/erpc_threading_mbed.cpp b/erpc_c/port/erpc_threading_mbed.cpp index bdd254f1c..aef9df8da 100644 --- a/erpc_c/port/erpc_threading_mbed.cpp +++ b/erpc_c/port/erpc_threading_mbed.cpp @@ -15,215 +15,221 @@ #if ERPC_THREADS_IS(MBED) -namespace erpc -{ +namespace erpc { //////////////////////////////////////////////////////////////////////////////// // Variables //////////////////////////////////////////////////////////////////////////////// - Thread *Thread::s_first = NULL; +Thread *Thread::s_first = NULL; //////////////////////////////////////////////////////////////////////////////// // Code //////////////////////////////////////////////////////////////////////////////// - Thread::Thread(const char *name) - : m_name(name) - , m_entry(0) - , m_arg(0) - , m_stackSize(0) - , m_priority(0) - , m_thread(NULL) - , m_next(NULL) - { - } +Thread::Thread(const char *name) +: m_name(name) +, m_entry(0) +, m_arg(0) +, m_stackSize(0) +, m_priority(0) +, m_thread(NULL) +, m_next(NULL) +{ +} - Thread::Thread(thread_entry_t entry, uint32_t priority, uint32_t stackSize, const char *name) - : m_name(name) - , m_entry(entry) - , m_arg(0) - , m_stackSize(stackSize) - , m_priority(priority) - , m_thread(NULL) - , m_next(NULL) +Thread::Thread(thread_entry_t entry, uint32_t priority, uint32_t stackSize, const char *name) +: m_name(name) +, m_entry(entry) +, m_arg(0) +, m_stackSize(stackSize) +, m_priority(priority) +, m_thread(NULL) +, m_next(NULL) +{ +} + +Thread::~Thread(void) +{ + if (m_thread != NULL) { + delete m_thread; + m_thread = NULL; } +} - Thread::~Thread(void) { - if(m_thread != NULL) { - delete m_thread; - m_thread = NULL; - } - } +void Thread::init(thread_entry_t entry, uint32_t priority, uint32_t stackSize) +{ + m_entry = entry; + m_stackSize = stackSize; + m_priority = priority; + m_thread = + new rtos::Thread(osPriorityNormal, // Ignore priority because erpc does not map their priority to anything + ((m_stackSize + sizeof(uint32_t) - 1) / sizeof(uint32_t)), // Round up number of words + NULL, m_name); +} - void Thread::init(thread_entry_t entry, uint32_t priority, uint32_t stackSize) - { - m_entry = entry; - m_stackSize = stackSize; - m_priority = priority; - m_thread = new rtos::Thread(osPriorityNormal, // Ignore priority because erpc does not map their priority to anything - ((m_stackSize + sizeof(uint32_t) - 1) / sizeof(uint32_t)),// Round up number of words - NULL, m_name); - } +void Thread::start(void *arg) +{ + m_arg = arg; - void Thread::start(void *arg) - { - m_arg = arg; + // Enter a critical section to disable preemptive scheduling until we add the newly + // created thread to the linked list. This prevents a race condition if the new thread is + // higher priority than the current thread, and the new thread calls getCurrenThread(), + // which will scan the linked list. + mbed::CriticalSectionLock::enable(); - // Enter a critical section to disable preemptive scheduling until we add the newly - // created thread to the linked list. This prevents a race condition if the new thread is - // higher priority than the current thread, and the new thread calls getCurrenThread(), - // which will scan the linked list. - mbed::CriticalSectionLock::enable(); + if (s_first) + { + m_next = s_first; + } + s_first = this; - if(s_first) - { - m_next = s_first; - } - s_first = this; + // Start the thread + m_thread->start(mbed::callback(&erpc::Thread::threadEntryPointStub, this)); - // Start the thread - m_thread->start(mbed::callback(&erpc::Thread::threadEntryPointStub, this)); + mbed::CriticalSectionLock::disable(); +} - mbed::CriticalSectionLock::disable(); - } +bool Thread::operator==(Thread &o) +{ + return (this->getThreadId() == o.getThreadId()); +} - bool Thread::operator==(Thread &o) - { - return (this->getThreadId() == o.getThreadId()); - } +Thread *Thread::getCurrentThread() +{ + osThreadId_t currentThreadId = rtos::ThisThread::get_id(); - Thread *Thread::getCurrentThread() + // Walk the threads list to find the Thread object for the current task. + mbed::CriticalSectionLock::enable(); + Thread *it = s_first; + while (it) { - osThreadId_t currentThreadId = rtos::ThisThread::get_id(); - -// Walk the threads list to find the Thread object for the current task. - mbed::CriticalSectionLock::enable(); - Thread *it = s_first; - while (it) + if (it->getThreadId() == currentThreadId) { - if (it->getThreadId() == currentThreadId) - { - break; - } - it = it->m_next; + break; } - mbed::CriticalSectionLock::disable(); - return it; + it = it->m_next; } + mbed::CriticalSectionLock::disable(); + return it; +} - void Thread::sleep(uint32_t usecs) - { - rtos::ThisThread::sleep_for(usecs/1000); - } +void Thread::sleep(uint32_t usecs) +{ + rtos::ThisThread::sleep_for(usecs / 1000); +} - void Thread::threadEntryPoint(void) +void Thread::threadEntryPoint(void) +{ + if (m_entry) { - if (m_entry) - { - m_entry(m_arg); - } + m_entry(m_arg); } +} + +void Thread::threadEntryPointStub(void *arg) +{ + Thread *_this = reinterpret_cast(arg); + MBED_ASSERT(_this); // Reinterpreting 'void *arg' to 'Thread *' failed. + _this->threadEntryPoint(); - void Thread::threadEntryPointStub(void *arg) + // Remove this thread from the linked list. + mbed::CriticalSectionLock::enable(); + Thread *it = s_first; + Thread *prev = NULL; + while (it) { - Thread *_this = reinterpret_cast(arg); - MBED_ASSERT(_this); // Reinterpreting 'void *arg' to 'Thread *' failed. - _this->threadEntryPoint(); - - // Remove this thread from the linked list. - mbed::CriticalSectionLock::enable(); - Thread *it = s_first; - Thread *prev = NULL; - while (it) + if (it == _this) { - if (it == _this) + if (it == s_first) + { + s_first = _this->m_next; + } + else if (prev) { - if (it == s_first) - { - s_first = _this->m_next; - } - else if (prev) - { - prev->m_next = _this->m_next; - } - _this->m_next = NULL; - - break; + prev->m_next = _this->m_next; } - prev = it; - it = it->m_next; + _this->m_next = NULL; + + break; } - mbed::CriticalSectionLock::disable(); + prev = it; + it = it->m_next; } + mbed::CriticalSectionLock::disable(); +} - Mutex::Mutex(void) - { - // Having a member variable mutex - // was causing memory alignment issues... - m_mutex = new rtos::Mutex(); - } +Mutex::Mutex(void) +{ + // Having a member variable mutex + // was causing memory alignment issues... + m_mutex = new rtos::Mutex(); +} - Mutex::~Mutex(void) +Mutex::~Mutex(void) +{ + if (m_mutex != NULL) { - if(m_mutex != NULL) { - delete m_mutex; - m_mutex = NULL; - } + delete m_mutex; + m_mutex = NULL; } +} - bool Mutex::tryLock(void) - { - // Pass a zero timeout to poll the mutex. - return m_mutex->trylock(); - } +bool Mutex::tryLock(void) +{ + // Pass a zero timeout to poll the mutex. + return m_mutex->trylock(); +} - bool Mutex::lock(void) - { - return m_mutex->lock(); - } +bool Mutex::lock(void) +{ + return m_mutex->lock(); +} - bool Mutex::unlock(void) - { - return m_mutex->unlock(); - } +bool Mutex::unlock(void) +{ + return m_mutex->unlock(); +} - Semaphore::Semaphore(int count) - : m_count(count) - { - m_sem = new rtos::Semaphore(m_count); - } +Semaphore::Semaphore(int count) +: m_count(count) +{ + m_sem = new rtos::Semaphore(m_count); +} - Semaphore::~Semaphore(void) +Semaphore::~Semaphore(void) +{ + if (m_sem != NULL) { - if(m_sem != NULL) { - delete m_sem; - m_sem = NULL; - } + delete m_sem; + m_sem = NULL; } +} - void Semaphore::put(void) - { - m_sem->release(); - } +void Semaphore::put(void) +{ + m_sem->release(); +} - bool Semaphore::get(uint32_t timeout) +bool Semaphore::get(uint32_t timeout) +{ + m_count = m_sem->wait(timeout); + if (m_count < 0) { - m_count = m_sem->wait(timeout); - if(m_count < 0) { - return true; - } - else { - return false; - } + return true; } - - int Semaphore::getCount(void) const + else { - return m_count; + return false; } +} +int Semaphore::getCount(void) const +{ + return m_count; } +} // namespace erpc + #endif diff --git a/erpc_c/setup/erpc_arbitrated_client_setup.cpp b/erpc_c/setup/erpc_arbitrated_client_setup.cpp index b03e75ba2..ec8d16501 100644 --- a/erpc_c/setup/erpc_arbitrated_client_setup.cpp +++ b/erpc_c/setup/erpc_arbitrated_client_setup.cpp @@ -1,6 +1,6 @@ /* * Copyright (c) 2016, Freescale Semiconductor, Inc. - * Copyright 2016-2017 NXP + * Copyright 2016-2020 NXP * All rights reserved. * * @@ -18,6 +18,10 @@ #endif #include +#if ERPC_THREADS_IS(NONE) +#error "Arbitrator code does not work in no-threading configuration." +#endif + using namespace erpc; //////////////////////////////////////////////////////////////////////////////// diff --git a/erpc_c/setup/erpc_setup_rpmsg_lite_master.cpp b/erpc_c/setup/erpc_setup_rpmsg_lite_master.cpp index 4cb00af8e..fa24806b5 100644 --- a/erpc_c/setup/erpc_setup_rpmsg_lite_master.cpp +++ b/erpc_c/setup/erpc_setup_rpmsg_lite_master.cpp @@ -1,6 +1,6 @@ /* * Copyright (c) 2014-2016, Freescale Semiconductor, Inc. - * Copyright 2016-2017 NXP + * Copyright 2016-2020 NXP * All rights reserved. * * @@ -18,7 +18,7 @@ using namespace erpc; //////////////////////////////////////////////////////////////////////////////// #if !defined(SH_MEM_TOTAL_SIZE) -#define SH_MEM_TOTAL_SIZE (6144) +#define SH_MEM_TOTAL_SIZE (6144U) #endif #if defined(__ICCARM__) /* IAR Workbench */ @@ -38,7 +38,7 @@ static ManuallyConstructed s_transport; // Code //////////////////////////////////////////////////////////////////////////////// -erpc_transport_t erpc_transport_rpmsg_lite_master_init(uint32_t src_addr, uint32_t dst_addr, int32_t rpmsg_link_id) +erpc_transport_t erpc_transport_rpmsg_lite_master_init(uint32_t src_addr, uint32_t dst_addr, uint32_t rpmsg_link_id) { s_transport.construct(); if (s_transport->init(src_addr, dst_addr, rpmsg_lite_base, SH_MEM_TOTAL_SIZE, rpmsg_link_id) == kErpcStatus_Success) diff --git a/erpc_c/setup/erpc_setup_rpmsg_lite_remote.cpp b/erpc_c/setup/erpc_setup_rpmsg_lite_remote.cpp index 900646532..efdb5c350 100644 --- a/erpc_c/setup/erpc_setup_rpmsg_lite_remote.cpp +++ b/erpc_c/setup/erpc_setup_rpmsg_lite_remote.cpp @@ -1,6 +1,6 @@ /* * Copyright (c) 2014-2016, Freescale Semiconductor, Inc. - * Copyright 2016-2017 NXP + * Copyright 2016-2020 NXP * All rights reserved. * * @@ -24,7 +24,7 @@ static ManuallyConstructed s_transport; //////////////////////////////////////////////////////////////////////////////// erpc_transport_t erpc_transport_rpmsg_lite_remote_init(uint32_t src_addr, uint32_t dst_addr, void *start_address, - int32_t rpmsg_link_id, rpmsg_ready_cb ready, + uint32_t rpmsg_link_id, rpmsg_ready_cb ready, char *nameservice_name) { s_transport.construct(); diff --git a/erpc_c/setup/erpc_setup_rpmsg_lite_rtos_master.cpp b/erpc_c/setup/erpc_setup_rpmsg_lite_rtos_master.cpp index 1d20569c1..43d8fe0cf 100644 --- a/erpc_c/setup/erpc_setup_rpmsg_lite_rtos_master.cpp +++ b/erpc_c/setup/erpc_setup_rpmsg_lite_rtos_master.cpp @@ -1,6 +1,6 @@ /* * Copyright (c) 2014-2016, Freescale Semiconductor, Inc. - * Copyright 2016-2017 NXP + * Copyright 2016-2020 NXP * All rights reserved. * * @@ -37,7 +37,8 @@ static ManuallyConstructed s_transport; // Code //////////////////////////////////////////////////////////////////////////////// -erpc_transport_t erpc_transport_rpmsg_lite_rtos_master_init(uint32_t src_addr, uint32_t dst_addr, int32_t rpmsg_link_id) +erpc_transport_t erpc_transport_rpmsg_lite_rtos_master_init(uint32_t src_addr, uint32_t dst_addr, + uint32_t rpmsg_link_id) { s_transport.construct(); if (s_transport->init(src_addr, dst_addr, rpmsg_lite_base, SH_MEM_TOTAL_SIZE, rpmsg_link_id) == kErpcStatus_Success) diff --git a/erpc_c/setup/erpc_setup_rpmsg_lite_rtos_remote.cpp b/erpc_c/setup/erpc_setup_rpmsg_lite_rtos_remote.cpp index 35fe535d8..517e3e315 100644 --- a/erpc_c/setup/erpc_setup_rpmsg_lite_rtos_remote.cpp +++ b/erpc_c/setup/erpc_setup_rpmsg_lite_rtos_remote.cpp @@ -1,6 +1,6 @@ /* * Copyright (c) 2014-2016, Freescale Semiconductor, Inc. - * Copyright 2016-2017 NXP + * Copyright 2016-2020 NXP * All rights reserved. * * @@ -24,7 +24,7 @@ static ManuallyConstructed s_transport; //////////////////////////////////////////////////////////////////////////////// erpc_transport_t erpc_transport_rpmsg_lite_rtos_remote_init(uint32_t src_addr, uint32_t dst_addr, void *start_address, - int32_t rpmsg_link_id, rpmsg_ready_cb ready, + uint32_t rpmsg_link_id, rpmsg_ready_cb ready, char *nameservice_name) { s_transport.construct(); diff --git a/erpc_c/setup/erpc_setup_rpmsg_tty_rtos_remote.cpp b/erpc_c/setup/erpc_setup_rpmsg_tty_rtos_remote.cpp index bfdfd52ac..153d5475b 100644 --- a/erpc_c/setup/erpc_setup_rpmsg_tty_rtos_remote.cpp +++ b/erpc_c/setup/erpc_setup_rpmsg_tty_rtos_remote.cpp @@ -1,6 +1,6 @@ /* * Copyright (c) 2016, Freescale Semiconductor, Inc. - * Copyright 2016-2019 NXP + * Copyright 2016-2020 NXP * All rights reserved. * * @@ -24,7 +24,7 @@ static ManuallyConstructed s_transport; //////////////////////////////////////////////////////////////////////////////// erpc_transport_t erpc_transport_rpmsg_lite_tty_rtos_remote_init(uint32_t src_addr, uint32_t dst_addr, - void *start_address, int32_t rpmsg_link_id, + void *start_address, uint32_t rpmsg_link_id, rpmsg_ready_cb ready, char *nameservice_name) { s_transport.construct(); diff --git a/erpc_c/setup/erpc_transport_setup.h b/erpc_c/setup/erpc_transport_setup.h index 1caf46668..af3e6abf2 100644 --- a/erpc_c/setup/erpc_transport_setup.h +++ b/erpc_c/setup/erpc_transport_setup.h @@ -1,6 +1,6 @@ /* * Copyright (c) 2014-2016, Freescale Semiconductor, Inc. - * Copyright 2016-2019 NXP + * Copyright 2016-2020 NXP * All rights reserved. * * @@ -161,7 +161,7 @@ erpc_transport_t erpc_transport_mu_init(void *baseAddr); * * @return Return NULL or erpc_transport_t instance pointer. */ -erpc_transport_t erpc_transport_rpmsg_lite_master_init(uint32_t src_addr, uint32_t dst_addr, int32_t rpmsg_link_id); +erpc_transport_t erpc_transport_rpmsg_lite_master_init(uint32_t src_addr, uint32_t dst_addr, uint32_t rpmsg_link_id); /*! * @brief Create an RPMsg-Lite transport. @@ -183,7 +183,7 @@ erpc_transport_t erpc_transport_rpmsg_lite_master_init(uint32_t src_addr, uint32 * @return Return NULL or erpc_transport_t instance pointer. */ erpc_transport_t erpc_transport_rpmsg_lite_remote_init(uint32_t src_addr, uint32_t dst_addr, void *start_address, - int32_t rpmsg_link_id, rpmsg_ready_cb ready, + uint32_t rpmsg_link_id, rpmsg_ready_cb ready, char *nameservice_name); /*! @@ -199,7 +199,7 @@ erpc_transport_t erpc_transport_rpmsg_lite_remote_init(uint32_t src_addr, uint32 * @return Return NULL or erpc_transport_t instance pointer. */ erpc_transport_t erpc_transport_rpmsg_lite_rtos_master_init(uint32_t src_addr, uint32_t dst_addr, - int32_t rpmsg_link_id); + uint32_t rpmsg_link_id); /*! * @brief Create an RPMsg-Lite RTOS transport. @@ -220,7 +220,7 @@ erpc_transport_t erpc_transport_rpmsg_lite_rtos_master_init(uint32_t src_addr, u * @return Return NULL or erpc_transport_t instance pointer. */ erpc_transport_t erpc_transport_rpmsg_lite_rtos_remote_init(uint32_t src_addr, uint32_t dst_addr, void *start_address, - int32_t rpmsg_link_id, rpmsg_ready_cb ready, + uint32_t rpmsg_link_id, rpmsg_ready_cb ready, char *nameservice_name); /*! @@ -243,7 +243,7 @@ erpc_transport_t erpc_transport_rpmsg_lite_rtos_remote_init(uint32_t src_addr, u * @return Return NULL or erpc_transport_t instance pointer. */ erpc_transport_t erpc_transport_rpmsg_lite_tty_rtos_remote_init(uint32_t src_addr, uint32_t dst_addr, - void *start_address, int32_t rpmsg_link_id, + void *start_address, uint32_t rpmsg_link_id, rpmsg_ready_cb ready, char *nameservice_name); /*! diff --git a/erpc_c/transports/erpc_rpmsg_lite_rtos_transport.cpp b/erpc_c/transports/erpc_rpmsg_lite_rtos_transport.cpp index c48eb0901..ead30f804 100644 --- a/erpc_c/transports/erpc_rpmsg_lite_rtos_transport.cpp +++ b/erpc_c/transports/erpc_rpmsg_lite_rtos_transport.cpp @@ -1,6 +1,6 @@ /* * Copyright (c) 2015, Freescale Semiconductor, Inc. - * Copyright 2016-2017 NXP + * Copyright 2016-2020 NXP * All rights reserved. * * @@ -17,7 +17,7 @@ using namespace erpc; //////////////////////////////////////////////////////////////////////////////// // Variables //////////////////////////////////////////////////////////////////////////////// -uint8_t RPMsgBaseTransport::s_initialized = 0; +uint8_t RPMsgBaseTransport::s_initialized = 0U; struct rpmsg_lite_instance *RPMsgBaseTransport::s_rpmsg; //////////////////////////////////////////////////////////////////////////////// @@ -37,43 +37,44 @@ RPMsgRTOSTransport::RPMsgRTOSTransport(void) RPMsgRTOSTransport::~RPMsgRTOSTransport(void) { rpmsg_lite_deinit(s_rpmsg); - s_initialized = 0; + s_initialized = 0U; } erpc_status_t RPMsgRTOSTransport::init(uint32_t src_addr, uint32_t dst_addr, void *base_address, uint32_t length, - int32_t rpmsg_link_id) + uint32_t rpmsg_link_id) { - if (!s_initialized) + if (0U == s_initialized) { s_rpmsg = rpmsg_lite_master_init(base_address, length, rpmsg_link_id, RL_NO_FLAGS); if (!s_rpmsg) { - return kErpcStatus_InitFailed; + return (erpc_status_t)kErpcStatus_InitFailed; } - s_initialized = 1; + s_initialized = 1U; } m_rpmsg_queue = rpmsg_queue_create(s_rpmsg); if (!m_rpmsg_queue) { - return kErpcStatus_InitFailed; + return (erpc_status_t)kErpcStatus_InitFailed; } m_rpmsg_ept = rpmsg_lite_create_ept(s_rpmsg, src_addr, rpmsg_queue_rx_cb, m_rpmsg_queue); m_dst_addr = dst_addr; - return m_rpmsg_ept == RL_NULL ? kErpcStatus_InitFailed : kErpcStatus_Success; + + return m_rpmsg_ept == RL_NULL ? (erpc_status_t)kErpcStatus_InitFailed : (erpc_status_t)kErpcStatus_Success; } -erpc_status_t RPMsgRTOSTransport::init(uint32_t src_addr, uint32_t dst_addr, void *base_address, int32_t rpmsg_link_id, +erpc_status_t RPMsgRTOSTransport::init(uint32_t src_addr, uint32_t dst_addr, void *base_address, uint32_t rpmsg_link_id, void (*ready_cb)(void), char *nameservice_name) { - if (!s_initialized) + if (0U == s_initialized) { s_rpmsg = rpmsg_lite_remote_init(base_address, rpmsg_link_id, RL_NO_FLAGS); if (!s_rpmsg) { - return kErpcStatus_InitFailed; + return (erpc_status_t)kErpcStatus_InitFailed; } /* Signal the other core we are ready */ @@ -82,11 +83,11 @@ erpc_status_t RPMsgRTOSTransport::init(uint32_t src_addr, uint32_t dst_addr, voi ready_cb(); } - while (!rpmsg_lite_is_link_up(s_rpmsg)) + while (0 == rpmsg_lite_is_link_up(s_rpmsg)) { } - s_initialized = 1; + s_initialized = 1U; } m_rpmsg_queue = rpmsg_queue_create(s_rpmsg); @@ -96,16 +97,17 @@ erpc_status_t RPMsgRTOSTransport::init(uint32_t src_addr, uint32_t dst_addr, voi } m_rpmsg_ept = rpmsg_lite_create_ept(s_rpmsg, src_addr, rpmsg_queue_rx_cb, m_rpmsg_queue); - if (nameservice_name) + if (NULL != nameservice_name) { - if (RL_SUCCESS != rpmsg_ns_announce(s_rpmsg, m_rpmsg_ept, nameservice_name, RL_NS_CREATE)) + if (RL_SUCCESS != rpmsg_ns_announce(s_rpmsg, m_rpmsg_ept, nameservice_name, (uint32_t)RL_NS_CREATE)) { - return kErpcStatus_InitFailed; + return (erpc_status_t)kErpcStatus_InitFailed; } } m_dst_addr = dst_addr; - return m_rpmsg_ept == RL_NULL ? kErpcStatus_InitFailed : kErpcStatus_Success; + + return m_rpmsg_ept == RL_NULL ? (erpc_status_t)kErpcStatus_InitFailed : (erpc_status_t)kErpcStatus_Success; } erpc_status_t RPMsgRTOSTransport::receive(MessageBuffer *message) @@ -116,7 +118,7 @@ erpc_status_t RPMsgRTOSTransport::receive(MessageBuffer *message) assert(buf); message->set((uint8_t *)buf, length); message->setUsed(length); - return ret_val != RL_SUCCESS ? kErpcStatus_ReceiveFailed : kErpcStatus_Success; + return ret_val != RL_SUCCESS ? (erpc_status_t)kErpcStatus_ReceiveFailed : (erpc_status_t)kErpcStatus_Success; } erpc_status_t RPMsgRTOSTransport::send(MessageBuffer *message) @@ -128,9 +130,9 @@ erpc_status_t RPMsgRTOSTransport::send(MessageBuffer *message) int32_t ret_val = rpmsg_lite_send_nocopy(s_rpmsg, m_rpmsg_ept, m_dst_addr, buf, used); if (ret_val == RL_SUCCESS) { - return kErpcStatus_Success; + return (erpc_status_t)kErpcStatus_Success; } message->set(buf, length); message->setUsed(used); - return kErpcStatus_SendFailed; + return (erpc_status_t)kErpcStatus_SendFailed; } diff --git a/erpc_c/transports/erpc_rpmsg_lite_rtos_transport.h b/erpc_c/transports/erpc_rpmsg_lite_rtos_transport.h index 3a07d9016..ba3351f74 100644 --- a/erpc_c/transports/erpc_rpmsg_lite_rtos_transport.h +++ b/erpc_c/transports/erpc_rpmsg_lite_rtos_transport.h @@ -1,6 +1,6 @@ /* * Copyright (c) 2015-2016, Freescale Semiconductor, Inc. - * Copyright 2016-2017 NXP + * Copyright 2016-2020 NXP * All rights reserved. * * @@ -63,7 +63,7 @@ class RPMsgRTOSTransport : public RPMsgBaseTransport * @retval kErpcStatus_InitFailed When rpmsg init function wasn't executed successfully. */ virtual erpc_status_t init(uint32_t src_addr, uint32_t dst_addr, void *base_address, uint32_t length, - int32_t rpmsg_link_id); + uint32_t rpmsg_link_id); /*! * @brief This function call RPMsg rtos init function - as RPMsg remote @@ -79,7 +79,7 @@ class RPMsgRTOSTransport : public RPMsgBaseTransport * @retval kErpcStatus_Success When rpmsg init function was executed successfully. * @retval kErpcStatus_InitFailed When rpmsg init function wasn't executed successfully. */ - virtual erpc_status_t init(uint32_t src_addr, uint32_t dst_addr, void *base_address, int32_t rpmsg_link_id, + virtual erpc_status_t init(uint32_t src_addr, uint32_t dst_addr, void *base_address, uint32_t rpmsg_link_id, void (*ready_cb)(void), char *nameservice_name); /*! diff --git a/erpc_c/transports/erpc_rpmsg_lite_transport.cpp b/erpc_c/transports/erpc_rpmsg_lite_transport.cpp index 8202f879d..d4e259d66 100644 --- a/erpc_c/transports/erpc_rpmsg_lite_transport.cpp +++ b/erpc_c/transports/erpc_rpmsg_lite_transport.cpp @@ -1,6 +1,6 @@ /* * Copyright (c) 2015-2016, Freescale Semiconductor, Inc. - * Copyright 2016-2017 NXP + * Copyright 2016-2020 NXP * All rights reserved. * * @@ -15,7 +15,7 @@ using namespace erpc; //////////////////////////////////////////////////////////////////////////////// // Variables //////////////////////////////////////////////////////////////////////////////// -uint8_t RPMsgBaseTransport::s_initialized = 0; +uint8_t RPMsgBaseTransport::s_initialized = 0U; struct rpmsg_lite_instance RPMsgTransport::s_rpmsg_ctxt; struct rpmsg_lite_instance *RPMsgBaseTransport::s_rpmsg = NULL; @@ -30,7 +30,7 @@ int32_t RPMsgTransport::rpmsg_read_cb(void *payload, uint32_t payload_len, uint3 { MessageBuffer message((uint8_t *)payload, payload_len); message.setUsed(payload_len); - transport->m_messageQueue.add(message); + (void)transport->m_messageQueue.add(message); } return RL_HOLD; } @@ -46,25 +46,25 @@ RPMsgTransport::RPMsgTransport(void) RPMsgTransport::~RPMsgTransport(void) {} erpc_status_t RPMsgTransport::init(uint32_t src_addr, uint32_t dst_addr, void *base_address, uint32_t length, - int32_t rpmsg_link_id) + uint32_t rpmsg_link_id) { - if (!s_initialized) + if (0U == s_initialized) { s_rpmsg = rpmsg_lite_master_init(base_address, length, rpmsg_link_id, RL_NO_FLAGS, &s_rpmsg_ctxt); - s_initialized = 1; + s_initialized = 1U; } m_rpmsg_ept = rpmsg_lite_create_ept(s_rpmsg, src_addr, rpmsg_read_cb, this, &m_rpmsg_ept_context); m_dst_addr = dst_addr; - return m_rpmsg_ept == RL_NULL ? kErpcStatus_InitFailed : kErpcStatus_Success; + return m_rpmsg_ept == RL_NULL ? (erpc_status_t)kErpcStatus_InitFailed : (erpc_status_t)kErpcStatus_Success; } -erpc_status_t RPMsgTransport::init(uint32_t src_addr, uint32_t dst_addr, void *base_address, int32_t rpmsg_link_id, +erpc_status_t RPMsgTransport::init(uint32_t src_addr, uint32_t dst_addr, void *base_address, uint32_t rpmsg_link_id, void (*ready_cb)(void), char *nameservice_name) { - if (!s_initialized) + if (0U == s_initialized) { s_rpmsg = rpmsg_lite_remote_init(base_address, rpmsg_link_id, RL_NO_FLAGS, &s_rpmsg_ctxt); @@ -74,26 +74,26 @@ erpc_status_t RPMsgTransport::init(uint32_t src_addr, uint32_t dst_addr, void *b ready_cb(); } - while (!rpmsg_lite_is_link_up(s_rpmsg)) + while (0 == rpmsg_lite_is_link_up(s_rpmsg)) { } - s_initialized = 1; + s_initialized = 1U; } m_rpmsg_ept = rpmsg_lite_create_ept(s_rpmsg, src_addr, rpmsg_read_cb, this, &m_rpmsg_ept_context); - if (nameservice_name) + if (NULL != nameservice_name) { - if (RL_SUCCESS != rpmsg_ns_announce(s_rpmsg, m_rpmsg_ept, nameservice_name, RL_NS_CREATE)) + if (RL_SUCCESS != rpmsg_ns_announce(s_rpmsg, m_rpmsg_ept, nameservice_name, (uint32_t)RL_NS_CREATE)) { - return kErpcStatus_InitFailed; + return (erpc_status_t)kErpcStatus_InitFailed; } } m_dst_addr = dst_addr; - return m_rpmsg_ept == RL_NULL ? kErpcStatus_InitFailed : kErpcStatus_Success; + return m_rpmsg_ept == RL_NULL ? (erpc_status_t)kErpcStatus_InitFailed : (erpc_status_t)kErpcStatus_Success; } erpc_status_t RPMsgTransport::receive(MessageBuffer *message) @@ -102,7 +102,7 @@ erpc_status_t RPMsgTransport::receive(MessageBuffer *message) { } - return kErpcStatus_Success; + return (erpc_status_t)kErpcStatus_Success; } erpc_status_t RPMsgTransport::send(MessageBuffer *message) @@ -110,5 +110,5 @@ erpc_status_t RPMsgTransport::send(MessageBuffer *message) int32_t ret_val = rpmsg_lite_send_nocopy(s_rpmsg, m_rpmsg_ept, m_dst_addr, (char *)message->get(), message->getUsed()); message->set(NULL, 0); - return ret_val != RL_SUCCESS ? kErpcStatus_SendFailed : kErpcStatus_Success; + return ret_val != RL_SUCCESS ? (erpc_status_t)kErpcStatus_SendFailed : (erpc_status_t)kErpcStatus_Success; } diff --git a/erpc_c/transports/erpc_rpmsg_lite_transport.h b/erpc_c/transports/erpc_rpmsg_lite_transport.h index 201bbcd57..429838555 100644 --- a/erpc_c/transports/erpc_rpmsg_lite_transport.h +++ b/erpc_c/transports/erpc_rpmsg_lite_transport.h @@ -1,6 +1,6 @@ /* * Copyright (c) 2015-2016, Freescale Semiconductor, Inc. - * Copyright 2016-2017 NXP + * Copyright 2016-2020 NXP * All rights reserved. * * @@ -66,7 +66,7 @@ class RPMsgTransport : public RPMsgBaseTransport * @retval kErpcStatus_InitFailed When rpmsg init function wasn't executed successfully. */ virtual erpc_status_t init(uint32_t src_addr, uint32_t dst_addr, void *base_address, uint32_t length, - int32_t rpmsg_link_id); + uint32_t rpmsg_link_id); /*! * @brief Initialization of RPMsgTransport layer - as RPMsg remote @@ -84,7 +84,7 @@ class RPMsgTransport : public RPMsgBaseTransport * @retval kErpcStatus_Success When rpmsg init function was executed successfully. * @retval kErpcStatus_InitFailed When rpmsg init function wasn't executed successfully. */ - virtual erpc_status_t init(uint32_t src_addr, uint32_t dst_addr, void *base_address, int32_t rpmsg_link_id, + virtual erpc_status_t init(uint32_t src_addr, uint32_t dst_addr, void *base_address, uint32_t rpmsg_link_id, void (*ready_cb)(void), char *nameservice_name); /*! diff --git a/erpc_c/transports/erpc_rpmsg_tty_rtos_transport.cpp b/erpc_c/transports/erpc_rpmsg_tty_rtos_transport.cpp index 983ecd1b5..403b29f08 100644 --- a/erpc_c/transports/erpc_rpmsg_tty_rtos_transport.cpp +++ b/erpc_c/transports/erpc_rpmsg_tty_rtos_transport.cpp @@ -1,6 +1,6 @@ /* * Copyright (c) 2016, Freescale Semiconductor, Inc. - * Copyright 2017-2019 NXP + * Copyright 2017-2020 NXP * All rights reserved. * * @@ -19,7 +19,7 @@ using namespace std; //////////////////////////////////////////////////////////////////////////////// // Variables //////////////////////////////////////////////////////////////////////////////// -uint8_t RPMsgBaseTransport::s_initialized = 0; +uint8_t RPMsgBaseTransport::s_initialized = 0U; struct rpmsg_lite_instance *RPMsgBaseTransport::s_rpmsg; //////////////////////////////////////////////////////////////////////////////// @@ -60,7 +60,7 @@ RPMsgTTYRTOSTransport::~RPMsgTTYRTOSTransport(void) return; } - s_initialized = 0; + s_initialized = 0U; } } @@ -71,39 +71,40 @@ void RPMsgTTYRTOSTransport::setCrc16(Crc16 *crcImpl) } erpc_status_t RPMsgTTYRTOSTransport::init(uint32_t src_addr, uint32_t dst_addr, void *base_address, uint32_t length, - int32_t rpmsg_link_id) + uint32_t rpmsg_link_id) { - if (!s_initialized) + if (0U == s_initialized) { s_rpmsg = rpmsg_lite_master_init(base_address, length, rpmsg_link_id, RL_NO_FLAGS); if (!s_rpmsg) { - return kErpcStatus_InitFailed; + return (erpc_status_t)kErpcStatus_InitFailed; } - s_initialized = 1; + s_initialized = 1U; } m_rpmsg_queue = rpmsg_queue_create(s_rpmsg); if (!m_rpmsg_queue) { - return kErpcStatus_InitFailed; + return (erpc_status_t)kErpcStatus_InitFailed; } m_rpmsg_ept = rpmsg_lite_create_ept(s_rpmsg, src_addr, rpmsg_queue_rx_cb, m_rpmsg_queue); m_dst_addr = dst_addr; - return m_rpmsg_ept == RL_NULL ? kErpcStatus_InitFailed : kErpcStatus_Success; + + return m_rpmsg_ept == RL_NULL ? (erpc_status_t)kErpcStatus_InitFailed : (erpc_status_t)kErpcStatus_Success; } erpc_status_t RPMsgTTYRTOSTransport::init(uint32_t src_addr, uint32_t dst_addr, void *base_address, - int32_t rpmsg_link_id, void (*ready_cb)(void), char *nameservice_name) + uint32_t rpmsg_link_id, void (*ready_cb)(void), char *nameservice_name) { - if (!s_initialized) + if (0U == s_initialized) { s_rpmsg = rpmsg_lite_remote_init(base_address, rpmsg_link_id, RL_NO_FLAGS); if (!s_rpmsg) { - return kErpcStatus_InitFailed; + return (erpc_status_t)kErpcStatus_InitFailed; } /* Signal the other core we are ready */ @@ -112,11 +113,11 @@ erpc_status_t RPMsgTTYRTOSTransport::init(uint32_t src_addr, uint32_t dst_addr, ready_cb(); } - while (!rpmsg_lite_is_link_up(s_rpmsg)) + while (0 == rpmsg_lite_is_link_up(s_rpmsg)) { } - s_initialized = 1; + s_initialized = 1U; } m_rpmsg_queue = rpmsg_queue_create(s_rpmsg); @@ -126,16 +127,17 @@ erpc_status_t RPMsgTTYRTOSTransport::init(uint32_t src_addr, uint32_t dst_addr, } m_rpmsg_ept = rpmsg_lite_create_ept(s_rpmsg, src_addr, rpmsg_queue_rx_cb, m_rpmsg_queue); - if (nameservice_name) + if (NULL != nameservice_name) { - if (RL_SUCCESS != rpmsg_ns_announce(s_rpmsg, m_rpmsg_ept, nameservice_name, RL_NS_CREATE)) + if (RL_SUCCESS != rpmsg_ns_announce(s_rpmsg, m_rpmsg_ept, nameservice_name, (uint32_t)RL_NS_CREATE)) { - return kErpcStatus_InitFailed; + return (erpc_status_t)kErpcStatus_InitFailed; } } m_dst_addr = dst_addr; - return m_rpmsg_ept == RL_NULL ? kErpcStatus_InitFailed : kErpcStatus_Success; + + return m_rpmsg_ept == RL_NULL ? (erpc_status_t)kErpcStatus_InitFailed : (erpc_status_t)kErpcStatus_Success; } erpc_status_t RPMsgTTYRTOSTransport::receive(MessageBuffer *message) @@ -152,15 +154,15 @@ erpc_status_t RPMsgTTYRTOSTransport::receive(MessageBuffer *message) message->set(&((uint8_t *)buf)[sizeof(h)], length - sizeof(h)); - // Verify CRC. + /* Verify CRC. */ uint16_t computedCrc = m_crcImpl->computeCRC16(&((uint8_t *)buf)[sizeof(h)], h.m_messageSize); if (computedCrc != h.m_crc) { - return kErpcStatus_CrcCheckFailed; + return (erpc_status_t)kErpcStatus_CrcCheckFailed; } message->setUsed(h.m_messageSize); - return ret_val != RL_SUCCESS ? kErpcStatus_ReceiveFailed : kErpcStatus_Success; + return ret_val != RL_SUCCESS ? (erpc_status_t)kErpcStatus_ReceiveFailed : (erpc_status_t)kErpcStatus_Success; } erpc_status_t RPMsgTTYRTOSTransport::send(MessageBuffer *message) @@ -180,9 +182,9 @@ erpc_status_t RPMsgTTYRTOSTransport::send(MessageBuffer *message) int32_t ret_val = rpmsg_lite_send_nocopy(s_rpmsg, m_rpmsg_ept, m_dst_addr, buf - sizeof(h), used + sizeof(h)); if (ret_val == RL_SUCCESS) { - return kErpcStatus_Success; + return (erpc_status_t)kErpcStatus_Success; } message->set(buf, length); message->setUsed(used); - return kErpcStatus_SendFailed; + return (erpc_status_t)kErpcStatus_SendFailed; } diff --git a/erpc_c/transports/erpc_rpmsg_tty_rtos_transport.h b/erpc_c/transports/erpc_rpmsg_tty_rtos_transport.h index 70c9a3d16..1c27edde1 100644 --- a/erpc_c/transports/erpc_rpmsg_tty_rtos_transport.h +++ b/erpc_c/transports/erpc_rpmsg_tty_rtos_transport.h @@ -1,6 +1,6 @@ /* * Copyright (c) 2016, Freescale Semiconductor, Inc. - * Copyright 2017 NXP + * Copyright 2020 NXP * All rights reserved. * * @@ -68,7 +68,7 @@ class RPMsgTTYRTOSTransport : public RPMsgBaseTransport * successfully. */ virtual erpc_status_t init(uint32_t src_addr, uint32_t dst_addr, void *base_address, uint32_t length, - int32_t rpmsg_link_id); + uint32_t rpmsg_link_id); /*! * @brief This function call RPMsg rtos init function - as RPMsg remote @@ -88,7 +88,7 @@ class RPMsgTTYRTOSTransport : public RPMsgBaseTransport * @retval kErpcStatus_InitFailed When rpmsg init function wasn't executed * successfully. */ - virtual erpc_status_t init(uint32_t src_addr, uint32_t dst_addr, void *base_address, int32_t rpmsg_link_id, + virtual erpc_status_t init(uint32_t src_addr, uint32_t dst_addr, void *base_address, uint32_t rpmsg_link_id, void (*ready_cb)(void), char *nameservice_name); /*! diff --git a/erpc_python/erpc/erpc_version.py b/erpc_python/erpc/erpc_version.py index d669c1a17..1a49ff352 100644 --- a/erpc_python/erpc/erpc_version.py +++ b/erpc_python/erpc/erpc_version.py @@ -1,9 +1,9 @@ #!/usr/bin/env python -# Copyright 2017-2019 NXP +# Copyright 2017-2020 NXP # All rights reserved. # # SPDX-License-Identifier: BSD-3-Clause #Should be same as in erpc_version.h -ERPC_VERSION = "1.7.3" +ERPC_VERSION = "1.7.4" diff --git a/examples/matrix_multiply_tcp_python/service/__init__.py b/examples/matrix_multiply_tcp_python/service/__init__.py index f6d859d0b..9f8092a1d 100644 --- a/examples/matrix_multiply_tcp_python/service/__init__.py +++ b/examples/matrix_multiply_tcp_python/service/__init__.py @@ -5,7 +5,7 @@ # SPDX-License-Identifier: BSD-3-Clause # -# Generated by erpcgen 1.7.3 on Mon Sep 23 13:00:45 2019. +# Generated by erpcgen 1.7.4 on Thu Apr 16 10:59:26 2020. # # AUTOGENERATED - DO NOT EDIT # diff --git a/examples/matrix_multiply_tcp_python/service/erpc_matrix_multiply/__init__.py b/examples/matrix_multiply_tcp_python/service/erpc_matrix_multiply/__init__.py index 5ecf43d93..cbe9f0c34 100644 --- a/examples/matrix_multiply_tcp_python/service/erpc_matrix_multiply/__init__.py +++ b/examples/matrix_multiply_tcp_python/service/erpc_matrix_multiply/__init__.py @@ -5,7 +5,7 @@ # SPDX-License-Identifier: BSD-3-Clause # -# Generated by erpcgen 1.7.3 on Mon Sep 23 13:00:45 2019. +# Generated by erpcgen 1.7.4 on Thu Apr 16 10:59:26 2020. # # AUTOGENERATED - DO NOT EDIT # @@ -15,8 +15,8 @@ version = erpc_version.ERPC_VERSION except ImportError: version = "unknown" -if version != "1.7.3": - raise ValueError("The generated shim code version (1.7.3) is different to the rest of eRPC code (%s). \ +if version != "1.7.4": + raise ValueError("The generated shim code version (1.7.4) is different to the rest of eRPC code (%s). \ Install newer version by running \"python setup.py install\" in folder erpc/erpc_python/." % repr(version)) from . import common diff --git a/examples/matrix_multiply_tcp_python/service/erpc_matrix_multiply/client.py b/examples/matrix_multiply_tcp_python/service/erpc_matrix_multiply/client.py index 834b30c68..ac494b594 100644 --- a/examples/matrix_multiply_tcp_python/service/erpc_matrix_multiply/client.py +++ b/examples/matrix_multiply_tcp_python/service/erpc_matrix_multiply/client.py @@ -5,7 +5,7 @@ # SPDX-License-Identifier: BSD-3-Clause # -# Generated by erpcgen 1.7.3 on Mon Sep 23 13:00:45 2019. +# Generated by erpcgen 1.7.4 on Thu Apr 16 10:59:26 2020. # # AUTOGENERATED - DO NOT EDIT # diff --git a/examples/matrix_multiply_tcp_python/service/erpc_matrix_multiply/common.py b/examples/matrix_multiply_tcp_python/service/erpc_matrix_multiply/common.py index 1e1264d1a..1e8f6a5ae 100644 --- a/examples/matrix_multiply_tcp_python/service/erpc_matrix_multiply/common.py +++ b/examples/matrix_multiply_tcp_python/service/erpc_matrix_multiply/common.py @@ -5,7 +5,7 @@ # SPDX-License-Identifier: BSD-3-Clause # -# Generated by erpcgen 1.7.3 on Mon Sep 23 13:00:45 2019. +# Generated by erpcgen 1.7.4 on Thu Apr 16 10:59:26 2020. # # AUTOGENERATED - DO NOT EDIT # diff --git a/examples/matrix_multiply_tcp_python/service/erpc_matrix_multiply/interface.py b/examples/matrix_multiply_tcp_python/service/erpc_matrix_multiply/interface.py index 6f3fe7733..b6ec9db4e 100644 --- a/examples/matrix_multiply_tcp_python/service/erpc_matrix_multiply/interface.py +++ b/examples/matrix_multiply_tcp_python/service/erpc_matrix_multiply/interface.py @@ -5,7 +5,7 @@ # SPDX-License-Identifier: BSD-3-Clause # -# Generated by erpcgen 1.7.3 on Mon Sep 23 13:00:45 2019. +# Generated by erpcgen 1.7.4 on Thu Apr 16 10:59:26 2020. # # AUTOGENERATED - DO NOT EDIT # diff --git a/examples/matrix_multiply_tcp_python/service/erpc_matrix_multiply/server.py b/examples/matrix_multiply_tcp_python/service/erpc_matrix_multiply/server.py index 6bbc32ee5..782c7c99d 100644 --- a/examples/matrix_multiply_tcp_python/service/erpc_matrix_multiply/server.py +++ b/examples/matrix_multiply_tcp_python/service/erpc_matrix_multiply/server.py @@ -5,7 +5,7 @@ # SPDX-License-Identifier: BSD-3-Clause # -# Generated by erpcgen 1.7.3 on Mon Sep 23 13:00:45 2019. +# Generated by erpcgen 1.7.4 on Thu Apr 16 10:59:26 2020. # # AUTOGENERATED - DO NOT EDIT # diff --git a/test/common/retarget_cpp_streamed_io.c b/test/common/retarget_cpp_streamed_io.c index 273180d04..6cb1e31c7 100644 --- a/test/common/retarget_cpp_streamed_io.c +++ b/test/common/retarget_cpp_streamed_io.c @@ -34,9 +34,10 @@ #define DEFAULT_HANDLE 0x100; -#if 0 //already defined in fsl_debug_console.c -char *_sys_command_string(char *cmd, int len) { return (cmd); } -#endif +char *_sys_command_string(char *cmd, int len) +{ + return (cmd); +} /* * These names are special strings which will be recognized by * _sys_open and will cause it to return the standard I/O handles, instead @@ -50,14 +51,18 @@ const char __stderr_name[] = "STDERR"; * Open a file. May return -1 if the file failed to open. We do not require * this function to do anything. Simply return a dummy handle. */ -FILEHANDLE _sys_open(const char *name, int openmode) { return DEFAULT_HANDLE; } +FILEHANDLE _sys_open(const char *name, int openmode) +{ + return DEFAULT_HANDLE; +} /* * Close a file. Should return 0 on success or a negative value on error. * Not required in this implementation. Always return success. */ -int _sys_close(FILEHANDLE fh) { - return 0; // return success +int _sys_close(FILEHANDLE fh) +{ + return 0; // return success } /* @@ -65,18 +70,18 @@ int _sys_close(FILEHANDLE fh) { * of characters _not_ written on partial success. This implementation sends * a buffer of size 'len' to the UART. */ -int _sys_write(FILEHANDLE fh, const unsigned char *buf, unsigned len, - int mode) { - // int i; - // for (i = 0; i < len; i++) - //{ - // // UART_write(buf[i]); - // LOG_Push((uint8_t *)(&buf[i]), 1); - //} - - DbgConsole_SendData((uint8_t *)buf, len); - - return 0; +int _sys_write(FILEHANDLE fh, const unsigned char *buf, unsigned len, int mode) +{ + // int i; + // for (i = 0; i < len; i++) + //{ + // // UART_write(buf[i]); + // LOG_Push((uint8_t *)(&buf[i]), 1); + //} + + DbgConsole_SendData((uint8_t *)buf, len); + + return 0; } /* @@ -90,65 +95,70 @@ int _sys_write(FILEHANDLE fh, const unsigned char *buf, unsigned len, * if required (backspace) and then echo the character to the Terminal * Emulator, printing the correct sequence after successive keystrokes. */ -int _sys_read(FILEHANDLE fh, unsigned char *buf, unsigned len, int mode) { - int pos = 0; - - do { - - // buf[pos]=UART_read(); - // LOG_ReadCharacter((uint8_t *)&buf[pos]); - DbgConsole_ReadCharacter((uint8_t *)&buf[pos]); - - // Advance position in buffer - pos++; - - // Handle backspace - if (buf[pos - 1] == '\b') { - // More than 1 char in buffer - if (pos > 1) { - // Delete character on terminal - // UART_write('\b'); - // UART_write(' '); - // UART_write('\b'); - - // Update position in buffer - pos -= 2; - } else if (pos > 0) - pos--; // Backspace pressed, empty buffer - } - // else UART_write(buf[pos-1]); // Echo normal char to terminal - else - // LOG_Push((uint8_t *)(&buf[pos - 1]), 1); // Echo normal char to - // terminal - DbgConsole_SendData((uint8_t *)(&buf[pos - 1]), - 1); // Echo normal char to terminal - - } while (buf[pos - 1] != '\r'); - - buf[pos] = '\0'; // Ensure Null termination - - return 0; +int _sys_read(FILEHANDLE fh, unsigned char *buf, unsigned len, int mode) +{ + int pos = 0; + + do + { + + // buf[pos]=UART_read(); + // LOG_ReadCharacter((uint8_t *)&buf[pos]); + DbgConsole_ReadCharacter((uint8_t *)&buf[pos]); + + // Advance position in buffer + pos++; + + // Handle backspace + if (buf[pos - 1] == '\b') + { + // More than 1 char in buffer + if (pos > 1) + { + // Delete character on terminal + // UART_write('\b'); + // UART_write(' '); + // UART_write('\b'); + + // Update position in buffer + pos -= 2; + } + else if (pos > 0) + pos--; // Backspace pressed, empty buffer + } + // else UART_write(buf[pos-1]); // Echo normal char to terminal + else + // LOG_Push((uint8_t *)(&buf[pos - 1]), 1); // Echo normal char to + // terminal + DbgConsole_SendData((uint8_t *)(&buf[pos - 1]), + 1); // Echo normal char to terminal + + } while (buf[pos - 1] != '\r'); + + buf[pos] = '\0'; // Ensure Null termination + + return 0; } -#if 0 //already defined in fsl_debug_console.c /* * Writes a character to the output channel. This function is used * for last-resort error message output. */ -void _ttywrch(int ch) { - // Convert correctly for endianness change - char ench = ch; - - // UART_write(ench); - // LOG_Push((uint8_t *)(&ench), 1); - DbgConsole_SendData((uint8_t *)(&ench), 1); +void _ttywrch(int ch) +{ + // Convert correctly for endianness change + char ench = ch; + + // UART_write(ench); + // LOG_Push((uint8_t *)(&ench), 1); + DbgConsole_SendData((uint8_t *)(&ench), 1); } -#endif /* * Return non-zero if the argument file is connected to a terminal. */ -int _sys_istty(FILEHANDLE fh) { - return 1; // no interactive device present +int _sys_istty(FILEHANDLE fh) +{ + return 1; // no interactive device present } /* @@ -156,8 +166,9 @@ int _sys_istty(FILEHANDLE fh) { * Returns >=0 on success, <0 on failure. Seeking is not supported for the * UART. */ -int _sys_seek(FILEHANDLE fh, long pos) { - return -1; // error +int _sys_seek(FILEHANDLE fh, long pos) +{ + return -1; // error } /* @@ -165,8 +176,9 @@ int _sys_seek(FILEHANDLE fh, long pos) { * is up to date on disk. Result is >=0 if OK, negative for an * error. */ -int _sys_ensure(FILEHANDLE fh) { - return 0; // success +int _sys_ensure(FILEHANDLE fh) +{ + return 0; // success } /* @@ -176,23 +188,29 @@ int _sys_ensure(FILEHANDLE fh) { * called when processing SEEK_END relative fseeks, and therefore a * call to _sys_flen is always followed by a call to _sys_seek. */ -long _sys_flen(FILEHANDLE fh) { return 0; } +long _sys_flen(FILEHANDLE fh) +{ + return 0; +} /* * Return the name for temporary file number sig in the buffer * name. Returns 0 on failure. maxlen is the maximum name length * allowed. */ -int _sys_tmpnam(char *name, int sig, unsigned maxlen) { - return 0; // fail, not supported +int _sys_tmpnam(char *name, int sig, unsigned maxlen) +{ + return 0; // fail, not supported } -#if 0 //already defined in fsl_debug_console.c /* * Terminate the program, passing a return code back to the user. * This function may not return. */ -void _sys_exit(int returncode) { while (1) { }; +void _sys_exit(int returncode) +{ + while (1) + { + }; } -#endif #endif /* __CC_ARM */ diff --git a/test/common/unit_test.h b/test/common/unit_test.h index dde7cf3fe..ace9e57fd 100644 --- a/test/common/unit_test.h +++ b/test/common/unit_test.h @@ -1,6 +1,6 @@ /* * Copyright (c) 2014, Freescale Semiconductor, Inc. - * Copyright 2016 NXP + * Copyright 2016 - 2020 NXP * All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause @@ -17,6 +17,10 @@ void add_services(erpc::SimpleServer *server); +void remove_services(erpc::SimpleServer *server); + void add_common_service(erpc::SimpleServer *server); +void remove_common_service(erpc::SimpleServer *server); + #endif // _EMBEDDED_RPC__UNIT_TEST_H_ diff --git a/test/common/unit_test_arbitrator_app0.cpp b/test/common/unit_test_arbitrator_app0.cpp index a1217f866..7aadad367 100644 --- a/test/common/unit_test_arbitrator_app0.cpp +++ b/test/common/unit_test_arbitrator_app0.cpp @@ -1,6 +1,6 @@ /* * Copyright (c) 2016, Freescale Semiconductor, Inc. - * Copyright 2016 NXP + * Copyright 2016 - 2020 NXP * All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause @@ -29,7 +29,12 @@ extern "C" { #include "board.h" #include "fsl_debug_console.h" #include "mcmgr.h" +#if defined(RPMSG) #include "rpmsg_lite.h" +#endif +#if defined(__CC_ARM) || defined(__ARMCC_VERSION) +int main(int argc, char **argv); +#endif #ifdef __cplusplus } #endif @@ -49,6 +54,7 @@ TaskHandle_t g_clientTask; volatile int waitQuit = 0; volatile uint16_t eRPCReadyEventData = 0; extern const uint32_t erpc_generated_crc; +erpc_service_t service = NULL; //////////////////////////////////////////////////////////////////////////////// // Code @@ -131,12 +137,21 @@ void runInit(void *arg) MCMGR_RegisterEvent(kMCMGR_RemoteApplicationEvent, eRPCReadyEventHandler, NULL); // Boot source for Core 1 - MCMGR_StartCore(kMCMGR_Core1, CORE1_BOOT_ADDRESS, (uint32_t)rpmsg_lite_base, kMCMGR_Start_Synchronous); +#if defined(RPMSG) + MCMGR_StartCore(kMCMGR_Core1, (void *)(char *)CORE1_BOOT_ADDRESS, (uint32_t)rpmsg_lite_base, + kMCMGR_Start_Synchronous); +#elif defined(MU) + MCMGR_StartCore(kMCMGR_Core1, (void *)(char *)CORE1_BOOT_ADDRESS, (uint32_t)0, kMCMGR_Start_Asynchronous); +#endif - // RPMsg-Lite transport layer initialization erpc_transport_t transportClient; erpc_transport_t transportServer; +#if defined(RPMSG) + // RPMsg-Lite transport layer initialization transportClient = erpc_transport_rpmsg_lite_rtos_master_init(100, 101, ERPC_TRANSPORT_RPMSG_LITE_LINK_ID); +#elif defined(MU) + transportClient = erpc_transport_mu_init(MU_BASE); +#endif if (transportClient == NULL) { // error in initialization of transport layer @@ -154,7 +169,11 @@ void runInit(void *arg) // MessageBufferFactory initialization erpc_mbf_t message_buffer_factory; +#if defined(RPMSG) message_buffer_factory = erpc_mbf_rpmsg_init(transportClient); +#elif defined(MU) + message_buffer_factory = erpc_mbf_dynamic_init(); +#endif // eRPC client side initialization transportServer = erpc_arbitrated_client_init(transportClient, message_buffer_factory); @@ -169,7 +188,8 @@ void runInit(void *arg) erpc_arbitrated_client_set_server_thread_id((void *)g_serverTask); // adding the service to the server - erpc_add_service_to_server(create_SecondInterface_service()); + service = create_SecondInterface_service(); + erpc_add_service_to_server(service); // unblock server and client task xTaskNotifyGive(g_serverTask); @@ -188,6 +208,12 @@ void runInit(void *arg) vTaskSuspend(NULL); } +/************************************************************************************ + * Following snippet reused from https://github.com/google/googletest/blob/master/googletest/docs/advanced.md + * Copyright 2008, Google Inc. + * SPDX-License-Identifier: BSD-3-Clause + */ + class MinimalistPrinter : public ::testing::EmptyTestEventListener { // Called before a test starts. @@ -199,8 +225,8 @@ class MinimalistPrinter : public ::testing::EmptyTestEventListener // Called after a failed assertion or a SUCCEED() invocation. virtual void OnTestPartResult(const ::testing::TestPartResult &test_part_result) { - PRINTF("%s in %s:%d\r\n%s\r\n", test_part_result.failed() ? "*** Failure" : "Success", test_part_result.file_name(), - test_part_result.line_number(), test_part_result.summary()); + PRINTF("%s in %s:%d\r\n%s\r\n", test_part_result.failed() ? "*** Failure" : "Success", + test_part_result.file_name(), test_part_result.line_number(), test_part_result.summary()); } // Called after a test ends. @@ -215,10 +241,10 @@ class MinimalistPrinter : public ::testing::EmptyTestEventListener test_case.failed_test_count()); } }; +/* + * end of reused snippet + ***********************************************************************************/ -#ifdef __cplusplus -extern "C" { -#endif int main(int argc, char **argv) { ::testing::InitGoogleTest(&argc, argv); @@ -235,10 +261,10 @@ int main(int argc, char **argv) // Calculate size of the image uint32_t core1_image_size; core1_image_size = get_core1_image_size(); - PRINTF("Copy CORE1 image to address: 0x%x, size: %d\r\n", CORE1_BOOT_ADDRESS, core1_image_size); + PRINTF("Copy CORE1 image to address: 0x%x, size: %d\r\n", (void *)(char *)CORE1_BOOT_ADDRESS, core1_image_size); // Copy application from FLASH to RAM - memcpy(CORE1_BOOT_ADDRESS, (void *)CORE1_IMAGE_START, core1_image_size); + memcpy((void *)(char *)CORE1_BOOT_ADDRESS, (void *)CORE1_IMAGE_START, core1_image_size); #endif g_waitQuitMutex = xSemaphoreCreateMutex(); @@ -252,12 +278,13 @@ int main(int argc, char **argv) { } } -#ifdef __cplusplus -} -#endif void quitSecondInterfaceServer() { + /* removing the service from the server */ + erpc_remove_service_from_server(service); + destroy_SecondInterface_service(); + // Stop server part erpc_server_stop(); increaseWaitQuit(); diff --git a/test/common/unit_test_arbitrator_app1.cpp b/test/common/unit_test_arbitrator_app1.cpp index add7eb75f..69259e6e4 100644 --- a/test/common/unit_test_arbitrator_app1.cpp +++ b/test/common/unit_test_arbitrator_app1.cpp @@ -1,6 +1,6 @@ /* * Copyright (c) 2016, Freescale Semiconductor, Inc. - * Copyright 2016 NXP + * Copyright 2016 - 2020 NXP * All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause @@ -26,7 +26,12 @@ extern "C" { #include "app_core1.h" #include "board.h" #include "mcmgr.h" +#if defined(RPMSG) #include "rpmsg_lite.h" +#endif +#if defined(__CC_ARM) || defined(__ARMCC_VERSION) +int main(int argc, char **argv); +#endif #ifdef __cplusplus } #endif @@ -47,6 +52,7 @@ uint32_t startupData; mcmgr_status_t status; volatile int stopTest = 0; extern const uint32_t erpc_generated_crc; +erpc_service_t service = NULL; //////////////////////////////////////////////////////////////////////////////// // Code @@ -143,14 +149,21 @@ void runInit(void *arg) status = MCMGR_GetStartupData(&startupData); } while (status != kStatus_MCMGR_Success); - // RPMsg-Lite transport layer initialization erpc_transport_t transportClient; erpc_transport_t transportServer; + erpc_mbf_t message_buffer_factory; + +#if defined(RPMSG) + // RPMsg-Lite transport layer initialization transportClient = erpc_transport_rpmsg_lite_rtos_remote_init(101, 100, (void *)startupData, 0, SignalReady, NULL); // MessageBufferFactory initialization - erpc_mbf_t message_buffer_factory; message_buffer_factory = erpc_mbf_rpmsg_init(transportClient); +#elif defined(MU) + // MU transport layer initialization + transportClient = erpc_transport_mu_init(MU_BASE); + message_buffer_factory = erpc_mbf_dynamic_init(); +#endif // eRPC client side initialization transportServer = erpc_arbitrated_client_init(transportClient, message_buffer_factory); @@ -165,7 +178,12 @@ void runInit(void *arg) erpc_arbitrated_client_set_server_thread_id((void *)g_serverTask); // adding the service to the server - erpc_add_service_to_server(create_FirstInterface_service()); + service = create_FirstInterface_service(); + erpc_add_service_to_server(service); + +#if defined(MU) + SignalReady(); +#endif // unblock server and client task xTaskNotifyGive(g_serverTask); @@ -184,9 +202,6 @@ void runInit(void *arg) vTaskSuspend(NULL); } -#ifdef __cplusplus -extern "C" { -#endif int main(int argc, char **argv) { BOARD_InitHardware(); @@ -202,9 +217,6 @@ int main(int argc, char **argv) { } } -#ifdef __cplusplus -} -#endif void stopSecondSide() { @@ -219,6 +231,10 @@ int32_t getResultFromSecondSide() void quitFirstInterfaceServer() { + /* removing the service from the server */ + erpc_remove_service_from_server(service); + destroy_FirstInterface_service(); + // Stop server part erpc_server_stop(); } diff --git a/test/common/unit_test_client.cpp b/test/common/unit_test_client.cpp index b83b22070..711eff05d 100644 --- a/test/common/unit_test_client.cpp +++ b/test/common/unit_test_client.cpp @@ -1,6 +1,6 @@ /* * Copyright (c) 2014, Freescale Semiconductor, Inc. - * Copyright 2016 NXP + * Copyright 2016-2020 NXP * All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause @@ -9,12 +9,13 @@ #include "erpc_client_setup.h" #include "erpc_mbf_setup.h" #include "erpc_transport_setup.h" +#include "board.h" #include "gtest.h" #include "gtestListener.h" #include "myAlloc.h" #include "test_unit_test_common.h" -#if (defined(RPMSG) || defined(UART)) +#if (defined(RPMSG) || defined(UART) || defined(MU)) extern "C" { #include "app_core0.h" #include "board.h" @@ -25,6 +26,9 @@ extern "C" { #elif defined(UART) #include "fsl_usart_cmsis.h" #endif +#if defined(__CC_ARM) || defined(__ARMCC_VERSION) +int main(int argc, char **argv); +#endif } #ifdef UNITY_DUMP_RESULTS @@ -37,6 +41,12 @@ using namespace std; // Classes //////////////////////////////////////////////////////////////////////////////// +/************************************************************************************ + * Following snippet reused from https://github.com/google/googletest/blob/master/googletest/docs/advanced.md + * Copyright 2008, Google Inc. + * SPDX-License-Identifier: BSD-3-Clause + */ + class MinimalistPrinter : public ::testing::EmptyTestEventListener { // Called before a test starts. @@ -48,8 +58,8 @@ class MinimalistPrinter : public ::testing::EmptyTestEventListener // Called after a failed assertion or a SUCCEED() invocation. virtual void OnTestPartResult(const ::testing::TestPartResult &test_part_result) { - PRINTF("%s in %s:%d\n%s\r\n", test_part_result.failed() ? "*** Failure" : "Success", test_part_result.file_name(), - test_part_result.line_number(), test_part_result.summary()); + PRINTF("%s in %s:%d\r\n%s\r\n", test_part_result.failed() ? "*** Failure" : "Success", + test_part_result.file_name(), test_part_result.line_number(), test_part_result.summary()); } // Called after a test ends. @@ -64,6 +74,9 @@ class MinimalistPrinter : public ::testing::EmptyTestEventListener test_case.failed_test_count()); } }; +/* + * end of reused snippet + ***********************************************************************************/ #endif //////////////////////////////////////////////////////////////////////////////// @@ -76,15 +89,15 @@ int MyAlloc::allocated_ = 0; #define APP_ERPC_READY_EVENT_DATA (1) extern char rpmsg_lite_base[]; volatile uint16_t eRPCReadyEventData = 0; +#elif defined(MU) +#define APP_ERPC_READY_EVENT_DATA (1) +volatile uint16_t eRPCReadyEventData = 0; #endif //////////////////////////////////////////////////////////////////////////////// // Code //////////////////////////////////////////////////////////////////////////////// -#ifdef __cplusplus -extern "C" { -#endif -#if defined(RPMSG) +#if (defined(RPMSG) || defined(MU)) /*! * @brief eRPC server side ready event handler */ @@ -113,7 +126,7 @@ int main(int argc, char **argv) ::testing::TestEventListeners &listeners = ::testing::UnitTest::GetInstance()->listeners(); listeners.Append(new LeakChecker); -#if (defined(RPMSG) || defined(UART)) +#if (defined(RPMSG) || defined(UART) || defined(MU)) delete listeners.Release(listeners.default_result_printer()); listeners.Append(new MinimalistPrinter); #ifdef UNITY_DUMP_RESULTS @@ -127,10 +140,10 @@ int main(int argc, char **argv) /* Calculate size of the image */ uint32_t core1_image_size; core1_image_size = get_core1_image_size(); - PRINTF("Copy CORE1 image to address: 0x%x, size: %d\r\n", CORE1_BOOT_ADDRESS, core1_image_size); + PRINTF("Copy CORE1 image to address: 0x%x, size: %d\r\n", (void *)(char *)CORE1_BOOT_ADDRESS, core1_image_size); /* Copy application from FLASH to RAM */ - memcpy(CORE1_BOOT_ADDRESS, (void *)CORE1_IMAGE_START, core1_image_size); + memcpy((void *)(char *)CORE1_BOOT_ADDRESS, (void *)CORE1_IMAGE_START, core1_image_size); #endif #if defined(RPMSG) @@ -146,7 +159,23 @@ int main(int argc, char **argv) MCMGR_RegisterEvent(kMCMGR_RemoteApplicationEvent, eRPCReadyEventHandler, NULL); /* Boot Secondary core application */ - MCMGR_StartCore(kMCMGR_Core1, CORE1_BOOT_ADDRESS, (uint32_t)rpmsg_lite_base, kMCMGR_Start_Synchronous); + MCMGR_StartCore(kMCMGR_Core1, (void *)(char *)CORE1_BOOT_ADDRESS, (uint32_t)rpmsg_lite_base, + kMCMGR_Start_Synchronous); + + /* Wait until the secondary core application signals the rpmsg remote has been initialized and is ready to + * communicate. */ + while (APP_ERPC_READY_EVENT_DATA != eRPCReadyEventData) + { + }; +#elif defined(MU) + /* Initialize MCMGR before calling its API */ + MCMGR_Init(); + + /* Register the application event before starting the secondary core */ + MCMGR_RegisterEvent(kMCMGR_RemoteApplicationEvent, eRPCReadyEventHandler, NULL); + + /* Boot Secondary core application */ + MCMGR_StartCore(kMCMGR_Core1, (void *)(char *)CORE1_BOOT_ADDRESS, (uint32_t)0, kMCMGR_Start_Asynchronous); /* Wait until the secondary core application signals the rpmsg remote has been initialized and is ready to * communicate. */ @@ -163,6 +192,9 @@ int main(int argc, char **argv) #elif defined(UART) transport = erpc_transport_cmsis_uart_init((void *)&Driver_USART0); message_buffer_factory = erpc_mbf_dynamic_init(); +#elif defined(MU) + transport = erpc_transport_mu_init(MU_BASE); + message_buffer_factory = erpc_mbf_dynamic_init(); #endif erpc_client_init(transport, message_buffer_factory); @@ -179,6 +211,3 @@ int main(int argc, char **argv) return i; } -#ifdef __cplusplus -} -#endif diff --git a/test/common/unit_test_serial_server.cpp b/test/common/unit_test_serial_server.cpp index 786c14de5..131565bc4 100644 --- a/test/common/unit_test_serial_server.cpp +++ b/test/common/unit_test_serial_server.cpp @@ -1,6 +1,6 @@ /* * Copyright (c) 2014-2016, Freescale Semiconductor, Inc. - * Copyright 2016 NXP + * Copyright 2016 - 2020 NXP * All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause @@ -43,6 +43,8 @@ SimpleServer g_server; int MyAlloc::allocated_ = 0; +Common_service *svc_common; + //////////////////////////////////////////////////////////////////////////////// // Code //////////////////////////////////////////////////////////////////////////////// @@ -79,17 +81,27 @@ int main(int argc, const char *argv[]) //////////////////////////////////////////////////////////////////////////////// void add_common_service(SimpleServer *server) { - Common_service *svc = new Common_service(); + svc_common = new Common_service(); - server->addService(svc); + server->addService(svc_common); +} + +void remove_common_service(SimpleServer *server) +{ + server->removeService(svc_common); + delete svc_common; } extern "C" void erpc_add_service_to_server(void *service) {} +extern "C" void erpc_remove_service_from_server(void *service) {} + //////////////////////////////////////////////////////////////////////////////// // Common service implementations here //////////////////////////////////////////////////////////////////////////////// void quit() { + remove_common_service(&g_server); + remove_services(&g_server); exit(0); } diff --git a/test/common/unit_test_server.cpp b/test/common/unit_test_server.cpp index 370af62d7..54f347a20 100644 --- a/test/common/unit_test_server.cpp +++ b/test/common/unit_test_server.cpp @@ -1,6 +1,6 @@ /* * Copyright (c) 2014-2016, Freescale Semiconductor, Inc. - * Copyright 2016 NXP + * Copyright 2016 - 2020 NXP * All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause @@ -10,11 +10,12 @@ #include "erpc_server_setup.h" #include "erpc_simple_server.h" #include "erpc_transport_setup.h" +#include "board.h" #include "myAlloc.h" #include "test_unit_test_common_server.h" #include "unit_test_wrapped.h" -#if (defined(RPMSG) || defined(UART)) +#if (defined(RPMSG) || defined(UART) || defined(MU)) extern "C" { #include "app_core1.h" #if defined(RPMSG) @@ -23,6 +24,12 @@ extern "C" { #include "rpmsg_lite.h" #elif defined(UART) #include "fsl_usart_cmsis.h" +#elif defined(MU) +#define APP_ERPC_READY_EVENT_DATA (1) +#include "mcmgr.h" +#endif +#if defined(__CC_ARM) || defined(__ARMCC_VERSION) +int main(int argc, const char *argv[]); #endif } #endif @@ -32,14 +39,12 @@ extern "C" { //////////////////////////////////////////////////////////////////////////////// int MyAlloc::allocated_ = 0; +erpc_service_t service_common = NULL; //////////////////////////////////////////////////////////////////////////////// // Code //////////////////////////////////////////////////////////////////////////////// -#ifdef __cplusplus -extern "C" { -#endif -#if defined(RPMSG) +#if (defined(RPMSG) || defined(MU)) static void SignalReady(void) { /* Signal the other core we are ready by trigerring the event and passing the APP_ERPC_READY_EVENT_DATA */ @@ -60,7 +65,7 @@ void SystemInitHook(void) int main(int argc, const char *argv[]) { -#if defined(RPMSG) +#if (defined(RPMSG) || defined(MU)) uint32_t startupData; mcmgr_status_t status; @@ -82,6 +87,9 @@ int main(int argc, const char *argv[]) #elif defined(UART) transport = erpc_transport_cmsis_uart_init((void *)&Driver_USART0); message_buffer_factory = erpc_mbf_dynamic_init(); +#elif defined(MU) + transport = erpc_transport_mu_init(MU_BASE); + message_buffer_factory = erpc_mbf_dynamic_init(); #endif /* Init server */ @@ -93,6 +101,9 @@ int main(int argc, const char *argv[]) /* Add common service */ add_common_service(); +#if defined(MU) + SignalReady(); +#endif /* Add run server */ erpc_server_run(); @@ -101,9 +112,6 @@ int main(int argc, const char *argv[]) return 0; } -#ifdef __cplusplus -} -#endif //////////////////////////////////////////////////////////////////////////////// // Server helper functions @@ -111,7 +119,8 @@ int main(int argc, const char *argv[]) void add_common_service() { - erpc_add_service_to_server(create_Common_service()); + service_common = create_Common_service(); + erpc_add_service_to_server(service_common); } //////////////////////////////////////////////////////////////////////////////// @@ -120,6 +129,12 @@ void add_common_service() void quit() { + /* removing common services from the server */ + remove_common_services_from_server(service_common); + + /* removing individual test services from the server */ + remove_services_from_server(); + erpc_server_stop(); } diff --git a/test/common/unit_test_tcp_arbitrator_client.cpp b/test/common/unit_test_tcp_arbitrator_client.cpp index 743f40619..0296e06b8 100644 --- a/test/common/unit_test_tcp_arbitrator_client.cpp +++ b/test/common/unit_test_tcp_arbitrator_client.cpp @@ -1,6 +1,6 @@ /* * Copyright (c) 2016, Freescale Semiconductor, Inc. - * Copyright 2016-2017 NXP + * Copyright 2016-2020 NXP * All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause @@ -186,6 +186,8 @@ int main(int argc, char **argv) void quitSecondInterfaceServer() { + // removing SecondInterface service from the server + remove_services(&g_server); // Stop server part g_server.stop(); increaseWaitQuit(); diff --git a/test/common/unit_test_tcp_arbitrator_server.cpp b/test/common/unit_test_tcp_arbitrator_server.cpp index d273134c7..d6296857b 100644 --- a/test/common/unit_test_tcp_arbitrator_server.cpp +++ b/test/common/unit_test_tcp_arbitrator_server.cpp @@ -1,6 +1,6 @@ /* * Copyright (c) 2016, Freescale Semiconductor, Inc. - * Copyright 2016-2017 NXP + * Copyright 2016-2020 NXP * All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause @@ -52,10 +52,10 @@ Mutex waitQuitMutex; extern const uint32_t erpc_generated_crc; Crc16 g_crc16(erpc_generated_crc); -int waitQuit = 0; -int waitClient = 0; -int isTestPassing = 0; -int stopTest = 0; +volatile int waitQuit = 0; +volatile int waitClient = 0; +volatile int isTestPassing = 0; +volatile int stopTest = 0; void increaseWaitQuit() { @@ -193,6 +193,8 @@ int32_t getResultFromSecondSide() void quitFirstInterfaceServer() { + // removing FirstInterface service from the server + remove_services(&g_server); // Stop server part g_server.stop(); } diff --git a/test/common/unit_test_tcp_server.cpp b/test/common/unit_test_tcp_server.cpp index 24453ee67..008a3431c 100644 --- a/test/common/unit_test_tcp_server.cpp +++ b/test/common/unit_test_tcp_server.cpp @@ -1,6 +1,6 @@ /* * Copyright (c) 2014-2016, Freescale Semiconductor, Inc. - * Copyright 2016-2017 NXP + * Copyright 2016-2020 NXP * All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause @@ -44,6 +44,8 @@ Crc16 g_crc16; int MyAlloc::allocated_ = 0; +Common_service *svc_common; + //////////////////////////////////////////////////////////////////////////////// // Code //////////////////////////////////////////////////////////////////////////////// @@ -89,18 +91,27 @@ int main(int argc, const char *argv[]) //////////////////////////////////////////////////////////////////////////////// void add_common_service(SimpleServer *server) { - Common_service *svc = new Common_service(); + svc_common = new Common_service(); + + server->addService(svc_common); +} - server->addService(svc); +void remove_common_service(SimpleServer *server) +{ + server->removeService(svc_common); + delete svc_common; } extern "C" void erpc_add_service_to_server(void *service) {} +extern "C" void erpc_remove_service_from_server(void *service) {} //////////////////////////////////////////////////////////////////////////////// // Common service implementations here //////////////////////////////////////////////////////////////////////////////// void quit() { + remove_common_service(&g_server); + remove_services(&g_server); g_server.stop(); } diff --git a/test/common/unit_test_wrapped.h b/test/common/unit_test_wrapped.h index b901ab51f..78c8016df 100644 --- a/test/common/unit_test_wrapped.h +++ b/test/common/unit_test_wrapped.h @@ -1,6 +1,6 @@ /* * Copyright (c) 2014-2016, Freescale Semiconductor, Inc. - * Copyright 2016 NXP + * Copyright 2016 - 2020 NXP * All rights reserved. * * @@ -17,6 +17,8 @@ extern "C" { #endif void add_services_to_server(); +void remove_services_from_server(); +void remove_common_services_from_server(erpc_service_t service); void add_common_service(); #ifdef __cplusplus } diff --git a/test/test_annotations/test_annotations_server_impl.cpp b/test/test_annotations/test_annotations_server_impl.cpp index 83433ecf7..68d9441c3 100644 --- a/test/test_annotations/test_annotations_server_impl.cpp +++ b/test/test_annotations/test_annotations_server_impl.cpp @@ -1,6 +1,6 @@ /* * Copyright (c) 2014-2016, Freescale Semiconductor, Inc. - * Copyright 2016 NXP + * Copyright 2016 - 2020 NXP * All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause @@ -8,10 +8,13 @@ #include "erpc_server_setup.h" #include "test_server.h" +#include "test_unit_test_common_server.h" #include "unit_test.h" #include "unit_test_wrapped.h" #include +AnnotateTest_service *svc; + //////////////////////////////////////////////////////////////////////////////// // Implementation of function code //////////////////////////////////////////////////////////////////////////////// @@ -37,21 +40,50 @@ myInt testIfMyIntAndConstExist(myInt a) void add_services(erpc::SimpleServer *server) { /* Define services to add using dynamic memory allocation - * Exapmle:ArithmeticService_service * svc = new ArithmeticService_service(); - */ // NOTE: possible memory leak? not ever deleting - AnnotateTest_service *svc = new AnnotateTest_service(); + * Exapmle:ArithmeticService_service * svc = new ArithmeticService_service(); + */ + svc = new AnnotateTest_service(); /* Add services * Example: server->addService (svc); */ server->addService(svc); } +//////////////////////////////////////////////////////////////////////////////// +// Remove service from server code +//////////////////////////////////////////////////////////////////////////////// + +void remove_services(erpc::SimpleServer *server) +{ + /* Remove services + * Example: server->removeService (svc); + */ + server->removeService(svc); + /* Delete unused service + */ + delete svc; +} + #ifdef __cplusplus extern "C" { #endif +erpc_service_t service_test = NULL; void add_services_to_server() { - erpc_add_service_to_server(create_AnnotateTest_service()); + service_test = create_AnnotateTest_service(); + erpc_add_service_to_server(service_test); +} + +void remove_services_from_server() +{ + erpc_remove_service_from_server(service_test); + destroy_AnnotateTest_service(&service_test); +} + +void remove_common_services_from_server(erpc_service_t service) +{ + erpc_remove_service_from_server(service); + destroy_Common_service(&service); } #ifdef __cplusplus } diff --git a/test/test_arbitrator/test_arbitrator_client_impl.cpp b/test/test_arbitrator/test_arbitrator_client_impl.cpp index 4e3120958..861542800 100644 --- a/test/test_arbitrator/test_arbitrator_client_impl.cpp +++ b/test/test_arbitrator/test_arbitrator_client_impl.cpp @@ -6,8 +6,8 @@ * SPDX-License-Identifier: BSD-3-Clause */ -#include "gtest.h" #include "erpc_simple_server.h" +#include "gtest.h" #include "test_firstInterface.h" #include "test_secondInterface_server.h" @@ -20,6 +20,7 @@ int i = 0; int numbers[number]; volatile bool enabled = false; +SecondInterface_service *svc; TEST(test_arbitrator, FirstSendReceiveInt) { @@ -95,12 +96,27 @@ void enableFirstSide() void add_services(erpc::SimpleServer *server) { /* Define services to add using dynamic memory allocation - * Exapmle:ArithmeticService_service * svc = new ArithmeticService_service(); - */ // NOTE: possible memory leak? not ever deleting - SecondInterface_service *svc = new SecondInterface_service(); + * Exapmle:ArithmeticService_service * svc = new ArithmeticService_service(); + */ + svc = new SecondInterface_service(); /* Add services * Example: server->addService(svc); */ server->addService(svc); } + +//////////////////////////////////////////////////////////////////////////////// +// Remove service from server code +//////////////////////////////////////////////////////////////////////////////// + +void remove_services(erpc::SimpleServer *server) +{ + /* Remove services + * Example: server->removeService (svc); + */ + server->removeService(svc); + /* Delete unused service + */ + delete svc; +} diff --git a/test/test_arbitrator/test_arbitrator_server_impl.cpp b/test/test_arbitrator/test_arbitrator_server_impl.cpp index ae52fa71d..c3bcf7367 100644 --- a/test/test_arbitrator/test_arbitrator_server_impl.cpp +++ b/test/test_arbitrator/test_arbitrator_server_impl.cpp @@ -17,6 +17,7 @@ #define number 15 int i = 0; int numbers[number]; +FirstInterface_service *svc; void firstSendInt(int32_t a) { @@ -43,12 +44,27 @@ int32_t callSecondSide() void add_services(erpc::SimpleServer *server) { /* Define services to add using dynamic memory allocation - * Exapmle:ArithmeticService_service * svc = new ArithmeticService_service(); - */ // NOTE: possible memory leak? not ever deleting - FirstInterface_service *svc = new FirstInterface_service(); + * Exapmle:ArithmeticService_service * svc = new ArithmeticService_service(); + */ + svc = new FirstInterface_service(); /* Add services * Example: server->addService(svc); */ server->addService(svc); } + +//////////////////////////////////////////////////////////////////////////////// +// Remove service from server code +//////////////////////////////////////////////////////////////////////////////// + +void remove_services(erpc::SimpleServer *server) +{ + /* Remove services + * Example: server->removeService (svc); + */ + server->removeService(svc); + /* Delete unused service + */ + delete svc; +} diff --git a/test/test_arrays/test_arrays_server_impl.cpp b/test/test_arrays/test_arrays_server_impl.cpp index 81cf34c28..0e4e0143c 100644 --- a/test/test_arrays/test_arrays_server_impl.cpp +++ b/test/test_arrays/test_arrays_server_impl.cpp @@ -1,6 +1,6 @@ /* * Copyright (c) 2014-2016, Freescale Semiconductor, Inc. - * Copyright 2016 NXP + * Copyright 2016 - 2020 NXP * All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause @@ -8,11 +8,14 @@ #include "erpc_server_setup.h" #include "test_server.h" +#include "test_unit_test_common_server.h" #include "unit_test.h" #include "unit_test_wrapped.h" #include #include +PointersService_service *svc; + //////////////////////////////////////////////////////////////////////////////// // Implementation of function code //////////////////////////////////////////////////////////////////////////////// @@ -377,19 +380,47 @@ void add_services(erpc::SimpleServer *server) { // define services to add on heap // allocate on heap so service doesn't go out of scope at end of method - // NOTE: possible memory leak? not ever deleting - PointersService_service *svc = new PointersService_service(); + svc = new PointersService_service(); // add services server->addService(svc); } +//////////////////////////////////////////////////////////////////////////////// +// Remove service from server code +//////////////////////////////////////////////////////////////////////////////// + +void remove_services(erpc::SimpleServer *server) +{ + /* Remove services + * Example: server->removeService (svc); + */ + server->removeService(svc); + /* Delete unused service + */ + delete svc; +} + #ifdef __cplusplus extern "C" { #endif +erpc_service_t service_test = NULL; void add_services_to_server() { - erpc_add_service_to_server(create_PointersService_service()); + service_test = create_PointersService_service(); + erpc_add_service_to_server(service_test); +} + +void remove_services_from_server() +{ + erpc_remove_service_from_server(service_test); + destroy_PointersService_service(); +} + +void remove_common_services_from_server(erpc_service_t service) +{ + erpc_remove_service_from_server(service); + destroy_Common_service(); } #ifdef __cplusplus } diff --git a/test/test_binary/test_binary_server_impl.cpp b/test/test_binary/test_binary_server_impl.cpp index d6207a2c5..74e73f3bf 100644 --- a/test/test_binary/test_binary_server_impl.cpp +++ b/test/test_binary/test_binary_server_impl.cpp @@ -1,6 +1,6 @@ /* * Copyright (c) 2014-2016, Freescale Semiconductor, Inc. - * Copyright 2016 NXP + * Copyright 2016 - 2020 NXP * All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause @@ -8,10 +8,13 @@ #include "erpc_server_setup.h" #include "test_server.h" +#include "test_unit_test_common_server.h" #include "unit_test.h" #include "unit_test_wrapped.h" #include +Binary_service *svc; + //////////////////////////////////////////////////////////////////////////////// // Implementation of function code //////////////////////////////////////////////////////////////////////////////// @@ -73,9 +76,9 @@ void test_binary_allDirectionLength(const uint8_t *a, const binary_t *b, binary_ void add_services(erpc::SimpleServer *server) { /* Define services to add using dynamic memory allocation - * Exapmle:ArithmeticService_service * svc = new ArithmeticService_service(); - */ // NOTE: possible memory leak? not ever deleting - Binary_service *svc = new Binary_service(); + * Exapmle:ArithmeticService_service * svc = new ArithmeticService_service(); + */ + svc = new Binary_service(); /* Add services * Example: server->addService(svc); @@ -83,12 +86,41 @@ void add_services(erpc::SimpleServer *server) server->addService(svc); } +//////////////////////////////////////////////////////////////////////////////// +// Remove service from server code +//////////////////////////////////////////////////////////////////////////////// + +void remove_services(erpc::SimpleServer *server) +{ + /* Remove services + * Example: server->removeService (svc); + */ + server->removeService(svc); + /* Delete unused service + */ + delete svc; +} + #ifdef __cplusplus extern "C" { #endif +erpc_service_t service_test = NULL; void add_services_to_server() { - erpc_add_service_to_server(create_Binary_service()); + service_test = create_Binary_service(); + erpc_add_service_to_server(service_test); +} + +void remove_services_from_server() +{ + erpc_remove_service_from_server(service_test); + destroy_Binary_service(); +} + +void remove_common_services_from_server(erpc_service_t service) +{ + erpc_remove_service_from_server(service); + destroy_Common_service(); } #ifdef __cplusplus } diff --git a/test/test_builtin/test_builtin_server_impl.cpp b/test/test_builtin/test_builtin_server_impl.cpp index b6ffd334b..bc67f9653 100644 --- a/test/test_builtin/test_builtin_server_impl.cpp +++ b/test/test_builtin/test_builtin_server_impl.cpp @@ -1,6 +1,6 @@ /* * Copyright (c) 2014-2016, Freescale Semiconductor, Inc. - * Copyright 2016 NXP + * Copyright 2016 - 2020 NXP * All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause @@ -8,11 +8,14 @@ #include "erpc_server_setup.h" #include "test_server.h" +#include "test_unit_test_common_server.h" #include "unit_test.h" #include "unit_test_wrapped.h" #include #include +BuiltinServices_service *svc; + //////////////////////////////////////////////////////////////////////////////// // Implementation of function code //////////////////////////////////////////////////////////////////////////////// @@ -153,19 +156,47 @@ void add_services(erpc::SimpleServer *server) { // define services to add on heap // allocate on heap so service doesn't go out of scope at end of method - // NOTE: possible memory leak? not ever deleting - BuiltinServices_service *svc = new BuiltinServices_service(); + svc = new BuiltinServices_service(); // add services server->addService(svc); } +//////////////////////////////////////////////////////////////////////////////// +// Remove service from server code +//////////////////////////////////////////////////////////////////////////////// + +void remove_services(erpc::SimpleServer *server) +{ + /* Remove services + * Example: server->removeService (svc); + */ + server->removeService(svc); + /* Delete unused service + */ + delete svc; +} + #ifdef __cplusplus extern "C" { #endif +erpc_service_t service_test = NULL; void add_services_to_server() { - erpc_add_service_to_server(create_BuiltinServices_service()); + service_test = create_BuiltinServices_service(); + erpc_add_service_to_server(service_test); +} + +void remove_services_from_server() +{ + erpc_remove_service_from_server(service_test); + destroy_BuiltinServices_service(); +} + +void remove_common_services_from_server(erpc_service_t service) +{ + erpc_remove_service_from_server(service); + destroy_Common_service(); } #ifdef __cplusplus } diff --git a/test/test_callbacks/test_callbacks_server_impl.cpp b/test/test_callbacks/test_callbacks_server_impl.cpp index 1d76d7ee7..384832845 100644 --- a/test/test_callbacks/test_callbacks_server_impl.cpp +++ b/test/test_callbacks/test_callbacks_server_impl.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2017 NXP + * Copyright 2017 - 2020 NXP * All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause @@ -8,10 +8,13 @@ #include "erpc_server_setup.h" #include "test_core0_server.h" #include "test_core1.h" +#include "test_unit_test_common_server.h" #include "unit_test.h" #include "unit_test_wrapped.h" #include +ClientCore0Services_service *svc; + //////////////////////////////////////////////////////////////////////////////// // Implementation of function code //////////////////////////////////////////////////////////////////////////////// @@ -57,19 +60,47 @@ void add_services(erpc::SimpleServer *server) { // define services to add on heap // allocate on heap so service doesn't go out of scope at end of method - // NOTE: possible memory leak? not ever deleting - ClientCore0Services_service *svc = new ClientCore0Services_service(); + svc = new ClientCore0Services_service(); // add services server->addService(svc); } +//////////////////////////////////////////////////////////////////////////////// +// Remove service from server code +//////////////////////////////////////////////////////////////////////////////// + +void remove_services(erpc::SimpleServer *server) +{ + /* Remove services + * Example: server->removeService (svc); + */ + server->removeService(svc); + /* Delete unused service + */ + delete svc; +} + #ifdef __cplusplus extern "C" { #endif +erpc_service_t service_test = NULL; void add_services_to_server() { - erpc_add_service_to_server(create_ClientCore0Services_service()); + service_test = create_ClientCore0Services_service(); + erpc_add_service_to_server(service_test); +} + +void remove_services_from_server() +{ + erpc_remove_service_from_server(service_test); + destroy_ClientCore0Services_service(); +} + +void remove_common_services_from_server(erpc_service_t service) +{ + erpc_remove_service_from_server(service); + destroy_Common_service(); } #ifdef __cplusplus } diff --git a/test/test_const/test_const_server_impl.cpp b/test/test_const/test_const_server_impl.cpp index 80465ad45..9c8961b67 100644 --- a/test/test_const/test_const_server_impl.cpp +++ b/test/test_const/test_const_server_impl.cpp @@ -1,12 +1,14 @@ /* * Copyright (c) 2014-2016, Freescale Semiconductor, Inc. - * Copyright 2016 NXP + * Copyright 2016 - 2020 NXP * All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ +#include "erpc_server_setup.h" #include "test_server.h" +#include "test_unit_test_common_server.h" #include "unit_test.h" #include "unit_test_wrapped.h" #include @@ -22,18 +24,39 @@ void add_services(erpc::SimpleServer *server) { /* Define services to add using dynamic memory allocation - * Exapmle:ArithmeticService_service * svc = new ArithmeticService_service(); - */ // NOTE: possible memory leak? not ever deleting + * Exapmle:ArithmeticService_service * svc = new ArithmeticService_service(); + */ /* Add services * Example: server->addService(svc); */ } +//////////////////////////////////////////////////////////////////////////////// +// Remove service from server code +//////////////////////////////////////////////////////////////////////////////// + +void remove_services(erpc::SimpleServer *server) +{ + /* Remove services + * Example: server->removeService (svc); + */ + + /* Delete unused service + */ +} + #ifdef __cplusplus extern "C" { #endif void add_services_to_server() {} +void remove_services_from_server() {} + +void remove_common_services_from_server(erpc_service_t service) +{ + erpc_remove_service_from_server(service); + destroy_Common_service(); +} #ifdef __cplusplus } #endif diff --git a/test/test_enums/test_enums_server_impl.cpp b/test/test_enums/test_enums_server_impl.cpp index a1674022f..87bccee43 100644 --- a/test/test_enums/test_enums_server_impl.cpp +++ b/test/test_enums/test_enums_server_impl.cpp @@ -1,6 +1,6 @@ /* * Copyright (c) 2014-2016, Freescale Semiconductor, Inc. - * Copyright 2016 NXP + * Copyright 2016 - 2020 NXP * All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause @@ -8,10 +8,13 @@ #include "erpc_server_setup.h" #include "test_server.h" +#include "test_unit_test_common_server.h" #include "unit_test.h" #include "unit_test_wrapped.h" #include +EnumsService_service *svc; + //////////////////////////////////////////////////////////////////////////////// // Implementation of function code //////////////////////////////////////////////////////////////////////////////// @@ -71,19 +74,47 @@ void add_services(erpc::SimpleServer *server) { // define services to add on heap // allocate on heap so service doesn't go out of scope at end of method - // NOTE: possible memory leak? not ever deleting - EnumsService_service *svc = new EnumsService_service(); + svc = new EnumsService_service(); // add services server->addService(svc); } +//////////////////////////////////////////////////////////////////////////////// +// Remove service from server code +//////////////////////////////////////////////////////////////////////////////// + +void remove_services(erpc::SimpleServer *server) +{ + /* Remove services + * Example: server->removeService (svc); + */ + server->removeService(svc); + /* Delete unused service + */ + delete svc; +} + #ifdef __cplusplus extern "C" { #endif +erpc_service_t service_test = NULL; void add_services_to_server() { - erpc_add_service_to_server(create_EnumsService_service()); + service_test = create_EnumsService_service(); + erpc_add_service_to_server(service_test); +} + +void remove_services_from_server() +{ + erpc_remove_service_from_server(service_test); + destroy_EnumsService_service(); +} + +void remove_common_services_from_server(erpc_service_t service) +{ + erpc_remove_service_from_server(service); + destroy_Common_service(); } #ifdef __cplusplus } diff --git a/test/test_lists/test_lists_server_impl.cpp b/test/test_lists/test_lists_server_impl.cpp index b5175b4d6..cad77fd08 100644 --- a/test/test_lists/test_lists_server_impl.cpp +++ b/test/test_lists/test_lists_server_impl.cpp @@ -1,6 +1,6 @@ /* * Copyright (c) 2014-2016, Freescale Semiconductor, Inc. - * Copyright 2016 NXP + * Copyright 2016 - 2020 NXP * All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause @@ -8,11 +8,14 @@ #include "erpc_server_setup.h" #include "test_server.h" +#include "test_unit_test_common_server.h" #include "unit_test.h" #include "unit_test_wrapped.h" #include #include +PointersService_service *svc; + //////////////////////////////////////////////////////////////////////////////// // Implementation of function code //////////////////////////////////////////////////////////////////////////////// @@ -312,19 +315,47 @@ void add_services(erpc::SimpleServer *server) { // define services to add on heap // allocate on heap so service doesn't go out of scope at end of method - // NOTE: possible memory leak? not ever deleting - PointersService_service *svc = new PointersService_service(); + svc = new PointersService_service(); // add services server->addService(svc); } +//////////////////////////////////////////////////////////////////////////////// +// Remove service from server code +//////////////////////////////////////////////////////////////////////////////// + +void remove_services(erpc::SimpleServer *server) +{ + /* Remove services + * Example: server->removeService (svc); + */ + server->removeService(svc); + /* Delete unused service + */ + delete svc; +} + #ifdef __cplusplus extern "C" { #endif +erpc_service_t service_test = NULL; void add_services_to_server() { - erpc_add_service_to_server(create_PointersService_service()); + service_test = create_PointersService_service(); + erpc_add_service_to_server(service_test); +} + +void remove_services_from_server() +{ + erpc_remove_service_from_server(service_test); + destroy_PointersService_service(); +} + +void remove_common_services_from_server(erpc_service_t service) +{ + erpc_remove_service_from_server(service); + destroy_Common_service(); } #ifdef __cplusplus } diff --git a/test/test_shared/test_shared_server_impl.cpp b/test/test_shared/test_shared_server_impl.cpp index 1be335d3d..772dfd901 100644 --- a/test/test_shared/test_shared_server_impl.cpp +++ b/test/test_shared/test_shared_server_impl.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2017 NXP + * Copyright 2017 - 2020 NXP * All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause @@ -7,10 +7,13 @@ #include "erpc_server_setup.h" #include "test_server.h" +#include "test_unit_test_common_server.h" #include "unit_test.h" #include "unit_test_wrapped.h" #include +SharedService_service *svc; + //////////////////////////////////////////////////////////////////////////////// // Implementation of function code //////////////////////////////////////////////////////////////////////////////// @@ -32,19 +35,47 @@ void add_services(erpc::SimpleServer *server) { // define services to add on heap // allocate on heap so service doesn't go out of scope at end of method - // NOTE: possible memory leak? not ever deleting - SharedService_service *svc = new SharedService_service(); + svc = new SharedService_service(); // add services server->addService(svc); } +//////////////////////////////////////////////////////////////////////////////// +// Remove service from server code +//////////////////////////////////////////////////////////////////////////////// + +void remove_services(erpc::SimpleServer *server) +{ + /* Remove services + * Example: server->removeService (svc); + */ + server->removeService(svc); + /* Delete unused service + */ + delete svc; +} + #ifdef __cplusplus extern "C" { #endif +erpc_service_t service_test = NULL; void add_services_to_server() { - erpc_add_service_to_server(create_SharedService_service()); + service_test = create_SharedService_service(); + erpc_add_service_to_server(service_test); +} + +void remove_services_from_server() +{ + erpc_remove_service_from_server(service_test); + destroy_SharedService_service(); +} + +void remove_common_services_from_server(erpc_service_t service) +{ + erpc_remove_service_from_server(service); + destroy_Common_service(); } #ifdef __cplusplus } diff --git a/test/test_struct/test_struct_server_impl.cpp b/test/test_struct/test_struct_server_impl.cpp index 9f9b2c467..12c894403 100644 --- a/test/test_struct/test_struct_server_impl.cpp +++ b/test/test_struct/test_struct_server_impl.cpp @@ -1,6 +1,6 @@ /* * Copyright (c) 2014-2016, Freescale Semiconductor, Inc. - * Copyright 2016 NXP + * Copyright 2016 - 2020 NXP * All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause @@ -8,11 +8,15 @@ #include "erpc_server_setup.h" #include "test_ArithmeticService_server.h" +#include "test_unit_test_common_server.h" #include "unit_test.h" #include "unit_test_wrapped.h" #include #include +ArithmeticService1_service *svc1; +ArithmeticService2_service *svc2; + //////////////////////////////////////////////////////////////////////////////// // Implementation of function code //////////////////////////////////////////////////////////////////////////////// @@ -181,22 +185,56 @@ void add_services(erpc::SimpleServer *server) { // define services to add on heap // allocate on heap so service doesn't go out of scope at end of method - // NOTE: possible memory leak? not ever deleting - ArithmeticService1_service *svc1 = new ArithmeticService1_service(); - ArithmeticService2_service *svc2 = new ArithmeticService2_service(); + svc1 = new ArithmeticService1_service(); + svc2 = new ArithmeticService2_service(); // add services server->addService(svc1); server->addService(svc2); } +//////////////////////////////////////////////////////////////////////////////// +// Remove service from server code +//////////////////////////////////////////////////////////////////////////////// + +void remove_services(erpc::SimpleServer *server) +{ + /* Remove services + * Example: server->removeService (svc); + */ + server->removeService(svc1); + server->removeService(svc2); + /* Delete unused service + */ + delete svc1; + delete svc2; +} + #ifdef __cplusplus extern "C" { #endif +erpc_service_t service1 = NULL; +erpc_service_t service2 = NULL; void add_services_to_server() { - erpc_add_service_to_server(create_ArithmeticService1_service()); - erpc_add_service_to_server(create_ArithmeticService2_service()); + service1 = create_ArithmeticService1_service(); + service2 = create_ArithmeticService2_service(); + erpc_add_service_to_server(service1); + erpc_add_service_to_server(service2); +} + +void remove_services_from_server() +{ + erpc_remove_service_from_server(service1); + erpc_remove_service_from_server(service2); + destroy_ArithmeticService1_service(); + destroy_ArithmeticService2_service(); +} + +void remove_common_services_from_server(erpc_service_t service) +{ + erpc_remove_service_from_server(service); + destroy_Common_service(); } #ifdef __cplusplus } diff --git a/test/test_typedef/test_typedef_server_impl.cpp b/test/test_typedef/test_typedef_server_impl.cpp index 3b7642e8c..722279293 100644 --- a/test/test_typedef/test_typedef_server_impl.cpp +++ b/test/test_typedef/test_typedef_server_impl.cpp @@ -1,6 +1,6 @@ /* * Copyright (c) 2014-2016, Freescale Semiconductor, Inc. - * Copyright 2016 NXP + * Copyright 2016 - 2020 NXP * All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause @@ -8,11 +8,14 @@ #include "erpc_server_setup.h" #include "test_server.h" +#include "test_unit_test_common_server.h" #include "unit_test.h" #include "unit_test_wrapped.h" #include #include +TypedefService_service *svc; + //////////////////////////////////////////////////////////////////////////////// // Implementation of function code //////////////////////////////////////////////////////////////////////////////// @@ -132,19 +135,47 @@ void add_services(erpc::SimpleServer *server) { // define services to add on heap // allocate on heap so service doesn't go out of scope at end of method - // NOTE: possible memory leak? not ever deleting - TypedefService_service *svc = new TypedefService_service(); + svc = new TypedefService_service(); // add services server->addService(svc); } +//////////////////////////////////////////////////////////////////////////////// +// Remove service from server code +//////////////////////////////////////////////////////////////////////////////// + +void remove_services(erpc::SimpleServer *server) +{ + /* Remove services + * Example: server->removeService (svc); + */ + server->removeService(svc); + /* Delete unused service + */ + delete svc; +} + #ifdef __cplusplus extern "C" { #endif +erpc_service_t service_test = NULL; void add_services_to_server() { - erpc_add_service_to_server(create_TypedefService_service()); + service_test = create_TypedefService_service(); + erpc_add_service_to_server(service_test); +} + +void remove_services_from_server() +{ + erpc_remove_service_from_server(service_test); + destroy_TypedefService_service(); +} + +void remove_common_services_from_server(erpc_service_t service) +{ + erpc_remove_service_from_server(service); + destroy_Common_service(); } #ifdef __cplusplus } diff --git a/test/test_unions/test_unions_server_impl.cpp b/test/test_unions/test_unions_server_impl.cpp index 94a86ef66..5dbde4d30 100644 --- a/test/test_unions/test_unions_server_impl.cpp +++ b/test/test_unions/test_unions_server_impl.cpp @@ -1,6 +1,6 @@ /* * Copyright (c) 2014-2016, Freescale Semiconductor, Inc. - * Copyright 2016-2017 NXP + * Copyright 2016-2020 NXP * All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause @@ -8,11 +8,14 @@ #include "erpc_server_setup.h" #include "test_server.h" +#include "test_unit_test_common_server.h" #include "unit_test.h" #include "unit_test_wrapped.h" #include #include +ArithmeticService_service *svc; + //////////////////////////////////////////////////////////////////////////////// // Implementation of function code //////////////////////////////////////////////////////////////////////////////// @@ -222,19 +225,47 @@ void add_services(erpc::SimpleServer *server) { // define services to add on heap // allocate on heap so service doesn't go out of scope at end of method - // NOTE: possible memory leak? not ever deleting - ArithmeticService_service *svc = new ArithmeticService_service(); + svc = new ArithmeticService_service(); // add services server->addService(svc); } +//////////////////////////////////////////////////////////////////////////////// +// Remove service from server code +//////////////////////////////////////////////////////////////////////////////// + +void remove_services(erpc::SimpleServer *server) +{ + /* Remove services + * Example: server->removeService (svc); + */ + server->removeService(svc); + /* Delete unused service + */ + delete svc; +} + #ifdef __cplusplus extern "C" { #endif +erpc_service_t service_test = NULL; void add_services_to_server() { - erpc_add_service_to_server(create_ArithmeticService_service()); + service_test = create_ArithmeticService_service(); + erpc_add_service_to_server(service_test); +} + +void remove_services_from_server() +{ + erpc_remove_service_from_server(service_test); + destroy_ArithmeticService_service(); +} + +void remove_common_services_from_server(erpc_service_t service) +{ + erpc_remove_service_from_server(service); + destroy_Common_service(); } #ifdef __cplusplus } From eae792567f707334769859afb437db31f45f9e7f Mon Sep 17 00:00:00 2001 From: wesley Date: Fri, 24 Jul 2020 13:51:16 +0800 Subject: [PATCH 14/96] support win32 thread --- erpc_c/config/erpc_config.h | 1 + erpc_c/port/erpc_config_internal.h | 2 + erpc_c/port/erpc_threading.h | 28 ++++ erpc_c/port/erpc_threading_win32.cpp | 199 +++++++++++++++++++++++++++ 4 files changed, 230 insertions(+) create mode 100644 erpc_c/port/erpc_threading_win32.cpp diff --git a/erpc_c/config/erpc_config.h b/erpc_c/config/erpc_config.h index ad16559f5..db492f9b0 100644 --- a/erpc_c/config/erpc_config.h +++ b/erpc_c/config/erpc_config.h @@ -27,6 +27,7 @@ #define ERPC_THREADS_FREERTOS (2) //!< FreeRTOS. #define ERPC_THREADS_ZEPHYR (3) //!< ZEPHYR. #define ERPC_THREADS_MBED (4) //!< Mbed OS +#define ERPC_THREADS_WIN32 (5) //!< WIN32 #define ERPC_NOEXCEPT_DISABLED (0) //!< Disabling noexcept feature. #define ERPC_NOEXCEPT_ENABLED (1) //!< Enabling noexcept feature. diff --git a/erpc_c/port/erpc_config_internal.h b/erpc_c/port/erpc_config_internal.h index d9bca3a03..12c975669 100644 --- a/erpc_c/port/erpc_config_internal.h +++ b/erpc_c/port/erpc_config_internal.h @@ -45,6 +45,8 @@ #elif ERPC_HAS_FREERTOSCONFIG_H // Use FreeRTOS if we can auto detect it. #define ERPC_THREADS (ERPC_THREADS_FREERTOS) + #elif defined(WIN32) + #define ERPC_THREADS (ERPC_THREADS_WIN32) #else // Otherwise default to no threads. #define ERPC_THREADS (ERPC_THREADS_NONE) diff --git a/erpc_c/port/erpc_threading.h b/erpc_c/port/erpc_threading.h index fbcc643bc..8d750f9a3 100644 --- a/erpc_c/port/erpc_threading.h +++ b/erpc_c/port/erpc_threading.h @@ -30,6 +30,8 @@ #else #warning mbed-rpc: Threading is enabled but Mbed RTOS is not present! #endif +#elif ERPC_THREADS_IS(WIN32) +#include "windows.h" #endif // ERPC_THREADS_IS /*! @@ -144,6 +146,8 @@ class Thread return reinterpret_cast(m_thread); #elif ERPC_THREADS_IS(MBED) return reinterpret_cast(m_thread->get_id()); +#elif ERPC_THREADS_IS(WIN32) + return reinterpret_cast(m_thread); #endif } @@ -162,6 +166,8 @@ class Thread return reinterpret_cast(k_current_get()); #elif ERPC_THREADS_IS(MBED) return reinterpret_cast(rtos::ThisThread::get_id()); +#elif ERPC_THREADS_IS(WIN32) + return reinterpret_cast(GetCurrentThread()); #endif } @@ -217,6 +223,13 @@ class Thread rtos::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(WIN32) + HANDLE m_thread; + unsigned int m_thrdaddr; + Thread *m_next; /*!< Pointer to next Thread. */ + static Thread *s_first; /*!< Pointer to first Thread. */ + static CRITICAL_SECTION m_critical_section; + static BOOL m_critical_section_inited; #endif #if ERPC_THREADS_IS(PTHREADS) @@ -255,6 +268,15 @@ class Thread */ static void threadEntryPointStub(void *arg); +#elif ERPC_THREADS_IS(WIN32) + + /*! + * @brief This function execute threadEntryPoint function. + * + * @param[in] arg Thread to execute. + */ + static unsigned WINAPI threadEntryPointStub(void *arg); + #endif private: @@ -360,6 +382,8 @@ class Mutex struct k_mutex m_mutex; /*!< Mutex.*/ #elif ERPC_THREADS_IS(MBED) rtos::Mutex *m_mutex; /*!< Mutex. */ +#elif ERPC_THREADS_IS(WIN32) + HANDLE m_mutex; #endif private: @@ -444,6 +468,10 @@ class Semaphore #elif ERPC_THREADS_IS(MBED) rtos::Semaphore *m_sem; /*!< Semaphore. */ int m_count; /*!< Semaphore count number. */ +#elif ERPC_THREADS_IS(WIN32) + Mutex m_mutex; /*!< Mutext. */ + int m_count; + HANDLE m_sem; #endif private: diff --git a/erpc_c/port/erpc_threading_win32.cpp b/erpc_c/port/erpc_threading_win32.cpp new file mode 100644 index 000000000..12a8cff7a --- /dev/null +++ b/erpc_c/port/erpc_threading_win32.cpp @@ -0,0 +1,199 @@ +/* + * Copyright (c) 2014-2016, Freescale Semiconductor, Inc. + * Copyright 2016 NXP + * All rights reserved. + * + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include "erpc_threading.h" +#include + +using namespace erpc; + +//////////////////////////////////////////////////////////////////////////////// +// Variables +//////////////////////////////////////////////////////////////////////////////// + +Thread *Thread::s_first = NULL; +BOOL Thread::m_critical_section_inited = FALSE; +CRITICAL_SECTION Thread::m_critical_section; + +//////////////////////////////////////////////////////////////////////////////// +// Code +//////////////////////////////////////////////////////////////////////////////// + +Thread::Thread(const char *name) +: m_name(name) +, m_entry(0) +, m_arg(0) +, m_stackSize(0) +, m_priority(0) +, m_thread(0) +, m_thrdaddr(0) +, m_next(0) +{ +} + +Thread::Thread(thread_entry_t entry, uint32_t priority, uint32_t stackSize, const char *name) +: m_name(name) +, m_entry(entry) +, m_arg(0) +, m_stackSize(stackSize) +, m_priority(priority) +, m_thread(0) +, m_thrdaddr(0) +, m_next(0) +{ +} + +Thread::~Thread(void) {} + +void Thread::init(thread_entry_t entry, uint32_t priority, uint32_t stackSize) +{ + m_entry = entry; + m_stackSize = stackSize; + m_priority = priority; + + if (m_critical_section_inited == FALSE) + { + InitializeCriticalSection(&m_critical_section); + m_critical_section_inited = TRUE; + } +} + +void Thread::start(void *arg) +{ + m_arg = arg; + + EnterCriticalSection(&m_critical_section); + m_thread = (HANDLE)_beginthreadex( + NULL, + m_stackSize, + threadEntryPointStub, + this, + 0, + &m_thrdaddr); + + // Link in this thread to the list. + if (NULL != s_first) + { + m_next = s_first; + } + s_first = this; + LeaveCriticalSection(&m_critical_section); +} + +bool Thread::operator==(Thread &o) +{ + return (m_thrdaddr == o.m_thrdaddr); +} + +Thread *Thread::getCurrentThread(void) +{ + unsigned int thisThrdaddr = GetCurrentThreadId(); + + // Walk the threads list to find the Thread object for the current task. + EnterCriticalSection(&m_critical_section); + Thread *it = s_first; + while (it) + { + if (it->m_thrdaddr == thisThrdaddr) + { + break; + } + it = it->m_next; + } + LeaveCriticalSection(&m_critical_section); + return it; +} + +void Thread::sleep(uint32_t usecs) +{ + Sleep(usecs); +} + +void Thread::threadEntryPoint(void) +{ + if (m_entry) + { + m_entry(m_arg); + } +} + +unsigned WINAPI Thread::threadEntryPointStub(void *arg) +{ + Thread *_this = reinterpret_cast(arg); + if (_this) + { + _this->threadEntryPoint(); + } + + return 0; +} + +Mutex::Mutex(void) +{ + m_mutex = CreateMutex(NULL, FALSE, ""); +} + +Mutex::~Mutex(void) +{ + CloseHandle(m_mutex); +} + +bool Mutex::tryLock(void) +{ + return (WAIT_OBJECT_0 == WaitForSingleObject(m_mutex, 0)); +} + +bool Mutex::lock(void) +{ + return (WAIT_OBJECT_0 == WaitForSingleObject(m_mutex, INFINITE)); +} + +bool Mutex::unlock(void) +{ + return ReleaseMutex(m_mutex); +} + +Semaphore::Semaphore(int count) +: m_count(count) +, m_sem() +, m_mutex() +{ + m_sem = CreateSemaphore(NULL, m_count, 1, ""); +} + +Semaphore::~Semaphore(void) +{ + CloseHandle(m_sem); +} + +void Semaphore::put(void) +{ + LONG precount; + ReleaseSemaphore(m_sem, 1, &precount); + m_mutex.lock(); + ++m_count; + m_mutex.unlock(); +} + +bool Semaphore::get(uint32_t timeout) +{ + DWORD ret = WaitForSingleObject(m_sem, timeout); + m_mutex.lock(); + --m_count; + m_mutex.unlock(); + return (WAIT_OBJECT_0 == ret); +} + +int Semaphore::getCount(void) const +{ + return m_count; +} + +//////////////////////////////////////////////////////////////////////////////// +// EOF +//////////////////////////////////////////////////////////////////////////////// From 43d09e6b9004183200e69f71a41f88bd8fb98a61 Mon Sep 17 00:00:00 2001 From: "Michal Princ (nxa17570)" Date: Wed, 5 Aug 2020 11:38:33 +0200 Subject: [PATCH 15/96] Travis update --- .travis.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 2afb8843a..dcf702755 100644 --- a/.travis.yml +++ b/.travis.yml @@ -7,13 +7,13 @@ compiler: os: - linux - osx -osx_image: xcode8.3 # OS X 10.12 +osx_image: xcode10.3 # OS X 10.14 before_install: - if [ $TRAVIS_OS_NAME == linux ]; then sudo apt-get update -qq; fi - if [ $TRAVIS_OS_NAME == linux ]; then sudo apt-get install python bison flex libboost-dev libboost-filesystem-dev libboost-system-dev python ; fi - if [ $TRAVIS_OS_NAME == linux ]; then pyenv install 2.7.12 ; pyenv global 2.7.12; fi - if [ $TRAVIS_OS_NAME == osx ]; then brew update; fi -- if [ $TRAVIS_OS_NAME == osx ]; then brew install python bison flex && brew upgrade boost || true; fi +- if [ $TRAVIS_OS_NAME == osx ]; then brew install python bison flex -v -f 2>&1 && brew upgrade boost || true; fi - if [ $TRAVIS_OS_NAME == osx ]; then curl "https://bootstrap.pypa.io/get-pip.py" | sudo python; fi install: From bcedf82f29f7f199a699cdd5f96acdff00b8c189 Mon Sep 17 00:00:00 2001 From: Florian Lefeuvre Date: Thu, 4 Apr 2019 12:34:17 -0700 Subject: [PATCH 16/96] Mismatch between C++ and Python for callback index type When multiple callbacks are defined, callbacks are stored in an array on both the client and server. When a callback is registered, only the index of the callback in this array is sent over the transport. In C++, the array index is encoded as a uint8, where as in Python it is encoded as a uint32. So, a Python client will not be aligned with a C++ server, leading to wrong information being decoded by the server. This fix aligns both to be a uint8 type for the callback index. --- erpcgen/src/templates/py_coders.template | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/erpcgen/src/templates/py_coders.template b/erpcgen/src/templates/py_coders.template index 60b5760fe..2daa5f9f1 100644 --- a/erpcgen/src/templates/py_coders.template +++ b/erpcgen/src/templates/py_coders.template @@ -80,7 +80,7 @@ codec.start_write_union({$self}discriminator) {#--------------- function ---------------#} {% elif info.type == "function" %} {% if info.tableName != "" %} -{$codec}.write_int32({$ info.tableName}.index({$name})){%>%} +{$codec}.write_int8({$ info.tableName}.index({$name})){%>%} {% else %} # When are defined less than 2 callback functions, eRPC don't need serialize any code. {% endif%} @@ -171,7 +171,7 @@ _n{$depth} = {$codec}.start_read_list() {#--------------- function ---------------#} {% elif info.type == "function" %} {% if info.tableName != "" %} -{$name} = {$ info.tableName}[{$codec}.read_int32()] +{$name} = {$ info.tableName}[{$codec}.read_int8()] {% else %} # When are defined less than 2 callback functions, eRPC don't need serialize any code. {$indent}{$name} = {$info.callbackName} From 840488ea4a973b4dddf63b3e17a2f2e03c4bfa44 Mon Sep 17 00:00:00 2001 From: zuzy Date: Fri, 5 Jun 2020 15:29:57 +0800 Subject: [PATCH 17/96] : Generate python union & type bug : 1. Move aliases into group. Incase of type struct/union when import other IDL file. 2. Delete spare Union definition. 3. Fix discriminator bug: when the discriminator is named by other parameter. 4. Value the union data in __init__, delete the data argument 5. Match test_length/name/union.yml --- erpcgen/src/PythonGenerator.cpp | 32 +++++++++++++++++++++++- erpcgen/src/templates/py_client.template | 2 +- erpcgen/src/templates/py_coders.template | 2 +- erpcgen/src/templates/py_common.template | 14 +++++++---- erpcgen/test/test_length_py.yml | 9 +++++-- erpcgen/test/test_name_py.yml | 1 - erpcgen/test/test_union_py.yml | 2 +- 7 files changed, 50 insertions(+), 12 deletions(-) diff --git a/erpcgen/src/PythonGenerator.cpp b/erpcgen/src/PythonGenerator.cpp index 755195c76..26ded4169 100644 --- a/erpcgen/src/PythonGenerator.cpp +++ b/erpcgen/src/PythonGenerator.cpp @@ -136,7 +136,7 @@ void PythonGenerator::generate() makeIncludesTemplateData(); - makeAliasesTemplateData(); + //makeAliasesTemplateData(); makeConstTemplateData(); @@ -407,6 +407,7 @@ data_map PythonGenerator::makeGroupSymbolsTemplateData(Group *group) data_list structs; data_list unions; + data_list aliases; Log::info("Group symbols:\n"); @@ -453,6 +454,10 @@ data_map PythonGenerator::makeGroupSymbolsTemplateData(Group *group) Log::info("%s\n", unionType->getDescription().c_str()); string name = filterName(getOutputName(unionType)); + if(name.find('$') != string::npos) { + Log::debug("%s is inside struct!\n", name.c_str()); + break; + } // check if template for this structure has not already been generated if (names.find(name) == names.end()) @@ -468,6 +473,30 @@ data_map PythonGenerator::makeGroupSymbolsTemplateData(Group *group) } break; } + case DataType::kAliasTypeSymbol: + { + AliasType *aliasType = dynamic_cast(symbol); + if (aliasType == nullptr) + break; + + DataType *elementDataType = aliasType->getElementType(); + DataType *trueDataType = elementDataType->getTrueDataType(); + // Only generate aliases for enums, unions and structs in Python. + if (!(trueDataType->isEnum() || trueDataType->isUnion() || trueDataType->isStruct())) + break; + + string realType = getOutputName(aliasType); + Log::debug("%s\n", realType.c_str()); + + info["name"] = filterName(realType); + info["elementType"] = getTypeInfo(elementDataType); + info["trueType"] = getTypeInfo(trueDataType); + + setTemplateComments(aliasType, info); + + aliases.push_back(info); + break; + } default: break; } @@ -475,6 +504,7 @@ data_map PythonGenerator::makeGroupSymbolsTemplateData(Group *group) symbolsTemplate["structs"] = structs; symbolsTemplate["unions"] = unions; + symbolsTemplate["aliases"] = aliases; return symbolsTemplate; } diff --git a/erpcgen/src/templates/py_client.template b/erpcgen/src/templates/py_client.template index e9f629e16..1c9824419 100644 --- a/erpcgen/src/templates/py_client.template +++ b/erpcgen/src/templates/py_client.template @@ -62,7 +62,7 @@ class {$iface.name}Client(interface.I{$iface.name}): {$p.name}._write(codec, {$p.discriminator}) {% else%} {% if p.direction == "inout" %} - {$encodeValue(p.type, p.name & ".value", "codec", " ", 0)} + {$encodeValue(p.type, p.name & ".value", "codec", " ", 0)} {% else %} {$encodeValue(p.type, p.name, "codec", " ", 0)} {% endif -- p.direction %} diff --git a/erpcgen/src/templates/py_coders.template b/erpcgen/src/templates/py_coders.template index 60b5760fe..73d2d998a 100644 --- a/erpcgen/src/templates/py_coders.template +++ b/erpcgen/src/templates/py_coders.template @@ -11,7 +11,7 @@ {% else %} {% set self = "self." %} {% endif %} -codec.start_write_union({$self}discriminator) +codec.start_write_union({$self}{$info.discriminatorName}) {# unions are always within structs, so we have self available #} {% set isFirst = true %} {% set hasNonVoidCase = false %} diff --git a/erpcgen/src/templates/py_common.template b/erpcgen/src/templates/py_common.template index e4fcc8289..8583e3da2 100644 --- a/erpcgen/src/templates/py_common.template +++ b/erpcgen/src/templates/py_common.template @@ -58,9 +58,13 @@ class {$s.name}(object): {% endfor -- union cases %} {% endfor -- members %} - def __init__(self{% for m in s.members if not m.lengthForMember %}, {$m.name}=None{% endfor %}): + def __init__(self{% for m in s.members if ((not m.lengthForMember) && m.type.type != 'union') %}, {$m.name}=None{% endfor %}): {% for m in s.members if not m.lengthForMember %} +{% if (m.type.type == 'union' && m.type.isNonEncapsulatedUnion == false) %} + self.{$m.name} = self.{$m.name}_union # {$prettyTypeName(m.name, m.type)} +{% else %} self.{$m.name} = {$m.name} # {$prettyTypeName(m.name, m.type)} +{% endif -- union type %} {% endfor -- members %} {# create read-only properties for @length counts #} @@ -146,10 +150,10 @@ class {$u.name}(object): {% endfor -- group.symbolsMap.unions %} {% endif -- not empty(group.symbolsMap.unions) %} +{% if not empty(group.symbolsMap.aliases) %} -{% if aliases %} # Type aliases -{% for a in aliases %} +{% for a in group.symbolsMap.aliases %} {$a.name} = {$a.elementType.name} -{% endfor -- aliases %} -{% endif -- aliases %} +{% endfor -- group.symbolsMap.aliases %} +{% endif -- not empty(group.symbolsMap.aliases) %} \ No newline at end of file diff --git a/erpcgen/test/test_length_py.yml b/erpcgen/test/test_length_py.yml index 85db39ec0..1ac4a1b06 100644 --- a/erpcgen/test/test_length_py.yml +++ b/erpcgen/test/test_length_py.yml @@ -48,7 +48,7 @@ test/interface.py: - def bar(self, l) test/client.py: - def bar(self, l) - - start_write_list(len(l)) + - start_write_list(len(l.value)) - perform_request - start_read_list - not: codec.read_int32() @@ -78,9 +78,14 @@ idl: | lang: py test/client.py: - def bar(self, v) + - if: dir in ('in', ) + then: + - write_{type}(v) + - if: dir in ('inout', ) + then: + - write_{type}(v.value) - if: dir in ('in', 'inout') then: - - write_{type}(v) - not: write_int32(len(v)) - perform_request - if: dir in ('inout',) diff --git a/erpcgen/test/test_name_py.yml b/erpcgen/test/test_name_py.yml index ad57ec695..6fd3de6d3 100644 --- a/erpcgen/test/test_name_py.yml +++ b/erpcgen/test/test_name_py.yml @@ -41,7 +41,6 @@ test/common.py: - if self.d is None - codec.write_int32(self.d) - self.d - - type = StructName test/client.py: - def function(self, m) diff --git a/erpcgen/test/test_union_py.yml b/erpcgen/test/test_union_py.yml index a2cf6b137..9c210920f 100644 --- a/erpcgen/test/test_union_py.yml +++ b/erpcgen/test/test_union_py.yml @@ -168,7 +168,7 @@ lang: py test/common.py: - not: class unionVariable_union(object) - "class structType(object):" - - def __init__(self, discriminator=None, unionVariable=None) + - def __init__(self, discriminator=None) - self.discriminator = discriminator # fruitType - self.unionVariable = unionVariable # unionType - self.unionVariable, self.discriminator = common.unionType()._read(codec) From 2499b13b7835426d90f3e14b09c1a429801f0d91 Mon Sep 17 00:00:00 2001 From: zuzy Date: Mon, 31 Aug 2020 16:18:08 +0800 Subject: [PATCH 18/96] : Some error in erpcgen/test/readme.md : - Because of path problem, py.test in `./erpcgen` folder cannot pass the `test/test_redundant_definitions.yml` case. And the case gets passed while in `./erpcgen/test`. --- erpcgen/test/readme.md | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/erpcgen/test/readme.md b/erpcgen/test/readme.md index baf8e6efb..c0730d2b9 100644 --- a/erpcgen/test/readme.md +++ b/erpcgen/test/readme.md @@ -4,9 +4,8 @@ erpcgen test system This file documents the parser and output test system for erpcgen. This test system is built on py.test using its extensive plugin hooks. To run the tests, just run -py.test in either the `erpc/erpgen/` or `erpc/erpcgen/test/` directory. -Because of py.test are trying run all tests in all subfolders, is safer to run py.test with parameter -source directory (from erpcgen directory run: "pytest test"). This prevent on windows to execute +py.test in `erpc/erpcgen/test/` directory. It's safer to run py.test with parameter source +directory (from erpcgen directory run: "pytest test"). This prevent on windows to execute boost test in boost folder. From a09a733f0884c7c1274a94b777096fd216e43f3d Mon Sep 17 00:00:00 2001 From: zuzy Date: Mon, 31 Aug 2020 17:03:45 +0800 Subject: [PATCH 19/96] : Some error in erpcgen/test/readme.md : - Because of path problem, py.test in `./erpcgen` folder cannot pass the `test/test_redundant_definitions.yml` case. And the case gets passed while in `./erpcgen/test`. - My py.test is 6.0.0, and cannot work. Then I used 5.0.0, it works. I add this in readme.md. --- erpcgen/test/readme.md | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/erpcgen/test/readme.md b/erpcgen/test/readme.md index baf8e6efb..66e151cfe 100644 --- a/erpcgen/test/readme.md +++ b/erpcgen/test/readme.md @@ -4,9 +4,8 @@ erpcgen test system This file documents the parser and output test system for erpcgen. This test system is built on py.test using its extensive plugin hooks. To run the tests, just run -py.test in either the `erpc/erpgen/` or `erpc/erpcgen/test/` directory. -Because of py.test are trying run all tests in all subfolders, is safer to run py.test with parameter -source directory (from erpcgen directory run: "pytest test"). This prevent on windows to execute +py.test in `erpc/erpcgen/test/` directory. It's safer to run py.test with parameter source +directory (from erpcgen directory run: "pytest test"). This prevent on windows to execute boost test in boost folder. @@ -15,7 +14,7 @@ Setup Python 2.7.x is required. It will also work with Python 3.5+. -py.test and pyYAML are required to run the tests. These can be installed via pip. +py.test(**Version 5.0.0-**) and pyYAML are required to run the tests. These can be installed via pip. pip install pytest pyyaml From c9ad45244f94caa6875fae2f19e88f270f0a006d Mon Sep 17 00:00:00 2001 From: Ramsey Harris Date: Thu, 25 Jun 2020 12:53:04 -0700 Subject: [PATCH 20/96] Fix Python template bugs on union discriminator and reference Fix Python codec template bugs related to unions. Both encoder and decoder were emitting a literal 'discriminator' instead of de-referencing this data structure member for the actual discriminator symbol name. In class method template, use object scope instead of global scope to invoke the write() method of a non-encapsulated union member. --- erpcgen/src/templates/py_coders.template | 2 +- erpcgen/src/templates/py_common.template | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/erpcgen/src/templates/py_coders.template b/erpcgen/src/templates/py_coders.template index 7e7618481..b123284f3 100644 --- a/erpcgen/src/templates/py_coders.template +++ b/erpcgen/src/templates/py_coders.template @@ -102,7 +102,7 @@ codec.start_write_union({$self}{$info.discriminatorName}) {% else %} {% set self = "self." %} {% endif %} -{$self}discriminator = codec.start_read_union() +{$self}{$info.discriminatorName} = codec.start_read_union() {% if self == "self." %} {$indent}{$name} = {$name}_union() {% endif %} diff --git a/erpcgen/src/templates/py_common.template b/erpcgen/src/templates/py_common.template index 8583e3da2..6a4479084 100644 --- a/erpcgen/src/templates/py_common.template +++ b/erpcgen/src/templates/py_common.template @@ -105,11 +105,11 @@ class {$s.name}(object): if {$self_m_name} is None: raise ValueError("{$m.name} is None") {% if (m.type.type == 'union' && m.type.isNonEncapsulatedUnion == true) %} - {$m.name}._write(codec, self.{$m.discriminator}) + self.{$m.name}._write(codec, self.{$m.discriminator}) {% else -- isNonEncapsulatedUnion %} {$encodeValue(m.type, self_m_name, "codec", " ", 0)} {% endif -- isNonEncapsulatedUnion %} -{% endif -- isNullable %} +{% endif -- isNullable %} {% endfor -- members %} def __str__(self): From 5d65c54c5b39daa6829539b65d9cd62b1ee73622 Mon Sep 17 00:00:00 2001 From: Philippe Date: Thu, 17 Sep 2020 00:56:01 -0700 Subject: [PATCH 21/96] add ustring for unsigned char and force cast to char* --- erpcgen/src/CGenerator.cpp | 2 ++ erpcgen/src/InterfaceDefinition.cpp | 1 + erpcgen/src/templates/c_coders.template | 2 +- erpcgen/src/types/BuiltinType.h | 3 ++- 4 files changed, 6 insertions(+), 2 deletions(-) diff --git a/erpcgen/src/CGenerator.cpp b/erpcgen/src/CGenerator.cpp index ca454b092..d877ccf82 100644 --- a/erpcgen/src/CGenerator.cpp +++ b/erpcgen/src/CGenerator.cpp @@ -2243,6 +2243,8 @@ string CGenerator::getBuiltinTypename(const BuiltinType *t) return "double"; case BuiltinType::kStringType: return "char *"; + case BuiltinType::kUStringType: + return "unsigned char*"; case BuiltinType::kBinaryType: return "uint8_t *"; default: diff --git a/erpcgen/src/InterfaceDefinition.cpp b/erpcgen/src/InterfaceDefinition.cpp index 88b641f03..b09316af3 100644 --- a/erpcgen/src/InterfaceDefinition.cpp +++ b/erpcgen/src/InterfaceDefinition.cpp @@ -83,6 +83,7 @@ void InterfaceDefinition::createBuiltinTypes() m_globals.addSymbol(new BuiltinType("float", BuiltinType::_builtin_type::kFloatType)); m_globals.addSymbol(new BuiltinType("double", BuiltinType::_builtin_type::kDoubleType)); m_globals.addSymbol(new BuiltinType("string", BuiltinType::_builtin_type::kStringType)); + m_globals.addSymbol(new BuiltinType("ustring", BuiltinType::_builtin_type::kUStringType)); m_globals.addSymbol(new BuiltinType("binary", BuiltinType::_builtin_type::kBinaryType)); } diff --git a/erpcgen/src/templates/c_coders.template b/erpcgen/src/templates/c_coders.template index 6ffcad07c..c1438f5b5 100644 --- a/erpcgen/src/templates/c_coders.template +++ b/erpcgen/src/templates/c_coders.template @@ -232,7 +232,7 @@ codec->readData({$info.name}, {$info.sizeTemp} * sizeof({$info.builtinTypeName}) {# Encode sending data #} {% def encodeBuiltinType(info) ----------------- %} {% if info.builtinType == "kStringType" %} -codec->writeString(strlen({$info.name}), {$info.name}); +codec->writeString(strlen((const char*){$info.name}), (const char*){$info.name}); {% else %} {% if source == "client" && info.pointerScalarTypes %} codec->write(*{$info.name}); diff --git a/erpcgen/src/types/BuiltinType.h b/erpcgen/src/types/BuiltinType.h index 93c475f20..107d4491b 100644 --- a/erpcgen/src/types/BuiltinType.h +++ b/erpcgen/src/types/BuiltinType.h @@ -42,6 +42,7 @@ class BuiltinType : public DataType kFloatType, kDoubleType, kStringType, + kUStringType, kBinaryType }; @@ -111,7 +112,7 @@ class BuiltinType : public DataType * @retval true When builtin type is string. * @retval false When builtin type isn't string. */ - virtual bool isString() const { return m_builtinType == kStringType; } + virtual bool isString() const { return m_builtinType == kStringType || m_builtinType == kUStringType; } /*! * @brief This function return true/false value for identify binary type. From 1417cd94a6a58518899ea3b5f80459dd43fa233c Mon Sep 17 00:00:00 2001 From: Philippe Date: Thu, 17 Sep 2020 02:14:11 -0700 Subject: [PATCH 22/96] more WIP --- erpcgen/src/CGenerator.cpp | 15 +++++++++++++-- erpcgen/src/types/BuiltinType.h | 12 ++++++++++-- erpcgen/src/types/DataType.h | 7 +++++++ 3 files changed, 30 insertions(+), 4 deletions(-) diff --git a/erpcgen/src/CGenerator.cpp b/erpcgen/src/CGenerator.cpp index d877ccf82..0e726d69a 100644 --- a/erpcgen/src/CGenerator.cpp +++ b/erpcgen/src/CGenerator.cpp @@ -1861,6 +1861,10 @@ string CGenerator::getErrorReturnValue(FunctionBase *fn) throw semantic_error(format_string("Expected value for @%s annotation for function on line %d", ERROR_RETURN_ANNOTATION, symbol->getLocation().m_firstLine)); } + else if (dataType->isUString()) + { + return "(unsigned char *) " + returnVal->toString(); + } else if (dataType->isString()) { return "(char *) " + returnVal->toString(); @@ -2295,7 +2299,14 @@ void CGenerator::getEncodeDecodeBuiltin(Group *group, BuiltinType *t, data_map & } templateData["freeingCall"] = m_templateData["freeData"]; // needDealloc(templateData, t, structType, nullptr); - templateData["builtinType"] = "kStringType"; + if (t->isUString()) { + templateData["builtinType"] = "kStringType"; + templateData["mallocType"] = "char*"; + } else { + templateData["builtinType"] = "kUStringType"; + templateData["mallocType"] = "unsigned char*"; + } + } else { @@ -3060,7 +3071,7 @@ data_map CGenerator::allocateCall(const string &name, Symbol *symbol) else { typeValue = "char"; - typePointerValue = "char *"; + typePointerValue = dataType->isUString() ? "unsigned char*" : "char *"; } alloc["name"] = name.c_str(); diff --git a/erpcgen/src/types/BuiltinType.h b/erpcgen/src/types/BuiltinType.h index 107d4491b..17d456547 100644 --- a/erpcgen/src/types/BuiltinType.h +++ b/erpcgen/src/types/BuiltinType.h @@ -109,10 +109,18 @@ class BuiltinType : public DataType /*! * @brief This function return true/false value for identify string type. * - * @retval true When builtin type is string. - * @retval false When builtin type isn't string. + * @retval true When builtin type is string or ustring. + * @retval false When builtin type isn't string or ustring. */ virtual bool isString() const { return m_builtinType == kStringType || m_builtinType == kUStringType; } + + /*! + * @brief This function return true/false value for identify ustring type. + * + * @retval true When builtin type is ustring. + * @retval false When builtin type isn't ustring. + */ + virtual bool isUString() const { return m_builtinType == kUStringType; } /*! * @brief This function return true/false value for identify binary type. diff --git a/erpcgen/src/types/DataType.h b/erpcgen/src/types/DataType.h index 11bb4fa68..3f1bac5c7 100644 --- a/erpcgen/src/types/DataType.h +++ b/erpcgen/src/types/DataType.h @@ -193,6 +193,13 @@ class DataType : public Symbol * @retval false Always return false. */ virtual bool isString() const { return false; } + + /*! + * @brief This function return "false" value as default for identify ustring type. + * + * @retval false Always return false. + */ + virtual bool isUString() const { return false; } /*! * @brief This function return "false" value as default for identify struct type. From e5387d76ce2b09927cbd7a65350f119f7664db40 Mon Sep 17 00:00:00 2001 From: Dusan Cervenka Date: Thu, 17 Sep 2020 15:52:38 +0200 Subject: [PATCH 23/96] Fixed warnings and error with using MessageLoggers. --- erpc_c/infra/erpc_client_manager.h | 558 ++++++++++---------- erpc_c/infra/erpc_server.h | 8 +- erpc_c/setup/erpc_arbitrated_client_setup.h | 1 + erpc_c/setup/erpc_client_setup.h | 229 ++++---- erpc_c/setup/erpc_server_setup.h | 1 + 5 files changed, 402 insertions(+), 395 deletions(-) diff --git a/erpc_c/infra/erpc_client_manager.h b/erpc_c/infra/erpc_client_manager.h index 9bef6d23c..002bbd1fb 100644 --- a/erpc_c/infra/erpc_client_manager.h +++ b/erpc_c/infra/erpc_client_manager.h @@ -1,278 +1,280 @@ -/* - * Copyright (c) 2014-2016, Freescale Semiconductor, Inc. - * Copyright 2016-2017 NXP - * All rights reserved. - * - * - * SPDX-License-Identifier: BSD-3-Clause - */ - -#ifndef _EMBEDDED_RPC__CLIENT_MANAGER_H_ -#define _EMBEDDED_RPC__CLIENT_MANAGER_H_ - -#ifdef __cplusplus -#include "erpc_codec.h" -#include "erpc_config_internal.h" -#if ERPC_MESSAGE_LOGGING -#include "erpc_message_loggers.h" -#endif -#if ERPC_NESTED_CALLS -#include "erpc_server.h" -#include "erpc_threading.h" -#endif - -/*! - * @addtogroup infra_client - * @{ - * @file - */ - -extern "C" { -#endif - -typedef void (*client_error_handler_t)(erpc_status_t err, - uint32_t functionID); /*!< eRPC error handler function type. */ - -#ifdef __cplusplus -} - -//////////////////////////////////////////////////////////////////////////////// -// Classes -//////////////////////////////////////////////////////////////////////////////// - -namespace erpc { -class RequestContext; -#if ERPC_NESTED_CALLS -class Server; -#endif - -/*! - * @brief Base client implementation. - * - * @ingroup infra_client - */ -#if ERPC_MESSAGE_LOGGING -class ClientManager : public MessageLoggers -#else -class ClientManager -#endif -{ -public: - /*! - * @brief Constructor. - * - * This function initializes object attributes. - */ - ClientManager(void) - : m_messageFactory(NULL) - , m_codecFactory(NULL) - , m_transport(NULL) - , m_sequence(0) - , m_errorHandler(NULL) -#if ERPC_NESTED_CALLS - , m_server(NULL) - , m_serverThreadId(NULL) -#endif -#if ERPC_MESSAGE_LOGGING - , MessageLoggers() -#endif - { - } - - /*! - * @brief ClientManager destructor - */ - virtual ~ClientManager(void) {} - - /*! - * @brief This function sets message buffer factory to use. - * - * @param[in] factory Message buffer factory to use. - */ - void setMessageBufferFactory(MessageBufferFactory *factory) { m_messageFactory = factory; } - - /*! - * @brief This function sets codec factory to use. - * - * @param[in] factory Codec factory to use. - */ - void setCodecFactory(CodecFactory *factory) { m_codecFactory = factory; } - - /*! - * @brief This function sets transport layer to use. - * - * It also set messageBufferFactory to the same as in transport layer. - * - * @param[in] transport Transport layer to use. - */ - void setTransport(Transport *transport); - - /*! - * @brief This function creates request context. - * - * @param[in] isOneway True if need send data only, else false. - */ - virtual RequestContext createRequest(bool isOneway); - - /*! - * @brief This function performs request. - * - * @param[in] request Request context to perform. - */ - virtual void performRequest(RequestContext &request); - - /*! - * @brief This function releases request context. - * - * @param[in] request Request context to release. - */ - virtual void releaseRequest(RequestContext &request); - - /*! - * @brief This function sets error handler function for infrastructure errors. - * - * @param[in] error_handler Pointer to error handler function. - */ - void setErrorHandler(client_error_handler_t error_handler) { m_errorHandler = error_handler; } - - /*! - * @brief This function calls error handler callback function with given status. - * - * Function is called in client shim code at the end of function when error occurred. - * - * @param[in] err Specify function status at the end of eRPC call. - * @param[in] functionID Specify eRPC function call. - */ - void callErrorHandler(erpc_status_t err, uint32_t functionID); - -#if ERPC_NESTED_CALLS - /*! - * @brief This function sets server used for nested calls. - * - * @param[in] server Server used for nested calls. - */ - void setServer(Server *server) { m_server = server; } - - /*! - * @brief This function sets server thread id. - * - * @param[in] serverThreadId Id of thread where server run function is executed. - */ - void setServerThreadId(Thread::thread_id_t serverThreadId) { m_serverThreadId = serverThreadId; } -#endif - -protected: - MessageBufferFactory *m_messageFactory; //!< Message buffer factory to use. - CodecFactory *m_codecFactory; //!< Codec to use. - Transport *m_transport; //!< Transport layer to use. - uint32_t m_sequence; //!< Sequence number. - client_error_handler_t m_errorHandler; //!< Pointer to function error handler. -#if ERPC_NESTED_CALLS - Server *m_server; //!< Server used for nested calls. - Thread::thread_id_t m_serverThreadId; //!< Thread in which server run function is called. -#endif - - /*! - * @brief This function performs request. - * - * Should be called in non server context (do not call another eRPC function in server - * remote call implementation). - * - * @param[in] request Request context to perform. - */ - virtual void performClientRequest(RequestContext &request); - -#if ERPC_NESTED_CALLS - /*! - * @brief This function performs nested request. - * - * Used when from eRPC function server implementation context is called new eRPC function. - * - * @param[in] request Request context to perform. - */ - virtual void performNestedClientRequest(RequestContext &request); -#endif - - //! @brief Validate that an incoming message is a reply. - virtual erpc_status_t verifyReply(RequestContext &request); - - /*! - * @brief Create message buffer and codec. - * - * The new codec is set to use the new message buffer. Both codec and buffer are allocated - * with the relevant factories. - * - * @return Pointer to created codec with message buffer. - */ - Codec *createBufferAndCodec(void); - -private: - ClientManager(const ClientManager &); //!< Disable copy ctor. - ClientManager &operator=(const ClientManager &); //!< Disable copy ctor. -}; - -/*! - * @brief Encapsulates all information about a request. - * - * @ingroup infra_client - */ -class RequestContext -{ -public: - /*! - * @brief Constructor. - * - * This function sets request context attributes. - * - * @param[in] sequence Sequence number. - * @param[in] codec Set in inout codec. - * @param[in] isOneway Set information if codec is only oneway or bidirectional. - */ - RequestContext(uint32_t sequence, Codec *codec, bool isOneway) - : m_sequence(sequence) - , m_codec(codec) - , m_oneway(isOneway) - { - } - - /*! - * @brief Get inout codec (for writing). - * - * @return Inout codec. - */ - Codec *getCodec(void) { return m_codec; } - - /*! - * @brief Get sequence number (be sure that reply belong to current request). - * - * @return Sequence number. - */ - uint32_t getSequence(void) const { return m_sequence; } - - /*! - * @brief Returns information if request context is oneway or not. - * - * @retval True when request context is oneway direction, else false. - */ - bool isOneway(void) const { return m_oneway; } - - /*! - * @brief Set request context to be oneway type (only send data). - * - * @return Set request context to be oneway. - */ - void setIsOneway(bool oneway) { m_oneway = oneway; } - -protected: - uint32_t m_sequence; //!< Sequence number. To be sure that reply belong to current request. - Codec *m_codec; //!< Inout codec. Codec for receiving and sending data. - bool m_oneway; //!< When true, request context will be oneway type (only send data). -}; - -} // namespace erpc - -/*! @} */ - -#endif - -#endif // _EMBEDDED_RPC__CLIENT_MANAGER_H_ +/* + * Copyright (c) 2014-2016, Freescale Semiconductor, Inc. + * Copyright 2016-2017 NXP + * All rights reserved. + * + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef _EMBEDDED_RPC__CLIENT_MANAGER_H_ +#define _EMBEDDED_RPC__CLIENT_MANAGER_H_ + +#ifdef __cplusplus +#include "erpc_codec.h" +#include "erpc_config_internal.h" +#if ERPC_MESSAGE_LOGGING +#include "erpc_message_loggers.h" +#endif +#if ERPC_NESTED_CALLS +#include "erpc_server.h" +#include "erpc_threading.h" +#endif + +/*! + * @addtogroup infra_client + * @{ + * @file + */ + +extern "C" { +#endif + +typedef void (*client_error_handler_t)(erpc_status_t err, + uint32_t functionID); /*!< eRPC error handler function type. */ + +#ifdef __cplusplus +} + +//////////////////////////////////////////////////////////////////////////////// +// Classes +//////////////////////////////////////////////////////////////////////////////// + +namespace erpc { +class RequestContext; +#if ERPC_NESTED_CALLS +class Server; +#endif + +/*! + * @brief Base client implementation. + * + * @ingroup infra_client + */ +#if ERPC_MESSAGE_LOGGING +class ClientManager : public MessageLoggers +#else +class ClientManager +#endif +{ +public: + /*! + * @brief Constructor. + * + * This function initializes object attributes. + */ + ClientManager(void) +#if ERPC_MESSAGE_LOGGING + : MessageLoggers() + , m_messageFactory(NULL) +#else + : m_messageFactory(NULL) +#endif + , m_codecFactory(NULL) + , m_transport(NULL) + , m_sequence(0) + , m_errorHandler(NULL) +#if ERPC_NESTED_CALLS + , m_server(NULL) + , m_serverThreadId(NULL) +#endif + { + } + + /*! + * @brief ClientManager destructor + */ + virtual ~ClientManager(void) {} + + /*! + * @brief This function sets message buffer factory to use. + * + * @param[in] factory Message buffer factory to use. + */ + void setMessageBufferFactory(MessageBufferFactory *factory) { m_messageFactory = factory; } + + /*! + * @brief This function sets codec factory to use. + * + * @param[in] factory Codec factory to use. + */ + void setCodecFactory(CodecFactory *factory) { m_codecFactory = factory; } + + /*! + * @brief This function sets transport layer to use. + * + * It also set messageBufferFactory to the same as in transport layer. + * + * @param[in] transport Transport layer to use. + */ + void setTransport(Transport *transport); + + /*! + * @brief This function creates request context. + * + * @param[in] isOneway True if need send data only, else false. + */ + virtual RequestContext createRequest(bool isOneway); + + /*! + * @brief This function performs request. + * + * @param[in] request Request context to perform. + */ + virtual void performRequest(RequestContext &request); + + /*! + * @brief This function releases request context. + * + * @param[in] request Request context to release. + */ + virtual void releaseRequest(RequestContext &request); + + /*! + * @brief This function sets error handler function for infrastructure errors. + * + * @param[in] error_handler Pointer to error handler function. + */ + void setErrorHandler(client_error_handler_t error_handler) { m_errorHandler = error_handler; } + + /*! + * @brief This function calls error handler callback function with given status. + * + * Function is called in client shim code at the end of function when error occurred. + * + * @param[in] err Specify function status at the end of eRPC call. + * @param[in] functionID Specify eRPC function call. + */ + void callErrorHandler(erpc_status_t err, uint32_t functionID); + +#if ERPC_NESTED_CALLS + /*! + * @brief This function sets server used for nested calls. + * + * @param[in] server Server used for nested calls. + */ + void setServer(Server *server) { m_server = server; } + + /*! + * @brief This function sets server thread id. + * + * @param[in] serverThreadId Id of thread where server run function is executed. + */ + void setServerThreadId(Thread::thread_id_t serverThreadId) { m_serverThreadId = serverThreadId; } +#endif + +protected: + MessageBufferFactory *m_messageFactory; //!< Message buffer factory to use. + CodecFactory *m_codecFactory; //!< Codec to use. + Transport *m_transport; //!< Transport layer to use. + uint32_t m_sequence; //!< Sequence number. + client_error_handler_t m_errorHandler; //!< Pointer to function error handler. +#if ERPC_NESTED_CALLS + Server *m_server; //!< Server used for nested calls. + Thread::thread_id_t m_serverThreadId; //!< Thread in which server run function is called. +#endif + + /*! + * @brief This function performs request. + * + * Should be called in non server context (do not call another eRPC function in server + * remote call implementation). + * + * @param[in] request Request context to perform. + */ + virtual void performClientRequest(RequestContext &request); + +#if ERPC_NESTED_CALLS + /*! + * @brief This function performs nested request. + * + * Used when from eRPC function server implementation context is called new eRPC function. + * + * @param[in] request Request context to perform. + */ + virtual void performNestedClientRequest(RequestContext &request); +#endif + + //! @brief Validate that an incoming message is a reply. + virtual erpc_status_t verifyReply(RequestContext &request); + + /*! + * @brief Create message buffer and codec. + * + * The new codec is set to use the new message buffer. Both codec and buffer are allocated + * with the relevant factories. + * + * @return Pointer to created codec with message buffer. + */ + Codec *createBufferAndCodec(void); + +private: + ClientManager(const ClientManager &); //!< Disable copy ctor. + ClientManager &operator=(const ClientManager &); //!< Disable copy ctor. +}; + +/*! + * @brief Encapsulates all information about a request. + * + * @ingroup infra_client + */ +class RequestContext +{ +public: + /*! + * @brief Constructor. + * + * This function sets request context attributes. + * + * @param[in] sequence Sequence number. + * @param[in] codec Set in inout codec. + * @param[in] isOneway Set information if codec is only oneway or bidirectional. + */ + RequestContext(uint32_t sequence, Codec *codec, bool isOneway) + : m_sequence(sequence) + , m_codec(codec) + , m_oneway(isOneway) + { + } + + /*! + * @brief Get inout codec (for writing). + * + * @return Inout codec. + */ + Codec *getCodec(void) { return m_codec; } + + /*! + * @brief Get sequence number (be sure that reply belong to current request). + * + * @return Sequence number. + */ + uint32_t getSequence(void) const { return m_sequence; } + + /*! + * @brief Returns information if request context is oneway or not. + * + * @retval True when request context is oneway direction, else false. + */ + bool isOneway(void) const { return m_oneway; } + + /*! + * @brief Set request context to be oneway type (only send data). + * + * @return Set request context to be oneway. + */ + void setIsOneway(bool oneway) { m_oneway = oneway; } + +protected: + uint32_t m_sequence; //!< Sequence number. To be sure that reply belong to current request. + Codec *m_codec; //!< Inout codec. Codec for receiving and sending data. + bool m_oneway; //!< When true, request context will be oneway type (only send data). +}; + +} // namespace erpc + +/*! @} */ + +#endif + +#endif // _EMBEDDED_RPC__CLIENT_MANAGER_H_ diff --git a/erpc_c/infra/erpc_server.h b/erpc_c/infra/erpc_server.h index 7e32f2c9b..0ce3b7184 100644 --- a/erpc_c/infra/erpc_server.h +++ b/erpc_c/infra/erpc_server.h @@ -114,13 +114,15 @@ class Server * This function initializes object attributes. */ Server(void) +#if ERPC_MESSAGE_LOGGING + : MessageLoggers() + , m_messageFactory() +#else : m_messageFactory() +#endif , m_codecFactory() , m_transport() , m_firstService() -#if ERPC_MESSAGE_LOGGING - , MessageLoggers() -#endif { } diff --git a/erpc_c/setup/erpc_arbitrated_client_setup.h b/erpc_c/setup/erpc_arbitrated_client_setup.h index 333a40e5c..22d2b4f45 100644 --- a/erpc_c/setup/erpc_arbitrated_client_setup.h +++ b/erpc_c/setup/erpc_arbitrated_client_setup.h @@ -19,6 +19,7 @@ #include "erpc_client_manager.h" #include "erpc_transport_setup.h" +#include /*! * @addtogroup client_setup * @{ diff --git a/erpc_c/setup/erpc_client_setup.h b/erpc_c/setup/erpc_client_setup.h index 16e0ae402..fd509f527 100644 --- a/erpc_c/setup/erpc_client_setup.h +++ b/erpc_c/setup/erpc_client_setup.h @@ -1,114 +1,115 @@ -/* - * Copyright (c) 2014-2016, Freescale Semiconductor, Inc. - * Copyright 2016-2017 NXP - * All rights reserved. - * - * - * SPDX-License-Identifier: BSD-3-Clause - */ - -#ifndef _EMBEDDED_RPC__CLIENT_SETUP_H_ -#define _EMBEDDED_RPC__CLIENT_SETUP_H_ - -#include "erpc_common.h" -#include "erpc_config_internal.h" -#include "erpc_mbf_setup.h" -#if ERPC_NESTED_CALLS -#include "erpc_server_setup.h" -#endif -#include "erpc_client_manager.h" -#include "erpc_transport_setup.h" - -/*! - * @addtogroup client_setup - * @{ - * @file - */ - -//////////////////////////////////////////////////////////////////////////////// -// API -//////////////////////////////////////////////////////////////////////////////// - -#ifdef __cplusplus -extern "C" { -#endif - -#include - -//! @name Client setup -//@{ - -/*! - * @brief This function initializes client. - * - * @param[in] transport Initiated transport. - * @param[in] message_buffer_factory Initiated message buffer factory. - * - * This function initializes client with all components necessary for serve client request. - */ -void erpc_client_init(erpc_transport_t transport, erpc_mbf_t message_buffer_factory); - -/*! - * @brief This function sets error handler function. - * - * Given error_handler function is called when error occur inside eRPC infrastructure. - * - * @param[in] error_handler Pointer to function error handler. - */ -void erpc_client_set_error_handler(client_error_handler_t error_handler); - -/*! - * @brief Can be used to set own crcStart number. - * - * For example can be used generated crc from erpcgen - * which is providing when @crc annotation is used. - * Accessed can be through 'extern const uint32_t erpc_generated_crc;' - * - * @param[in] crcStart Set start number for crc. - */ -void erpc_client_set_crc(uint32_t crcStart); - -#if ERPC_NESTED_CALLS -/*! - * @brief This function sets server object for handling nested eRPC calls. - * - * @param[in] server Initiated server. - */ -void erpc_client_set_server(erpc_server_t server); - -/*! - * @brief This function sets server thread id. - * - * @param[in] serverThreadId Id of thread where server run function is executed. - */ -void erpc_client_set_server_thread_id(void *serverThreadId); -#endif - -#if ERPC_MESSAGE_LOGGING -/*! - * @brief This function adds transport object for logging send/receive messages. - * - * @param[in] transport Initiated transport. - * - * @retval True When transport was successfully added. - * @retval False When transport wasn't added. - */ -bool erpc_client_add_message_logger(erpc_transport_t transport); -#endif - -/*! - * @brief This function de-initializes client. - * - * This function de-initializes client and all components which it own. - */ -void erpc_client_deinit(void); - -//@} - -#ifdef __cplusplus -} -#endif - -/*! @} */ - -#endif // _EMBEDDED_RPC__CLIENT_SETUP_H_ +/* + * Copyright (c) 2014-2016, Freescale Semiconductor, Inc. + * Copyright 2016-2017 NXP + * All rights reserved. + * + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef _EMBEDDED_RPC__CLIENT_SETUP_H_ +#define _EMBEDDED_RPC__CLIENT_SETUP_H_ + +#include "erpc_common.h" +#include "erpc_config_internal.h" +#include "erpc_mbf_setup.h" +#if ERPC_NESTED_CALLS +#include "erpc_server_setup.h" +#endif +#include "erpc_client_manager.h" +#include "erpc_transport_setup.h" +#include + +/*! + * @addtogroup client_setup + * @{ + * @file + */ + +//////////////////////////////////////////////////////////////////////////////// +// API +//////////////////////////////////////////////////////////////////////////////// + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +//! @name Client setup +//@{ + +/*! + * @brief This function initializes client. + * + * @param[in] transport Initiated transport. + * @param[in] message_buffer_factory Initiated message buffer factory. + * + * This function initializes client with all components necessary for serve client request. + */ +void erpc_client_init(erpc_transport_t transport, erpc_mbf_t message_buffer_factory); + +/*! + * @brief This function sets error handler function. + * + * Given error_handler function is called when error occur inside eRPC infrastructure. + * + * @param[in] error_handler Pointer to function error handler. + */ +void erpc_client_set_error_handler(client_error_handler_t error_handler); + +/*! + * @brief Can be used to set own crcStart number. + * + * For example can be used generated crc from erpcgen + * which is providing when @crc annotation is used. + * Accessed can be through 'extern const uint32_t erpc_generated_crc;' + * + * @param[in] crcStart Set start number for crc. + */ +void erpc_client_set_crc(uint32_t crcStart); + +#if ERPC_NESTED_CALLS +/*! + * @brief This function sets server object for handling nested eRPC calls. + * + * @param[in] server Initiated server. + */ +void erpc_client_set_server(erpc_server_t server); + +/*! + * @brief This function sets server thread id. + * + * @param[in] serverThreadId Id of thread where server run function is executed. + */ +void erpc_client_set_server_thread_id(void *serverThreadId); +#endif + +#if ERPC_MESSAGE_LOGGING +/*! + * @brief This function adds transport object for logging send/receive messages. + * + * @param[in] transport Initiated transport. + * + * @retval True When transport was successfully added. + * @retval False When transport wasn't added. + */ +bool erpc_client_add_message_logger(erpc_transport_t transport); +#endif + +/*! + * @brief This function de-initializes client. + * + * This function de-initializes client and all components which it own. + */ +void erpc_client_deinit(void); + +//@} + +#ifdef __cplusplus +} +#endif + +/*! @} */ + +#endif // _EMBEDDED_RPC__CLIENT_SETUP_H_ diff --git a/erpc_c/setup/erpc_server_setup.h b/erpc_c/setup/erpc_server_setup.h index dd6d42f34..f7c802075 100644 --- a/erpc_c/setup/erpc_server_setup.h +++ b/erpc_c/setup/erpc_server_setup.h @@ -14,6 +14,7 @@ #include "erpc_config_internal.h" #include "erpc_mbf_setup.h" #include "erpc_transport_setup.h" +#include /*! * @addtogroup server_setup From f3a9564bb7eefedded1cdc5f28aff3532154d213 Mon Sep 17 00:00:00 2001 From: Dusan Cervenka Date: Thu, 17 Sep 2020 15:58:48 +0200 Subject: [PATCH 24/96] Fix crlf --- erpc_c/infra/erpc_client_manager.h | 560 ++++++++++++++--------------- erpc_c/setup/erpc_client_setup.h | 230 ++++++------ 2 files changed, 395 insertions(+), 395 deletions(-) diff --git a/erpc_c/infra/erpc_client_manager.h b/erpc_c/infra/erpc_client_manager.h index 002bbd1fb..2560bfc7c 100644 --- a/erpc_c/infra/erpc_client_manager.h +++ b/erpc_c/infra/erpc_client_manager.h @@ -1,280 +1,280 @@ -/* - * Copyright (c) 2014-2016, Freescale Semiconductor, Inc. - * Copyright 2016-2017 NXP - * All rights reserved. - * - * - * SPDX-License-Identifier: BSD-3-Clause - */ - -#ifndef _EMBEDDED_RPC__CLIENT_MANAGER_H_ -#define _EMBEDDED_RPC__CLIENT_MANAGER_H_ - -#ifdef __cplusplus -#include "erpc_codec.h" -#include "erpc_config_internal.h" -#if ERPC_MESSAGE_LOGGING -#include "erpc_message_loggers.h" -#endif -#if ERPC_NESTED_CALLS -#include "erpc_server.h" -#include "erpc_threading.h" -#endif - -/*! - * @addtogroup infra_client - * @{ - * @file - */ - -extern "C" { -#endif - -typedef void (*client_error_handler_t)(erpc_status_t err, - uint32_t functionID); /*!< eRPC error handler function type. */ - -#ifdef __cplusplus -} - -//////////////////////////////////////////////////////////////////////////////// -// Classes -//////////////////////////////////////////////////////////////////////////////// - -namespace erpc { -class RequestContext; -#if ERPC_NESTED_CALLS -class Server; -#endif - -/*! - * @brief Base client implementation. - * - * @ingroup infra_client - */ -#if ERPC_MESSAGE_LOGGING -class ClientManager : public MessageLoggers -#else -class ClientManager -#endif -{ -public: - /*! - * @brief Constructor. - * - * This function initializes object attributes. - */ - ClientManager(void) -#if ERPC_MESSAGE_LOGGING - : MessageLoggers() - , m_messageFactory(NULL) -#else - : m_messageFactory(NULL) -#endif - , m_codecFactory(NULL) - , m_transport(NULL) - , m_sequence(0) - , m_errorHandler(NULL) -#if ERPC_NESTED_CALLS - , m_server(NULL) - , m_serverThreadId(NULL) -#endif - { - } - - /*! - * @brief ClientManager destructor - */ - virtual ~ClientManager(void) {} - - /*! - * @brief This function sets message buffer factory to use. - * - * @param[in] factory Message buffer factory to use. - */ - void setMessageBufferFactory(MessageBufferFactory *factory) { m_messageFactory = factory; } - - /*! - * @brief This function sets codec factory to use. - * - * @param[in] factory Codec factory to use. - */ - void setCodecFactory(CodecFactory *factory) { m_codecFactory = factory; } - - /*! - * @brief This function sets transport layer to use. - * - * It also set messageBufferFactory to the same as in transport layer. - * - * @param[in] transport Transport layer to use. - */ - void setTransport(Transport *transport); - - /*! - * @brief This function creates request context. - * - * @param[in] isOneway True if need send data only, else false. - */ - virtual RequestContext createRequest(bool isOneway); - - /*! - * @brief This function performs request. - * - * @param[in] request Request context to perform. - */ - virtual void performRequest(RequestContext &request); - - /*! - * @brief This function releases request context. - * - * @param[in] request Request context to release. - */ - virtual void releaseRequest(RequestContext &request); - - /*! - * @brief This function sets error handler function for infrastructure errors. - * - * @param[in] error_handler Pointer to error handler function. - */ - void setErrorHandler(client_error_handler_t error_handler) { m_errorHandler = error_handler; } - - /*! - * @brief This function calls error handler callback function with given status. - * - * Function is called in client shim code at the end of function when error occurred. - * - * @param[in] err Specify function status at the end of eRPC call. - * @param[in] functionID Specify eRPC function call. - */ - void callErrorHandler(erpc_status_t err, uint32_t functionID); - -#if ERPC_NESTED_CALLS - /*! - * @brief This function sets server used for nested calls. - * - * @param[in] server Server used for nested calls. - */ - void setServer(Server *server) { m_server = server; } - - /*! - * @brief This function sets server thread id. - * - * @param[in] serverThreadId Id of thread where server run function is executed. - */ - void setServerThreadId(Thread::thread_id_t serverThreadId) { m_serverThreadId = serverThreadId; } -#endif - -protected: - MessageBufferFactory *m_messageFactory; //!< Message buffer factory to use. - CodecFactory *m_codecFactory; //!< Codec to use. - Transport *m_transport; //!< Transport layer to use. - uint32_t m_sequence; //!< Sequence number. - client_error_handler_t m_errorHandler; //!< Pointer to function error handler. -#if ERPC_NESTED_CALLS - Server *m_server; //!< Server used for nested calls. - Thread::thread_id_t m_serverThreadId; //!< Thread in which server run function is called. -#endif - - /*! - * @brief This function performs request. - * - * Should be called in non server context (do not call another eRPC function in server - * remote call implementation). - * - * @param[in] request Request context to perform. - */ - virtual void performClientRequest(RequestContext &request); - -#if ERPC_NESTED_CALLS - /*! - * @brief This function performs nested request. - * - * Used when from eRPC function server implementation context is called new eRPC function. - * - * @param[in] request Request context to perform. - */ - virtual void performNestedClientRequest(RequestContext &request); -#endif - - //! @brief Validate that an incoming message is a reply. - virtual erpc_status_t verifyReply(RequestContext &request); - - /*! - * @brief Create message buffer and codec. - * - * The new codec is set to use the new message buffer. Both codec and buffer are allocated - * with the relevant factories. - * - * @return Pointer to created codec with message buffer. - */ - Codec *createBufferAndCodec(void); - -private: - ClientManager(const ClientManager &); //!< Disable copy ctor. - ClientManager &operator=(const ClientManager &); //!< Disable copy ctor. -}; - -/*! - * @brief Encapsulates all information about a request. - * - * @ingroup infra_client - */ -class RequestContext -{ -public: - /*! - * @brief Constructor. - * - * This function sets request context attributes. - * - * @param[in] sequence Sequence number. - * @param[in] codec Set in inout codec. - * @param[in] isOneway Set information if codec is only oneway or bidirectional. - */ - RequestContext(uint32_t sequence, Codec *codec, bool isOneway) - : m_sequence(sequence) - , m_codec(codec) - , m_oneway(isOneway) - { - } - - /*! - * @brief Get inout codec (for writing). - * - * @return Inout codec. - */ - Codec *getCodec(void) { return m_codec; } - - /*! - * @brief Get sequence number (be sure that reply belong to current request). - * - * @return Sequence number. - */ - uint32_t getSequence(void) const { return m_sequence; } - - /*! - * @brief Returns information if request context is oneway or not. - * - * @retval True when request context is oneway direction, else false. - */ - bool isOneway(void) const { return m_oneway; } - - /*! - * @brief Set request context to be oneway type (only send data). - * - * @return Set request context to be oneway. - */ - void setIsOneway(bool oneway) { m_oneway = oneway; } - -protected: - uint32_t m_sequence; //!< Sequence number. To be sure that reply belong to current request. - Codec *m_codec; //!< Inout codec. Codec for receiving and sending data. - bool m_oneway; //!< When true, request context will be oneway type (only send data). -}; - -} // namespace erpc - -/*! @} */ - -#endif - -#endif // _EMBEDDED_RPC__CLIENT_MANAGER_H_ +/* + * Copyright (c) 2014-2016, Freescale Semiconductor, Inc. + * Copyright 2016-2017 NXP + * All rights reserved. + * + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef _EMBEDDED_RPC__CLIENT_MANAGER_H_ +#define _EMBEDDED_RPC__CLIENT_MANAGER_H_ + +#ifdef __cplusplus +#include "erpc_codec.h" +#include "erpc_config_internal.h" +#if ERPC_MESSAGE_LOGGING +#include "erpc_message_loggers.h" +#endif +#if ERPC_NESTED_CALLS +#include "erpc_server.h" +#include "erpc_threading.h" +#endif + +/*! + * @addtogroup infra_client + * @{ + * @file + */ + +extern "C" { +#endif + +typedef void (*client_error_handler_t)(erpc_status_t err, + uint32_t functionID); /*!< eRPC error handler function type. */ + +#ifdef __cplusplus +} + +//////////////////////////////////////////////////////////////////////////////// +// Classes +//////////////////////////////////////////////////////////////////////////////// + +namespace erpc { +class RequestContext; +#if ERPC_NESTED_CALLS +class Server; +#endif + +/*! + * @brief Base client implementation. + * + * @ingroup infra_client + */ +#if ERPC_MESSAGE_LOGGING +class ClientManager : public MessageLoggers +#else +class ClientManager +#endif +{ +public: + /*! + * @brief Constructor. + * + * This function initializes object attributes. + */ + ClientManager(void) +#if ERPC_MESSAGE_LOGGING + : MessageLoggers() + , m_messageFactory(NULL) +#else + : m_messageFactory(NULL) +#endif + , m_codecFactory(NULL) + , m_transport(NULL) + , m_sequence(0) + , m_errorHandler(NULL) +#if ERPC_NESTED_CALLS + , m_server(NULL) + , m_serverThreadId(NULL) +#endif + { + } + + /*! + * @brief ClientManager destructor + */ + virtual ~ClientManager(void) {} + + /*! + * @brief This function sets message buffer factory to use. + * + * @param[in] factory Message buffer factory to use. + */ + void setMessageBufferFactory(MessageBufferFactory *factory) { m_messageFactory = factory; } + + /*! + * @brief This function sets codec factory to use. + * + * @param[in] factory Codec factory to use. + */ + void setCodecFactory(CodecFactory *factory) { m_codecFactory = factory; } + + /*! + * @brief This function sets transport layer to use. + * + * It also set messageBufferFactory to the same as in transport layer. + * + * @param[in] transport Transport layer to use. + */ + void setTransport(Transport *transport); + + /*! + * @brief This function creates request context. + * + * @param[in] isOneway True if need send data only, else false. + */ + virtual RequestContext createRequest(bool isOneway); + + /*! + * @brief This function performs request. + * + * @param[in] request Request context to perform. + */ + virtual void performRequest(RequestContext &request); + + /*! + * @brief This function releases request context. + * + * @param[in] request Request context to release. + */ + virtual void releaseRequest(RequestContext &request); + + /*! + * @brief This function sets error handler function for infrastructure errors. + * + * @param[in] error_handler Pointer to error handler function. + */ + void setErrorHandler(client_error_handler_t error_handler) { m_errorHandler = error_handler; } + + /*! + * @brief This function calls error handler callback function with given status. + * + * Function is called in client shim code at the end of function when error occurred. + * + * @param[in] err Specify function status at the end of eRPC call. + * @param[in] functionID Specify eRPC function call. + */ + void callErrorHandler(erpc_status_t err, uint32_t functionID); + +#if ERPC_NESTED_CALLS + /*! + * @brief This function sets server used for nested calls. + * + * @param[in] server Server used for nested calls. + */ + void setServer(Server *server) { m_server = server; } + + /*! + * @brief This function sets server thread id. + * + * @param[in] serverThreadId Id of thread where server run function is executed. + */ + void setServerThreadId(Thread::thread_id_t serverThreadId) { m_serverThreadId = serverThreadId; } +#endif + +protected: + MessageBufferFactory *m_messageFactory; //!< Message buffer factory to use. + CodecFactory *m_codecFactory; //!< Codec to use. + Transport *m_transport; //!< Transport layer to use. + uint32_t m_sequence; //!< Sequence number. + client_error_handler_t m_errorHandler; //!< Pointer to function error handler. +#if ERPC_NESTED_CALLS + Server *m_server; //!< Server used for nested calls. + Thread::thread_id_t m_serverThreadId; //!< Thread in which server run function is called. +#endif + + /*! + * @brief This function performs request. + * + * Should be called in non server context (do not call another eRPC function in server + * remote call implementation). + * + * @param[in] request Request context to perform. + */ + virtual void performClientRequest(RequestContext &request); + +#if ERPC_NESTED_CALLS + /*! + * @brief This function performs nested request. + * + * Used when from eRPC function server implementation context is called new eRPC function. + * + * @param[in] request Request context to perform. + */ + virtual void performNestedClientRequest(RequestContext &request); +#endif + + //! @brief Validate that an incoming message is a reply. + virtual erpc_status_t verifyReply(RequestContext &request); + + /*! + * @brief Create message buffer and codec. + * + * The new codec is set to use the new message buffer. Both codec and buffer are allocated + * with the relevant factories. + * + * @return Pointer to created codec with message buffer. + */ + Codec *createBufferAndCodec(void); + +private: + ClientManager(const ClientManager &); //!< Disable copy ctor. + ClientManager &operator=(const ClientManager &); //!< Disable copy ctor. +}; + +/*! + * @brief Encapsulates all information about a request. + * + * @ingroup infra_client + */ +class RequestContext +{ +public: + /*! + * @brief Constructor. + * + * This function sets request context attributes. + * + * @param[in] sequence Sequence number. + * @param[in] codec Set in inout codec. + * @param[in] isOneway Set information if codec is only oneway or bidirectional. + */ + RequestContext(uint32_t sequence, Codec *codec, bool isOneway) + : m_sequence(sequence) + , m_codec(codec) + , m_oneway(isOneway) + { + } + + /*! + * @brief Get inout codec (for writing). + * + * @return Inout codec. + */ + Codec *getCodec(void) { return m_codec; } + + /*! + * @brief Get sequence number (be sure that reply belong to current request). + * + * @return Sequence number. + */ + uint32_t getSequence(void) const { return m_sequence; } + + /*! + * @brief Returns information if request context is oneway or not. + * + * @retval True when request context is oneway direction, else false. + */ + bool isOneway(void) const { return m_oneway; } + + /*! + * @brief Set request context to be oneway type (only send data). + * + * @return Set request context to be oneway. + */ + void setIsOneway(bool oneway) { m_oneway = oneway; } + +protected: + uint32_t m_sequence; //!< Sequence number. To be sure that reply belong to current request. + Codec *m_codec; //!< Inout codec. Codec for receiving and sending data. + bool m_oneway; //!< When true, request context will be oneway type (only send data). +}; + +} // namespace erpc + +/*! @} */ + +#endif + +#endif // _EMBEDDED_RPC__CLIENT_MANAGER_H_ diff --git a/erpc_c/setup/erpc_client_setup.h b/erpc_c/setup/erpc_client_setup.h index fd509f527..b1a406628 100644 --- a/erpc_c/setup/erpc_client_setup.h +++ b/erpc_c/setup/erpc_client_setup.h @@ -1,115 +1,115 @@ -/* - * Copyright (c) 2014-2016, Freescale Semiconductor, Inc. - * Copyright 2016-2017 NXP - * All rights reserved. - * - * - * SPDX-License-Identifier: BSD-3-Clause - */ - -#ifndef _EMBEDDED_RPC__CLIENT_SETUP_H_ -#define _EMBEDDED_RPC__CLIENT_SETUP_H_ - -#include "erpc_common.h" -#include "erpc_config_internal.h" -#include "erpc_mbf_setup.h" -#if ERPC_NESTED_CALLS -#include "erpc_server_setup.h" -#endif -#include "erpc_client_manager.h" -#include "erpc_transport_setup.h" -#include - -/*! - * @addtogroup client_setup - * @{ - * @file - */ - -//////////////////////////////////////////////////////////////////////////////// -// API -//////////////////////////////////////////////////////////////////////////////// - -#ifdef __cplusplus -extern "C" { -#endif - -#include - -//! @name Client setup -//@{ - -/*! - * @brief This function initializes client. - * - * @param[in] transport Initiated transport. - * @param[in] message_buffer_factory Initiated message buffer factory. - * - * This function initializes client with all components necessary for serve client request. - */ -void erpc_client_init(erpc_transport_t transport, erpc_mbf_t message_buffer_factory); - -/*! - * @brief This function sets error handler function. - * - * Given error_handler function is called when error occur inside eRPC infrastructure. - * - * @param[in] error_handler Pointer to function error handler. - */ -void erpc_client_set_error_handler(client_error_handler_t error_handler); - -/*! - * @brief Can be used to set own crcStart number. - * - * For example can be used generated crc from erpcgen - * which is providing when @crc annotation is used. - * Accessed can be through 'extern const uint32_t erpc_generated_crc;' - * - * @param[in] crcStart Set start number for crc. - */ -void erpc_client_set_crc(uint32_t crcStart); - -#if ERPC_NESTED_CALLS -/*! - * @brief This function sets server object for handling nested eRPC calls. - * - * @param[in] server Initiated server. - */ -void erpc_client_set_server(erpc_server_t server); - -/*! - * @brief This function sets server thread id. - * - * @param[in] serverThreadId Id of thread where server run function is executed. - */ -void erpc_client_set_server_thread_id(void *serverThreadId); -#endif - -#if ERPC_MESSAGE_LOGGING -/*! - * @brief This function adds transport object for logging send/receive messages. - * - * @param[in] transport Initiated transport. - * - * @retval True When transport was successfully added. - * @retval False When transport wasn't added. - */ -bool erpc_client_add_message_logger(erpc_transport_t transport); -#endif - -/*! - * @brief This function de-initializes client. - * - * This function de-initializes client and all components which it own. - */ -void erpc_client_deinit(void); - -//@} - -#ifdef __cplusplus -} -#endif - -/*! @} */ - -#endif // _EMBEDDED_RPC__CLIENT_SETUP_H_ +/* + * Copyright (c) 2014-2016, Freescale Semiconductor, Inc. + * Copyright 2016-2017 NXP + * All rights reserved. + * + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef _EMBEDDED_RPC__CLIENT_SETUP_H_ +#define _EMBEDDED_RPC__CLIENT_SETUP_H_ + +#include "erpc_common.h" +#include "erpc_config_internal.h" +#include "erpc_mbf_setup.h" +#if ERPC_NESTED_CALLS +#include "erpc_server_setup.h" +#endif +#include "erpc_client_manager.h" +#include "erpc_transport_setup.h" +#include + +/*! + * @addtogroup client_setup + * @{ + * @file + */ + +//////////////////////////////////////////////////////////////////////////////// +// API +//////////////////////////////////////////////////////////////////////////////// + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +//! @name Client setup +//@{ + +/*! + * @brief This function initializes client. + * + * @param[in] transport Initiated transport. + * @param[in] message_buffer_factory Initiated message buffer factory. + * + * This function initializes client with all components necessary for serve client request. + */ +void erpc_client_init(erpc_transport_t transport, erpc_mbf_t message_buffer_factory); + +/*! + * @brief This function sets error handler function. + * + * Given error_handler function is called when error occur inside eRPC infrastructure. + * + * @param[in] error_handler Pointer to function error handler. + */ +void erpc_client_set_error_handler(client_error_handler_t error_handler); + +/*! + * @brief Can be used to set own crcStart number. + * + * For example can be used generated crc from erpcgen + * which is providing when @crc annotation is used. + * Accessed can be through 'extern const uint32_t erpc_generated_crc;' + * + * @param[in] crcStart Set start number for crc. + */ +void erpc_client_set_crc(uint32_t crcStart); + +#if ERPC_NESTED_CALLS +/*! + * @brief This function sets server object for handling nested eRPC calls. + * + * @param[in] server Initiated server. + */ +void erpc_client_set_server(erpc_server_t server); + +/*! + * @brief This function sets server thread id. + * + * @param[in] serverThreadId Id of thread where server run function is executed. + */ +void erpc_client_set_server_thread_id(void *serverThreadId); +#endif + +#if ERPC_MESSAGE_LOGGING +/*! + * @brief This function adds transport object for logging send/receive messages. + * + * @param[in] transport Initiated transport. + * + * @retval True When transport was successfully added. + * @retval False When transport wasn't added. + */ +bool erpc_client_add_message_logger(erpc_transport_t transport); +#endif + +/*! + * @brief This function de-initializes client. + * + * This function de-initializes client and all components which it own. + */ +void erpc_client_deinit(void); + +//@} + +#ifdef __cplusplus +} +#endif + +/*! @} */ + +#endif // _EMBEDDED_RPC__CLIENT_SETUP_H_ From 1bc5a1f43b82fd3b7a5db2dfa3b361172d59a628 Mon Sep 17 00:00:00 2001 From: Philippe Date: Thu, 17 Sep 2020 17:51:22 -0700 Subject: [PATCH 25/96] finalize ustring --- erpcgen/src/CGenerator.cpp | 16 +++------------- erpcgen/src/templates/c_coders.template | 2 +- 2 files changed, 4 insertions(+), 14 deletions(-) diff --git a/erpcgen/src/CGenerator.cpp b/erpcgen/src/CGenerator.cpp index 0e726d69a..e3b62a076 100644 --- a/erpcgen/src/CGenerator.cpp +++ b/erpcgen/src/CGenerator.cpp @@ -1861,13 +1861,9 @@ string CGenerator::getErrorReturnValue(FunctionBase *fn) throw semantic_error(format_string("Expected value for @%s annotation for function on line %d", ERROR_RETURN_ANNOTATION, symbol->getLocation().m_firstLine)); } - else if (dataType->isUString()) - { - return "(unsigned char *) " + returnVal->toString(); - } else if (dataType->isString()) { - return "(char *) " + returnVal->toString(); + return (dataType->isUString() ? "(unsigned char *)" : "(char*)") + returnVal->toString(); } else if (dataType->isScalar()) { @@ -2299,14 +2295,8 @@ void CGenerator::getEncodeDecodeBuiltin(Group *group, BuiltinType *t, data_map & } templateData["freeingCall"] = m_templateData["freeData"]; // needDealloc(templateData, t, structType, nullptr); - if (t->isUString()) { - templateData["builtinType"] = "kStringType"; - templateData["mallocType"] = "char*"; - } else { - templateData["builtinType"] = "kUStringType"; - templateData["mallocType"] = "unsigned char*"; - } - + templateData["builtinType"] = "kStringType"; + templateData["builtinTypeName"] = t->isUString() ? "unsigned char*" : "char*"; } else { diff --git a/erpcgen/src/templates/c_coders.template b/erpcgen/src/templates/c_coders.template index c1438f5b5..5f43a9613 100644 --- a/erpcgen/src/templates/c_coders.template +++ b/erpcgen/src/templates/c_coders.template @@ -4,7 +4,7 @@ uint32_t {$info.stringLocalName}_len; char * {$info.stringLocalName}_local; codec->readString(&{$info.stringLocalName}_len, &{$info.stringLocalName}_local); {% if ((source == "client" && info.withoutAlloc == false) or source == "server") %} -{$info.name} = (char *) erpc_malloc(({$info.stringAllocSize} + 1) * sizeof(char)); +{$info.name} = ({$info.builtinTypeName}) erpc_malloc(({$info.stringAllocSize} + 1) * sizeof(char)); {% if generateAllocErrorChecks == true %} if ({$info.name} == NULL) { From c88a9715c935591d920ce982290e375228d85b85 Mon Sep 17 00:00:00 2001 From: Dusan Cervenka Date: Fri, 18 Sep 2020 13:48:14 +0200 Subject: [PATCH 26/96] Fixed stdbool include position --- erpc_c/setup/erpc_arbitrated_client_setup.h | 2 +- erpc_c/setup/erpc_client_setup.h | 2 +- erpc_c/setup/erpc_server_setup.h | 1 - 3 files changed, 2 insertions(+), 3 deletions(-) diff --git a/erpc_c/setup/erpc_arbitrated_client_setup.h b/erpc_c/setup/erpc_arbitrated_client_setup.h index 22d2b4f45..e5ce7fe60 100644 --- a/erpc_c/setup/erpc_arbitrated_client_setup.h +++ b/erpc_c/setup/erpc_arbitrated_client_setup.h @@ -19,7 +19,6 @@ #include "erpc_client_manager.h" #include "erpc_transport_setup.h" -#include /*! * @addtogroup client_setup * @{ @@ -34,6 +33,7 @@ extern "C" { #endif +#include #include //! @name Arbitrated client setup diff --git a/erpc_c/setup/erpc_client_setup.h b/erpc_c/setup/erpc_client_setup.h index b1a406628..61c90e53c 100644 --- a/erpc_c/setup/erpc_client_setup.h +++ b/erpc_c/setup/erpc_client_setup.h @@ -18,7 +18,6 @@ #endif #include "erpc_client_manager.h" #include "erpc_transport_setup.h" -#include /*! * @addtogroup client_setup @@ -34,6 +33,7 @@ extern "C" { #endif +#include #include //! @name Client setup diff --git a/erpc_c/setup/erpc_server_setup.h b/erpc_c/setup/erpc_server_setup.h index f7c802075..dd6d42f34 100644 --- a/erpc_c/setup/erpc_server_setup.h +++ b/erpc_c/setup/erpc_server_setup.h @@ -14,7 +14,6 @@ #include "erpc_config_internal.h" #include "erpc_mbf_setup.h" #include "erpc_transport_setup.h" -#include /*! * @addtogroup server_setup From 883426ccf85c06a6c73f7921f9d73e16b0735a11 Mon Sep 17 00:00:00 2001 From: Dusan Cervenka Date: Wed, 23 Sep 2020 12:07:00 +0200 Subject: [PATCH 27/96] Update Copyright related to #78 Add deinit function for rpmsg tty transport. #78 --- erpc_c/setup/erpc_setup_rpmsg_tty_rtos_remote.cpp | 1 + erpc_c/setup/erpc_transport_setup.h | 1 + erpc_c/transports/erpc_rpmsg_tty_rtos_transport.cpp | 1 + 3 files changed, 3 insertions(+) diff --git a/erpc_c/setup/erpc_setup_rpmsg_tty_rtos_remote.cpp b/erpc_c/setup/erpc_setup_rpmsg_tty_rtos_remote.cpp index 153d5475b..a3a1662e5 100644 --- a/erpc_c/setup/erpc_setup_rpmsg_tty_rtos_remote.cpp +++ b/erpc_c/setup/erpc_setup_rpmsg_tty_rtos_remote.cpp @@ -1,6 +1,7 @@ /* * Copyright (c) 2016, Freescale Semiconductor, Inc. * Copyright 2016-2020 NXP + * Copyright 2019 ACRIOS Systems s.r.o. * All rights reserved. * * diff --git a/erpc_c/setup/erpc_transport_setup.h b/erpc_c/setup/erpc_transport_setup.h index af3e6abf2..37a429b86 100644 --- a/erpc_c/setup/erpc_transport_setup.h +++ b/erpc_c/setup/erpc_transport_setup.h @@ -1,6 +1,7 @@ /* * Copyright (c) 2014-2016, Freescale Semiconductor, Inc. * Copyright 2016-2020 NXP + * Copyright 2019 ACRIOS Systems s.r.o. * All rights reserved. * * diff --git a/erpc_c/transports/erpc_rpmsg_tty_rtos_transport.cpp b/erpc_c/transports/erpc_rpmsg_tty_rtos_transport.cpp index 403b29f08..d71870ff4 100644 --- a/erpc_c/transports/erpc_rpmsg_tty_rtos_transport.cpp +++ b/erpc_c/transports/erpc_rpmsg_tty_rtos_transport.cpp @@ -1,6 +1,7 @@ /* * Copyright (c) 2016, Freescale Semiconductor, Inc. * Copyright 2017-2020 NXP + * Copyright 2019 ACRIOS Systems s.r.o. * All rights reserved. * * From e6099dd16ef6ee5d79db66a14254843c21aa5a68 Mon Sep 17 00:00:00 2001 From: Dusan Cervenka Date: Wed, 23 Sep 2020 12:09:10 +0200 Subject: [PATCH 28/96] Update Copyright related to #84 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Freeing services in server causing hardfault issue for staticli alloc… #84 --- erpc_c/infra/erpc_simple_server.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/erpc_c/infra/erpc_simple_server.cpp b/erpc_c/infra/erpc_simple_server.cpp index 7777c3e5f..27fa1344f 100644 --- a/erpc_c/infra/erpc_simple_server.cpp +++ b/erpc_c/infra/erpc_simple_server.cpp @@ -1,6 +1,7 @@ /* * Copyright (c) 2014, Freescale Semiconductor, Inc. * Copyright 2016-2017 NXP + * Copyright 2019 ACRIOS Systems s.r.o. * All rights reserved. * * From 19bf57a60bcade55c927b9ea84ea9e46bd5e4532 Mon Sep 17 00:00:00 2001 From: Dusan Cervenka Date: Wed, 23 Sep 2020 12:11:37 +0200 Subject: [PATCH 29/96] Update Copyright related to #127 Message loggin fix #127 --- erpc_c/infra/erpc_client_manager.h | 1 + erpc_c/infra/erpc_server.h | 1 + erpc_c/setup/erpc_arbitrated_client_setup.h | 1 + erpc_c/setup/erpc_client_setup.h | 1 + 4 files changed, 4 insertions(+) diff --git a/erpc_c/infra/erpc_client_manager.h b/erpc_c/infra/erpc_client_manager.h index 2560bfc7c..b51a13d6b 100644 --- a/erpc_c/infra/erpc_client_manager.h +++ b/erpc_c/infra/erpc_client_manager.h @@ -1,6 +1,7 @@ /* * Copyright (c) 2014-2016, Freescale Semiconductor, Inc. * Copyright 2016-2017 NXP + * Copyright 2020 ACRIOS Systems s.r.o. * All rights reserved. * * diff --git a/erpc_c/infra/erpc_server.h b/erpc_c/infra/erpc_server.h index 0ce3b7184..ae4b56a0b 100644 --- a/erpc_c/infra/erpc_server.h +++ b/erpc_c/infra/erpc_server.h @@ -1,6 +1,7 @@ /* * Copyright (c) 2014, Freescale Semiconductor, Inc. * Copyright 2016-2017 NXP + * Copyright 2020 ACRIOS Systems s.r.o. * All rights reserved. * * diff --git a/erpc_c/setup/erpc_arbitrated_client_setup.h b/erpc_c/setup/erpc_arbitrated_client_setup.h index e5ce7fe60..46df41a90 100644 --- a/erpc_c/setup/erpc_arbitrated_client_setup.h +++ b/erpc_c/setup/erpc_arbitrated_client_setup.h @@ -1,6 +1,7 @@ /* * Copyright (c) 2016, Freescale Semiconductor, Inc. * Copyright 2016-2017 NXP + * Copyright 2019 ACRIOS Systems s.r.o. * All rights reserved. * * diff --git a/erpc_c/setup/erpc_client_setup.h b/erpc_c/setup/erpc_client_setup.h index 61c90e53c..906522860 100644 --- a/erpc_c/setup/erpc_client_setup.h +++ b/erpc_c/setup/erpc_client_setup.h @@ -1,6 +1,7 @@ /* * Copyright (c) 2014-2016, Freescale Semiconductor, Inc. * Copyright 2016-2017 NXP + * Copyright 2019 ACRIOS Systems s.r.o. * All rights reserved. * * From 5050614a1dcf4e8d27f574312b89d2a6168cd9de Mon Sep 17 00:00:00 2001 From: Dusan Cervenka Date: Fri, 25 Sep 2020 01:05:33 +0200 Subject: [PATCH 30/96] Added pre post cb functions for erpc calls. Also with default implementation for FreeRTOS. --- erpc_c/config/erpc_config.h | 23 + erpc_c/infra/erpc_client_manager.h | 550 +++++++++--------- erpc_c/infra/erpc_client_server_common.h | 96 +++ erpc_c/infra/erpc_pre_post_action.cpp | 49 ++ erpc_c/infra/erpc_pre_post_action.h | 95 +++ erpc_c/infra/erpc_server.h | 16 +- erpc_c/infra/erpc_simple_server.cpp | 17 + erpc_c/port/erpc_config_internal.h | 11 + erpc_c/port/erpc_setup_extensions.h | 81 +++ .../port/erpc_setup_extensions_freertos.cpp | 51 ++ erpc_c/port/erpc_threading.h | 3 +- erpc_c/setup/erpc_arbitrated_client_setup.cpp | 17 + erpc_c/setup/erpc_arbitrated_client_setup.h | 21 + erpc_c/setup/erpc_client_setup.cpp | 17 + erpc_c/setup/erpc_client_setup.h | 21 + erpc_c/setup/erpc_server_setup.cpp | 17 + erpc_c/setup/erpc_server_setup.h | 22 + .../src/templates/c_client_source.template | 17 + 18 files changed, 830 insertions(+), 294 deletions(-) create mode 100644 erpc_c/infra/erpc_client_server_common.h create mode 100644 erpc_c/infra/erpc_pre_post_action.cpp create mode 100644 erpc_c/infra/erpc_pre_post_action.h create mode 100644 erpc_c/port/erpc_setup_extensions.h create mode 100644 erpc_c/port/erpc_setup_extensions_freertos.cpp diff --git a/erpc_c/config/erpc_config.h b/erpc_c/config/erpc_config.h index db492f9b0..c8da1592d 100644 --- a/erpc_c/config/erpc_config.h +++ b/erpc_c/config/erpc_config.h @@ -1,6 +1,7 @@ /* * Copyright (c) 2016, Freescale Semiconductor, Inc. * Copyright 2016-2020 NXP + * Copyright 2020 ACRIOS Systems s.r.o. * All rights reserved. * * @@ -43,6 +44,12 @@ #define ERPC_TRANSPORT_MU_USE_MCMGR_DISABLED (0) //!< Do not use MCMGR for MU ISR management. #define ERPC_TRANSPORT_MU_USE_MCMGR_ENABLED (1) //!< Use MCMGR for MU ISR management. + +#define ERPC_PRE_POST_ACTION_DISABLED (0) //!< Pre post shim callbacks functions disabled. +#define ERPC_PRE_POST_ACTION_ENABLED (1) //!< Pre post shim callback functions enabled. + +#define ERPC_PRE_POST_ACTION_DEFAULT_DISABLED (0) //!< Pre post shim default callbacks functions disabled. +#define ERPC_PRE_POST_ACTION_DEFAULT_ENABLED (1) //!< Pre post shim default callback functions enabled. //@} //! @name Configuration options @@ -119,6 +126,22 @@ //#define ERPC_TRANSPORT_MU_USE_MCMGR ERPC_TRANSPORT_MU_USE_MCMGR_DISABLED //@} +//! @def ERPC_PRE_POST_ACTION +//! +//! Enable eRPC pre and post callback functions shim code. Take look into "erpc_pre_post_action.h". Can be used for +//! detection of eRPC call freeze, ... Default set to ERPC_PRE_POST_ACTION_DISABLED. +//! +//! Uncomment for using pre post callback feature. +//#define ERPC_PRE_POST_ACTION (ERPC_PRE_POST_ACTION_ENABLED) + +//! @def ERPC_PRE_POST_ACTION_DEFAULT +//! +//! Enable eRPC pre and post default callback functions. Take look into "erpc_setup_extensions.h". Can be used for +//! detection of eRPC call freeze, ... Default set to ERPC_PRE_POST_ACTION_DEFAULT_DISABLED. +//! +//! Uncomment for using pre post default callback feature. +//#define ERPC_PRE_POST_ACTION_DEFAULT (ERPC_PRE_POST_ACTION_DEFAULT_ENABLED) + /*! @} */ #endif // _ERPC_CONFIG_H_ //////////////////////////////////////////////////////////////////////////////// diff --git a/erpc_c/infra/erpc_client_manager.h b/erpc_c/infra/erpc_client_manager.h index 2560bfc7c..26302a967 100644 --- a/erpc_c/infra/erpc_client_manager.h +++ b/erpc_c/infra/erpc_client_manager.h @@ -1,280 +1,270 @@ -/* - * Copyright (c) 2014-2016, Freescale Semiconductor, Inc. - * Copyright 2016-2017 NXP - * All rights reserved. - * - * - * SPDX-License-Identifier: BSD-3-Clause - */ - -#ifndef _EMBEDDED_RPC__CLIENT_MANAGER_H_ -#define _EMBEDDED_RPC__CLIENT_MANAGER_H_ - -#ifdef __cplusplus -#include "erpc_codec.h" -#include "erpc_config_internal.h" -#if ERPC_MESSAGE_LOGGING -#include "erpc_message_loggers.h" -#endif -#if ERPC_NESTED_CALLS -#include "erpc_server.h" -#include "erpc_threading.h" -#endif - -/*! - * @addtogroup infra_client - * @{ - * @file - */ - -extern "C" { -#endif - -typedef void (*client_error_handler_t)(erpc_status_t err, - uint32_t functionID); /*!< eRPC error handler function type. */ - -#ifdef __cplusplus -} - -//////////////////////////////////////////////////////////////////////////////// -// Classes -//////////////////////////////////////////////////////////////////////////////// - -namespace erpc { -class RequestContext; -#if ERPC_NESTED_CALLS -class Server; -#endif - -/*! - * @brief Base client implementation. - * - * @ingroup infra_client - */ -#if ERPC_MESSAGE_LOGGING -class ClientManager : public MessageLoggers -#else -class ClientManager -#endif -{ -public: - /*! - * @brief Constructor. - * - * This function initializes object attributes. - */ - ClientManager(void) -#if ERPC_MESSAGE_LOGGING - : MessageLoggers() - , m_messageFactory(NULL) -#else - : m_messageFactory(NULL) -#endif - , m_codecFactory(NULL) - , m_transport(NULL) - , m_sequence(0) - , m_errorHandler(NULL) -#if ERPC_NESTED_CALLS - , m_server(NULL) - , m_serverThreadId(NULL) -#endif - { - } - - /*! - * @brief ClientManager destructor - */ - virtual ~ClientManager(void) {} - - /*! - * @brief This function sets message buffer factory to use. - * - * @param[in] factory Message buffer factory to use. - */ - void setMessageBufferFactory(MessageBufferFactory *factory) { m_messageFactory = factory; } - - /*! - * @brief This function sets codec factory to use. - * - * @param[in] factory Codec factory to use. - */ - void setCodecFactory(CodecFactory *factory) { m_codecFactory = factory; } - - /*! - * @brief This function sets transport layer to use. - * - * It also set messageBufferFactory to the same as in transport layer. - * - * @param[in] transport Transport layer to use. - */ - void setTransport(Transport *transport); - - /*! - * @brief This function creates request context. - * - * @param[in] isOneway True if need send data only, else false. - */ - virtual RequestContext createRequest(bool isOneway); - - /*! - * @brief This function performs request. - * - * @param[in] request Request context to perform. - */ - virtual void performRequest(RequestContext &request); - - /*! - * @brief This function releases request context. - * - * @param[in] request Request context to release. - */ - virtual void releaseRequest(RequestContext &request); - - /*! - * @brief This function sets error handler function for infrastructure errors. - * - * @param[in] error_handler Pointer to error handler function. - */ - void setErrorHandler(client_error_handler_t error_handler) { m_errorHandler = error_handler; } - - /*! - * @brief This function calls error handler callback function with given status. - * - * Function is called in client shim code at the end of function when error occurred. - * - * @param[in] err Specify function status at the end of eRPC call. - * @param[in] functionID Specify eRPC function call. - */ - void callErrorHandler(erpc_status_t err, uint32_t functionID); - -#if ERPC_NESTED_CALLS - /*! - * @brief This function sets server used for nested calls. - * - * @param[in] server Server used for nested calls. - */ - void setServer(Server *server) { m_server = server; } - - /*! - * @brief This function sets server thread id. - * - * @param[in] serverThreadId Id of thread where server run function is executed. - */ - void setServerThreadId(Thread::thread_id_t serverThreadId) { m_serverThreadId = serverThreadId; } -#endif - -protected: - MessageBufferFactory *m_messageFactory; //!< Message buffer factory to use. - CodecFactory *m_codecFactory; //!< Codec to use. - Transport *m_transport; //!< Transport layer to use. - uint32_t m_sequence; //!< Sequence number. - client_error_handler_t m_errorHandler; //!< Pointer to function error handler. -#if ERPC_NESTED_CALLS - Server *m_server; //!< Server used for nested calls. - Thread::thread_id_t m_serverThreadId; //!< Thread in which server run function is called. -#endif - - /*! - * @brief This function performs request. - * - * Should be called in non server context (do not call another eRPC function in server - * remote call implementation). - * - * @param[in] request Request context to perform. - */ - virtual void performClientRequest(RequestContext &request); - -#if ERPC_NESTED_CALLS - /*! - * @brief This function performs nested request. - * - * Used when from eRPC function server implementation context is called new eRPC function. - * - * @param[in] request Request context to perform. - */ - virtual void performNestedClientRequest(RequestContext &request); -#endif - - //! @brief Validate that an incoming message is a reply. - virtual erpc_status_t verifyReply(RequestContext &request); - - /*! - * @brief Create message buffer and codec. - * - * The new codec is set to use the new message buffer. Both codec and buffer are allocated - * with the relevant factories. - * - * @return Pointer to created codec with message buffer. - */ - Codec *createBufferAndCodec(void); - -private: - ClientManager(const ClientManager &); //!< Disable copy ctor. - ClientManager &operator=(const ClientManager &); //!< Disable copy ctor. -}; - -/*! - * @brief Encapsulates all information about a request. - * - * @ingroup infra_client - */ -class RequestContext -{ -public: - /*! - * @brief Constructor. - * - * This function sets request context attributes. - * - * @param[in] sequence Sequence number. - * @param[in] codec Set in inout codec. - * @param[in] isOneway Set information if codec is only oneway or bidirectional. - */ - RequestContext(uint32_t sequence, Codec *codec, bool isOneway) - : m_sequence(sequence) - , m_codec(codec) - , m_oneway(isOneway) - { - } - - /*! - * @brief Get inout codec (for writing). - * - * @return Inout codec. - */ - Codec *getCodec(void) { return m_codec; } - - /*! - * @brief Get sequence number (be sure that reply belong to current request). - * - * @return Sequence number. - */ - uint32_t getSequence(void) const { return m_sequence; } - - /*! - * @brief Returns information if request context is oneway or not. - * - * @retval True when request context is oneway direction, else false. - */ - bool isOneway(void) const { return m_oneway; } - - /*! - * @brief Set request context to be oneway type (only send data). - * - * @return Set request context to be oneway. - */ - void setIsOneway(bool oneway) { m_oneway = oneway; } - -protected: - uint32_t m_sequence; //!< Sequence number. To be sure that reply belong to current request. - Codec *m_codec; //!< Inout codec. Codec for receiving and sending data. - bool m_oneway; //!< When true, request context will be oneway type (only send data). -}; - -} // namespace erpc - -/*! @} */ - -#endif - -#endif // _EMBEDDED_RPC__CLIENT_MANAGER_H_ +/* + * Copyright (c) 2014-2016, Freescale Semiconductor, Inc. + * Copyright 2016-2017 NXP + * All rights reserved. + * + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef _EMBEDDED_RPC__CLIENT_MANAGER_H_ +#define _EMBEDDED_RPC__CLIENT_MANAGER_H_ + +#ifdef __cplusplus +#include "erpc_codec.h" +#include "erpc_config_internal.h" +#include "erpc_client_server_common.h" +#if ERPC_NESTED_CALLS +#include "erpc_server.h" +#include "erpc_threading.h" +#endif + +/*! + * @addtogroup infra_client + * @{ + * @file + */ + +extern "C" { +#endif + +typedef void (*client_error_handler_t)(erpc_status_t err, + uint32_t functionID); /*!< eRPC error handler function type. */ + +#ifdef __cplusplus +} + +//////////////////////////////////////////////////////////////////////////////// +// Classes +//////////////////////////////////////////////////////////////////////////////// + +namespace erpc { +class RequestContext; +#if ERPC_NESTED_CALLS +class Server; +#endif + +/*! + * @brief Base client implementation. + * + * @ingroup infra_client + */ +class ClientManager : public ClientServerCommon +{ +public: + /*! + * @brief Constructor. + * + * This function initializes object attributes. + */ + ClientManager(void) + : ClientServerCommon() + , m_messageFactory(NULL) + , m_codecFactory(NULL) + , m_transport(NULL) + , m_sequence(0) + , m_errorHandler(NULL) +#if ERPC_NESTED_CALLS + , m_server(NULL) + , m_serverThreadId(NULL) +#endif + { + } + + /*! + * @brief ClientManager destructor + */ + virtual ~ClientManager(void) {} + + /*! + * @brief This function sets message buffer factory to use. + * + * @param[in] factory Message buffer factory to use. + */ + void setMessageBufferFactory(MessageBufferFactory *factory) { m_messageFactory = factory; } + + /*! + * @brief This function sets codec factory to use. + * + * @param[in] factory Codec factory to use. + */ + void setCodecFactory(CodecFactory *factory) { m_codecFactory = factory; } + + /*! + * @brief This function sets transport layer to use. + * + * It also set messageBufferFactory to the same as in transport layer. + * + * @param[in] transport Transport layer to use. + */ + void setTransport(Transport *transport); + + /*! + * @brief This function creates request context. + * + * @param[in] isOneway True if need send data only, else false. + */ + virtual RequestContext createRequest(bool isOneway); + + /*! + * @brief This function performs request. + * + * @param[in] request Request context to perform. + */ + virtual void performRequest(RequestContext &request); + + /*! + * @brief This function releases request context. + * + * @param[in] request Request context to release. + */ + virtual void releaseRequest(RequestContext &request); + + /*! + * @brief This function sets error handler function for infrastructure errors. + * + * @param[in] error_handler Pointer to error handler function. + */ + void setErrorHandler(client_error_handler_t error_handler) { m_errorHandler = error_handler; } + + /*! + * @brief This function calls error handler callback function with given status. + * + * Function is called in client shim code at the end of function when error occurred. + * + * @param[in] err Specify function status at the end of eRPC call. + * @param[in] functionID Specify eRPC function call. + */ + void callErrorHandler(erpc_status_t err, uint32_t functionID); + +#if ERPC_NESTED_CALLS + /*! + * @brief This function sets server used for nested calls. + * + * @param[in] server Server used for nested calls. + */ + void setServer(Server *server) { m_server = server; } + + /*! + * @brief This function sets server thread id. + * + * @param[in] serverThreadId Id of thread where server run function is executed. + */ + void setServerThreadId(Thread::thread_id_t serverThreadId) { m_serverThreadId = serverThreadId; } +#endif + +protected: + MessageBufferFactory *m_messageFactory; //!< Message buffer factory to use. + CodecFactory *m_codecFactory; //!< Codec to use. + Transport *m_transport; //!< Transport layer to use. + uint32_t m_sequence; //!< Sequence number. + client_error_handler_t m_errorHandler; //!< Pointer to function error handler. +#if ERPC_NESTED_CALLS + Server *m_server; //!< Server used for nested calls. + Thread::thread_id_t m_serverThreadId; //!< Thread in which server run function is called. +#endif + + /*! + * @brief This function performs request. + * + * Should be called in non server context (do not call another eRPC function in server + * remote call implementation). + * + * @param[in] request Request context to perform. + */ + virtual void performClientRequest(RequestContext &request); + +#if ERPC_NESTED_CALLS + /*! + * @brief This function performs nested request. + * + * Used when from eRPC function server implementation context is called new eRPC function. + * + * @param[in] request Request context to perform. + */ + virtual void performNestedClientRequest(RequestContext &request); +#endif + + //! @brief Validate that an incoming message is a reply. + virtual erpc_status_t verifyReply(RequestContext &request); + + /*! + * @brief Create message buffer and codec. + * + * The new codec is set to use the new message buffer. Both codec and buffer are allocated + * with the relevant factories. + * + * @return Pointer to created codec with message buffer. + */ + Codec *createBufferAndCodec(void); + +private: + ClientManager(const ClientManager &); //!< Disable copy ctor. + ClientManager &operator=(const ClientManager &); //!< Disable copy ctor. +}; + +/*! + * @brief Encapsulates all information about a request. + * + * @ingroup infra_client + */ +class RequestContext +{ +public: + /*! + * @brief Constructor. + * + * This function sets request context attributes. + * + * @param[in] sequence Sequence number. + * @param[in] codec Set in inout codec. + * @param[in] isOneway Set information if codec is only oneway or bidirectional. + */ + RequestContext(uint32_t sequence, Codec *codec, bool isOneway) + : m_sequence(sequence) + , m_codec(codec) + , m_oneway(isOneway) + { + } + + /*! + * @brief Get inout codec (for writing). + * + * @return Inout codec. + */ + Codec *getCodec(void) { return m_codec; } + + /*! + * @brief Get sequence number (be sure that reply belong to current request). + * + * @return Sequence number. + */ + uint32_t getSequence(void) const { return m_sequence; } + + /*! + * @brief Returns information if request context is oneway or not. + * + * @retval True when request context is oneway direction, else false. + */ + bool isOneway(void) const { return m_oneway; } + + /*! + * @brief Set request context to be oneway type (only send data). + * + * @return Set request context to be oneway. + */ + void setIsOneway(bool oneway) { m_oneway = oneway; } + +protected: + uint32_t m_sequence; //!< Sequence number. To be sure that reply belong to current request. + Codec *m_codec; //!< Inout codec. Codec for receiving and sending data. + bool m_oneway; //!< When true, request context will be oneway type (only send data). +}; + +} // namespace erpc + +/*! @} */ + +#endif + +#endif // _EMBEDDED_RPC__CLIENT_MANAGER_H_ diff --git a/erpc_c/infra/erpc_client_server_common.h b/erpc_c/infra/erpc_client_server_common.h new file mode 100644 index 000000000..8935c7ad2 --- /dev/null +++ b/erpc_c/infra/erpc_client_server_common.h @@ -0,0 +1,96 @@ +/* + * Copyright 2020 NXP + * Copyright 2020 ACRIOS Systems s.r.o. + * All rights reserved. + * + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef _EMBEDDED_RPC__CLIENTSERVERCOMMON_H_ +#define _EMBEDDED_RPC__CLIENTSERVERCOMMON_H_ + +#include "erpc_config_internal.h" +#if ERPC_MESSAGE_LOGGING +#include "erpc_message_loggers.h" +#endif +#if ERPC_PRE_POST_ACTION +#include "erpc_pre_post_action.h" +#endif + +/*! + * @addtogroup infra_transport + * @{ + * @file + */ + +//////////////////////////////////////////////////////////////////////////////// +// Classes +//////////////////////////////////////////////////////////////////////////////// + +namespace erpc { + +/*! + * @brief Common class inheritand by client and server class. + * + * @ingroup infra_utility + */ +class ClientServerCommon +#if ERPC_MESSAGE_LOGGING +# ifdef ERPC_OTHER_INHERITANCE +, +# else +# define ERPC_OTHER_INHERITANCE 1 +: +# endif +public MessageLoggers +#endif +#if ERPC_PRE_POST_ACTION +# ifdef ERPC_OTHER_INHERITANCE +, +# else +# define ERPC_OTHER_INHERITANCE 1 +: +# endif +public PrePostAction +#endif +{ +public: + /*! + * @brief ClientServerCommon constructor. + */ + ClientServerCommon(void) +#ifdef ERPC_OTHER_INHERITANCE +# undef ERPC_OTHER_INHERITANCE +#endif +#if ERPC_MESSAGE_LOGGING +# ifdef ERPC_OTHER_INHERITANCE + , +# else +# define ERPC_OTHER_INHERITANCE 1 + : +# endif + MessageLoggers() +#endif +#if ERPC_PRE_POST_ACTION +# ifdef ERPC_OTHER_INHERITANCE + , +# else +# define ERPC_OTHER_INHERITANCE 1 + : +# endif + PrePostAction() +#endif +{}; + + /*! + * @brief ClientServerCommon destructor + */ + ~ClientServerCommon(void){}; +}; + +} // namespace erpc + +/*! @} */ + +#endif // _EMBEDDED_RPC__CLIENTSERVERCOMMON_H_ diff --git a/erpc_c/infra/erpc_pre_post_action.cpp b/erpc_c/infra/erpc_pre_post_action.cpp new file mode 100644 index 000000000..eaa2619a8 --- /dev/null +++ b/erpc_c/infra/erpc_pre_post_action.cpp @@ -0,0 +1,49 @@ +/* + * Copyright 2020 NXP + * Copyright 2020 ACRIOS Systems s.r.o. + * All rights reserved. + * + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include "erpc_pre_post_action.h" +#include "erpc_config_internal.h" +#if ERPC_PRE_POST_ACTION_DEFAULT +#include "erpc_setup_extensions.h" +#endif + +using namespace erpc; +using namespace std; + +//////////////////////////////////////////////////////////////////////////////// +// Code +//////////////////////////////////////////////////////////////////////////////// + +void PrePostAction::addPreCB(pre_post_action_cb preCB) +{ + if (preCB) + { + m_preCB = preCB; + } +#if ERPC_PRE_POST_ACTION_DEFAULT + else + { + m_preCB = erpc_pre_cb_default; + } +#endif +} + +void PrePostAction::addPostCB(pre_post_action_cb postCB) +{ + if (postCB) + { + m_postCB = postCB; + } +#if ERPC_PRE_POST_ACTION_DEFAULT + else + { + m_postCB = erpc_post_cb_default; + } +#endif +} \ No newline at end of file diff --git a/erpc_c/infra/erpc_pre_post_action.h b/erpc_c/infra/erpc_pre_post_action.h new file mode 100644 index 000000000..bedb0679d --- /dev/null +++ b/erpc_c/infra/erpc_pre_post_action.h @@ -0,0 +1,95 @@ +/* + * Copyright 2020 NXP + * Copyright 2020 ACRIOS Systems s.r.o. + * All rights reserved. + * + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef _EMBEDDED_RPC__PREPOSTACTION_H_ +#define _EMBEDDED_RPC__PREPOSTACTION_H_ + +#ifdef __cplusplus +#include +/*! + * @addtogroup infra_transport + * @{ + * @file + */ +extern "C" { +#endif + +typedef void (*pre_post_action_cb)(void); + +#ifdef __cplusplus +} + +//////////////////////////////////////////////////////////////////////////////// +// Classes +//////////////////////////////////////////////////////////////////////////////// + +namespace erpc { + +/*! + * @brief Client and server may used cb functions before and after rpc call. + * + * @ingroup infra_utility + */ +class PrePostAction +{ +public: + /*! + * @brief PrePostAction constructor. + */ + PrePostAction() + : m_preCB(NULL) + , m_postCB(NULL){}; + + /*! + * @brief This function sets "before eRPC call start" callback function. + * + * @param[in] preCB Pointer for callback function. When NULL and ERPC_PRE_POST_ACTION_DEFAULT + * is enabled then default function will be set. + */ + void addPreCB(pre_post_action_cb preCB); + + /*! + * @brief This function sets "after eRPC call finish" callback function. + * + * @param[in] postCB Pointer for callback function. When NULL and ERPC_PRE_POST_ACTION_DEFAULT + * is enabled then default function will be set. + */ + void addPostCB(pre_post_action_cb postCB); + + /*! + * @brief This function returns "before eRPC call start" callback function. + * + * @return preCB Pointer for callback function. + */ + pre_post_action_cb getPreCB() { return m_preCB; } + + /*! + * @brief This function returns "after eRPC call finish" callback function. + * + * @return postCB Pointer for callback function. + */ + pre_post_action_cb getPostCB() { return m_postCB; } + + /*! + * @brief PrePostAction destructor + */ + ~PrePostAction(void){}; + +protected: + pre_post_action_cb m_preCB; /*!< Pointer to "before eRPC call start" callback function. */ + pre_post_action_cb m_postCB; /*!< Pointer to after eRPC call finish" callback function. */ +}; + +} // namespace erpc + +/*! @} */ + +#endif + +#endif // _EMBEDDED_RPC__PREPOSTACTION_H_ diff --git a/erpc_c/infra/erpc_server.h b/erpc_c/infra/erpc_server.h index 0ce3b7184..9482eb6b5 100644 --- a/erpc_c/infra/erpc_server.h +++ b/erpc_c/infra/erpc_server.h @@ -12,12 +12,10 @@ #include "erpc_codec.h" #include "erpc_config_internal.h" +#include "erpc_client_server_common.h" #if ERPC_NESTED_CALLS #include "erpc_client_manager.h" #endif -#if ERPC_MESSAGE_LOGGING -#include "erpc_message_loggers.h" -#endif /*! * @addtogroup infra_server @@ -101,11 +99,7 @@ class Service * * @ingroup infra_server */ -#if ERPC_MESSAGE_LOGGING -class Server : public MessageLoggers -#else -class Server -#endif +class Server : public ClientServerCommon { public: /*! @@ -114,12 +108,8 @@ class Server * This function initializes object attributes. */ Server(void) -#if ERPC_MESSAGE_LOGGING - : MessageLoggers() + : ClientServerCommon() , m_messageFactory() -#else - : m_messageFactory() -#endif , m_codecFactory() , m_transport() , m_firstService() diff --git a/erpc_c/infra/erpc_simple_server.cpp b/erpc_c/infra/erpc_simple_server.cpp index 7777c3e5f..d895d2013 100644 --- a/erpc_c/infra/erpc_simple_server.cpp +++ b/erpc_c/infra/erpc_simple_server.cpp @@ -61,6 +61,15 @@ erpc_status_t SimpleServer::runInternalBegin(Codec **codec, MessageBuffer &buff, // Receive the next invocation request. erpc_status_t err = m_transport->receive(&buff); + +#if ERPC_PRE_POST_ACTION + pre_post_action_cb preCB = this->getPreCB(); + if (preCB) + { + preCB(); + } +#endif + if (err) { // Dispose of buffers. @@ -132,6 +141,14 @@ erpc_status_t SimpleServer::runInternalEnd(Codec *codec, message_type_t msgType, // Dispose of buffers and codecs. disposeBufferAndCodec(codec); +#if ERPC_PRE_POST_ACTION + pre_post_action_cb postCB = this->getPostCB(); + if (postCB) + { + postCB(); + } +#endif + return err; } diff --git a/erpc_c/port/erpc_config_internal.h b/erpc_c/port/erpc_config_internal.h index 12c975669..f49cabbf2 100644 --- a/erpc_c/port/erpc_config_internal.h +++ b/erpc_c/port/erpc_config_internal.h @@ -1,6 +1,7 @@ /* * Copyright (c) 2016, Freescale Semiconductor, Inc. * Copyright 2016-2017 NXP + * Copyright 2020 ACRIOS Systems s.r.o. * All rights reserved. * * @@ -132,6 +133,16 @@ #endif #endif +// Disabling pre and post callback function related code. +#if !defined(ERPC_PRE_POST_ACTION) + #define ERPC_PRE_POST_ACTION (ERPC_PRE_POST_ACTION_DISABLED) +#endif + +// Disabling pre and post default callback function code. +#if !defined(ERPC_PRE_POST_ACTION_DEFAULT) + #define ERPC_PRE_POST_ACTION_DEFAULT (ERPC_PRE_POST_ACTION_DEFAULT_DISABLED) +#endif + /* clang-format on */ #endif // _ERPC_DETECT_H_ //////////////////////////////////////////////////////////////////////////////// diff --git a/erpc_c/port/erpc_setup_extensions.h b/erpc_c/port/erpc_setup_extensions.h new file mode 100644 index 000000000..ed443df8a --- /dev/null +++ b/erpc_c/port/erpc_setup_extensions.h @@ -0,0 +1,81 @@ +/* + * Copyright 2020 NXP + * Copyright 2020 ACRIOS Systems s.r.o. + * All rights reserved. + * + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef _EMBEDDED_RPC__SETUP_EXTENSIONS_H_ +#define _EMBEDDED_RPC__SETUP_EXTENSIONS_H_ + + +#include "erpc_config_internal.h" + +#if ERPC_THREADS + +#if ERPC_THREADS_IS(FREERTOS) +#include "FreeRTOS.h" +#include "timers.h" +#include "task.h" +#endif + +#endif // ERPC_THREADS + +/*! + * @addtogroup port_setup_extensions + * @{ + * @file + */ + +//////////////////////////////////////////////////////////////////////////////// +// Declarations +//////////////////////////////////////////////////////////////////////////////// + +#ifdef __cplusplus + +namespace erpc { +/*! + * @brief This function is used for default pre erpc call action. + */ +void erpc_pre_cb_default(void); + +/*! + * @brief This function is used for default post erpc call action. + */ +void erpc_post_cb_default(void); +} + +extern "C" { +#endif + +/*! + * @brief This function is used for creating default timer for task freeze detection. + * + * @param[in] waitTime Platform specific time to throw error cb in case of eRPC call freeze. + */ +void erpc_create_timer_default(uint32_t waitTime); + +/*! + * @brief This function returns default eRPC call progress status. + * + * @return True if eRPC call is in progress, otherwise False. + */ +bool is_erpc_call_executed_default(void); + +/*! + * @brief This function sets default eRPC call progress status. + * + * @param[in] erpc_call Set erpc call progress status. + * (E.G. in case of frezee and user will reinitialize eRPC communication) + */ +void set_erpc_call_execution_state_default(bool erpc_call); + +#ifdef __cplusplus +} +#endif + +/*! @} */ + +#endif // _EMBEDDED_RPC__SETUP_EXTENSIONS_H_ diff --git a/erpc_c/port/erpc_setup_extensions_freertos.cpp b/erpc_c/port/erpc_setup_extensions_freertos.cpp new file mode 100644 index 000000000..57be8b745 --- /dev/null +++ b/erpc_c/port/erpc_setup_extensions_freertos.cpp @@ -0,0 +1,51 @@ +/* + * Copyright 2020 NXP + * Copyright 2020 ACRIOS Systems s.r.o. + * All rights reserved. + * + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include "erpc_setup_extensions.h" + +#include + +using namespace erpc; + +static bool s_erpc_call = false; +TimerHandle_t g_erpc_call_timer_cb = NULL; + +void erpc::erpc_pre_cb_default() +{ + s_erpc_call = true; + assert(g_erpc_call_timer_cb && "If you want use default pre cb action, do not forget call erpc_create_timer."); + xTimerStart(g_erpc_call_timer_cb, 0); +} + +void erpc::erpc_post_cb_default() +{ + xTimerStop(g_erpc_call_timer_cb, 0); + s_erpc_call = false; +} + +void erpc_call_timer_cb_default(TimerHandle_t xTimer) +{ + assert(1 != 1 && "eRPC task freezed."); +} + +void erpc_create_timer_default(uint32_t waitTime = 5 * 60 * 1000) +{ + g_erpc_call_timer_cb = xTimerCreate("Erpc client call timer", waitTime, pdFALSE, NULL, erpc_call_timer_cb_default); + assert(g_erpc_call_timer_cb && "Creating eRPC timer failed."); +} + +bool is_erpc_call_executed_default() +{ + return s_erpc_call; +} + +void set_erpc_call_execution_state_default(bool erpc_call) +{ + s_erpc_call = erpc_call; +} \ No newline at end of file diff --git a/erpc_c/port/erpc_threading.h b/erpc_c/port/erpc_threading.h index 8d750f9a3..2c0b9e058 100644 --- a/erpc_c/port/erpc_threading.h +++ b/erpc_c/port/erpc_threading.h @@ -32,7 +32,8 @@ #endif #elif ERPC_THREADS_IS(WIN32) #include "windows.h" -#endif // ERPC_THREADS_IS + +#endif // ERPC_THREADS /*! * @addtogroup port_threads diff --git a/erpc_c/setup/erpc_arbitrated_client_setup.cpp b/erpc_c/setup/erpc_arbitrated_client_setup.cpp index ec8d16501..a40278373 100644 --- a/erpc_c/setup/erpc_arbitrated_client_setup.cpp +++ b/erpc_c/setup/erpc_arbitrated_client_setup.cpp @@ -1,6 +1,7 @@ /* * Copyright (c) 2016, Freescale Semiconductor, Inc. * Copyright 2016-2020 NXP + * Copyright 2020 ACRIOS Systems s.r.o. * All rights reserved. * * @@ -111,6 +112,22 @@ bool erpc_arbitrated_client_add_message_logger(erpc_transport_t transport) } #endif +#if ERPC_PRE_POST_ACTION +void erpc_arbitrated_client_add_pre_cb_action(pre_post_action_cb preCB) +{ + assert(g_client); + + g_client->addPreCB(preCB); +} + +void erpc_arbitrated_client_add_post_cb_action(pre_post_action_cb postCB) +{ + assert(g_client); + + g_client->addPostCB(postCB); +} +#endif + void erpc_arbitrated_client_deinit(void) { s_client.destroy(); diff --git a/erpc_c/setup/erpc_arbitrated_client_setup.h b/erpc_c/setup/erpc_arbitrated_client_setup.h index e5ce7fe60..bbe257247 100644 --- a/erpc_c/setup/erpc_arbitrated_client_setup.h +++ b/erpc_c/setup/erpc_arbitrated_client_setup.h @@ -13,6 +13,9 @@ #include "erpc_common.h" #include "erpc_config_internal.h" #include "erpc_mbf_setup.h" +#if ERPC_PRE_POST_ACTION +#include "erpc_pre_post_action.h" +#endif #if ERPC_NESTED_CALLS #include "erpc_server_setup.h" #endif @@ -107,6 +110,24 @@ void erpc_arbitrated_client_set_server_thread_id(void *serverThreadId); bool erpc_arbitrated_client_add_message_logger(erpc_transport_t transport); #endif +#if ERPC_PRE_POST_ACTION +/*! + * @brief This function set callback function executed at the beginning of eRPC call. + * + * @param[in] preCB Callback used at the beginning of eRPC call. When NULL and ERPC_PRE_POST_ACTION_DEFAULT + * is enabled then default function will be set. + */ +void erpc_arbitrated_client_add_pre_cb_action(pre_post_action_cb preCB); + +/*! + * @brief This function set callback function executed at the end of eRPC call. + * + * @param[in] postCB Callback used at the end of eRPC call. When NULL and ERPC_PRE_POST_ACTION_DEFAULT + * is enabled then default function will be set. + */ +void erpc_arbitrated_client_add_post_cb_action(pre_post_action_cb postCB); +#endif + /*! * @brief This function de-initializes client. * diff --git a/erpc_c/setup/erpc_client_setup.cpp b/erpc_c/setup/erpc_client_setup.cpp index 0b5c6137c..d9823ec76 100644 --- a/erpc_c/setup/erpc_client_setup.cpp +++ b/erpc_c/setup/erpc_client_setup.cpp @@ -1,6 +1,7 @@ /* * Copyright (c) 2014-2016, Freescale Semiconductor, Inc. * Copyright 2016-2017 NXP + * Copyright 2020 ACRIOS Systems s.r.o. * All rights reserved. * * @@ -95,6 +96,22 @@ bool erpc_client_add_message_logger(erpc_transport_t transport) } #endif +#if ERPC_PRE_POST_ACTION +void erpc_client_add_pre_cb_action(pre_post_action_cb preCB) +{ + assert(g_client); + + g_client->addPreCB(preCB); +} + +void erpc_client_add_post_cb_action(pre_post_action_cb postCB) +{ + assert(g_client); + + g_client->addPostCB(postCB); +} +#endif + void erpc_client_deinit(void) { s_crc16.destroy(); diff --git a/erpc_c/setup/erpc_client_setup.h b/erpc_c/setup/erpc_client_setup.h index 61c90e53c..c544f1ae5 100644 --- a/erpc_c/setup/erpc_client_setup.h +++ b/erpc_c/setup/erpc_client_setup.h @@ -13,6 +13,9 @@ #include "erpc_common.h" #include "erpc_config_internal.h" #include "erpc_mbf_setup.h" +#if ERPC_PRE_POST_ACTION +#include "erpc_pre_post_action.h" +#endif #if ERPC_NESTED_CALLS #include "erpc_server_setup.h" #endif @@ -97,6 +100,24 @@ void erpc_client_set_server_thread_id(void *serverThreadId); bool erpc_client_add_message_logger(erpc_transport_t transport); #endif +#if ERPC_PRE_POST_ACTION +/*! + * @brief This function set callback function executed at the beginning of eRPC call. + * + * @param[in] preCB Callback used at the beginning of eRPC call. When NULL and ERPC_PRE_POST_ACTION_DEFAULT + * is enabled then default function will be set. + */ +void erpc_client_add_pre_cb_action(pre_post_action_cb preCB); + +/*! + * @brief This function set callback function executed at the end of eRPC call. + * + * @param[in] postCB Callback used at the end of eRPC call. When NULL and ERPC_PRE_POST_ACTION_DEFAULT + * is enabled then default function will be set. + */ +void erpc_client_add_post_cb_action(pre_post_action_cb postCB); +#endif + /*! * @brief This function de-initializes client. * diff --git a/erpc_c/setup/erpc_server_setup.cpp b/erpc_c/setup/erpc_server_setup.cpp index 5bf370574..e3379f0be 100644 --- a/erpc_c/setup/erpc_server_setup.cpp +++ b/erpc_c/setup/erpc_server_setup.cpp @@ -1,6 +1,7 @@ /* * Copyright (c) 2014-2016, Freescale Semiconductor, Inc. * Copyright 2016-2017 NXP + * Copyright 2020 ACRIOS Systems s.r.o. * All rights reserved. * * @@ -116,3 +117,19 @@ bool erpc_server_add_message_logger(erpc_transport_t transport) return false; } #endif + +#if ERPC_PRE_POST_ACTION +void erpc_client_add_pre_cb_action(pre_post_action_cb preCB) +{ + assert(g_server); + + g_server->addPreCB(preCB); +} + +void erpc_client_add_post_cb_action(pre_post_action_cb postCB) +{ + assert(g_server); + + g_server->addPostCB(postCB); +} +#endif diff --git a/erpc_c/setup/erpc_server_setup.h b/erpc_c/setup/erpc_server_setup.h index dd6d42f34..cbee335c0 100644 --- a/erpc_c/setup/erpc_server_setup.h +++ b/erpc_c/setup/erpc_server_setup.h @@ -1,6 +1,7 @@ /* * Copyright (c) 2014-2016, Freescale Semiconductor, Inc. * Copyright 2016-2017 NXP + * Copyright 2020 ACRIOS Systems s.r.o. * All rights reserved. * * @@ -14,6 +15,9 @@ #include "erpc_config_internal.h" #include "erpc_mbf_setup.h" #include "erpc_transport_setup.h" +#if ERPC_PRE_POST_ACTION +#include "erpc_pre_post_action.h" +#endif /*! * @addtogroup server_setup @@ -124,6 +128,24 @@ void erpc_server_stop(void); bool erpc_server_add_message_logger(erpc_transport_t transport); #endif +#if ERPC_PRE_POST_ACTION +/*! + * @brief This function set callback function executed at the beginning of eRPC call. + * + * @param[in] preCB Callback used at the beginning of eRPC call. When NULL and ERPC_PRE_POST_ACTION_DEFAULT + * is enabled then default function will be set. + */ +void erpc_server_add_pre_cb_action(pre_post_action_cb preCB); + +/*! + * @brief This function set callback function executed at the end of eRPC call. + * + * @param[in] postCB Callback used at the end of eRPC call. When NULL and ERPC_PRE_POST_ACTION_DEFAULT + * is enabled then default function will be set. + */ +void erpc_server_add_post_cb_action(pre_post_action_cb postCB); +#endif + //@} #ifdef __cplusplus diff --git a/erpcgen/src/templates/c_client_source.template b/erpcgen/src/templates/c_client_source.template index 10711d7c9..63ccc2fef 100644 --- a/erpcgen/src/templates/c_client_source.template +++ b/erpcgen/src/templates/c_client_source.template @@ -47,6 +47,14 @@ extern ClientManager *g_client; {% if fn.returnValue.type.isNotVoid %} {$fn.returnValue.resultVariable}{% if fn.returnValue.isNullReturnType %} = NULL{%endif%}; +#if ERPC_PRE_POST_ACTION + pre_post_action_cb preCB = g_client->getPreCB(); + if (preCB) + { + preCB(); + } +#endif + {% endif -- isNotVoid %} // Get a new request. {% if !fn.isReturnValue %} @@ -132,6 +140,15 @@ extern ClientManager *g_client; g_client->callErrorHandler(err, {$functionIDName}); {% endif -- generateErrorChecks %} {% if generateErrorChecks && fn.returnValue.type.isNotVoid %} + +#if ERPC_PRE_POST_ACTION + pre_post_action_cb postCB = g_client->getPostCB(); + if (postCB) + { + postCB(); + } +#endif + {% if empty(fn.returnValue.errorReturnValue) == false && fn.returnValue.isNullReturnType == false %} if (err) From 2414bbad5360652af3d773a95c026f1a71bb3d43 Mon Sep 17 00:00:00 2001 From: Cervenka Dusan Date: Fri, 25 Sep 2020 09:50:43 +0200 Subject: [PATCH 31/96] Extend error msg for python server service handle function. --- erpc_python/erpc/server.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/erpc_python/erpc/server.py b/erpc_python/erpc/server.py index ab14a9582..9c991e193 100644 --- a/erpc_python/erpc/server.py +++ b/erpc_python/erpc/server.py @@ -1,6 +1,7 @@ #!/usr/bin/env python # Copyright 2016 NXP +# Copyright 2020 ACRIOS Systems s.r.o. # All rights reserved. # # SPDX-License-Identifier: BSD-3-Clause @@ -20,8 +21,8 @@ def service_id(self): def handle_invocation(self, methodId, sequence, codec): try: self._methods[methodId](sequence, codec) - except KeyError: - raise RequestError("invalid method ID (%d)" % (methodId)) + except Exception as e: + raise RequestError("invalid method ID (%d) or method implementation: %s" % (methodId, str(e))) class Server(object): def __init__(self, transport=None, codecClass=None): From d3cc8fc74e5fbb4c5fc48139933d05d444a82c30 Mon Sep 17 00:00:00 2001 From: Dusan Cervenka Date: Fri, 25 Sep 2020 23:28:12 +0200 Subject: [PATCH 32/96] Update based on qcabrol review. --- erpc_c/port/erpc_setup_extensions.h | 31 ++++++--- .../port/erpc_setup_extensions_freertos.cpp | 66 ++++++++++++++----- 2 files changed, 72 insertions(+), 25 deletions(-) diff --git a/erpc_c/port/erpc_setup_extensions.h b/erpc_c/port/erpc_setup_extensions.h index ed443df8a..0824a62ab 100644 --- a/erpc_c/port/erpc_setup_extensions.h +++ b/erpc_c/port/erpc_setup_extensions.h @@ -10,15 +10,14 @@ #ifndef _EMBEDDED_RPC__SETUP_EXTENSIONS_H_ #define _EMBEDDED_RPC__SETUP_EXTENSIONS_H_ - #include "erpc_config_internal.h" #if ERPC_THREADS #if ERPC_THREADS_IS(FREERTOS) #include "FreeRTOS.h" -#include "timers.h" #include "task.h" +#include "timers.h" #endif #endif // ERPC_THREADS @@ -45,32 +44,44 @@ void erpc_pre_cb_default(void); * @brief This function is used for default post erpc call action. */ void erpc_post_cb_default(void); -} +} // namespace erpc extern "C" { #endif +#if ERPC_THREADS_IS(FREERTOS) +typedef TimerCallbackFunction_t erpc_call_timer_cb_default_t; +#else +typedef void *erpc_call_timer_cb_default_t; +#endif + /*! - * @brief This function is used for creating default timer for task freeze detection. + * @brief This function is used for initializing variables for task freeze detection. * + * @param[in] erpc_call_timer_cb Callback function called when eRPC call freeze. + * When NULL default callback will be used. * @param[in] waitTime Platform specific time to throw error cb in case of eRPC call freeze. */ -void erpc_create_timer_default(uint32_t waitTime); +void erpc_init_call_progress_detection_default(erpc_call_timer_cb_default_t erpc_call_timer_cb, uint32_t waitTime); + +/*! + * @brief This function is used for deinitialization variables for task freeze detection. + */ +void erpc_deinit_call_progress_detection_default(void); /*! * @brief This function returns default eRPC call progress status. * * @return True if eRPC call is in progress, otherwise False. */ -bool is_erpc_call_executed_default(void); +bool erpc_is_call_in_progress_default(void); /*! - * @brief This function sets default eRPC call progress status. + * @brief This function resets eRPC state. * - * @param[in] erpc_call Set erpc call progress status. - * (E.G. in case of frezee and user will reinitialize eRPC communication) + * Can be used when user reinitialize communication between client and server. */ -void set_erpc_call_execution_state_default(bool erpc_call); +void erpc_reset_in_progress_state_default(void); #ifdef __cplusplus } diff --git a/erpc_c/port/erpc_setup_extensions_freertos.cpp b/erpc_c/port/erpc_setup_extensions_freertos.cpp index 57be8b745..e7bd72409 100644 --- a/erpc_c/port/erpc_setup_extensions_freertos.cpp +++ b/erpc_c/port/erpc_setup_extensions_freertos.cpp @@ -8,25 +8,27 @@ */ #include "erpc_setup_extensions.h" +#include "erpc_threading.h" #include using namespace erpc; -static bool s_erpc_call = false; -TimerHandle_t g_erpc_call_timer_cb = NULL; +static Semaphore *s_erpc_call_in_progress = NULL; +static TimerHandle_t s_erpc_call_timer_cb = NULL; void erpc::erpc_pre_cb_default() { - s_erpc_call = true; - assert(g_erpc_call_timer_cb && "If you want use default pre cb action, do not forget call erpc_create_timer."); - xTimerStart(g_erpc_call_timer_cb, 0); + assert(s_erpc_call_in_progress && "If you want use default pre cb action, do not forget call erpc_init_call_progress_detection_default."); + s_erpc_call_in_progress->get(s_erpc_call_in_progress->kWaitForever); + assert(s_erpc_call_timer_cb && "If you want use default pre cb action, do not forget call erpc_init_call_progress_detection_default."); + xTimerStart(s_erpc_call_timer_cb, 0); } void erpc::erpc_post_cb_default() { - xTimerStop(g_erpc_call_timer_cb, 0); - s_erpc_call = false; + xTimerStop(s_erpc_call_timer_cb, 0); + s_erpc_call_in_progress->put(); } void erpc_call_timer_cb_default(TimerHandle_t xTimer) @@ -34,18 +36,52 @@ void erpc_call_timer_cb_default(TimerHandle_t xTimer) assert(1 != 1 && "eRPC task freezed."); } -void erpc_create_timer_default(uint32_t waitTime = 5 * 60 * 1000) +void erpc_init_call_progress_detection_default(erpc_call_timer_cb_default_t erpc_call_timer_cb = NULL, uint32_t waitTime = 5 * 60 * 1000) { - g_erpc_call_timer_cb = xTimerCreate("Erpc client call timer", waitTime, pdFALSE, NULL, erpc_call_timer_cb_default); - assert(g_erpc_call_timer_cb && "Creating eRPC timer failed."); + s_erpc_call_in_progress = new Semaphore(1); + assert(s_erpc_call_in_progress && "Creating eRPC semaphore failed."); + + if (!erpc_call_timer_cb) + { + erpc_call_timer_cb = erpc_call_timer_cb_default; + } + s_erpc_call_timer_cb = xTimerCreate("Erpc client call timer", waitTime / 1000 / portTICK_PERIOD_MS, pdFALSE, NULL, erpc_call_timer_cb); + assert(s_erpc_call_timer_cb && "Creating eRPC timer failed."); +} + +void erpc_deinit_call_progress_detection_default() +{ + if(s_erpc_call_in_progress) + { + delete s_erpc_call_in_progress; + s_erpc_call_in_progress = NULL; + } + + if(s_erpc_call_timer_cb) + { + xTimerDelete(s_erpc_call_timer_cb, 0); + s_erpc_call_timer_cb = NULL; + } } -bool is_erpc_call_executed_default() +bool erpc_is_call_in_progress_default() { - return s_erpc_call; + assert(s_erpc_call_in_progress && "If you want use default pre cb action, do not forget call erpc_init_call_progress_detection_default."); + if (s_erpc_call_in_progress->get(0)) + { + s_erpc_call_in_progress->put(); + return false; + } + return true; } -void set_erpc_call_execution_state_default(bool erpc_call) +void erpc_reset_in_progress_state_default() { - s_erpc_call = erpc_call; -} \ No newline at end of file + + assert(s_erpc_call_in_progress && "If you want use default pre cb action, do not forget call erpc_init_call_progress_detection_default."); + s_erpc_call_in_progress->get(0); + s_erpc_call_in_progress->put(); + + assert(s_erpc_call_timer_cb && "If you want use default pre cb action, do not forget call erpc_init_call_progress_detection_default."); + xTimerStop(s_erpc_call_timer_cb, 0); +} From ef118a1ba37714829f2170eaf1fc05d88f42bd6f Mon Sep 17 00:00:00 2001 From: Dusan Cervenka Date: Fri, 25 Sep 2020 23:40:53 +0200 Subject: [PATCH 33/96] Lost copyright during merge --- erpc_c/infra/erpc_client_manager.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/erpc_c/infra/erpc_client_manager.h b/erpc_c/infra/erpc_client_manager.h index 5ccb5c03f..130b31c84 100644 --- a/erpc_c/infra/erpc_client_manager.h +++ b/erpc_c/infra/erpc_client_manager.h @@ -1,6 +1,7 @@ /* * Copyright (c) 2014-2016, Freescale Semiconductor, Inc. * Copyright 2016-2017 NXP + * Copyright 2020 ACRIOS Systems s.r.o. * All rights reserved. * * @@ -11,9 +12,9 @@ #define _EMBEDDED_RPC__CLIENT_MANAGER_H_ #ifdef __cplusplus +#include "erpc_client_server_common.h" #include "erpc_codec.h" #include "erpc_config_internal.h" -#include "erpc_client_server_common.h" #if ERPC_NESTED_CALLS #include "erpc_server.h" #include "erpc_threading.h" From e575decbe24f0807486b47107710d7e824044283 Mon Sep 17 00:00:00 2001 From: Dusan Cervenka Date: Sun, 27 Sep 2020 01:44:10 +0200 Subject: [PATCH 34/96] Formatting extension for VSC. --- utilities/styles/VSC/.vscode/launch.json | 15 ++ utilities/styles/VSC/.vscodeignore | 4 + utilities/styles/VSC/CHANGELOG.md | 9 + utilities/styles/VSC/README.md | 38 ++++ utilities/styles/VSC/img/erpcPic.png | Bin 0 -> 223127 bytes utilities/styles/VSC/img/templatePic.png | Bin 0 -> 230616 bytes .../styles/VSC/language-configuration.json | 30 +++ utilities/styles/VSC/package.json | 34 ++++ .../styles/VSC/syntaxes/erpc.tmLanguage.json | 174 ++++++++++++++++++ .../VSC/syntaxes/template.tmLanguage.json | 65 +++++++ .../styles/VSC/vsc-extension-quickstart.md | 29 +++ 11 files changed, 398 insertions(+) create mode 100644 utilities/styles/VSC/.vscode/launch.json create mode 100644 utilities/styles/VSC/.vscodeignore create mode 100644 utilities/styles/VSC/CHANGELOG.md create mode 100644 utilities/styles/VSC/README.md create mode 100644 utilities/styles/VSC/img/erpcPic.png create mode 100644 utilities/styles/VSC/img/templatePic.png create mode 100644 utilities/styles/VSC/language-configuration.json create mode 100644 utilities/styles/VSC/package.json create mode 100644 utilities/styles/VSC/syntaxes/erpc.tmLanguage.json create mode 100644 utilities/styles/VSC/syntaxes/template.tmLanguage.json create mode 100644 utilities/styles/VSC/vsc-extension-quickstart.md diff --git a/utilities/styles/VSC/.vscode/launch.json b/utilities/styles/VSC/.vscode/launch.json new file mode 100644 index 000000000..25f73a1b9 --- /dev/null +++ b/utilities/styles/VSC/.vscode/launch.json @@ -0,0 +1,15 @@ +// A launch configuration that launches the extension inside a new window +// Use IntelliSense to learn about possible attributes. +// Hover to view descriptions of existing attributes. +// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 +{ + "version": "1.0.0", + "configurations": [{ + "name": "Debug eRPC syntax highlighting", + "type": "extensionHost", + "request": "launch", + "args": [ + "--extensionDevelopmentPath=${workspaceFolder}" + ] + }] +} diff --git a/utilities/styles/VSC/.vscodeignore b/utilities/styles/VSC/.vscodeignore new file mode 100644 index 000000000..f369b5e55 --- /dev/null +++ b/utilities/styles/VSC/.vscodeignore @@ -0,0 +1,4 @@ +.vscode/** +.vscode-test/** +.gitignore +vsc-extension-quickstart.md diff --git a/utilities/styles/VSC/CHANGELOG.md b/utilities/styles/VSC/CHANGELOG.md new file mode 100644 index 000000000..55784e862 --- /dev/null +++ b/utilities/styles/VSC/CHANGELOG.md @@ -0,0 +1,9 @@ +# Change Log + +All notable changes to the "erpc-code-style" extension will be documented in this file. + +Check [Keep a Changelog](http://keepachangelog.com/) for recommendations on how to structure this file. + +## [Unreleased] + +- Initial release \ No newline at end of file diff --git a/utilities/styles/VSC/README.md b/utilities/styles/VSC/README.md new file mode 100644 index 000000000..7dc984ce3 --- /dev/null +++ b/utilities/styles/VSC/README.md @@ -0,0 +1,38 @@ +# erpc-code-style README + +This exension formats code for eRPC related files. More about eRPC project is described on webpage: https://github.com/EmbeddedRPC/erpc + +This extension was created thankfully this page and author of post: +https://gcthesoftwareengineer.com/2017/01/how-to-create-custom-syntax-highlighting-in-a-visual-studio-code-extension/ + + +## Features + +This extension format erpc idl files and cpptemplate related files. + +eRPC IDL example: +![eRPC IDL example](img/erpcPic.png) + +template example: +![cpptemplate example](img/templatePic.png) + + +## Requirements + +-- + +## Extension Settings + +-- + +## Known Issues + +-- + +## Release Notes + + +### 1.0.0 + +Initial release + - Covering most of usecases. Still some need be covered. diff --git a/utilities/styles/VSC/img/erpcPic.png b/utilities/styles/VSC/img/erpcPic.png new file mode 100644 index 0000000000000000000000000000000000000000..099510b9e227b981c3cd0577b719c518b8aa4a79 GIT binary patch literal 223127 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 z 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%0AWVs=q(3Vv&_R+AZ2vg0^q6UG zS*={&=NItpi;FseU*{L*rF{1fcE$=nKI0dai$uxEkl{OeLuEqm+}tnRT6+%A5aFp} zX>r2TKC8We|DpK7v@S_A;T_^vQ&Y*DX+(q{F1*AcqE+4zImZ8w=|N4&!BOAT#NEoz zB&JlUAzP$s%$QiBTm-;~d5K3}XM}6)+c!~oTZJ3vt#lYmC~UK%Jp%CNhryF!5Y<|3tH@U6)eHG8lwj%O;yycjiE=pClW`QZ70%qy;k;@{moD( z{h|7ZiJ9!KAR$fqXgOG5`Rex2ps^q|1uY#R|PchYO? z-(v;`PIoqj9x-4|B_)=$3rXwF^^-w01CUR4p;Ro@SE*-B0mwq(eB~N#__z#fbH5w# zJcFK`h|J?A@HdtruU0=hYDyNCue);Qlt8X(8PZ#QsOHKXi%(|*A%U<=*RQ1D4XuKW z>c@~2xs-zChrFVT5&oSQoCzi&Z110}m->%9?@}0_9%6!cA9hg!E>g7BFQHe`If()f zv1wq5vm>ulBGC1IK{L=1c@cT}NC1W#4(z4j;o+T$0+V?EBw65)Zk!mdERAxB{Y|dj z#Z`}UUGdnhUEXJ5C$=N^lYuy7DzD@c-zk08>s9KYufvyXk9k6RmWk9hIH#n^4dLzy zE!OkuD^UHLY3SEEbz|%u?3$9BvK7AS;XVYsH0S%(91EFEa!^CP*Hf0s%kd!W5!ZW( zl_FMCJfD937JEKWt`1NH>`5G5s#v-}>zy3){nvG3MRK~_o#Ut-nTbc7sQZByz={bKlP!cvg9YC-i+l~RLkB3CU{MX(b6M)UrXikghaoUXVW>Myrj z6&a1j3nkv32C11N#3T9JfDe-TYVWiD*~S)y*l>S)Lwh& zb*i$%n|=NItz>kxE_`7_bK>hBXQo&LpP%1vU=dN4TalB$FvwMu&Q^))M`)^4DjyG0 zQ^hwS>~1{kB*u z0|{w<4?mPa9hO9h+&q~Fp=CGe(R;;Vc zVOsN+2|E7*#XD?|BMIo!usXq^tK}%>p#Is@p$3J?KE3z(Bqjdc)q(pKwZNCsGwJzo%TKi{b%tYxrhJF)TbUsymlbzI-ZMDMHhUck{H@<$ zdn2u?Gv2;)An>cp!v(5E$G*H`xglHMpA?s22^%*~mb+OrnqTJA6$IEBkN;#6FCS#* zd+aRVkvy91_6S_}iu}KDFeGE;%riDu-VdftM@#xo*H16(q>mc*g1V}{T!yFpCPWtA z_6G# z1cL;rVsYi@xLsBSfkw~oJ_5Fx(H!m6R2L;>D<9v#)jfF z$HP~(H(8_VYP5+F3CqAai93;UaA@ywevwAo_TbFfT)%Ovk7iPOJ4b}es9M$1W?m8RN)pk=;^ogM6#cwMYAwGGX=_D4JM^*? zi9!S|&l3f$p}$iHe?9KSNJQ?IFutc`*}m|Z?vgQN-*$3m%V_dfwa~k^Uw%M;IE$M3 zzH~ecRH6tRkH^OBdvo~s`yg!wwjN-)htv}0`Ila{4%x+?v+l3oo1GkrA?V7a{elr? zoyLTZ?0bz$hp*X>03T!h*lU3NoFxqrD87*0?@?r6uf1$znDmoqn+KaiO|3YW?__Y{ z{Di-I{fu+jbt?fUO?b>v*~xt52ef&(Nm%){@#a!UCsW$d4J`s6oJO# zij!nCP}tZ0V%Had1Ny{02twx*=y;{}d7txhIe854LXR!QQ};kcdM3y5`~)*00Vyr4 z4JI(_IkxmJc^%M4=j8JRdPCAZyrWsJ2v;6Snfa7?TllyuY~gdlgaDh@G#GZ%*49>B zTwI!84VD7(#;P-rVqi>+)yU!1d37&Tx5V-iPPw=)nmvk#1M77N>^QOXxYkd}?FVrS zR&x(8VdU1%lELC!@YyF6u5SYD=R@`N%>-s?7&P({|6pG?_#NFJJY+SH66n-3cn`AX zunMSGNY~wO-FfptG-xu;u8U=o`(jT|W!3b(zbz+r{B0AlSaG{iVV0r~E0C*d{>0Z< z!o>jE{BFJUhScQS<)%Q3k-0LJX0Ni*UU#egfHYsguLll=gGMqx3zLj#SDKz z;cuALt0+DMUVLR%*%V`(LU*$LeWzC*bnXW*2F$nm{CJ;i*PyQ~cS-}eCI!?L_lNq3 z$fZ7#098m5i{hG8rPC$7Osj!HV${J>BEz)drP1p&D0Q1jDRCVEY!Jp>-5rxyJ56Os z1Gb`OBVGi5BJwT8+*8H#uJ4F+#^v2Sf21Y(fD^LOqI&=Wj^=8Bp>aoq3Pp^^!sUvG zw~5qH1V@F(F|+<@>)D`!zI7A`^y`rnWW!4m=86K>kQ3A!cLudPl6zG^aA8gWqM4tf zw*wHQ9Iz0gRDmf&%7F2>XtQ=GUiB889fgabU13ZWAHdvNiyZ>2zcn&Fwnuvy$AS`uqNc1=wwQHwR&S535vWMp z6%(k>CY^qro`d595d8M1F8^Q?7J$+ui|kL;P9B{&q~Lr+yI$V%>TGIc!UOj02ze|~ za~_cKWyp#jB05eah$v)gVFB2O1QFs)i5BbxplC2{tF065$H2A4guqY3xFL{JVl%IZ z=^0X2N-}(8Vo%Pju{f%8x3=mrxfp}RgkgQmuT1);(>DZqo(@CN{c+AmjP?4Sx*ZjI z?`selty?b0D=F*OAV^+q4C~#qEB7-TL~)Lf=tugER}m}UIk6R_g-HcfAT+3!k;8gt zHPUroGszP;tFj}&ZyOWDa4xNn+H%yrpPJq+LhBBy+q1hq=F2_71~wsZuy*IVBkL&9 z(#-*=E*B-Q<&%UQDS%=PcW={6nxD88>evP%oqG$1W^LRpv2_EjQc;5rpw)GB}R8vbh$%w=>U= zUn*<1Vme6D>QT||^C+~#5Eb4*h4M$P&mc$_L_MFt5&L^B&-&+QIeEy@39OzLsVCz_e?|nNM?;@@qwtHT!N8_hWx_) z;%2MY%T^|#pAPn*PjmHvnoI$O57`Jzg&Z$d>SspIsy}Q%aoN0|9?v=0x z+RrrUKdpM-iaWr+-;0Hn-Z^`d-_LX zY=j-uAEP!xXYWGudT8nf{e!5~v*Twz)$p$O|N3`1PK7$-^j{>ybPof;)AM@=82 zN>zx4%~ARFNE;(wUrv0na_?R^wNPB7E;r@1W)}C>8pYVEqKSe=)~Y`Revr?;e(ezY zNO{|pL}I72l@_#&ivXsA=tCpEj`TFK;B_Jx2XTVx*8d$>qqq7rN1n}r)QPZA_m(#i z!~b$^i_cX+Q>kkGDdnZ%ODETOGFgw)!Rd}m#k7%PRZ4d8B2I? zUqs*apzxPhNde9bMm1s+7H07HQ^*Dp%v}E(*44UCS1%@=e%NuusfJ8zFHwx*8KNLDcDuj*)DjGF3;_9RNNGJ1yBn4*Fv z`{8J2RTHE+uxCHQC^FVZ{Tp5skiSEA)7u~B2L!9Q_~Gn?SDqT0KXbpkeK}fx+DFEL z1I21XsHNlqIp)43WZs^;6H<29BRPsph)${!GM-dKtkvza3R74MWQg%F{YCA-V6)-i zwp8zZtl~by1NA)LiNuijU6`^v28JBDIXiEV48TmA^A&a$FYb_i&_MT|^22)kQptpp z#UMcx70Z6X5`%D8lUWp_iX(a;>fxf*<+?oKuF@hWu&ia zELaK0&B4^RF^~2!sT`DT`<*kx_d9oFP`+BLH!tLXNCONZCMsM_2GF~t0~X9NFHUZD z;J%ksFXrEzRpI}&+uf+|)~VIl_W0!FKq)DOt>GOVVH=_W#yPWNA!{dcRise=%-p=S zCWSLfSK}6|N4&j@%Z1;E!B#5v`Kl*E3l0Jla%LfDRC@0i+_~-HLn9qRLtkAK2NC#W zC(d%aPR?b}_eZ)K9xo+Q9ARy=jS5x?{pL$blQ(9}K_dy}V69SioGgOS$xRYv@@!ws z%Cf)DL$QPE!GU(c1<}7LbA-VtApU^CyQgaB%pXds76?8oW((S%S}ie!g{gfc-@X+q zrNP}NrJ3zo-YfXlI9)OmO4{Z7t#MrREnLhp83rWU|9ol4*txn@j&CJOZs|L`%Y_!_ zNX5or##|AP$+GJRK6Y-Ojn7!!%)4gZ#~25OEHXuh#g8#RE#8es+Y~SgVt{{ue84|p zuiw4y_^|JA)%;0QzLfFqZ*DL4%XmUl<(xz^>jLnLy8ia}5_%qo-0mn6l>OvWml#4D zuQN3bX-cX%J-x`69J;!4x>AgSUToXiyn5S0oSOCY0@q}A5ONq!ZPHak1lkbmWEXJa4l^q^GBLY(=fT;kkYX2Lf-g?Pnsx^0noiB zBm+DrtsUO&mzRlD1y%Mzu$@i{BRMS)6?C%dq1+CwRG+sL~hi$cVgU6Zqqs^`MoA7{+u8+RN-R;i_O7% zB!+b`JxQt*b(L}NtFzJ&3Us{+Ruipoc`PTOD#FcrHkY8+5JJF_f#CQgDc~VQfE@I? zPy?Pq8vB(hhW)YU5d>#ds%}o49BTr!AOU*#QTq?yi=`0A7|+$Uc02Mw!&p~~Niof> zpnmHruIbe~CK4O#12hn&YViT?ZUh7y`^AQBlwD>hTsSAah>9BB;8q@1Y%bdwjqCmhI}h7a<$$!&lI9~oE8p9mS9hn40WIi!YZ%6Peo1Gep3fFojz%`z4({g_&9dq zJbDpqq&BuheiPGIXWuItQFXH5h9*j`!=7M#?HZwnH>@ej-{@{)*{PLW{~`ioO_?sJ z-ND)2Xb_px==HvRGVRUwW`Cbve`7WIjr;H3{+hLX)#RlLy}kXr$U&D4(?H>CY7qpT zrSlNHfy+vI&A>{hyDPbu$KG4^p9Gsh8iTqi(T1YhzsJK&?-$l@S$Owd&Y|%RTG2kY z7w!a~Kt1f(3hysVvJNx=0AJ;KFk%TmUbppI5{FBtx6rnmJl*jC@nV&<)sn;e`fcmP z#N`vx0>)oT(Eg+_A@px%q-Rf TY2vYLZQbe&3uNwZQCuiwFe*P}Z0JX!Aqp;%Mv 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�*ns%g=bpkW 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 Xql^&oUC)4f0~kDA{an^LB{Ts5swL!k literal 0 HcmV?d00001 diff --git a/utilities/styles/VSC/img/templatePic.png b/utilities/styles/VSC/img/templatePic.png new file mode 100644 index 0000000000000000000000000000000000000000..4a09def19ada4e2fe0e08a26a7646298bd697ba5 GIT binary patch literal 230616 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 z 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 z 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 literal 0 HcmV?d00001 diff --git a/utilities/styles/VSC/language-configuration.json b/utilities/styles/VSC/language-configuration.json new file mode 100644 index 000000000..8f162a0c4 --- /dev/null +++ b/utilities/styles/VSC/language-configuration.json @@ -0,0 +1,30 @@ +{ + "comments": { + // symbol used for single line comment. Remove this entry if your language does not support line comments + "lineComment": "//", + // symbols used for start and end a block comment. Remove this entry if your language does not support block comments + "blockComment": [ "/*", "*/" ] + }, + // symbols used as brackets + "brackets": [ + ["{", "}"], + ["[", "]"], + ["(", ")"] + ], + // symbols that are auto closed when typing + "autoClosingPairs": [ + ["{", "}"], + ["[", "]"], + ["(", ")"], + ["\"", "\""], + ["'", "'"] + ], + // symbols that can be used to surround a selection + "surroundingPairs": [ + ["{", "}"], + ["[", "]"], + ["(", ")"], + ["\"", "\""], + ["'", "'"] + ] +} \ No newline at end of file diff --git a/utilities/styles/VSC/package.json b/utilities/styles/VSC/package.json new file mode 100644 index 000000000..548d9a8ff --- /dev/null +++ b/utilities/styles/VSC/package.json @@ -0,0 +1,34 @@ +{ + "name": "erpc-code-style", + "displayName": "ERPC code style", + "description": "Formatting code relevant to eRPC language", + "version": "1.0.0", + "engines": { + "vscode": "^1.49.0" + }, + "categories": [ + "Programming Languages" + ], + "contributes": { + "languages": [{ + "id": "erpc", + "aliases": ["erpc", "erpc"], + "extensions": [".erpc"], + "configuration": "./language-configuration.json" + }, { + "id": "template", + "aliases": ["template", "template"], + "extensions": [".template"], + "configuration": "./language-configuration.json" + }], + "grammars": [{ + "language": "erpc", + "scopeName": "source.erpc", + "path": "./syntaxes/erpc.tmLanguage.json" + }, { + "language": "template", + "scopeName": "source.template", + "path": "./syntaxes/template.tmLanguage.json" + }] + } +} diff --git a/utilities/styles/VSC/syntaxes/erpc.tmLanguage.json b/utilities/styles/VSC/syntaxes/erpc.tmLanguage.json new file mode 100644 index 000000000..76714bc5e --- /dev/null +++ b/utilities/styles/VSC/syntaxes/erpc.tmLanguage.json @@ -0,0 +1,174 @@ +{ + "$schema": "https://raw.githubusercontent.com/martinring/tmlanguage/master/tmlanguage.json", + "name": "erpc", + "patterns": [{ + "include": "#multilineCommentsDocument" + }, { + "include": "#multilineCommentsDocument2" + }, + { + "include": "#multilineComments" + }, + { + "include": "#comments" + }, + { + "include": "#annotations" + }, + { + "include": "#enums" + }, + { + "include": "#structs" + }, + { + "include": "#structsMembers" + }, + { + "include": "#members" + }, + { + "include": "#typeNames" + }, + { + "include": "#functionTypeNames" + }, + { + "include": "#returnTypes" + }, + { + "include": "#keywords" + }, + { + "include": "#strings" + } + ], + "repository": { + "keywords": { + "patterns": [{ + "name": "keyword.control.erpc", + "match": "\\b(const|enum|in|inout|interface|oneway|out|program|struct|type)\\b" + }, { + "name": "entity.name.type", + "match": "\\b(binary|bool|uint8|uint16|uint32|int8|int16|int32|void)\\b" + }, { + "name": "keyword.other.erpc", + "match": "[{}(),=\\->;\\[\\]+*/;]" + }] + }, + "strings": { + "name": "string.quoted.double.erpc", + "begin": "\"", + "end": "\"", + "patterns": [{ + "name": "constant.character.escape.erpc", + "match": "\\\\." + }] + }, + "comments": { + "name": "comment.line.erpc", + "match": "\\\\.*" + }, + "multilineCommentsDocument": { + "name": "comment.block.erpc", + "begin": "/\\*\\*", + "end": "\\*/" + }, + "multilineCommentsDocument2": { + "name": "comment.block.erpc", + "begin": "/\\*\\!", + "end": "\\*/" + }, + "multilineComments": { + "name": "comment.block.erpc", + "begin": "/\\*", + "end": "\\*/" + }, + "annotations": { + "name": "support.property-value.erpc", + "begin": "@[^\\(]*\\(", + "end": "\\)", + "patterns": [{ + "name": "string.quoted.double.erpc", + "match": "\"[^)]*" + }, { + "name": "string.unquoted.erpc", + "match": "[^\")][^)]*" + }] + }, + "enums": { + "name": "keyword.control.erpc", + "match": "enum\\s*([a-zA-Z0-9_]+)", + "captures": { + "1": { + "name": "entity.name.type.erpc" + } + } + }, + "structs": { + "name": "keyword.control.erpc", + "match": "struct\\s*([a-zA-Z0-9_]+)", + "captures": { + "1": { + "name": "entity.name.type.erpc" + } + } + }, + "structsMembers": { + "name": "variable.name", + "match": "([a-zA-Z0-9_]*)\\s([a-zA-Z0-9_]*)(;)", + "captures": { + "1": { + "name": "entity.name.type.erpc" + }, + "3": { + "name": "keyword.other.erpc" + } + } + }, + "typeNames": { + "name": "keyword.control.erpc", + "match": "type\\s[^=]*", + "captures": { + "0": { + "patterns": [{ + "name": "entity.name.type.erpc", + "match": "\\s.*" + }] + } + } + }, + "functionTypeNames": { + "name": "keyword.other.erpc", + "begin": "\\(", + "end": "\\)", + "patterns": [{ + "name": "", + "match": "(in\\s|out\\s|inout\\s)?([a-zA-Z0-9_\\[\\]]+\\s)([a-zA-Z0-9_]+)", + "captures": { + "1": { + "name": "keyword.control.erpc" + }, + "2": { + "name": "entity.name.type.erpc" + }, + "3": { + "name": "variable.name.erpc" + } + } + }] + }, + "returnTypes": { + "match": "(->)\\s*([a-zA-Z0-9_]*)", + "captures": { + "1": { + "name": "keyword.other.erpc" + }, + "2": { + "name": "entity.name.type.erpc" + } + } + } + }, + "scopeName": "source.erpc" +} diff --git a/utilities/styles/VSC/syntaxes/template.tmLanguage.json b/utilities/styles/VSC/syntaxes/template.tmLanguage.json new file mode 100644 index 000000000..cef0700b9 --- /dev/null +++ b/utilities/styles/VSC/syntaxes/template.tmLanguage.json @@ -0,0 +1,65 @@ +{ + "$schema": "https://raw.githubusercontent.com/martinring/tmlanguage/master/tmlanguage.json", + "name": "template", + "patterns": [{ + "include": "#condition" + }, { + "include": "#variable" + }, { + "include": "#variable" + }], + "repository": { + "condition": { + "name": "", + "match": "{%[^}]*}", + "captures": { + "0": { + "name": "", + "patterns": [{ + "name": "comment.line", + "match": "({%)\\s*([a-zA-Z0-9_]*)([^-%>]*)?([^}]*})", + "captures": { + "1": { + "name": "comment.line" + }, + "2": { + "name": "keyword.control" + }, + "3": { + "name": "entity.name.function" + }, + "4": { + "name": "comment.line" + } + } + }] + } + } + }, + "variable": { + "name": "", + "match": "{\\$[^}]*}", + "captures": { + "0": { + "name": "", + "patterns": [{ + "name": "comment.line", + "match": "({\\$>?)\\s*([^>}]*)(>?})", + "captures": { + "1": { + "name": "comment.line" + }, + "2": { + "name": "variable.other" + }, + "3": { + "name": "comment.line" + } + } + }] + } + } + } + }, + "scopeName": "source.template" +} diff --git a/utilities/styles/VSC/vsc-extension-quickstart.md b/utilities/styles/VSC/vsc-extension-quickstart.md new file mode 100644 index 000000000..1ae0d0a62 --- /dev/null +++ b/utilities/styles/VSC/vsc-extension-quickstart.md @@ -0,0 +1,29 @@ +# Welcome to your VS Code Extension + +## What's in the folder + +* This folder contains all of the files necessary for your extension. +* `package.json` - this is the manifest file in which you declare your language support and define the location of the grammar file that has been copied into your extension. +* `syntaxes/erpc.tmLanguage.json` - this is the Text mate grammar file that is used for tokenization. +* `language-configuration.json` - this is the language configuration, defining the tokens that are used for comments and brackets. + +## Get up and running straight away + +* Make sure the language configuration settings in `language-configuration.json` are accurate. +* Press `F5` to open a new window with your extension loaded. +* Create a new file with a file name suffix matching your language. +* Verify that syntax highlighting works and that the language configuration settings are working. + +## Make changes + +* You can relaunch the extension from the debug toolbar after making changes to the files listed above. +* You can also reload (`Ctrl+R` or `Cmd+R` on Mac) the VS Code window with your extension to load your changes. + +## Add more language features + +* To add features such as intellisense, hovers and validators check out the VS Code extenders documentation at https://code.visualstudio.com/docs + +## Install your extension + +* To start using your extension with Visual Studio Code copy it into the `/.vscode/extensions` folder and restart Code. +* To share your extension with the world, read on https://code.visualstudio.com/docs about publishing an extension. From 6f338f00d3151455889298e47c7babbe94336613 Mon Sep 17 00:00:00 2001 From: Dusan Cervenka Date: Sun, 27 Sep 2020 02:45:34 +0200 Subject: [PATCH 35/96] Changes necessary for publish to oficial marketplace. --- utilities/styles/VSC/package.json | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/utilities/styles/VSC/package.json b/utilities/styles/VSC/package.json index 548d9a8ff..ae0e22036 100644 --- a/utilities/styles/VSC/package.json +++ b/utilities/styles/VSC/package.json @@ -1,8 +1,13 @@ { + "publisher": "Hadatko", "name": "erpc-code-style", "displayName": "ERPC code style", "description": "Formatting code relevant to eRPC language", "version": "1.0.0", + "repository": { + "type": "git", + "url": "https://github.com/EmbeddedRPC/erpc.git" + }, "engines": { "vscode": "^1.49.0" }, From ad3061967a7f88e9c6404308ae76980d92a76d2c Mon Sep 17 00:00:00 2001 From: Cervenka Dusan Date: Tue, 29 Sep 2020 11:36:52 +0200 Subject: [PATCH 36/96] Fixed xTimerCreate time to tick conversion. --- erpc_c/port/erpc_setup_extensions.h | 4 ++-- erpc_c/port/erpc_setup_extensions_freertos.cpp | 8 ++------ 2 files changed, 4 insertions(+), 8 deletions(-) diff --git a/erpc_c/port/erpc_setup_extensions.h b/erpc_c/port/erpc_setup_extensions.h index 0824a62ab..d7666eda3 100644 --- a/erpc_c/port/erpc_setup_extensions.h +++ b/erpc_c/port/erpc_setup_extensions.h @@ -60,9 +60,9 @@ typedef void *erpc_call_timer_cb_default_t; * * @param[in] erpc_call_timer_cb Callback function called when eRPC call freeze. * When NULL default callback will be used. - * @param[in] waitTime Platform specific time to throw error cb in case of eRPC call freeze. + * @param[in] waitTimeMs Platform specific time to throw error cb in case of eRPC call freeze in [ms]. */ -void erpc_init_call_progress_detection_default(erpc_call_timer_cb_default_t erpc_call_timer_cb, uint32_t waitTime); +void erpc_init_call_progress_detection_default(erpc_call_timer_cb_default_t erpc_call_timer_cb, uint32_t waitTimeMs); /*! * @brief This function is used for deinitialization variables for task freeze detection. diff --git a/erpc_c/port/erpc_setup_extensions_freertos.cpp b/erpc_c/port/erpc_setup_extensions_freertos.cpp index e7bd72409..f71e653e2 100644 --- a/erpc_c/port/erpc_setup_extensions_freertos.cpp +++ b/erpc_c/port/erpc_setup_extensions_freertos.cpp @@ -36,16 +36,12 @@ void erpc_call_timer_cb_default(TimerHandle_t xTimer) assert(1 != 1 && "eRPC task freezed."); } -void erpc_init_call_progress_detection_default(erpc_call_timer_cb_default_t erpc_call_timer_cb = NULL, uint32_t waitTime = 5 * 60 * 1000) +void erpc_init_call_progress_detection_default(erpc_call_timer_cb_default_t erpc_call_timer_cb = erpc_call_timer_cb_default, uint32_t waitTimeMs = 5 * 60 * 1000) { s_erpc_call_in_progress = new Semaphore(1); assert(s_erpc_call_in_progress && "Creating eRPC semaphore failed."); - if (!erpc_call_timer_cb) - { - erpc_call_timer_cb = erpc_call_timer_cb_default; - } - s_erpc_call_timer_cb = xTimerCreate("Erpc client call timer", waitTime / 1000 / portTICK_PERIOD_MS, pdFALSE, NULL, erpc_call_timer_cb); + s_erpc_call_timer_cb = xTimerCreate("Erpc client call timer", waitTimeMs / portTICK_PERIOD_MS, pdFALSE, NULL, erpc_call_timer_cb); assert(s_erpc_call_timer_cb && "Creating eRPC timer failed."); } From 421f400e52a60e573d1b4d11c3e5348414060217 Mon Sep 17 00:00:00 2001 From: Jean-Christian de Rivaz <84882+jcdr@users.noreply.github.com> Date: Sat, 3 Oct 2020 03:58:59 +0200 Subject: [PATCH 37/96] erpc_port.h: remove extra ; --- erpc_c/port/erpc_port.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erpc_c/port/erpc_port.h b/erpc_c/port/erpc_port.h index 34ad36fd1..6b5c7927c 100644 --- a/erpc_c/port/erpc_port.h +++ b/erpc_c/port/erpc_port.h @@ -45,7 +45,7 @@ void *erpc_malloc(size_t size); void erpc_free(void *ptr); #ifdef __cplusplus -}; +} #endif /*! @} */ From b1c3e959450df2230715d3c7315a555e0339c178 Mon Sep 17 00:00:00 2001 From: Jean-Christian de Rivaz <84882+jcdr@users.noreply.github.com> Date: Sat, 3 Oct 2020 16:59:31 +0200 Subject: [PATCH 38/96] PythonGenerator.cpp: remove extra ; --- erpcgen/src/PythonGenerator.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erpcgen/src/PythonGenerator.cpp b/erpcgen/src/PythonGenerator.cpp index 26ded4169..9a0311cd6 100644 --- a/erpcgen/src/PythonGenerator.cpp +++ b/erpcgen/src/PythonGenerator.cpp @@ -65,7 +65,7 @@ void PythonGenerator::generateInitFile(string fileName) { fileName += "/__init__.py"; generateOutputFile(fileName, "py_init", m_templateData, kPyInit); -}; +} void PythonGenerator::generateCommonFile(string fileName) { From 6a2b1f71b8fbae60798d9dd14628acb17d4304b0 Mon Sep 17 00:00:00 2001 From: Jean-Christian de Rivaz <84882+jcdr@users.noreply.github.com> Date: Sun, 4 Oct 2020 03:16:23 +0200 Subject: [PATCH 39/96] gtest.cpp: fix extra ; --- test/common/gtest/gtest.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/test/common/gtest/gtest.cpp b/test/common/gtest/gtest.cpp index 50b127ff8..367462136 100644 --- a/test/common/gtest/gtest.cpp +++ b/test/common/gtest/gtest.cpp @@ -5210,13 +5210,13 @@ class DefaultStoredResultEventListener : public StoredResultEventListener{ const BaseTestPartResult* DefaultStoredResultEventListener::TransformTestPartResult(const TestPartResult& test_part_result) { return new TestPartResult(test_part_result.type(),test_part_result.file_name(), test_part_result.line_number(), test_part_result.message()); -}; +} #if !GTEST_OS_BARE_METAL void DefaultStoredResultEventListener::OutputXmlTestPartResult(::std::ostream* stream, const BaseTestPartResult* base_test_part_result) { XmlUnitTestResultPrinter::OutputXmlTestPartResult(stream, base_test_part_result); -}; +} #endif // End DefaultStoredResultEventListener @@ -5237,7 +5237,7 @@ class BaseStoredResultEventListener : public StoredResultEventListener{ const BaseTestPartResult* BaseStoredResultEventListener::TransformTestPartResult(const TestPartResult& test_part_result) { return new BaseTestPartResult(test_part_result.type()); -}; +} #if !GTEST_OS_BARE_METAL void BaseStoredResultEventListener::OutputXmlTestPartResult(::std::ostream* stream, @@ -5245,7 +5245,7 @@ void BaseStoredResultEventListener::OutputXmlTestPartResult(::std::ostream* stre *stream << " type() == BaseTestPartResult::kFatalFailure) ? "fatal_failure" : "non_fatal_failure") << "\">\n"; -}; +} #endif // End BaseStoredResultEventListener From efc589348d1c509d96ab5f819a347466961f8c24 Mon Sep 17 00:00:00 2001 From: Jean-Christian de Rivaz <84882+jcdr@users.noreply.github.com> Date: Sat, 3 Oct 2020 03:57:46 +0200 Subject: [PATCH 40/96] erpc_transport.h: setCrc16() void unused parameter crcImpl --- erpc_c/infra/erpc_transport.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erpc_c/infra/erpc_transport.h b/erpc_c/infra/erpc_transport.h index c3b3edc87..255c0f884 100644 --- a/erpc_c/infra/erpc_transport.h +++ b/erpc_c/infra/erpc_transport.h @@ -83,7 +83,7 @@ class Transport * * @param[in] crcImpl Object containing crc-16 compute function. */ - virtual void setCrc16(Crc16 *crcImpl){}; + virtual void setCrc16(Crc16 *crcImpl) { (void)crcImpl; } }; /*! From 0adf5648742600a371005163aeeb3eba6965cae8 Mon Sep 17 00:00:00 2001 From: Jean-Christian de Rivaz <84882+jcdr@users.noreply.github.com> Date: Sat, 3 Oct 2020 04:00:00 +0200 Subject: [PATCH 41/96] erpc_serial.cpp: serial_setup(): void unused parameter speed on POSIX --- erpc_c/port/erpc_serial.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/erpc_c/port/erpc_serial.cpp b/erpc_c/port/erpc_serial.cpp index e0cbe77ad..51d06d858 100644 --- a/erpc_c/port/erpc_serial.cpp +++ b/erpc_c/port/erpc_serial.cpp @@ -72,6 +72,7 @@ int serial_setup(int fd, speed_t speed) return -1; } #else + (void)speed; struct termios tty; memset(&tty, 0x00, sizeof(tty)); From b7e80d40916b0f2390af931ee65d014b900c7c3a Mon Sep 17 00:00:00 2001 From: Jean-Christian de Rivaz <84882+jcdr@users.noreply.github.com> Date: Sat, 3 Oct 2020 14:59:53 +0200 Subject: [PATCH 42/96] erpc_arbitrated_client_manager.h: void unused parameter transport --- erpc_c/infra/erpc_arbitrated_client_manager.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erpc_c/infra/erpc_arbitrated_client_manager.h b/erpc_c/infra/erpc_arbitrated_client_manager.h index d6bf0922a..6b909f877 100644 --- a/erpc_c/infra/erpc_arbitrated_client_manager.h +++ b/erpc_c/infra/erpc_arbitrated_client_manager.h @@ -72,7 +72,7 @@ class ArbitratedClientManager : public ClientManager virtual void performClientRequest(RequestContext &request); //! @brief This method is not used with this class. - void setTransport(Transport *transport) {} + void setTransport(Transport *transport) { (void)transport; } }; } // namespace erpc From 264cb53b8f128d9e5af7e369708d34c11d176ef2 Mon Sep 17 00:00:00 2001 From: Jean-Christian de Rivaz <84882+jcdr@users.noreply.github.com> Date: Sat, 3 Oct 2020 15:02:52 +0200 Subject: [PATCH 43/96] erpc_port_stdlib.cpp: void unused parameter tag --- erpc_c/port/erpc_port_stdlib.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/erpc_c/port/erpc_port_stdlib.cpp b/erpc_c/port/erpc_port_stdlib.cpp index 8155d3417..de26d88b1 100644 --- a/erpc_c/port/erpc_port_stdlib.cpp +++ b/erpc_c/port/erpc_port_stdlib.cpp @@ -21,6 +21,7 @@ void *operator new(size_t count) THROW_BADALLOC void *operator new(size_t count, const nothrow_t &tag) THROW NOEXCEPT { + (void)tag; void *p = erpc_malloc(count); return p; } @@ -33,6 +34,7 @@ void *operator new[](size_t count) THROW_BADALLOC void *operator new[](size_t count, const nothrow_t &tag) THROW NOEXCEPT { + (void)tag; void *p = erpc_malloc(count); return p; } From dad9759b8323f89aefdf9ce2c566b5be2408b8cd Mon Sep 17 00:00:00 2001 From: Jean-Christian de Rivaz <84882+jcdr@users.noreply.github.com> Date: Sat, 3 Oct 2020 15:37:50 +0200 Subject: [PATCH 44/96] SearchPath.cpp: void unused parameter targetType --- erpcgen/src/SearchPath.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/erpcgen/src/SearchPath.cpp b/erpcgen/src/SearchPath.cpp index b60894f5f..39e23f777 100644 --- a/erpcgen/src/SearchPath.cpp +++ b/erpcgen/src/SearchPath.cpp @@ -64,6 +64,7 @@ void PathSearcher::setTempPath(const std::string &path) //! \retval false No match could be made. \a result has been left unmodified. bool PathSearcher::search(const std::string &base, target_type_t targetType, bool searchCwd, std::string &result) { + (void)targetType; FILE *tempFile; bool absolute = isAbsolute(base); From 95b92a241e2d26828e1eb8ebe992fa7275912e5a Mon Sep 17 00:00:00 2001 From: Jean-Christian de Rivaz <84882+jcdr@users.noreply.github.com> Date: Sat, 3 Oct 2020 15:41:37 +0200 Subject: [PATCH 45/96] AstWalker.h: void unused parameters node --- erpcgen/src/AstWalker.h | 72 ++++++++++++++++++++--------------------- 1 file changed, 36 insertions(+), 36 deletions(-) diff --git a/erpcgen/src/AstWalker.h b/erpcgen/src/AstWalker.h index ad054b249..207a00b8c 100644 --- a/erpcgen/src/AstWalker.h +++ b/erpcgen/src/AstWalker.h @@ -117,24 +117,24 @@ class AstWalker * @brief Top-down handlers types, which can be called. */ //@{ - virtual void handleRoot(AstNode *node, top_down){}; - virtual AstNode *handleProgram(AstNode *node, top_down) { return nullptr; } - virtual AstNode *handleConst(AstNode *node, top_down) { return nullptr; } - virtual AstNode *handleChildren(AstNode *node, top_down) { return nullptr; } - virtual AstNode *handleType(AstNode *node, top_down) { return nullptr; } - virtual AstNode *handleEnum(AstNode *node, top_down) { return nullptr; } - virtual AstNode *handleEnumMember(AstNode *node, top_down) { return nullptr; } - virtual AstNode *handleStruct(AstNode *node, top_down) { return nullptr; } - virtual AstNode *handleStructMember(AstNode *node, top_down) { return nullptr; } - virtual AstNode *handleUnion(AstNode *node, top_down) { return nullptr; } - virtual AstNode *handleUnionCase(AstNode *node, top_down) { return nullptr; } - virtual AstNode *handleInterface(AstNode *node, top_down) { return nullptr; } - virtual AstNode *handleFunction(AstNode *node, top_down) { return nullptr; } - virtual AstNode *handleParam(AstNode *node, top_down) { return nullptr; } - virtual AstNode *handleExpr(AstNode *node, top_down) { return nullptr; } - virtual AstNode *handleBinaryOp(AstNode *node, top_down) { return nullptr; } - virtual AstNode *handleUnaryOp(AstNode *node, top_down) { return nullptr; } - virtual AstNode *handleAnnotation(AstNode *node, top_down) { return nullptr; } + virtual void handleRoot(AstNode *node, top_down) { (void)node; }; + virtual AstNode *handleProgram(AstNode *node, top_down) { (void)node; return nullptr; } + virtual AstNode *handleConst(AstNode *node, top_down) { (void)node; return nullptr; } + virtual AstNode *handleChildren(AstNode *node, top_down) { (void)node; return nullptr; } + virtual AstNode *handleType(AstNode *node, top_down) { (void)node; return nullptr; } + virtual AstNode *handleEnum(AstNode *node, top_down) { (void)node; return nullptr; } + virtual AstNode *handleEnumMember(AstNode *node, top_down) { (void)node; return nullptr; } + virtual AstNode *handleStruct(AstNode *node, top_down) { (void)node; return nullptr; } + virtual AstNode *handleStructMember(AstNode *node, top_down) { (void)node; return nullptr; } + virtual AstNode *handleUnion(AstNode *node, top_down) { (void)node; return nullptr; } + virtual AstNode *handleUnionCase(AstNode *node, top_down) { (void)node; return nullptr; } + virtual AstNode *handleInterface(AstNode *node, top_down) { (void)node; return nullptr; } + virtual AstNode *handleFunction(AstNode *node, top_down) { (void)node; return nullptr; } + virtual AstNode *handleParam(AstNode *node, top_down) { (void)node; return nullptr; } + virtual AstNode *handleExpr(AstNode *node, top_down) { (void)node; return nullptr; } + virtual AstNode *handleBinaryOp(AstNode *node, top_down) { (void)node; return nullptr; } + virtual AstNode *handleUnaryOp(AstNode *node, top_down) { (void)node; return nullptr; } + virtual AstNode *handleAnnotation(AstNode *node, top_down) { (void)node; return nullptr; } //@} /* @@ -143,24 +143,24 @@ class AstWalker * @brief Bottom-up handlers types, which can be called. */ //@{ - virtual void handleRoot(AstNode *node, bottom_up){}; - virtual AstNode *handleProgram(AstNode *node, bottom_up) { return nullptr; } - virtual AstNode *handleConst(AstNode *node, bottom_up) { return nullptr; } - virtual AstNode *handleChildren(AstNode *node, bottom_up) { return nullptr; } - virtual AstNode *handleType(AstNode *node, bottom_up) { return nullptr; } - virtual AstNode *handleEnum(AstNode *node, bottom_up) { return nullptr; } - virtual AstNode *handleEnumMember(AstNode *node, bottom_up) { return nullptr; } - virtual AstNode *handleStruct(AstNode *node, bottom_up) { return nullptr; } - virtual AstNode *handleStructMember(AstNode *node, bottom_up) { return nullptr; } - virtual AstNode *handleUnion(AstNode *node, bottom_up) { return nullptr; } - virtual AstNode *handleUnionCase(AstNode *node, bottom_up) { return nullptr; } - virtual AstNode *handleInterface(AstNode *node, bottom_up) { return nullptr; } - virtual AstNode *handleFunction(AstNode *node, bottom_up) { return nullptr; } - virtual AstNode *handleParam(AstNode *node, bottom_up) { return nullptr; } - virtual AstNode *handleExpr(AstNode *node, bottom_up) { return nullptr; } - virtual AstNode *handleBinaryOp(AstNode *node, bottom_up) { return nullptr; } - virtual AstNode *handleUnaryOp(AstNode *node, bottom_up) { return nullptr; } - virtual AstNode *handleAnnotation(AstNode *node, bottom_up) { return nullptr; } + virtual void handleRoot(AstNode *node, bottom_up){ (void)node; }; + virtual AstNode *handleProgram(AstNode *node, bottom_up) { (void)node; return nullptr; } + virtual AstNode *handleConst(AstNode *node, bottom_up) { (void)node; return nullptr; } + virtual AstNode *handleChildren(AstNode *node, bottom_up) { (void)node; return nullptr; } + virtual AstNode *handleType(AstNode *node, bottom_up) { (void)node; return nullptr; } + virtual AstNode *handleEnum(AstNode *node, bottom_up) { (void)node; return nullptr; } + virtual AstNode *handleEnumMember(AstNode *node, bottom_up) { (void)node; return nullptr; } + virtual AstNode *handleStruct(AstNode *node, bottom_up) { (void)node; return nullptr; } + virtual AstNode *handleStructMember(AstNode *node, bottom_up) { (void)node; return nullptr; } + virtual AstNode *handleUnion(AstNode *node, bottom_up) { (void)node; return nullptr; } + virtual AstNode *handleUnionCase(AstNode *node, bottom_up) { (void)node; return nullptr; } + virtual AstNode *handleInterface(AstNode *node, bottom_up) { (void)node; return nullptr; } + virtual AstNode *handleFunction(AstNode *node, bottom_up) { (void)node; return nullptr; } + virtual AstNode *handleParam(AstNode *node, bottom_up) { (void)node; return nullptr; } + virtual AstNode *handleExpr(AstNode *node, bottom_up) { (void)node; return nullptr; } + virtual AstNode *handleBinaryOp(AstNode *node, bottom_up) { (void)node; return nullptr; } + virtual AstNode *handleUnaryOp(AstNode *node, bottom_up) { (void)node; return nullptr; } + virtual AstNode *handleAnnotation(AstNode *node, bottom_up) { (void)node; return nullptr; } //@} }; From 24226416d669eb45200557c5a4ed9b78add7e638 Mon Sep 17 00:00:00 2001 From: Jean-Christian de Rivaz <84882+jcdr@users.noreply.github.com> Date: Sat, 3 Oct 2020 15:44:20 +0200 Subject: [PATCH 46/96] erpcgen_parser.y: void unused parameters resultAST --- erpcgen/src/erpcgen_parser.y | 1 + 1 file changed, 1 insertion(+) diff --git a/erpcgen/src/erpcgen_parser.y b/erpcgen/src/erpcgen_parser.y index bbf4bba95..9362db249 100644 --- a/erpcgen/src/erpcgen_parser.y +++ b/erpcgen/src/erpcgen_parser.y @@ -1244,6 +1244,7 @@ static int yylex(YYSTYPE * lvalp, YYLTYPE * yylloc, ErpcLexer * lexer) static void yyerror(YYLTYPE * yylloc, ErpcLexer * lexer, AstNode ** resultAST, const char * error) { + (void)resultAST; throw syntax_error(format_string("file %s:%d:%d: %s\n", lexer->getFileName().c_str(), yylloc->m_firstLine, yylloc->m_firstChar, error)); } From 9e30f87029abbf201b25cb699b0fac47a36982f5 Mon Sep 17 00:00:00 2001 From: Jean-Christian de Rivaz <84882+jcdr@users.noreply.github.com> Date: Sat, 3 Oct 2020 15:48:28 +0200 Subject: [PATCH 47/96] SymbolScanner.cpp: void unused parameters node --- erpcgen/src/SymbolScanner.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/erpcgen/src/SymbolScanner.cpp b/erpcgen/src/SymbolScanner.cpp index f88d50149..836f526e3 100644 --- a/erpcgen/src/SymbolScanner.cpp +++ b/erpcgen/src/SymbolScanner.cpp @@ -30,6 +30,7 @@ using namespace std; //////////////////////////////////////////////////////////////////////////////// void SymbolScanner::handleRoot(AstNode *node, bottom_up) { + (void)node; if (m_forwardDeclarations.size() != 0) { string forwardTypes; @@ -859,6 +860,7 @@ AstNode *SymbolScanner::handleUnion(AstNode *node, bottom_up) AstNode *SymbolScanner::handleUnionCase(AstNode *node, top_down) { + (void)node; return nullptr; } @@ -1303,6 +1305,7 @@ void SymbolScanner::setParameterDirection(StructMember *param, AstNode *directio AstNode *SymbolScanner::handleExpr(AstNode *node, bottom_up) { + (void)node; /* Log::debug("expr: %s\n", node->getDescription().c_str()); */ return nullptr; } From d4d2177a0a6acb3f4a2e425ec0bb7f5ae6a8b55b Mon Sep 17 00:00:00 2001 From: Jean-Christian de Rivaz <84882+jcdr@users.noreply.github.com> Date: Sat, 3 Oct 2020 16:09:20 +0200 Subject: [PATCH 48/96] erpcsniffer.cpp: void unused parameter envp --- erpcsniffer/src/erpcsniffer.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/erpcsniffer/src/erpcsniffer.cpp b/erpcsniffer/src/erpcsniffer.cpp index a88345b34..60bda31ae 100644 --- a/erpcsniffer/src/erpcsniffer.cpp +++ b/erpcsniffer/src/erpcsniffer.cpp @@ -445,6 +445,7 @@ class erpcsnifferTool */ int main(int argc, char *argv[], char *envp[]) { + (void)envp; try { return erpcsniffer::erpcsnifferTool(argc, argv).run(); From 99564cf2eaf37784dc90b82357db24f1af3fd0c0 Mon Sep 17 00:00:00 2001 From: Jean-Christian de Rivaz <84882+jcdr@users.noreply.github.com> Date: Sat, 3 Oct 2020 16:11:24 +0200 Subject: [PATCH 49/96] Generator.h: void unused parameter structMember --- erpcgen/src/Generator.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erpcgen/src/Generator.h b/erpcgen/src/Generator.h index 52c5835f6..5c2e52cc0 100644 --- a/erpcgen/src/Generator.h +++ b/erpcgen/src/Generator.h @@ -175,7 +175,7 @@ class Generator * * @param[in] structMember Structure member, Function parameter or Union member. */ - virtual void setBinaryList(StructMember *structMember){}; + virtual void setBinaryList(StructMember *structMember) { (void)structMember; }; /*! * @brief This function sets group symbols template data. From c0fd79153ef982b5e3e88371a38f932bf35b0d65 Mon Sep 17 00:00:00 2001 From: Jean-Christian de Rivaz <84882+jcdr@users.noreply.github.com> Date: Sat, 3 Oct 2020 16:51:11 +0200 Subject: [PATCH 50/96] CGenerator.cpp: void unused parameters --- erpcgen/src/CGenerator.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/erpcgen/src/CGenerator.cpp b/erpcgen/src/CGenerator.cpp index ca454b092..41237e1ee 100644 --- a/erpcgen/src/CGenerator.cpp +++ b/erpcgen/src/CGenerator.cpp @@ -1267,6 +1267,7 @@ data_map CGenerator::getUnionDeclarationTemplateData(UnionType *unionType) data_map CGenerator::getUnionDefinitionTemplateData(Group *group, UnionType *unionType, data_map &unionInfo, bool &needUnionsServerFree) { + (void)group; bool needTempVariable = false; unionInfo["coderCall"] = getEncodeDecodeCall("data->", nullptr, unionType, nullptr, true, nullptr, needTempVariable, false); @@ -1842,6 +1843,7 @@ void CGenerator::setSymbolDataToSide(const Symbol *symbolType, const set<_param_ data_map CGenerator::getTypeInfo(DataType *t, bool isFunction) { + (void)isFunction; data_map info; info["isNotVoid"] = make_data(t->getDataType() != DataType::kVoidType); return info; From 44b1fa0555304df7fa2a1585db707b786d9b937e Mon Sep 17 00:00:00 2001 From: Jean-Christian de Rivaz <84882+jcdr@users.noreply.github.com> Date: Sat, 3 Oct 2020 17:03:28 +0200 Subject: [PATCH 51/96] erpcgen.cpp: void unused parameter --- erpcgen/src/erpcgen.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/erpcgen/src/erpcgen.cpp b/erpcgen/src/erpcgen.cpp index b698bdb61..7ea5af5fc 100644 --- a/erpcgen/src/erpcgen.cpp +++ b/erpcgen/src/erpcgen.cpp @@ -381,6 +381,7 @@ class erpcgenTool */ int main(int argc, char *argv[], char *envp[]) { + (void)envp; try { return erpcgen::erpcgenTool(argc, argv).run(); From 1f9c65e3bc6f555f35aa1f5810848ff9fff60b7f Mon Sep 17 00:00:00 2001 From: Jean-Christian de Rivaz <84882+jcdr@users.noreply.github.com> Date: Sat, 3 Oct 2020 17:07:02 +0200 Subject: [PATCH 52/96] cpptempl.cpp: void unused parameters --- erpcgen/src/cpptemplate/cpptempl.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/erpcgen/src/cpptemplate/cpptempl.cpp b/erpcgen/src/cpptemplate/cpptempl.cpp index 0830a3195..28a3ceed4 100644 --- a/erpcgen/src/cpptemplate/cpptempl.cpp +++ b/erpcgen/src/cpptemplate/cpptempl.cpp @@ -521,6 +521,7 @@ bool DataBool::empty() } void DataBool::dump(int indent) { + (void)indent; std::cout << "(bool)" << getvalue() << std::endl; } int DataBool::getint() const @@ -540,6 +541,7 @@ bool DataInt::empty() } void DataInt::dump(int indent) { + (void)indent; std::cout << "(int)" << m_value << std::endl; } int DataInt::getint() const @@ -561,6 +563,7 @@ int DataValue::getint() const } void DataValue::dump(int indent) { + (void)indent; std::string text = boost::algorithm::replace_all_copy(getvalue(), "\n", "\\n"); std::cout << "\"" << text << "\"" << std::endl; } @@ -624,6 +627,7 @@ bool DataTemplate::empty() void DataTemplate::dump(int indent) { + (void)indent; std::cout << "(template)\n"; } @@ -1806,6 +1810,7 @@ NodeType NodeDef::gettype() void NodeDef::gettext(std::ostream &stream, data_map &data) { + (void)stream; // Follow the key path. data_ptr &target = data.parse_path(m_name, true); @@ -1825,6 +1830,7 @@ NodeType NodeSet::gettype() void NodeSet::gettext(std::ostream &stream, data_map &data) { + (void)stream; TokenIterator tok(m_expr); tok.match(SET_TOKEN, "expected 'set'"); std::string path = tok.match(KEY_PATH_TOKEN, "expected key path")->get_value(); From 917d5e2e9c6641042d4577363e1f2b89130547f4 Mon Sep 17 00:00:00 2001 From: Jean-Christian de Rivaz <84882+jcdr@users.noreply.github.com> Date: Sat, 3 Oct 2020 17:00:43 +0200 Subject: [PATCH 53/96] PythonGenerator.cpp: void unused parameters --- erpcgen/src/PythonGenerator.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/erpcgen/src/PythonGenerator.cpp b/erpcgen/src/PythonGenerator.cpp index 9a0311cd6..685ddf4af 100644 --- a/erpcgen/src/PythonGenerator.cpp +++ b/erpcgen/src/PythonGenerator.cpp @@ -167,6 +167,7 @@ void PythonGenerator::setTemplateComments(Symbol *symbol, data_map &symbolInfo) data_map PythonGenerator::getFunctionTemplateData(Group *group, Function *fn) { + (void)group; data_map info; string proto = getFunctionPrototype(fn); @@ -789,6 +790,7 @@ string PythonGenerator::filterName(const string &name) string PythonGenerator::convertComment(const string &comment, comment_type commentType) { + (void)commentType; // Longer patterns are ordered earlier than similar shorter patterns. static const char *const kCommentBegins[] = { "//!<", "//!", "///<", "///", "/*!<", "/*!", "/**<", "/**", 0 }; static const char *const kCommentEnds[] = { "*/", 0 }; From 916bef66d75ce4a9bf71fbefee56c3d1a500974b Mon Sep 17 00:00:00 2001 From: Jean-Christian de Rivaz <84882+jcdr@users.noreply.github.com> Date: Sat, 3 Oct 2020 15:49:32 +0200 Subject: [PATCH 54/96] SymbolScanner.cpp: fix comparison of integer expressions of different signedness --- erpcgen/src/SymbolScanner.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erpcgen/src/SymbolScanner.cpp b/erpcgen/src/SymbolScanner.cpp index 836f526e3..786685041 100644 --- a/erpcgen/src/SymbolScanner.cpp +++ b/erpcgen/src/SymbolScanner.cpp @@ -1138,7 +1138,7 @@ AstNode *SymbolScanner::handleFunction(AstNode *node, bottom_up) const StructType::member_vector_t &callbackParams = callbackFunctionType->getParameters().getMembers(); if (callbackFunctionType->getParameters().getMembers().size() > paramsSize) { - for (int i = paramsSize; i < callbackParams.size(); ++i) + for (unsigned int i = paramsSize; i < callbackParams.size(); ++i) { if (callbackParams[i]->getName().compare("") == 0) { From 2583ae6ba462db70f0f8a9a29e88d8eb9d449cfa Mon Sep 17 00:00:00 2001 From: Jean-Christian de Rivaz <84882+jcdr@users.noreply.github.com> Date: Sat, 3 Oct 2020 15:55:57 +0200 Subject: [PATCH 55/96] erpcgen_lexer.l: fix comparison of integer expressions of different signedness MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit erpc/erpcgen/src/erpcgen_lexer.l: In member function ‘virtual int erpcgen::ErpcLexer::yylex()’: erpc/erpcgen/src/erpcgen_lexer.l:213:52: error: comparison of integer expressions of different signedness: ‘int’ and ‘uint32_t’ {aka ‘unsigned int’} [-Werror=sign-compare] if (yyleng > m_indents) // remove indent spaces ~~~~~~~^~~~~~~~~~~ --- erpcgen/src/erpcgen_lexer.l | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erpcgen/src/erpcgen_lexer.l b/erpcgen/src/erpcgen_lexer.l index f7166b85c..b3aff1243 100644 --- a/erpcgen/src/erpcgen_lexer.l +++ b/erpcgen/src/erpcgen_lexer.l @@ -210,7 +210,7 @@ void { return TOK_VOID; } } } - if (yyleng > m_indents) // remove indent spaces + if (yyleng > (int)m_indents) // remove indent spaces { yytext += m_indents; yyleng -= m_indents; From edbcb342b4a15e5c2dcbf6bd27ec2f51140c9894 Mon Sep 17 00:00:00 2001 From: Jean-Christian de Rivaz <84882+jcdr@users.noreply.github.com> Date: Sat, 3 Oct 2020 16:06:14 +0200 Subject: [PATCH 56/96] Sniffer.cpp: fix comparison of integer expressions of different signedness --- erpcsniffer/src/Sniffer.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/erpcsniffer/src/Sniffer.cpp b/erpcsniffer/src/Sniffer.cpp index 9bc1f7e19..93cde2af8 100644 --- a/erpcsniffer/src/Sniffer.cpp +++ b/erpcsniffer/src/Sniffer.cpp @@ -376,7 +376,7 @@ erpc_status_t Sniffer::parseDataType(DataType *dataType, string &parsedDataInfo) return err; } string binaryValue; - for (int i = 0; i < length; ++i) + for (unsigned int i = 0; i < length; ++i) { binaryValue += format_string("%d|", value[i]); } @@ -394,7 +394,7 @@ erpc_status_t Sniffer::parseDataType(DataType *dataType, string &parsedDataInfo) { EnumType *e = dynamic_cast(dataType); assert(e); - int32_t value; + uint32_t value; m_codec->read(&value); if ((err = m_codec->getStatus())) { @@ -447,7 +447,7 @@ erpc_status_t Sniffer::parseDataType(DataType *dataType, string &parsedDataInfo) { return err; } - for (int i = 0; i < listSize; i++) + for (unsigned int i = 0; i < listSize; i++) { string parseDataInfo; err = parseDataType(listType->getElementType(), parseDataInfo); @@ -474,7 +474,7 @@ erpc_status_t Sniffer::parseDataType(DataType *dataType, string &parsedDataInfo) assert(structType); parsedDataInfo = "struct " + structType->getName() + ":\n"; StructType::member_vector_t members = structType->getMembers(); - for (int i = 0; i < members.size(); ++i) + for (unsigned int i = 0; i < members.size(); ++i) { string parseDataInfo; err = parseMemberType(structType, members[i], parseDataInfo); From c9b4e8a22a3233a213926a7fa30c82aa31044938 Mon Sep 17 00:00:00 2001 From: Jean-Christian de Rivaz <84882+jcdr@users.noreply.github.com> Date: Sat, 3 Oct 2020 16:14:32 +0200 Subject: [PATCH 57/96] Type.cpp: fix comparison of integer expressions of different signedness --- erpcgen/src/types/Type.cpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/erpcgen/src/types/Type.cpp b/erpcgen/src/types/Type.cpp index c04a2cf90..ddb1ab2f7 100644 --- a/erpcgen/src/types/Type.cpp +++ b/erpcgen/src/types/Type.cpp @@ -94,7 +94,7 @@ Annotation *Symbol::findAnnotation(string name, Annotation::program_lang_t lang) vector Symbol::getAnnotations(string name, Annotation::program_lang_t lang) { vector anList; - for (int i = 0; i < m_annotations.size(); ++i) + for (unsigned int i = 0; i < m_annotations.size(); ++i) { if (m_annotations[i].getName() == name && (m_annotations[i].getLang() == lang || m_annotations[i].getLang() == Annotation::kAll)) @@ -239,7 +239,7 @@ void SymbolScope::replaceSymbol(Symbol *oldSym, Symbol *newSym) int32_t SymbolScope::getSymbolPos(Symbol *sym) { - for (int i = 0; i < m_symbolVector.size(); i++) + for (unsigned int i = 0; i < m_symbolVector.size(); i++) { if (m_symbolVector[i] == sym) { @@ -323,7 +323,7 @@ void StructType::addMember(StructMember *newMember) string StructType::getDescription() const { string members; - int n = 0; + unsigned int n = 0; for (auto it : m_members) { members += format_string("%d:", n); @@ -363,7 +363,7 @@ void EnumType::addMember(EnumMember *newMember) string EnumType::getDescription() const { string members; - int n = 0; + unsigned int n = 0; for (auto it : m_members) { members += format_string("%d:", n); @@ -437,7 +437,7 @@ const set<_param_direction> Group::getSymbolDirections(Symbol *symbol) const string Group::getDescription() const { string ifaces; - int n = 0; + unsigned int n = 0; for (auto it : m_interfaces) { ifaces += format_string("%d:", n); @@ -517,7 +517,7 @@ void Interface::addFunction(Function *func) string Interface::getDescription() const { string fns; - int n = 0; + unsigned int n = 0; for (auto it : m_functions) { fns += format_string("%d:", n); @@ -619,7 +619,7 @@ bool UnionType::casesAreTheSame(UnionCase *a, UnionCase *b) { return false; } - for (int i = 0; i < aNames.size(); ++i) + for (unsigned int i = 0; i < aNames.size(); ++i) { if (aNames[i] != bNames[i]) { From 4e74763f482e84c9710d134621c606273d51dfe7 Mon Sep 17 00:00:00 2001 From: Jean-Christian de Rivaz <84882+jcdr@users.noreply.github.com> Date: Sat, 3 Oct 2020 16:17:03 +0200 Subject: [PATCH 58/96] UniqueIdChecker.cpp: fix comparison of integer expressions of different signedness --- erpcgen/src/UniqueIdChecker.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/erpcgen/src/UniqueIdChecker.cpp b/erpcgen/src/UniqueIdChecker.cpp index 3f39fdebe..b03f06ece 100644 --- a/erpcgen/src/UniqueIdChecker.cpp +++ b/erpcgen/src/UniqueIdChecker.cpp @@ -60,7 +60,7 @@ void UniqueIdChecker::initUsedInterfaceIds(SymbolScope::symbol_vector_t ifaces) { if (0 < ifaces.size()) { - for (int i = 0; i < ifaces.size(); ++i) + for (unsigned int i = 0; i < ifaces.size(); ++i) { Interface *iface = dynamic_cast(ifaces[i]); assert(iface); @@ -75,7 +75,7 @@ void UniqueIdChecker::initUsedFunctionIds(Interface *iface) Interface::function_vector_t functions = iface->getFunctions(); if (0 < functions.size()) { - for (int i = 0; i < functions.size(); ++i) + for (unsigned int i = 0; i < functions.size(); ++i) { m_usedFunctionIds.push_back(make_pair(functions[i]->getUniqueId(), functions[i]->getName())); } @@ -98,7 +98,7 @@ void UniqueIdChecker::setInterfaceId(Interface *iface, Annotation *interfaceId) format_string("@id value for interface %s must be greater than zero", iface->getName().c_str())); } iface->setUniqueId(newIdValue); - for (int i = 0; i < m_usedInterfaceIds.size(); ++i) + for (unsigned int i = 0; i < m_usedInterfaceIds.size(); ++i) { if (0 == m_usedInterfaceIds[i].second.compare(iface->getName())) { @@ -132,7 +132,7 @@ void UniqueIdChecker::setFunctionId(Function *fn, Annotation *idAnnotation) printf("%d: \n",i, usedFunctionIds[i].first, usedFunctionIds[i].second.c_str()); } */ - for (int i = 0; i < m_usedFunctionIds.size(); ++i) + for (unsigned int i = 0; i < m_usedFunctionIds.size(); ++i) { // printf("usedFunctionIds at i: %s\t", usedFunctionIds[i].second.c_str()); // printf("fn name: %s\n", fn->getName().c_str()); From b73fdf49bc9aab29db9a77c915f2d9ab6e7e6267 Mon Sep 17 00:00:00 2001 From: Jean-Christian de Rivaz <84882+jcdr@users.noreply.github.com> Date: Sat, 3 Oct 2020 16:49:35 +0200 Subject: [PATCH 59/96] CGenerator.cpp: fix comparison of integer expressions of different signedness --- erpcgen/src/CGenerator.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/erpcgen/src/CGenerator.cpp b/erpcgen/src/CGenerator.cpp index 41237e1ee..53121ef34 100644 --- a/erpcgen/src/CGenerator.cpp +++ b/erpcgen/src/CGenerator.cpp @@ -629,7 +629,7 @@ data_map CGenerator::getEnumTemplateData(EnumType *enumType) data_list CGenerator::getEnumMembersTemplateData(EnumType *enumType) { - int j = 0; + unsigned int j = 0; data_list enumMembersList; for (auto member : enumType->getMembers()) { @@ -720,12 +720,12 @@ void CGenerator::makeAliasesTemplateData() else { /* skip structure, unions and functions type definitions */ - for (int aliasTypesIt = i; aliasTypesIt < aliasTypeVector.size(); ++aliasTypesIt) + for (unsigned int aliasTypesIt = i; aliasTypesIt < aliasTypeVector.size(); ++aliasTypesIt) { if (callbackParamType == aliasTypeVector[aliasTypesIt]) { // Add aliases in IDL declaration order. - int nextIt = aliasTypesIt + 1; + unsigned int nextIt = aliasTypesIt + 1; while (nextIt < aliasTypeVector.size()) { AliasType *nextAlias = dynamic_cast(aliasTypeVector[nextIt]); @@ -1939,7 +1939,7 @@ string CGenerator::getFunctionServerCall(Function *fn, FunctionType *functionTyp if (params.size()) { - int n = 0; + unsigned int n = 0; for (auto it : params) { bool isLast = (n == params.size() - 1); @@ -2015,7 +2015,7 @@ string CGenerator::getFunctionPrototype(Group *group, FunctionBase *fn, std::str if (params.size()) { - int n = 0; + unsigned int n = 0; for (auto it : params) { bool isLast = (n == params.size() - 1); From a2107dc4c7f20590034509b97d4e4bb6a0ce1e5f Mon Sep 17 00:00:00 2001 From: Jean-Christian de Rivaz <84882+jcdr@users.noreply.github.com> Date: Sun, 4 Oct 2020 14:44:53 +0200 Subject: [PATCH 60/96] PythonGenerator.cpp: comparison of integer expressions of different signedness --- erpcgen/src/PythonGenerator.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/erpcgen/src/PythonGenerator.cpp b/erpcgen/src/PythonGenerator.cpp index 685ddf4af..703403432 100644 --- a/erpcgen/src/PythonGenerator.cpp +++ b/erpcgen/src/PythonGenerator.cpp @@ -907,11 +907,11 @@ string PythonGenerator::stripWhitespace(const string &s) uint32_t n; // Strip leading whitespace. - for (n = 0, i = 0; i < result.size(); ++i, ++n) + for (n = 0, i = 0; i < (int)result.size(); ++i, ++n) { char c = result[i]; - if ((i < result.size() - 1 && c == ' ' && !checkWhitspaceChar(result[i + 1])) || !checkWhitspaceChar(c)) + if ((i < (int)result.size() - 1 && c == ' ' && !checkWhitspaceChar(result[i + 1])) || !checkWhitspaceChar(c)) { break; } @@ -922,7 +922,7 @@ string PythonGenerator::stripWhitespace(const string &s) } // Strip trailing whitespace. - for (n = 0, i = result.size() - 1; i > 0; --i, ++n) + for (n = 0, i = (int)result.size() - 1; i > 0; --i, ++n) { char c = result[i]; if (!checkWhitspaceChar(c)) From bbc866635ce0ddb3d6e4276b13e2aa8c379369e2 Mon Sep 17 00:00:00 2001 From: Jean-Christian de Rivaz <84882+jcdr@users.noreply.github.com> Date: Sat, 3 Oct 2020 16:58:24 +0200 Subject: [PATCH 61/96] Generator.cpp: fix comparison of integer expressions of different signedness --- erpcgen/src/Generator.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erpcgen/src/Generator.cpp b/erpcgen/src/Generator.cpp index f088ad77d..7d37fe0bf 100644 --- a/erpcgen/src/Generator.cpp +++ b/erpcgen/src/Generator.cpp @@ -430,7 +430,7 @@ data_list Generator::makeGroupInterfacesTemplateData(Group *group) data_list functions = getFunctionsTemplateData(group, iface); ifaceInfo["functions"] = functions; ifaceInfo["isNonExternalInterface"] = false; - for (int i = 0; i < functions.size(); ++i) + for (unsigned int i = 0; i < functions.size(); ++i) { assert(dynamic_cast(functions[i].get().get())); string isNonExternalFunction = From d911f0905e212db70fa4103af42d0ea956196161 Mon Sep 17 00:00:00 2001 From: Jean-Christian de Rivaz <84882+jcdr@users.noreply.github.com> Date: Sat, 3 Oct 2020 15:26:40 +0200 Subject: [PATCH 62/96] erpc_port_stdlib.cpp: Add missing delete operators MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit erpc_c/port/erpc_port_stdlib.cpp:42:6: error: the program should also define ‘void operator delete(void*, std::size_t)’ [-Werror=sized-deallocation] erpc_c/port/erpc_port_stdlib.cpp:47:6: error: the program should also define ‘void operator delete [](void*, std::size_t)’ [-Werror=sized-deallocation] --- erpc_c/port/erpc_port_stdlib.cpp | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/erpc_c/port/erpc_port_stdlib.cpp b/erpc_c/port/erpc_port_stdlib.cpp index de26d88b1..2a7e76248 100644 --- a/erpc_c/port/erpc_port_stdlib.cpp +++ b/erpc_c/port/erpc_port_stdlib.cpp @@ -44,11 +44,23 @@ void operator delete(void *ptr) THROW NOEXCEPT erpc_free(ptr); } +void operator delete(void* ptr, std::size_t count) THROW NOEXCEPT +{ + (void)count; + erpc_free(ptr); +} + void operator delete[](void *ptr) THROW NOEXCEPT { erpc_free(ptr); } +void operator delete[](void* ptr, std::size_t count) THROW NOEXCEPT +{ + (void)count; + erpc_free(ptr); +} + void *erpc_malloc(size_t size) { void *p = malloc(size); From c0723393deb6ce267b62ff3ea71f3682aab9b6fa Mon Sep 17 00:00:00 2001 From: Jean-Christian de Rivaz <84882+jcdr@users.noreply.github.com> Date: Sat, 3 Oct 2020 04:01:07 +0200 Subject: [PATCH 63/96] erpc_threading_pthreads.cpp: Thread::sleep() Initialize struct timespec.tv_ns --- erpc_c/port/erpc_threading_pthreads.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erpc_c/port/erpc_threading_pthreads.cpp b/erpc_c/port/erpc_threading_pthreads.cpp index 3594f14b3..e29d2f129 100644 --- a/erpc_c/port/erpc_threading_pthreads.cpp +++ b/erpc_c/port/erpc_threading_pthreads.cpp @@ -84,7 +84,7 @@ void Thread::sleep(uint32_t usecs) { // Sleep for the requested number of microseconds. struct timespec rq = { .tv_sec = usecs / 1000000, .tv_nsec = (usecs % 1000000) * 1000 }; - struct timespec actual = { 0 }; + struct timespec actual = { 0, 0 }; // Keep sleeping until the requested time elapses even if we get interrupted by a signal. while (nanosleep(&rq, &actual) == EINTR) From f2b06f7bea540f696e74cb46ba00b49754c07615 Mon Sep 17 00:00:00 2001 From: Jean-Christian de Rivaz <84882+jcdr@users.noreply.github.com> Date: Sat, 3 Oct 2020 15:34:04 +0200 Subject: [PATCH 64/96] erpc_tcp_transport.cpp: fix missing initializer for members of addrinfo MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit erpc/erpc_c/transports/erpc_tcp_transport.cpp: In member function ‘virtual erpc_status_t erpc::TCPTransport::connectClient()’: erpc/erpc_c/transports/erpc_tcp_transport.cpp:89:33: error: missing initializer for member ‘addrinfo::ai_family’ [-Werror=missing-field-initializers] struct addrinfo hints = { 0 }; ^ erpc/erpc_c/transports/erpc_tcp_transport.cpp:89:33: error: missing initializer for member ‘addrinfo::ai_socktype’ [-Werror=missing-field-initializers] erpc/erpc_c/transports/erpc_tcp_transport.cpp:89:33: error: missing initializer for member ‘addrinfo::ai_protocol’ [-Werror=missing-field-initializers] erpc/erpc_c/transports/erpc_tcp_transport.cpp:89:33: error: missing initializer for member ‘addrinfo::ai_addrlen’ [-Werror=missing-field-initializers] erpc/erpc_c/transports/erpc_tcp_transport.cpp:89:33: error: missing initializer for member ‘addrinfo::ai_addr’ [-Werror=missing-field-initializers] erpc/erpc_c/transports/erpc_tcp_transport.cpp:89:33: error: missing initializer for member ‘addrinfo::ai_canonname’ [-Werror=missing-field-initializers] erpc/erpc_c/transports/erpc_tcp_transport.cpp:89:33: error: missing initializer for member ‘addrinfo::ai_next’ [-Werror=missing-field-initializers] --- erpc_c/transports/erpc_tcp_transport.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/erpc_c/transports/erpc_tcp_transport.cpp b/erpc_c/transports/erpc_tcp_transport.cpp index cb6b1a438..c76d9747a 100644 --- a/erpc_c/transports/erpc_tcp_transport.cpp +++ b/erpc_c/transports/erpc_tcp_transport.cpp @@ -86,7 +86,8 @@ erpc_status_t TCPTransport::connectClient(void) } // Fill in hints structure for getaddrinfo. - struct addrinfo hints = { 0 }; + struct addrinfo hints; + memset(&hints, 0, sizeof(struct addrinfo)); hints.ai_flags = AI_NUMERICSERV; hints.ai_family = PF_UNSPEC; hints.ai_socktype = SOCK_STREAM; From fcfb6bc3e01f585c18ea9a80e1c046eecbce90a9 Mon Sep 17 00:00:00 2001 From: Jean-Christian de Rivaz <84882+jcdr@users.noreply.github.com> Date: Sat, 3 Oct 2020 17:08:10 +0200 Subject: [PATCH 65/96] =?UTF-8?q?cpptempl.cpp:=20fix=20missing=20initializ?= =?UTF-8?q?er=20for=20member=20=E2=80=98cpptempl::impl::KeywordDef::keywor?= =?UTF-8?q?d=E2=80=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- erpcgen/src/cpptemplate/cpptempl.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erpcgen/src/cpptemplate/cpptempl.cpp b/erpcgen/src/cpptemplate/cpptempl.cpp index 28a3ceed4..68503a84f 100644 --- a/erpcgen/src/cpptemplate/cpptempl.cpp +++ b/erpcgen/src/cpptemplate/cpptempl.cpp @@ -798,7 +798,7 @@ const KeywordDef k_keywords[] = { { TRUE_TOKEN, "true" }, { FALSE_TOKEN, "fa { ELSE_TOKEN, "else" }, { DEF_TOKEN, "def" }, { SET_TOKEN, "set" }, { ENDFOR_TOKEN, "endfor" }, { ENDIF_TOKEN, "endif" }, { ENDDEF_TOKEN, "enddef" }, { AND_TOKEN, "and" }, { OR_TOKEN, "or" }, { NOT_TOKEN, "not" }, - { INVALID_TOKEN } }; + { INVALID_TOKEN, NULL } }; TokenType get_keyword_token(const std::string &s) { From 84c4eb2f4e09ed97f35db5a9babd1e829b5181b5 Mon Sep 17 00:00:00 2001 From: Jean-Christian de Rivaz <84882+jcdr@users.noreply.github.com> Date: Sun, 4 Oct 2020 00:08:20 +0200 Subject: [PATCH 66/96] Don't use designated initializers to be gnu++11 compatible with paranoid flags --- erpc_c/port/erpc_threading_pthreads.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/erpc_c/port/erpc_threading_pthreads.cpp b/erpc_c/port/erpc_threading_pthreads.cpp index e29d2f129..023b6b094 100644 --- a/erpc_c/port/erpc_threading_pthreads.cpp +++ b/erpc_c/port/erpc_threading_pthreads.cpp @@ -83,7 +83,9 @@ Thread *Thread::getCurrentThread(void) void Thread::sleep(uint32_t usecs) { // Sleep for the requested number of microseconds. - struct timespec rq = { .tv_sec = usecs / 1000000, .tv_nsec = (usecs % 1000000) * 1000 }; + struct timespec rq; + rq.tv_sec = usecs / 1000000; + rq.tv_nsec = (usecs % 1000000) * 1000; struct timespec actual = { 0, 0 }; // Keep sleeping until the requested time elapses even if we get interrupted by a signal. @@ -190,7 +192,9 @@ bool Semaphore::get(uint32_t timeout) // Create an absolute timeout time. struct timeval tv; gettimeofday(&tv, NULL); - struct timespec wait = { .tv_sec = tv.tv_sec + (timeout / 1000000), .tv_nsec = (timeout % 1000000) * 1000 }; + struct timespec wait; + wait.tv_sec = tv.tv_sec + (timeout / 1000000); + wait.tv_nsec = (timeout % 1000000) * 1000; err = pthread_cond_timedwait(&m_cond, m_mutex.getPtr(), &wait); if (err) { From a5ddeec556962b549a9c730a50710d5fdce0f819 Mon Sep 17 00:00:00 2001 From: Jean-Christian de Rivaz <84882+jcdr@users.noreply.github.com> Date: Sun, 4 Oct 2020 02:04:37 +0200 Subject: [PATCH 67/96] erpc_tcp_transport.cpp: fix ISO C99 requires rest arguments to be used --- erpc_c/transports/erpc_tcp_transport.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/erpc_c/transports/erpc_tcp_transport.cpp b/erpc_c/transports/erpc_tcp_transport.cpp index c76d9747a..e52061035 100644 --- a/erpc_c/transports/erpc_tcp_transport.cpp +++ b/erpc_c/transports/erpc_tcp_transport.cpp @@ -81,7 +81,7 @@ erpc_status_t TCPTransport::connectClient(void) { if (m_socket != -1) { - TCP_DEBUG_PRINT("socket already connected\n"); + TCP_DEBUG_PRINT("%s", "socket already connected\n"); return kErpcStatus_Success; } @@ -248,7 +248,7 @@ erpc_status_t TCPTransport::underlyingSend(const uint8_t *data, uint32_t size) void TCPTransport::serverThread(void) { - TCP_DEBUG_PRINT("in server thread\n"); + TCP_DEBUG_PRINT("%s", "in server thread\n"); // Create socket. int serverSocket = socket(AF_INET, SOCK_STREAM, 0); @@ -293,7 +293,7 @@ void TCPTransport::serverThread(void) return; } - TCP_DEBUG_PRINT("Listening for connections\n"); + TCP_DEBUG_PRINT("%s", "Listening for connections\n"); while (m_runServer) { From 986b2572b9e9563303ef7039a0e563062db9d365 Mon Sep 17 00:00:00 2001 From: Jean-Christian de Rivaz <84882+jcdr@users.noreply.github.com> Date: Sun, 4 Oct 2020 03:52:55 +0200 Subject: [PATCH 68/96] gtest.h gtest.cpp: fix '#' is not followed by a macro parameter --- test/common/gtest/gtest.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/test/common/gtest/gtest.cpp b/test/common/gtest/gtest.cpp index 367462136..3ac4413e6 100644 --- a/test/common/gtest/gtest.cpp +++ b/test/common/gtest/gtest.cpp @@ -1863,7 +1863,10 @@ void AssertHelper::operator=(const Message& message) const { } // Mutex for linked pointers. +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wmissing-field-initializers" GTEST_API_ GTEST_DEFINE_STATIC_MUTEX_(g_linked_ptr_mutex); +#pragma GCC diagnostic pop // Application pathname gotten in InitGoogleTest. std::string g_executable_path; From bc4eb89db11869b0900c1c488ab9f47c0bb27833 Mon Sep 17 00:00:00 2001 From: Jean-Christian de Rivaz <84882+jcdr@users.noreply.github.com> Date: Sat, 3 Oct 2020 17:13:45 +0200 Subject: [PATCH 69/96] =?UTF-8?q?cpptempl.cpp:=20fix=20catching=20polymorp?= =?UTF-8?q?hic=20type=20=E2=80=98class=20cpptempl::TemplateException?= =?UTF-8?q?=E2=80=99=20by=20value?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- erpcgen/src/cpptemplate/cpptempl.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/erpcgen/src/cpptemplate/cpptempl.cpp b/erpcgen/src/cpptemplate/cpptempl.cpp index 68503a84f..5cbb00917 100644 --- a/erpcgen/src/cpptemplate/cpptempl.cpp +++ b/erpcgen/src/cpptemplate/cpptempl.cpp @@ -1582,7 +1582,7 @@ void NodeVar::gettext(std::ostream &stream, data_map &data) stream << str; } - catch (TemplateException e) + catch (TemplateException &e) { e.set_line_if_missing(get_line()); throw e; @@ -1690,7 +1690,7 @@ void NodeFor::gettext(std::ostream &stream, data_map &data) // ignore exception - the for loop key variable doesn't exist, so just // don't execute the for loop at all } - catch (TemplateException e) + catch (TemplateException &e) { e.set_line_if_missing(get_line()); throw e; @@ -1764,7 +1764,7 @@ bool NodeIf::is_true(data_map &data) return !d->empty(); } - catch (TemplateException e) + catch (TemplateException &e) { e.set_line_if_missing(get_line()); throw e; @@ -1935,7 +1935,7 @@ node_vector &TemplateParser::parse() return m_top_nodes; } - catch (TemplateException e) + catch (TemplateException &e) { e.set_line_if_missing(m_current_line); throw e; From 7b6c3419b153fc26a89e43b290fbecbd9e268fbe Mon Sep 17 00:00:00 2001 From: Jean-Christian de Rivaz <84882+jcdr@users.noreply.github.com> Date: Sat, 3 Oct 2020 17:28:31 +0200 Subject: [PATCH 70/96] =?UTF-8?q?Function.h:=20fix=20base=20=E2=80=98erpcg?= =?UTF-8?q?en::Symbol=E2=80=99=20will=20be=20initialized=20after...?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- erpcgen/src/types/Function.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/erpcgen/src/types/Function.h b/erpcgen/src/types/Function.h index 60b0c3dee..caeae0fe5 100644 --- a/erpcgen/src/types/Function.h +++ b/erpcgen/src/types/Function.h @@ -125,8 +125,8 @@ class Function : public FunctionBase, public Symbol * @param[in] m_interface Parent interface. */ Function(const Token &tok, Interface *interface) - : Symbol(kFunctionSymbol, tok) - , FunctionBase() + : FunctionBase() + , Symbol(kFunctionSymbol, tok) , m_uniqueId(++s_idCounter) , m_interface(interface) , m_functionType(nullptr) @@ -143,8 +143,8 @@ class Function : public FunctionBase, public Symbol * @param[in] uniqueId Given unique function id. */ Function(const Token &tok, Interface *interface, uint32_t uniqueId) - : Symbol(kFunctionSymbol, tok) - , FunctionBase() + : FunctionBase() + , Symbol(kFunctionSymbol, tok) , m_uniqueId(uniqueId) , m_interface(interface) , m_functionType(nullptr) From e2eb02bdb02fa2e26a0d85f44e6f6eb4bb063d24 Mon Sep 17 00:00:00 2001 From: Jean-Christian de Rivaz <84882+jcdr@users.noreply.github.com> Date: Sat, 3 Oct 2020 17:36:22 +0200 Subject: [PATCH 71/96] =?UTF-8?q?ErpcLexer.h:=20fix=20=E2=80=98erpcgen::Er?= =?UTF-8?q?pcLexer::m=5Findents=E2=80=99=20will=20be=20initialized=20after?= =?UTF-8?q?=20CurrentFileInfo=20*m=5FcurrentFileInfo?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- erpcgen/src/ErpcLexer.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erpcgen/src/ErpcLexer.h b/erpcgen/src/ErpcLexer.h index 2fa004cd0..f4fb2a368 100644 --- a/erpcgen/src/ErpcLexer.h +++ b/erpcgen/src/ErpcLexer.h @@ -161,8 +161,8 @@ class ErpcLexer : public yyFlexLexer protected: Value *m_value; /*!< Value for the current token. */ token_loc_t m_location; /*!< Location for the current token. */ - CurrentFileInfo *m_currentFileInfo; /*!< Pointer to current file info. */ uint32_t m_indents; /*!< How much indents can be removed from newlines in doxygen comments. */ + CurrentFileInfo *m_currentFileInfo; /*!< Pointer to current file info. */ uint16_t m_idlCrc16; /*!< Crc16 of IDL files. */ /*! From 5f8146dc5540743c066928f7d95aa1a368aa7c3b Mon Sep 17 00:00:00 2001 From: Jean-Christian de Rivaz <84882+jcdr@users.noreply.github.com> Date: Sat, 3 Oct 2020 17:40:03 +0200 Subject: [PATCH 72/96] Generator.cpp: fix initialization order --- erpcgen/src/Generator.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/erpcgen/src/Generator.cpp b/erpcgen/src/Generator.cpp index 7d37fe0bf..1346c4dd7 100644 --- a/erpcgen/src/Generator.cpp +++ b/erpcgen/src/Generator.cpp @@ -26,9 +26,9 @@ using namespace std; //////////////////////////////////////////////////////////////////////////////// Generator::Generator(InterfaceDefinition *def, generator_type_t generatorType) -: m_def(def) +: m_idlCrc16(def->getIdlCrc16()) +, m_def(def) , m_globals(&(def->getGlobals())) -, m_idlCrc16(def->getIdlCrc16()) , m_generatorType(generatorType) { m_templateData["erpcVersion"] = ERPC_VERSION; From 03544c6e6cc7d5bda522b6aca7e8061bd203afe4 Mon Sep 17 00:00:00 2001 From: Jean-Christian de Rivaz <84882+jcdr@users.noreply.github.com> Date: Sat, 3 Oct 2020 17:42:30 +0200 Subject: [PATCH 73/96] Generator.cpp: fix initialization order --- erpcgen/src/InterfaceDefinition.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erpcgen/src/InterfaceDefinition.cpp b/erpcgen/src/InterfaceDefinition.cpp index 88b641f03..b6dec2773 100644 --- a/erpcgen/src/InterfaceDefinition.cpp +++ b/erpcgen/src/InterfaceDefinition.cpp @@ -29,10 +29,10 @@ using namespace std; InterfaceDefinition::InterfaceDefinition() : m_ast(nullptr) , m_globals() +, m_program(nullptr) , m_programName("") , m_outputFilename("") , m_codec(kNotSpecified) -, m_program(nullptr) { init(); } From a9f74ac6c1af2f2dedbfea1f9eb17e787d00121d Mon Sep 17 00:00:00 2001 From: Jean-Christian de Rivaz <84882+jcdr@users.noreply.github.com> Date: Sat, 3 Oct 2020 15:52:23 +0200 Subject: [PATCH 74/96] =?UTF-8?q?SymbolScanner.cpp:=20fix=20declaration=20?= =?UTF-8?q?of=20=E2=80=98nameOfType=E2=80=99=20shadows=20a=20previous=20lo?= =?UTF-8?q?cal?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- erpcgen/src/SymbolScanner.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erpcgen/src/SymbolScanner.cpp b/erpcgen/src/SymbolScanner.cpp index 786685041..89cb92bb7 100644 --- a/erpcgen/src/SymbolScanner.cpp +++ b/erpcgen/src/SymbolScanner.cpp @@ -1484,7 +1484,7 @@ void SymbolScanner::addAnnotations(AstNode *childNode, Symbol *symbol) string nameOfType; if (childNode->getParent()->getChild(0)) { - string nameOfType = childNode->getParent()->getChild(0)->getToken().getStringValue(); + nameOfType = childNode->getParent()->getChild(0)->getToken().getStringValue(); Log::log("Handling annotations for %s\n", nameOfType.c_str()); } else From 954c14c4cf0d448176534f67194368dbbeb1bd4c Mon Sep 17 00:00:00 2001 From: Jean-Christian de Rivaz <84882+jcdr@users.noreply.github.com> Date: Sat, 3 Oct 2020 16:56:20 +0200 Subject: [PATCH 75/96] CGenerator.cpp: fix shadowed declarations --- erpcgen/src/CGenerator.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/erpcgen/src/CGenerator.cpp b/erpcgen/src/CGenerator.cpp index 53121ef34..af0ce7a1c 100644 --- a/erpcgen/src/CGenerator.cpp +++ b/erpcgen/src/CGenerator.cpp @@ -1574,9 +1574,9 @@ data_map CGenerator::getFunctionBaseTemplateData(Group *group, FunctionBase *fn) Symbol *symbol = fn->getParameters().getScope().getSymbol(maxLengthName, false); if (symbol) { - StructMember *structMember = dynamic_cast(symbol); - assert(structMember); - if (structMember->getDirection() != kInDirection) + StructMember *symbolStructMember = dynamic_cast(symbol); + assert(symbolStructMember); + if (symbolStructMember->getDirection() != kInDirection) { throw semantic_error( format_string("line %d, ref %d: The parameter named by a max_length annotation must be " @@ -2129,7 +2129,7 @@ string CGenerator::generateIncludeGuardName(const string &filename) size_t found = filename.find_last_of("/\\"); if (found != string::npos) { - string fileNoPath = filename.substr(found + 1); + fileNoPath = filename.substr(found + 1); } // Create include guard macro name. guard = "_"; From 1da74c7f6ca2c50fb6456c0f31c39fb7d7783f6d Mon Sep 17 00:00:00 2001 From: Jean-Christian de Rivaz <84882+jcdr@users.noreply.github.com> Date: Sun, 4 Oct 2020 01:46:30 +0200 Subject: [PATCH 76/96] =?UTF-8?q?erpc=5Fclient=5Fmanager.h:=20try=20to=20f?= =?UTF-8?q?ix=20declaration=20of=20=E2=80=98isOneway=E2=80=99=20shadows=20?= =?UTF-8?q?a=20member=20of=20'this'?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Compiling erpc_c/infra/erpc_arbitrated_client_manager.cpp 690In file included from /home/travis/build/EmbeddedRPC/erpc/erpc_c/infra/erpc_arbitrated_client_manager.h:13:0, 691 from /home/travis/build/EmbeddedRPC/erpc/erpc_c/infra/erpc_arbitrated_client_manager.cpp:10: 692/home/travis/build/EmbeddedRPC/erpc/erpc_c/infra/erpc_client_manager.h: In constructor ‘erpc::RequestContext::RequestContext(uint32_t, erpc::Codec*, bool)’: 693/home/travis/build/EmbeddedRPC/erpc/erpc_c/infra/erpc_client_manager.h:225:5: error: declaration of ‘isOneway’ shadows a member of 'this' [-Werror=shadow] 694 : m_sequence(sequence) 695 ^ --- erpc_c/infra/erpc_client_manager.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/erpc_c/infra/erpc_client_manager.h b/erpc_c/infra/erpc_client_manager.h index 130b31c84..851aa14d4 100644 --- a/erpc_c/infra/erpc_client_manager.h +++ b/erpc_c/infra/erpc_client_manager.h @@ -221,10 +221,10 @@ class RequestContext * @param[in] codec Set in inout codec. * @param[in] isOneway Set information if codec is only oneway or bidirectional. */ - RequestContext(uint32_t sequence, Codec *codec, bool isOneway) + RequestContext(uint32_t sequence, Codec *codec, bool argIsOneway) : m_sequence(sequence) , m_codec(codec) - , m_oneway(isOneway) + , m_oneway(argIsOneway) { } From f640e6b38485ecd439e6cd83eb1315ab2cdc5962 Mon Sep 17 00:00:00 2001 From: Jean-Christian de Rivaz <84882+jcdr@users.noreply.github.com> Date: Sun, 4 Oct 2020 02:51:56 +0200 Subject: [PATCH 77/96] Fix various declarations shadows a member of 'this' --- erpcgen/src/options.cpp | 8 ++++---- erpcgen/src/types/Function.h | 2 +- erpcgen/src/types/Type.cpp | 8 ++++---- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/erpcgen/src/options.cpp b/erpcgen/src/options.cpp index 485dc2dd7..b6c6c578c 100644 --- a/erpcgen/src/options.cpp +++ b/erpcgen/src/options.cpp @@ -159,10 +159,10 @@ void OptArgvIter::rewind(void) static const char WHITESPACE[] = " \t\n\r\v\f"; const char *OptStrTokIter::default_delims = WHITESPACE; -OptStrTokIter::OptStrTokIter(const char *tokens, const char *delimiters) +OptStrTokIter::OptStrTokIter(const char *tokens, const char *arg_delimiters) : len(unsigned(strlen(tokens))) , str(tokens) -, seps(delimiters) +, seps(arg_delimiters) , cur(NULLSTR) , tokstr(NULLSTR) { @@ -641,13 +641,13 @@ unsigned OptionSpec::Format(char *buf, unsigned optctrls) const #define DIR_SEP_CHAR '/' #endif -Options::Options(const char *name, const char *const optv[]) +Options::Options(const char *arg_name, const char *const optv[]) : explicit_end(0) , optctrls(DEFAULT) , optvec(optv) , nextchar(NULLSTR) , listopt(NULLSTR) -, cmdname(name) +, cmdname(arg_name) { const char *basename = ::strrchr(cmdname, DIR_SEP_CHAR); if (basename) diff --git a/erpcgen/src/types/Function.h b/erpcgen/src/types/Function.h index caeae0fe5..4d2f91671 100644 --- a/erpcgen/src/types/Function.h +++ b/erpcgen/src/types/Function.h @@ -82,7 +82,7 @@ class FunctionBase * * @param[in] isOneway Set, if function return type is oneway. */ - void setIsOneway(bool isOneway) { m_isOneway = isOneway; } + void setIsOneway(bool argIsOneway) { m_isOneway = argIsOneway; } /*! * @brief This function returns description about the interface function. diff --git a/erpcgen/src/types/Type.cpp b/erpcgen/src/types/Type.cpp index ddb1ab2f7..dd4d2abeb 100644 --- a/erpcgen/src/types/Type.cpp +++ b/erpcgen/src/types/Type.cpp @@ -592,21 +592,21 @@ string UnionType::getDescription() const UnionType::case_vector_t UnionType::getUniqueCases() { UnionType::case_vector_t uniqueCases; - bool addCase = true; + bool uniqueAddCase = true; for (auto unionCase : getCases()) { for (auto uniqueCase : uniqueCases) { if (casesAreTheSame(unionCase, uniqueCase)) { - addCase = false; + uniqueAddCase = false; } } - if (addCase) + if (uniqueAddCase) { uniqueCases.push_back(unionCase); } - addCase = true; + uniqueAddCase = true; } return uniqueCases; } From a59cadd8f66afdef12fd4893b54d368fbcee19e4 Mon Sep 17 00:00:00 2001 From: Jean-Christian de Rivaz <84882+jcdr@users.noreply.github.com> Date: Sun, 4 Oct 2020 03:00:30 +0200 Subject: [PATCH 78/96] =?UTF-8?q?Sniffer.cpp:=20fix=20declaration=20of=20?= =?UTF-8?q?=E2=80=98countSpaces=E2=80=99=20shadows=20a=20member=20of=20'th?= =?UTF-8?q?is'?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- erpcsniffer/src/Sniffer.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/erpcsniffer/src/Sniffer.cpp b/erpcsniffer/src/Sniffer.cpp index 93cde2af8..158c0b41c 100644 --- a/erpcsniffer/src/Sniffer.cpp +++ b/erpcsniffer/src/Sniffer.cpp @@ -75,8 +75,8 @@ erpc_status_t Sniffer::run() 0 : chrono::duration_cast(currentTime - previousTime).count()); uint32_t timeDifferenceSize = timeDifference.size(); - uint32_t countSpaces = floor((timeDifferenceSize - 1) / 3); - for (uint32_t i = 1; i <= countSpaces; ++i) + uint32_t diffCountSpaces = floor((timeDifferenceSize - 1) / 3); + for (uint32_t i = 1; i <= diffCountSpaces; ++i) { timeDifference = timeDifference.insert(timeDifferenceSize - i * 3, " "); } From b0f588b5530cc87d013e54c7532498a977332ea1 Mon Sep 17 00:00:00 2001 From: Jean-Christian de Rivaz <84882+jcdr@users.noreply.github.com> Date: Sun, 4 Oct 2020 03:08:47 +0200 Subject: [PATCH 79/96] =?UTF-8?q?gtest.h:=20fix=20declaration=20of=20?= =?UTF-8?q?=E2=80=98type=E2=80=99=20shadows=20a=20member=20of=20'this'?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- test/common/gtest/gtest.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/common/gtest/gtest.h b/test/common/gtest/gtest.h index ca8f6926d..e07c3371c 100644 --- a/test/common/gtest/gtest.h +++ b/test/common/gtest/gtest.h @@ -17757,7 +17757,7 @@ class BaseTestPartResult{ // C'tor. BaseTestPartResult does NOT have a default constructor. // Always use this constructor (with parameters) to create a // BaseTestPartResult object. - BaseTestPartResult(Type type){type_ = type;} + BaseTestPartResult(Type arg_type){type_ = arg_type;} // D'tor. BaseTestPartResult have a virtual destructor because it could // be used for inheritance. From 1a1b773e3fb98da0a770ed767ebc9cb649de8c0b Mon Sep 17 00:00:00 2001 From: Jean-Christian de Rivaz <84882+jcdr@users.noreply.github.com> Date: Sun, 4 Oct 2020 14:49:20 +0200 Subject: [PATCH 80/96] =?UTF-8?q?unit=5Ftest=5Fserial=5Fclient.cpp:=20decl?= =?UTF-8?q?aration=20of=20=E2=80=98i=E2=80=99=20shadows=20a=20global=20dec?= =?UTF-8?q?laration?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- test/common/unit_test_serial_client.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/common/unit_test_serial_client.cpp b/test/common/unit_test_serial_client.cpp index a2d4b2816..8efa01911 100644 --- a/test/common/unit_test_serial_client.cpp +++ b/test/common/unit_test_serial_client.cpp @@ -69,12 +69,12 @@ int main(int argc, char **argv) g_client->setTransport(&g_transport); g_client->setCodecFactory(&g_basicCodecFactory); - int i = RUN_ALL_TESTS(); + int ret = RUN_ALL_TESTS(); quit(); free(m_logger); free(g_client); - return i; + return ret; } //////////////////////////////////////////////////////////////////////////////// From 97c00b2cae3e9765ad28110678127dd616e99754 Mon Sep 17 00:00:00 2001 From: Jean-Christian de Rivaz <84882+jcdr@users.noreply.github.com> Date: Sun, 4 Oct 2020 04:02:57 +0200 Subject: [PATCH 81/96] unit_test_tcp_client.cpp test_annotations_client_impl.cpp: fix declarations shadows a global declaration --- test/common/unit_test_tcp_client.cpp | 4 ++-- test/test_annotations/test_annotations_client_impl.cpp | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/test/common/unit_test_tcp_client.cpp b/test/common/unit_test_tcp_client.cpp index 6f56405c3..dd814d7a1 100644 --- a/test/common/unit_test_tcp_client.cpp +++ b/test/common/unit_test_tcp_client.cpp @@ -90,13 +90,13 @@ int main(int argc, char **argv) g_client->addMessageLogger(&g_messageLogger); #endif // USE_MESSAGE_LOGGING - int i = RUN_ALL_TESTS(); + int ret = RUN_ALL_TESTS(); quit(); free(m_logger); g_transport.close(); free(g_client); - return i; + return ret; } //////////////////////////////////////////////////////////////////////////////// diff --git a/test/test_annotations/test_annotations_client_impl.cpp b/test/test_annotations/test_annotations_client_impl.cpp index 276f32b6e..61c2f748f 100644 --- a/test/test_annotations/test_annotations_client_impl.cpp +++ b/test/test_annotations/test_annotations_client_impl.cpp @@ -22,8 +22,8 @@ TEST(test_annotations, IncludeAnnotationCheck) { EXPECT_TRUE(5 == addOne(4)); - includedInt_t myInt = 5; - EXPECT_TRUE(5 == myInt); + includedInt_t testInt = 5; + EXPECT_TRUE(5 == testInt); } TEST(test_annotations, testIfMyIntAndConstExist) From 319394571725dfda74ea2fb084244a417ea5a1f6 Mon Sep 17 00:00:00 2001 From: Jean-Christian de Rivaz <84882+jcdr@users.noreply.github.com> Date: Sat, 3 Oct 2020 14:27:32 +0200 Subject: [PATCH 82/96] mk/flags.mk cpptemplate/Makefile: Add paranoid compiler flags to ensure it compile on project that use them The paranoid flags are commented out into mk/flags.mk because the generated code don't yet compile with them. --- erpcgen/src/cpptemplate/Makefile | 1 + mk/flags.mk | 1 + 2 files changed, 2 insertions(+) diff --git a/erpcgen/src/cpptemplate/Makefile b/erpcgen/src/cpptemplate/Makefile index 2bd8f0bf9..0c8efb39e 100644 --- a/erpcgen/src/cpptemplate/Makefile +++ b/erpcgen/src/cpptemplate/Makefile @@ -33,6 +33,7 @@ LIBRARIES = -lc -lstdc++ -lm -lboost_unit_test_framework-mt -L$(BOOST_ROOT)/lib INCLUDES = -I$(BOOST_ROOT)/include CXXFLAGS = -std=gnu++11 -Werror -g3 -O0 -MMD -MP $(INCLUDES) +CXXFLAGS += -Wall -Wextra -Wshadow -pedantic-errors .PHONY: all all: cpptempl_test diff --git a/mk/flags.mk b/mk/flags.mk index 8c87d0021..1326271f7 100644 --- a/mk/flags.mk +++ b/mk/flags.mk @@ -29,6 +29,7 @@ else endif CXXFLAGS += -std=gnu++11 -D LINUX -Wunused-variable -Wno-deprecated-register -Wno-narrowing -Werror $(MARCH) +#CXXFLAGS += -Wall -Wextra -Wshadow -pedantic-errors CFLAGS += -std=gnu11 -D LINUX -D _GNU_SOURCE -Werror $(MARCH) YYFLAGS += -Wno-other # --debug --verbose LLFLAGS += From fc9f1662f751082a69ea054d5a07fd1f3cf164f7 Mon Sep 17 00:00:00 2001 From: Jean-Christian de Rivaz <84882+jcdr@users.noreply.github.com> Date: Sat, 3 Oct 2020 14:50:09 +0200 Subject: [PATCH 83/96] matrix_multiply.py: Add --serial and --baud argument --- .../matrix_multiply_tcp_python/matrix_multiply.py | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/examples/matrix_multiply_tcp_python/matrix_multiply.py b/examples/matrix_multiply_tcp_python/matrix_multiply.py index af4e4890c..107a4a922 100644 --- a/examples/matrix_multiply_tcp_python/matrix_multiply.py +++ b/examples/matrix_multiply_tcp_python/matrix_multiply.py @@ -140,6 +140,9 @@ def runClient(transport): argParser.add_argument('-s', '--server', action='store_true', help='Run server') argParser.add_argument('-t', '--host', default='localhost', help='Host IP address (default value is localhost)') argParser.add_argument('-p', '--port', default='40', help='Port (default value is 40)') + argParser.add_argument('-S', '--serial', default=None, help='Serial device (default value is None)') + argParser.add_argument('-B', '--baud', default='115200', help='Baud (default value is 115200)') + args = argParser.parse_args() # check if either server or client has been selected @@ -149,8 +152,12 @@ def runClient(transport): print('eRPC Matrix Multiply TCP example') - # initialize TCP transport layer - transport = erpc.transport.TCPTransport(args.host, int(args.port), args.server) + if args.serial: + # initialize Serial transport layer + transport = erpc.transport.SerialTransport(args.serial, int(args.baud)) + else: + # initialize TCP transport layer + transport = erpc.transport.TCPTransport(args.host, int(args.port), args.server) if args.client: print('Client connecting to a host on %s:%s' % (args.host, args.port)) From 9da3ae2634803e0d557e327b3ec3028eb0040a09 Mon Sep 17 00:00:00 2001 From: Jean-Christian de Rivaz <84882+jcdr@users.noreply.github.com> Date: Mon, 5 Oct 2020 19:50:19 +0200 Subject: [PATCH 84/96] =?UTF-8?q?infra/erpc=5Fsimple=5Fserver.cpp:=20fix?= =?UTF-8?q?=20declaration=20of=20=E2=80=98err=E2=80=99=20shadows=20a=20pre?= =?UTF-8?q?vious=20local?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit erpc_simple_server.cpp: In member function ‘virtual erpc_status_t erpc::SimpleServer::run(erpc::RequestContext&)’: erpc_simple_server.cpp:181:23: error: declaration of ‘err’ shadows a previous local [-Werror=shadow] erpc_status_t err = runInternalBegin(&codec, buff, msgType, serviceId, methodId, sequence); ^~~ erpc_simple_server.cpp:169:19: note: shadowed declaration is here erpc_status_t err = kErpcStatus_Success; ^~~ --- erpc_c/infra/erpc_simple_server.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erpc_c/infra/erpc_simple_server.cpp b/erpc_c/infra/erpc_simple_server.cpp index c1198f20f..5972ce38f 100644 --- a/erpc_c/infra/erpc_simple_server.cpp +++ b/erpc_c/infra/erpc_simple_server.cpp @@ -178,7 +178,7 @@ erpc_status_t SimpleServer::run(RequestContext &request) uint32_t methodId; uint32_t sequence; - erpc_status_t err = runInternalBegin(&codec, buff, msgType, serviceId, methodId, sequence); + err = runInternalBegin(&codec, buff, msgType, serviceId, methodId, sequence); if (err) { From 12815bff96cbd47aa956e0f3b152c7f1b598e99e Mon Sep 17 00:00:00 2001 From: Chris Trowbridge Date: Fri, 24 Apr 2020 09:19:09 -0400 Subject: [PATCH 85/96] deadlock fix proposals + TCP transport prototype + TCP_NODELAY --- erpc_c/infra/erpc_manually_constructed.h | 6 ++++ erpc_c/infra/erpc_transport_arbitrator.cpp | 13 +++++++- erpc_c/port/erpc_port_mbed.cpp | 29 +++++++++++++++++ erpc_c/port/erpc_threading_freertos.cpp | 2 +- erpc_c/setup/erpc_setup_tcp.cpp | 38 ++++++++++++++++++++++ erpc_c/setup/erpc_transport_setup.h | 31 ++++++++++++++++++ erpc_c/transports/erpc_tcp_transport.cpp | 30 ++++++++++++----- erpc_c/transports/erpc_tcp_transport.h | 3 +- 8 files changed, 140 insertions(+), 12 deletions(-) create mode 100644 erpc_c/port/erpc_port_mbed.cpp create mode 100644 erpc_c/setup/erpc_setup_tcp.cpp diff --git a/erpc_c/infra/erpc_manually_constructed.h b/erpc_c/infra/erpc_manually_constructed.h index feed514ae..297bee8c9 100644 --- a/erpc_c/infra/erpc_manually_constructed.h +++ b/erpc_c/infra/erpc_manually_constructed.h @@ -91,6 +91,12 @@ class ManuallyConstructed { new (m_storage) T(a1, a2, a3, a4, a5); } + + template + void construct(const A1 &a1, const A2 &a2, const A3 &a3, const A4 &a4, const A5 &a5, const A6 &a6) + { + new (m_storage) T(a1, a2, a3, a4, a5, a6); + } //@} /*! diff --git a/erpc_c/infra/erpc_transport_arbitrator.cpp b/erpc_c/infra/erpc_transport_arbitrator.cpp index 158e576c6..56736f01d 100644 --- a/erpc_c/infra/erpc_transport_arbitrator.cpp +++ b/erpc_c/infra/erpc_transport_arbitrator.cpp @@ -56,9 +56,20 @@ erpc_status_t TransportArbitrator::receive(MessageBuffer *message) erpc_status_t err = m_sharedTransport->receive(message); if (err) { + // if we timeout, we must unblock all pending client(s) + if (err == kErpcStatus_Timeout) + { + PendingClientInfo *client = m_clientList; + for (; client; client = client->m_next) + { + if (client->m_isValid) + { + client->m_sem.put(); + } + } + } return err; } - m_codec->setBuffer(*message); // Parse the message header. diff --git a/erpc_c/port/erpc_port_mbed.cpp b/erpc_c/port/erpc_port_mbed.cpp new file mode 100644 index 000000000..b8c66dfb9 --- /dev/null +++ b/erpc_c/port/erpc_port_mbed.cpp @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2020, Embedded Planet, Inc + * All rights reserved. + * + * For supporting transports and examples see: + * https://github.com/EmbeddedPlanet/mbed-rpc + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include "erpc_port.h" + +#if ERPC_THREADS_IS(MBED) + +#include + +using namespace std; + +void *erpc_malloc(size_t size) +{ + void *p = malloc(size); + return p; +} + +void erpc_free(void *ptr) +{ + free(ptr); +} +#endif diff --git a/erpc_c/port/erpc_threading_freertos.cpp b/erpc_c/port/erpc_threading_freertos.cpp index 748e55cb4..c00775080 100644 --- a/erpc_c/port/erpc_threading_freertos.cpp +++ b/erpc_c/port/erpc_threading_freertos.cpp @@ -175,7 +175,7 @@ void Thread::threadEntryPointStub(void *arg) Mutex::Mutex(void) : m_mutex(0) { - m_mutex = xSemaphoreCreateMutex(); + m_mutex = xSemaphoreCreateRecursiveMutex(); } Mutex::~Mutex(void) diff --git a/erpc_c/setup/erpc_setup_tcp.cpp b/erpc_c/setup/erpc_setup_tcp.cpp new file mode 100644 index 000000000..607f41dba --- /dev/null +++ b/erpc_c/setup/erpc_setup_tcp.cpp @@ -0,0 +1,38 @@ +/* + * Copyright 2020 (c) Sierra Wireless + * All rights reserved. + * + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include "erpc_manually_constructed.h" +#include "erpc_transport_setup.h" +#include "erpc_tcp_transport.h" + +using namespace erpc; + +//////////////////////////////////////////////////////////////////////////////// +// Variables +//////////////////////////////////////////////////////////////////////////////// + +static ManuallyConstructed s_transport; + +//////////////////////////////////////////////////////////////////////////////// +// Code +//////////////////////////////////////////////////////////////////////////////// + +erpc_transport_t erpc_transport_tcp_init(const char *host, uint16_t port, bool isServer) +{ + s_transport.construct(host, port, isServer); + if (kErpcStatus_Success == s_transport->open()) + { + return reinterpret_cast(s_transport.get()); + } + return NULL; +} + +void erpc_transport_tcp_close(void) +{ + s_transport.get()->close(true); +} diff --git a/erpc_c/setup/erpc_transport_setup.h b/erpc_c/setup/erpc_transport_setup.h index af3e6abf2..ef46c86de 100644 --- a/erpc_c/setup/erpc_transport_setup.h +++ b/erpc_c/setup/erpc_transport_setup.h @@ -34,6 +34,7 @@ extern "C" { #endif #include +#include //! @name Transport setup //@{ @@ -282,6 +283,36 @@ erpc_transport_t erpc_transport_rpmsg_linux_init(int16_t local_addr, int8_t type void erpc_transport_rpmsg_linux_deinit(void); //@} +//! @name TCP transport setup +//@{ + +/*! + * @brief Create and open TCP transport + * + * For server, create a TCP listen socket and wait for connections + * For client, connect to server + * + * @param[in] host hostname/IP address to listen on or server to connect to + * @param[in] port port to listen on or server to connect to + * @param[in] isServer true if we are a server + * + * @return Return NULL or erpc_transport_t instance pointer. + */ +erpc_transport_t erpc_transport_tcp_init(const char *host, uint16_t port, bool isServer); + +/*! + * @brief Close TCP connection + * + * For server, stop listening and close all sockets. Note that the server mode + * uses and accept() which is a not-recommended blocking method so we can't exit + * until a connection attempts is made. This is a deadlock but assuming that TCP + * code is supposed to be for test, I assume it's acceptable. Otherwise a non-blocking + * socket or select() shoudl be used + * For client, close server connection + * + * @return Return TRUE if listen/connection successful + */ +void erpc_transport_tcp_close(void); //@} #ifdef __cplusplus diff --git a/erpc_c/transports/erpc_tcp_transport.cpp b/erpc_c/transports/erpc_tcp_transport.cpp index cb6b1a438..ceb8c2d4f 100644 --- a/erpc_c/transports/erpc_tcp_transport.cpp +++ b/erpc_c/transports/erpc_tcp_transport.cpp @@ -8,13 +8,16 @@ */ #include "erpc_tcp_transport.h" #include +#if ERPC_HAS_POSIX #include +#endif #include #include #include #include #include #include +#include #include using namespace erpc; @@ -86,7 +89,7 @@ erpc_status_t TCPTransport::connectClient(void) } // Fill in hints structure for getaddrinfo. - struct addrinfo hints = { 0 }; + struct addrinfo hints = { }; hints.ai_flags = AI_NUMERICSERV; hints.ai_family = PF_UNSPEC; hints.ai_socktype = SOCK_STREAM; @@ -140,13 +143,16 @@ erpc_status_t TCPTransport::connectClient(void) TCP_DEBUG_ERR("connecting failed"); return kErpcStatus_ConnectionFailure; } + + int set = 1; + setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (void *)&set, sizeof(int)); // On some systems (BSD) we can disable SIGPIPE on the socket. For others (Linux), we have to // ignore SIGPIPE. #if defined(SO_NOSIGPIPE) // Disable SIGPIPE for this socket. This will cause write() to return an EPIPE error if the // other side has disappeared instead of our process receiving a SIGPIPE. - int set = 1; + set = 1; if (setsockopt(sock, SOL_SOCKET, SO_NOSIGPIPE, (void *)&set, sizeof(int)) < 0) { ::close(sock); @@ -162,9 +168,9 @@ erpc_status_t TCPTransport::connectClient(void) return kErpcStatus_Success; } -erpc_status_t TCPTransport::close(void) +erpc_status_t TCPTransport::close(bool stopServer) { - if (m_isServer) + if (m_isServer && stopServer) { m_runServer = false; } @@ -197,7 +203,8 @@ erpc_status_t TCPTransport::underlyingReceive(uint8_t *data, uint32_t size) // Length will be zero if the connection is closed. if (length == 0) { - close(); + // close socket, not server + close(false); return kErpcStatus_ConnectionClosed; } else if (length < 0) @@ -218,7 +225,8 @@ erpc_status_t TCPTransport::underlyingSend(const uint8_t *data, uint32_t size) { if (m_socket <= 0) { - return kErpcStatus_Success; + // we should not pretend to have a succesful Send or we create a deadlock + return kErpcStatus_ConnectionFailure; } // Loop until all data is sent. @@ -234,8 +242,8 @@ erpc_status_t TCPTransport::underlyingSend(const uint8_t *data, uint32_t size) { if (errno == EPIPE) { - // Server closed. - close(); + // close socket, not server + close(false); return kErpcStatus_ConnectionClosed; } return kErpcStatus_SendFailed; @@ -298,18 +306,22 @@ void TCPTransport::serverThread(void) { struct sockaddr incomingAddress; socklen_t incomingAddressLength = sizeof(struct sockaddr); + // we should use select() otherwise we can't end the server properly int incomingSocket = accept(serverSocket, &incomingAddress, &incomingAddressLength); if (incomingSocket > 0) { // Successfully accepted a connection. m_socket = incomingSocket; + // should be inherited from accept() socket but it's not always ... + int yes = 1; + setsockopt(m_socket, IPPROTO_TCP, TCP_NODELAY, (void *)&yes, sizeof(yes)); } else { TCP_DEBUG_ERR("accept failed"); } } - + ::close(serverSocket); } diff --git a/erpc_c/transports/erpc_tcp_transport.h b/erpc_c/transports/erpc_tcp_transport.h index e1bb9db65..a4779b99b 100644 --- a/erpc_c/transports/erpc_tcp_transport.h +++ b/erpc_c/transports/erpc_tcp_transport.h @@ -76,9 +76,10 @@ class TCPTransport : public FramedTransport /*! * @brief This function disconnects client or stop server host. * + * @param[in] stopServer Specify is server shall be closed as well (stop listen()) * @retval #kErpcStatus_Success Always return this. */ - virtual erpc_status_t close(void); + virtual erpc_status_t close(bool stopServer = true); protected: bool m_isServer; /*!< If true then server is using transport, else client. */ From b91f2b92254afc0d7b6c8b619c9bb220966d6270 Mon Sep 17 00:00:00 2001 From: Cervenka Dusan Date: Thu, 8 Oct 2020 15:03:28 +0200 Subject: [PATCH 86/96] AllowShortFunctionsOnASingleLine was twice. -- Code style of document was confusing. -- Added link to documentation for current version. --- .clang-format | 128 +++++++++++++++++++++++++------------------------- 1 file changed, 64 insertions(+), 64 deletions(-) diff --git a/.clang-format b/.clang-format index d934c5cc5..6ea839576 100644 --- a/.clang-format +++ b/.clang-format @@ -1,70 +1,70 @@ -AlignTrailingComments : true -AllowAllParametersOfDeclarationOnNextLine : true -AllowShortBlocksOnASingleLine : false -AllowShortFunctionsOnASingleLine : "None" -AllowShortIfStatementsOnASingleLine : false -AllowShortLoopsOnASingleLine : false -AlwaysBreakBeforeMultilineStrings : true -BasedOnStyle : "Google" +#https://releases.llvm.org/5.0.2/tools/clang/docs/ClangFormatStyleOptions.html +AlignTrailingComments: true +AllowAllParametersOfDeclarationOnNextLine: true +AllowShortBlocksOnASingleLine: false +AllowShortFunctionsOnASingleLine: "Inline" +AllowShortIfStatementsOnASingleLine: false +AllowShortLoopsOnASingleLine: false +AlwaysBreakBeforeMultilineStrings: true +BasedOnStyle: "Google" #BinPackParameters : false -BreakBeforeBinaryOperators : false -BreakBeforeBraces : "Custom" -BreakBeforeTernaryOperators : false -ColumnLimit : 120 -ContinuationIndentWidth : 4 -DerivePointerAlignment : false -DisableFormat : false -IndentCaseLabels : true -IndentWrappedFunctionNames : false -IndentWidth : 4 -Language : "Cpp" -MaxEmptyLinesToKeep : 1 -PointerBindsToType : false -SpaceBeforeAssignmentOperators : true -SpaceBeforeParens : "ControlStatements" -SpacesBeforeTrailingComments : 1 -SpacesInCStyleCastParentheses : false -SpacesInParentheses : false -Standard : "Cpp03" -TabWidth : 1 -UseTab : "Never" -AccessModifierOffset : -4 -AlignAfterOpenBracket : "Align" -AlignEscapedNewlines : "Left" -AlignOperands : true -AllowShortCaseLabelsOnASingleLine : false -AllowShortFunctionsOnASingleLine : "Inline" -AlwaysBreakAfterReturnType : "None" -AlwaysBreakTemplateDeclarations : true -BreakBeforeInheritanceComma : false -BreakConstructorInitializers : "BeforeComma" -CompactNamespaces : false -ConstructorInitializerAllOnOneLineOrOnePerLine : false -ConstructorInitializerIndentWidth : 0 -Cpp11BracedListStyle : false -FixNamespaceComments : true -NamespaceIndentation : "None" -PointerAlignment : "Right" -SortIncludes : true -SortUsingDeclarations : true -SpacesInAngles : false -SpaceAfterCStyleCast : false -SpaceInEmptyParentheses : false -SpacesInSquareBrackets : false +BreakBeforeBinaryOperators: false +BreakBeforeBraces: "Custom" +BreakBeforeTernaryOperators: false +ColumnLimit: 120 +ContinuationIndentWidth: 4 +DerivePointerAlignment: false +DisableFormat: false +IndentCaseLabels: true +IndentWrappedFunctionNames: false +IndentWidth: 4 +Language: "Cpp" +MaxEmptyLinesToKeep: 1 +PointerBindsToType: false +SpaceBeforeAssignmentOperators: true +SpaceBeforeParens: "ControlStatements" +SpacesBeforeTrailingComments: 1 +SpacesInCStyleCastParentheses: false +SpacesInParentheses: false +Standard: "Cpp03" +TabWidth: 1 +UseTab: "Never" +AccessModifierOffset: -4 +AlignAfterOpenBracket: "Align" +AlignEscapedNewlines: "Left" +AlignOperands: true +AllowShortCaseLabelsOnASingleLine: false +AlwaysBreakAfterReturnType: "None" +AlwaysBreakTemplateDeclarations: true +BreakBeforeInheritanceComma: false +BreakConstructorInitializers: "BeforeComma" +CompactNamespaces: false +ConstructorInitializerAllOnOneLineOrOnePerLine: false +ConstructorInitializerIndentWidth: 0 +Cpp11BracedListStyle: false +FixNamespaceComments: true +NamespaceIndentation: "None" +PointerAlignment: "Right" +SortIncludes: true +SortUsingDeclarations: true +SpacesInAngles: false +SpaceAfterCStyleCast: false +SpaceInEmptyParentheses: false +SpacesInSquareBrackets: false KeepEmptyLinesAtTheStartOfBlocks: true BraceWrapping: - AfterClass: true + AfterClass: true AfterControlStatement: true - AfterEnum: true - AfterFunction: true - AfterNamespace: false + AfterEnum: true + AfterFunction: true + AfterNamespace: false AfterObjCDeclaration: true - AfterStruct: true - AfterUnion: true - BeforeCatch: true - BeforeElse: true + AfterStruct: true + AfterUnion: true + BeforeCatch: true + BeforeElse: true IncludeCategories: - - Regex: '^<' # system includes - Priority: 10 - - Regex: '^"erpc_' # erpc public includes - Priority: 1 + - Regex: "^<" # system includes + Priority: 10 + - Regex: '^"erpc_' # erpc public includes + Priority: 1 From 5e1c43c5cd38520a5c90359bb296888b63cd4f1e Mon Sep 17 00:00:00 2001 From: Cervenka Dusan Date: Thu, 8 Oct 2020 15:28:57 +0200 Subject: [PATCH 87/96] Only advice for newer clang version. --- .clang-format | 1 + 1 file changed, 1 insertion(+) diff --git a/.clang-format b/.clang-format index 6ea839576..eeed4bea7 100644 --- a/.clang-format +++ b/.clang-format @@ -63,6 +63,7 @@ BraceWrapping: AfterUnion: true BeforeCatch: true BeforeElse: true +#IncludeBlocks: "Preserve" # for future version of clang IncludeCategories: - Regex: "^<" # system includes Priority: 10 From 4056943b1d1dac8c1f39ad719a9a2f0c8906f2b5 Mon Sep 17 00:00:00 2001 From: Dusan Cervenka Date: Fri, 9 Oct 2020 07:15:11 +0200 Subject: [PATCH 88/96] Create greetings.yml --- .github/workflows/greetings.yml | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 .github/workflows/greetings.yml diff --git a/.github/workflows/greetings.yml b/.github/workflows/greetings.yml new file mode 100644 index 000000000..ec766b0d9 --- /dev/null +++ b/.github/workflows/greetings.yml @@ -0,0 +1,13 @@ +name: Greetings + +on: [pull_request, issues] + +jobs: + greeting: + runs-on: ubuntu-latest + steps: + - uses: actions/first-interaction@v1 + with: + repo-token: ${{ secrets.GITHUB_TOKEN }} + issue-message: 'Hi eRPC user. Thank you for your interest and welcomme. We hope you will enjoy this framework well.' + pr-message: 'Hi eRPC user. Thank you for your PR. We are appreciating that and we will try to review it as soon as possible. We hope you are enjoying this framework so far.' From e33d430ef830b2b85a8ade95b24f1e967d3dd6ca Mon Sep 17 00:00:00 2001 From: Dusan Cervenka Date: Fri, 9 Oct 2020 07:30:55 +0200 Subject: [PATCH 89/96] Create clang-format.yml --- .github/workflows/clang-format.yml | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 .github/workflows/clang-format.yml diff --git a/.github/workflows/clang-format.yml b/.github/workflows/clang-format.yml new file mode 100644 index 000000000..e3f5934ab --- /dev/null +++ b/.github/workflows/clang-format.yml @@ -0,0 +1,13 @@ +name: clang-format lint + +on: [push] + +jobs: + build: + runs-on: ubuntu-latest + + steps: + - uses: DoozyX/clang-format-lint-action@v0.10 + with: + exclude: 'test/common/gtest/gtest.h test/common/gtest/gtest.cpp erpcgen/src/cpptemplate/cpptempl.h erpcgen/src/cpptemplate/cpptempl.cpp erpcgen/src/cpptemplate/cpptempl_test.cpp' + clangFormatVersion: 5 From 2b25930eedfcf481f05fd68343afcec2eec7d53d Mon Sep 17 00:00:00 2001 From: Jean-Christian de Rivaz <84882+jcdr@users.noreply.github.com> Date: Fri, 9 Oct 2020 07:32:07 +0200 Subject: [PATCH 90/96] erpc_framed_transport.cpp: return error if received message has zero length This was spotted on a SAML21 controller: #0 usart_sync_read (io_descr=0x200006dc , buf=0x20000378 , length=0) at ../hal/src/hal_usart_sync.c:271 #1 0x000001e0 in io_read (io_descr=0x200006dc , buf=0x20000378 , length=0) at ../hal/src/hal_io.c:62 #2 0x0000e3da in erpc::UsartSyncTransport::underlyingReceive (this=0x20000578 , data=0x20000378 , size=0) at ../erpc_usart_sync_transport.cpp:29 #3 0x0000dd96 in erpc::FramedTransport::receive (this=0x20000578 , message=0x200026c4) at ../erpc_framed_transport.cpp:63 #4 0x0000d7da in erpc::SimpleServer::runInternalBegin (this=0x20000340 , codec=0x200026c0, buff=..., msgType=@0x200026bf: 32, serviceId=@0x200026b8: 536880832, methodId=@0x200026b4: 536871784, sequence=@0x200026b0: 536871784) at ../erpc_simple_server.cpp:64 #5 0x0000d72a in erpc::SimpleServer::runInternal (this=0x20000340 ) at ../erpc_simple_server.cpp:42 #6 0x0000d99e in erpc::SimpleServer::poll (this=0x20000340 ) at ../erpc_simple_server.cpp:223 #7 0x0000d44e in erpc_server_poll () at ../erpc_server_setup.cpp:97 #8 0x00006fa4 in main () at ../main.c:72 The UART need to be restarted to recover from a such error, for ex.: if (erpc_server_poll()) { usart_sync_disable(&USART_0); usart_sync_enable(&USART_0); } --- erpc_c/infra/erpc_framed_transport.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/erpc_c/infra/erpc_framed_transport.cpp b/erpc_c/infra/erpc_framed_transport.cpp index 63a709e91..2ae781101 100644 --- a/erpc_c/infra/erpc_framed_transport.cpp +++ b/erpc_c/infra/erpc_framed_transport.cpp @@ -53,6 +53,12 @@ erpc_status_t FramedTransport::receive(MessageBuffer *message) return ret; } + // received size can't be zero. + if (h.m_messageSize == 0) + { + return kErpcStatus_ReceiveFailed; + } + // received size can't be larger then buffer length. if (h.m_messageSize > message->getLength()) { From b0e640f5987a53fd2955bb2b62c8c248f52840c7 Mon Sep 17 00:00:00 2001 From: Dusan Cervenka Date: Fri, 9 Oct 2020 12:50:38 +0200 Subject: [PATCH 91/96] Update clang-format.yml --- .github/workflows/clang-format.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/clang-format.yml b/.github/workflows/clang-format.yml index e3f5934ab..e54e59bcf 100644 --- a/.github/workflows/clang-format.yml +++ b/.github/workflows/clang-format.yml @@ -9,5 +9,6 @@ jobs: steps: - uses: DoozyX/clang-format-lint-action@v0.10 with: + source: '.' exclude: 'test/common/gtest/gtest.h test/common/gtest/gtest.cpp erpcgen/src/cpptemplate/cpptempl.h erpcgen/src/cpptemplate/cpptempl.cpp erpcgen/src/cpptemplate/cpptempl_test.cpp' clangFormatVersion: 5 From 365ff0b3579ae6ac8cd60c23b0453ab576e48388 Mon Sep 17 00:00:00 2001 From: Dusan Cervenka Date: Fri, 9 Oct 2020 12:51:29 +0200 Subject: [PATCH 92/96] Update clang-format.yml --- .github/workflows/clang-format.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/clang-format.yml b/.github/workflows/clang-format.yml index e54e59bcf..9dcf28a57 100644 --- a/.github/workflows/clang-format.yml +++ b/.github/workflows/clang-format.yml @@ -7,6 +7,7 @@ jobs: runs-on: ubuntu-latest steps: + - uses: actions/checkout@v2 - uses: DoozyX/clang-format-lint-action@v0.10 with: source: '.' From 2526606a280f7b2d26d7adbed373e5c573dd0159 Mon Sep 17 00:00:00 2001 From: "Michal Princ (nxa17570)" Date: Tue, 13 Oct 2020 09:21:54 +0200 Subject: [PATCH 93/96] eRPC updates 10/2020 -- Update makefile. -- Update CMSIS UART transport layer to avoid busy loops in rtos environments, introduce semaphores. -- Introduced new USB CDC transport. -- Introduced new Linux spidev-based transport. -- Native _WIN32 erpc serial transport and threading. -- Enable deallocation in server shim code when callback/function pointer used as out parameter in IDL. -- Core re-formatted using Clang version 10. -- erpcgen testing update. -- Minor documentation updates. -- Version changed to 1.8.0. --- .github/workflows/clang-format.yml | 2 +- doxygen/Doxyfile.erpc | 2 +- doxygen/Doxyfile.erpcgen | 2 +- erpc_c/Makefile | 9 +- .../infra/erpc_arbitrated_client_manager.cpp | 4 + erpc_c/infra/erpc_basic_codec.cpp | 1 + erpc_c/infra/erpc_basic_codec.h | 1 + erpc_c/infra/erpc_client_manager.cpp | 3 + erpc_c/infra/erpc_client_server_common.h | 52 ++-- erpc_c/infra/erpc_codec.h | 4 +- erpc_c/infra/erpc_framed_transport.cpp | 1 + erpc_c/infra/erpc_framed_transport.h | 1 + erpc_c/infra/erpc_manually_constructed.h | 8 +- erpc_c/infra/erpc_message_buffer.cpp | 1 + erpc_c/infra/erpc_message_buffer.h | 5 +- erpc_c/infra/erpc_message_loggers.cpp | 1 + erpc_c/infra/erpc_pre_post_action.cpp | 1 + erpc_c/infra/erpc_server.cpp | 1 + erpc_c/infra/erpc_server.h | 2 +- erpc_c/infra/erpc_static_queue.h | 12 +- erpc_c/infra/erpc_transport.h | 1 + erpc_c/infra/erpc_transport_arbitrator.cpp | 8 +- erpc_c/infra/erpc_version.h | 4 +- erpc_c/port/erpc_config_internal.h | 11 +- erpc_c/port/erpc_port_freertos.cpp | 3 +- erpc_c/port/erpc_port_memmanager.cpp | 3 +- erpc_c/port/erpc_port_mqx.cpp | 3 +- erpc_c/port/erpc_port_stdlib.cpp | 7 +- erpc_c/port/erpc_port_zephyr.cpp | 3 +- erpc_c/port/erpc_serial.cpp | 196 ++++++++------ erpc_c/port/erpc_serial.h | 4 +- erpc_c/port/erpc_setup_extensions.h | 2 + .../port/erpc_setup_extensions_freertos.cpp | 25 +- erpc_c/port/erpc_spidev.cpp | 82 ++++++ erpc_c/port/erpc_spidev.h | 30 +++ erpc_c/port/erpc_sysgpio.c | 209 +++++++++++++++ erpc_c/port/erpc_sysgpio.h | 31 +++ erpc_c/port/erpc_threading.h | 11 +- erpc_c/port/erpc_threading_freertos.cpp | 1 + erpc_c/port/erpc_threading_pthreads.cpp | 1 + erpc_c/port/erpc_threading_win32.cpp | 28 +- erpc_c/port/erpc_threading_zephyr.cpp | 1 + erpc_c/port/port.dox | 12 + erpc_c/setup/erpc_arbitrated_client_setup.cpp | 245 +++++++++--------- erpc_c/setup/erpc_client_setup.cpp | 242 ++++++++--------- erpc_c/setup/erpc_server_setup.cpp | 2 + erpc_c/setup/erpc_setup_mbf_dynamic.cpp | 1 + erpc_c/setup/erpc_setup_mbf_rpmsg.cpp | 2 + erpc_c/setup/erpc_setup_mbf_rpmsg_tty.cpp | 2 + erpc_c/setup/erpc_setup_mbf_static.cpp | 1 + erpc_c/setup/erpc_setup_spidev_master.cpp | 30 +++ erpc_c/setup/erpc_setup_tcp.cpp | 8 +- erpc_c/setup/erpc_setup_usb_cdc.cpp | 36 +++ erpc_c/setup/erpc_transport_setup.h | 50 +++- erpc_c/setup/setup.dox | 12 + .../transports/erpc_dspi_master_transport.cpp | 2 + .../transports/erpc_dspi_master_transport.h | 2 + .../transports/erpc_dspi_slave_transport.cpp | 2 + erpc_c/transports/erpc_dspi_slave_transport.h | 2 + .../erpc_inter_thread_buffer_transport.cpp | 1 + erpc_c/transports/erpc_mu_transport.cpp | 2 + erpc_c/transports/erpc_mu_transport.h | 1 + .../transports/erpc_rpmsg_linux_transport.cpp | 1 + .../erpc_rpmsg_lite_base_transport.h | 1 + .../erpc_rpmsg_lite_rtos_transport.cpp | 3 + .../erpc_rpmsg_lite_rtos_transport.h | 1 + .../transports/erpc_rpmsg_lite_transport.cpp | 2 + erpc_c/transports/erpc_rpmsg_lite_transport.h | 1 + .../erpc_rpmsg_tty_rtos_transport.cpp | 3 + .../erpc_rpmsg_tty_rtos_transport.h | 3 +- erpc_c/transports/erpc_serial_transport.cpp | 17 ++ erpc_c/transports/erpc_serial_transport.h | 6 + .../transports/erpc_spi_master_transport.cpp | 108 ++++++-- erpc_c/transports/erpc_spi_master_transport.h | 2 + .../transports/erpc_spi_slave_transport.cpp | 107 +++++++- erpc_c/transports/erpc_spi_slave_transport.h | 2 + .../erpc_spidev_master_transport.cpp | 187 +++++++++++++ .../transports/erpc_spidev_master_transport.h | 86 ++++++ erpc_c/transports/erpc_tcp_transport.cpp | 9 +- .../transports/erpc_uart_cmsis_transport.cpp | 43 ++- erpc_c/transports/erpc_uart_cmsis_transport.h | 27 +- erpc_c/transports/erpc_usb_cdc_transport.cpp | 182 +++++++++++++ erpc_c/transports/erpc_usb_cdc_transport.h | 124 +++++++++ erpc_c/transports/transports.dox | 18 ++ erpc_python/erpc/erpc_version.py | 2 +- erpcgen/src/AstNode.cpp | 5 +- erpcgen/src/AstNode.h | 1 + erpcgen/src/AstWalker.cpp | 1 + erpcgen/src/AstWalker.h | 206 ++++++++++++--- erpcgen/src/CGenerator.cpp | 187 +++++-------- erpcgen/src/CGenerator.h | 1 + erpcgen/src/ErpcLexer.cpp | 9 +- erpcgen/src/ErpcLexer.h | 1 + erpcgen/src/Generator.cpp | 27 +- erpcgen/src/Generator.h | 1 + erpcgen/src/HexValues.cpp | 1 + erpcgen/src/InterfaceDefinition.cpp | 1 + erpcgen/src/InterfaceDefinition.h | 1 + erpcgen/src/Logging.cpp | 1 + erpcgen/src/ParseErrors.h | 1 + erpcgen/src/PythonGenerator.cpp | 43 ++- erpcgen/src/PythonGenerator.h | 1 + erpcgen/src/SearchPath.cpp | 1 + erpcgen/src/SymbolScanner.cpp | 5 +- erpcgen/src/Token.cpp | 1 + erpcgen/src/UniqueIdChecker.cpp | 1 + erpcgen/src/UniqueIdChecker.h | 8 +- erpcgen/src/Value.h | 16 +- erpcgen/src/cpptemplate/unit_testing.h | 1 + erpcgen/src/erpcgen.cpp | 8 +- erpcgen/src/format_string.cpp | 2 + erpcgen/src/options.cpp | 8 +- erpcgen/src/types/AliasType.h | 1 + erpcgen/src/types/Annotation.h | 1 + erpcgen/src/types/ArrayType.h | 1 + erpcgen/src/types/BuiltinType.h | 3 +- erpcgen/src/types/ConstType.h | 1 + erpcgen/src/types/DataType.h | 3 +- erpcgen/src/types/EnumMember.h | 1 + erpcgen/src/types/EnumType.h | 1 + erpcgen/src/types/Function.h | 1 + erpcgen/src/types/FunctionType.h | 1 + erpcgen/src/types/Group.h | 1 + erpcgen/src/types/Interface.h | 1 + erpcgen/src/types/ListType.h | 1 + erpcgen/src/types/Program.h | 1 + erpcgen/src/types/StructMember.h | 1 + erpcgen/src/types/StructType.h | 1 + erpcgen/src/types/Symbol.h | 1 + erpcgen/src/types/SymbolScope.h | 1 + erpcgen/src/types/Type.cpp | 7 +- erpcgen/src/types/UnionType.h | 1 + erpcgen/src/types/VoidType.h | 1 + erpcgen/test/test_forward_declaration_c.yml | 12 +- erpcgen/test/test_nullable_c.yml | 54 +++- erpcsniffer/src/Sniffer.cpp | 84 +++--- erpcsniffer/src/Sniffer.h | 2 + erpcsniffer/src/erpcsniffer.cpp | 44 ++-- .../service/__init__.py | 2 +- .../service/erpc_matrix_multiply/__init__.py | 6 +- .../service/erpc_matrix_multiply/client.py | 2 +- .../service/erpc_matrix_multiply/common.py | 3 +- .../service/erpc_matrix_multiply/interface.py | 2 +- .../service/erpc_matrix_multiply/server.py | 2 +- run_clang_format.py | 2 +- test/common/unit_test_arbitrator_app0.cpp | 7 +- test/common/unit_test_arbitrator_app1.cpp | 8 +- test/common/unit_test_client.cpp | 1 + test/common/unit_test_serial_client.cpp | 1 + test/common/unit_test_serial_server.cpp | 2 + test/common/unit_test_server.cpp | 3 + .../unit_test_tcp_arbitrator_client.cpp | 2 + .../unit_test_tcp_arbitrator_server.cpp | 2 + test/common/unit_test_tcp_client.cpp | 1 + test/common/unit_test_tcp_server.cpp | 1 + test/skeleton/server_skeleton.cpp | 5 +- test/test_annotations/external.h | 7 +- .../test_annotations_server_impl.cpp | 2 + .../test_arbitrator_client_impl.cpp | 1 + .../test_arbitrator_server_impl.cpp | 1 + test/test_arrays/test_arrays_client_impl.cpp | 1 + test/test_arrays/test_arrays_server_impl.cpp | 6 +- test/test_binary/test_binary_server_impl.cpp | 2 + .../test_builtin/test_builtin_client_impl.cpp | 1 + .../test_builtin/test_builtin_server_impl.cpp | 2 + .../test_callbacks_server_impl.cpp | 5 +- test/test_const/test_const_server_impl.cpp | 2 + test/test_enums/test_enums_server_impl.cpp | 2 + test/test_lists/test_lists_client_impl.cpp | 1 + test/test_lists/test_lists_server_impl.cpp | 2 + test/test_shared/test_shared_server_impl.cpp | 2 + test/test_struct/test_struct_client_impl.cpp | 1 + test/test_struct/test_struct_server_impl.cpp | 2 + .../test_typedef/test_typedef_client_impl.cpp | 1 + .../test_typedef/test_typedef_server_impl.cpp | 2 + test/test_unions/test_unions_client_impl.cpp | 1 + test/test_unions/test_unions_server_impl.cpp | 38 +-- 177 files changed, 2447 insertions(+), 820 deletions(-) create mode 100644 erpc_c/port/erpc_spidev.cpp create mode 100644 erpc_c/port/erpc_spidev.h create mode 100644 erpc_c/port/erpc_sysgpio.c create mode 100644 erpc_c/port/erpc_sysgpio.h create mode 100644 erpc_c/setup/erpc_setup_spidev_master.cpp create mode 100644 erpc_c/setup/erpc_setup_usb_cdc.cpp create mode 100644 erpc_c/transports/erpc_spidev_master_transport.cpp create mode 100644 erpc_c/transports/erpc_spidev_master_transport.h create mode 100644 erpc_c/transports/erpc_usb_cdc_transport.cpp create mode 100644 erpc_c/transports/erpc_usb_cdc_transport.h diff --git a/.github/workflows/clang-format.yml b/.github/workflows/clang-format.yml index 9dcf28a57..8c7729bae 100644 --- a/.github/workflows/clang-format.yml +++ b/.github/workflows/clang-format.yml @@ -12,4 +12,4 @@ jobs: with: source: '.' exclude: 'test/common/gtest/gtest.h test/common/gtest/gtest.cpp erpcgen/src/cpptemplate/cpptempl.h erpcgen/src/cpptemplate/cpptempl.cpp erpcgen/src/cpptemplate/cpptempl_test.cpp' - clangFormatVersion: 5 + clangFormatVersion: 10 diff --git a/doxygen/Doxyfile.erpc b/doxygen/Doxyfile.erpc index 16cd59f72..0ff74c944 100644 --- a/doxygen/Doxyfile.erpc +++ b/doxygen/Doxyfile.erpc @@ -38,7 +38,7 @@ PROJECT_NAME = "eRPC API Reference" # could be handy for archiving the generated documentation or if some version # control system is used. -PROJECT_NUMBER = "Rev. 1.7.4" +PROJECT_NUMBER = "Rev. 1.8.0" # Using the PROJECT_BRIEF tag one can provide an optional one line description # for a project that appears at the top of each page and should give viewer a diff --git a/doxygen/Doxyfile.erpcgen b/doxygen/Doxyfile.erpcgen index 8a767aeff..e62412998 100644 --- a/doxygen/Doxyfile.erpcgen +++ b/doxygen/Doxyfile.erpcgen @@ -38,7 +38,7 @@ PROJECT_NAME = "eRPC Generator (erpcgen)" # could be handy for archiving the generated documentation or if some version # control system is used. -PROJECT_NUMBER = "Rev. 1.7.4" +PROJECT_NUMBER = "Rev. 1.8.0" # Using the PROJECT_BRIEF tag one can provide an optional one line description # for a project that appears at the top of each page and should give viewer a diff --git a/erpc_c/Makefile b/erpc_c/Makefile index 36b172ad9..9d67344bf 100644 --- a/erpc_c/Makefile +++ b/erpc_c/Makefile @@ -1,6 +1,6 @@ #------------------------------------------------------------------------------- # Copyright (C) 2016 Freescale Semiconductor, Inc. -# Copyright 2016-2017 NXP +# Copyright 2016-2020 NXP # All rights reserved. # # THIS SOFTWARE IS PROVIDED BY FREESCALE "AS IS" AND ANY EXPRESS OR IMPLIED @@ -60,11 +60,14 @@ SOURCES += $(ERPC_C_ROOT)/infra/erpc_arbitrated_client_manager.cpp \ $(ERPC_C_ROOT)/infra/erpc_server.cpp \ $(ERPC_C_ROOT)/infra/erpc_simple_server.cpp \ $(ERPC_C_ROOT)/infra/erpc_transport_arbitrator.cpp \ + $(ERPC_C_ROOT)/infra/erpc_pre_post_action.cpp \ $(ERPC_C_ROOT)/port/erpc_port_stdlib.cpp \ $(ERPC_C_ROOT)/port/erpc_threading_pthreads.cpp \ $(ERPC_C_ROOT)/port/erpc_serial.cpp \ $(ERPC_C_ROOT)/setup/erpc_arbitrated_client_setup.cpp \ $(ERPC_C_ROOT)/setup/erpc_client_setup.cpp \ + $(ERPC_C_ROOT)/setup/erpc_setup_mbf_dynamic.cpp \ + $(ERPC_C_ROOT)/setup/erpc_setup_mbf_static.cpp \ $(ERPC_C_ROOT)/setup/erpc_server_setup.cpp \ $(ERPC_C_ROOT)/setup/erpc_setup_serial.cpp \ $(ERPC_C_ROOT)/transports/erpc_inter_thread_buffer_transport.cpp \ @@ -87,12 +90,16 @@ HEADERS += $(ERPC_C_ROOT)/config/erpc_config.h \ $(ERPC_C_ROOT)/infra/erpc_static_queue.h \ $(ERPC_C_ROOT)/infra/erpc_transport_arbitrator.h \ $(ERPC_C_ROOT)/infra/erpc_transport.h \ + $(ERPC_C_ROOT)/infra/erpc_client_server_common.h \ + $(ERPC_C_ROOT)/infra/erpc_pre_post_action.h \ + $(ERPC_C_ROOT)/port/erpc_setup_extensions.h \ $(ERPC_C_ROOT)/port/erpc_config_internal.h \ $(ERPC_C_ROOT)/port/erpc_port.h \ $(ERPC_C_ROOT)/port/erpc_threading.h \ $(ERPC_C_ROOT)/port/erpc_serial.h \ $(ERPC_C_ROOT)/setup/erpc_arbitrated_client_setup.h \ $(ERPC_C_ROOT)/setup/erpc_client_setup.h \ + $(ERPC_C_ROOT)/setup/erpc_mbf_setup.h \ $(ERPC_C_ROOT)/setup/erpc_server_setup.h \ $(ERPC_C_ROOT)/setup/erpc_transport_setup.h \ $(ERPC_C_ROOT)/transports/erpc_inter_thread_buffer_transport.h \ diff --git a/erpc_c/infra/erpc_arbitrated_client_manager.cpp b/erpc_c/infra/erpc_arbitrated_client_manager.cpp index 15312e3d8..bf9e0ffde 100644 --- a/erpc_c/infra/erpc_arbitrated_client_manager.cpp +++ b/erpc_c/infra/erpc_arbitrated_client_manager.cpp @@ -8,7 +8,9 @@ */ #include "erpc_arbitrated_client_manager.h" + #include "erpc_transport_arbitrator.h" + #include "assert.h" #if ERPC_THREADS_IS(NONE) @@ -23,9 +25,11 @@ using namespace erpc; #if ERPC_NESTED_CALLS_DETECTION extern bool nestingDetection; +#ifndef _WIN32 #pragma weak nestingDetection bool nestingDetection = false; #endif +#endif void ArbitratedClientManager::setArbitrator(TransportArbitrator *arbitrator) { diff --git a/erpc_c/infra/erpc_basic_codec.cpp b/erpc_c/infra/erpc_basic_codec.cpp index 2b5349cdc..ff22d12ae 100644 --- a/erpc_c/infra/erpc_basic_codec.cpp +++ b/erpc_c/infra/erpc_basic_codec.cpp @@ -8,6 +8,7 @@ */ #include "erpc_basic_codec.h" + #include using namespace erpc; diff --git a/erpc_c/infra/erpc_basic_codec.h b/erpc_c/infra/erpc_basic_codec.h index 4032ee96f..07aa18249 100644 --- a/erpc_c/infra/erpc_basic_codec.h +++ b/erpc_c/infra/erpc_basic_codec.h @@ -11,6 +11,7 @@ #define _EMBEDDED_RPC__BASIC_SERIALIZATION_H_ #include "erpc_codec.h" + #include /*! diff --git a/erpc_c/infra/erpc_client_manager.cpp b/erpc_c/infra/erpc_client_manager.cpp index 2a4e025c6..2955c6edf 100644 --- a/erpc_c/infra/erpc_client_manager.cpp +++ b/erpc_c/infra/erpc_client_manager.cpp @@ -8,6 +8,7 @@ */ #include "erpc_client_manager.h" + #include "assert.h" using namespace erpc; @@ -18,9 +19,11 @@ using namespace erpc; #if ERPC_NESTED_CALLS_DETECTION extern bool nestingDetection; +#ifndef _WIN32 #pragma weak nestingDetection bool nestingDetection = false; #endif +#endif void ClientManager::setTransport(Transport *transport) { diff --git a/erpc_c/infra/erpc_client_server_common.h b/erpc_c/infra/erpc_client_server_common.h index 8935c7ad2..e47571cb9 100644 --- a/erpc_c/infra/erpc_client_server_common.h +++ b/erpc_c/infra/erpc_client_server_common.h @@ -37,22 +37,22 @@ namespace erpc { */ class ClientServerCommon #if ERPC_MESSAGE_LOGGING -# ifdef ERPC_OTHER_INHERITANCE -, -# else -# define ERPC_OTHER_INHERITANCE 1 +#ifdef ERPC_OTHER_INHERITANCE + , +#else +#define ERPC_OTHER_INHERITANCE 1 : -# endif -public MessageLoggers +#endif + public MessageLoggers #endif #if ERPC_PRE_POST_ACTION -# ifdef ERPC_OTHER_INHERITANCE -, -# else -# define ERPC_OTHER_INHERITANCE 1 +#ifdef ERPC_OTHER_INHERITANCE + , +#else +#define ERPC_OTHER_INHERITANCE 1 : -# endif -public PrePostAction +#endif + public PrePostAction #endif { public: @@ -61,27 +61,27 @@ public PrePostAction */ ClientServerCommon(void) #ifdef ERPC_OTHER_INHERITANCE -# undef ERPC_OTHER_INHERITANCE +#undef ERPC_OTHER_INHERITANCE #endif #if ERPC_MESSAGE_LOGGING -# ifdef ERPC_OTHER_INHERITANCE - , -# else -# define ERPC_OTHER_INHERITANCE 1 +#ifdef ERPC_OTHER_INHERITANCE + , +#else +#define ERPC_OTHER_INHERITANCE 1 : -# endif - MessageLoggers() +#endif + MessageLoggers() #endif #if ERPC_PRE_POST_ACTION -# ifdef ERPC_OTHER_INHERITANCE - , -# else -# define ERPC_OTHER_INHERITANCE 1 +#ifdef ERPC_OTHER_INHERITANCE + , +#else +#define ERPC_OTHER_INHERITANCE 1 : -# endif - PrePostAction() #endif -{}; + PrePostAction() +#endif + {}; /*! * @brief ClientServerCommon destructor diff --git a/erpc_c/infra/erpc_codec.h b/erpc_c/infra/erpc_codec.h index 60956a76c..a8e3a9e93 100644 --- a/erpc_c/infra/erpc_codec.h +++ b/erpc_c/infra/erpc_codec.h @@ -13,6 +13,7 @@ #include "erpc_common.h" #include "erpc_message_buffer.h" #include "erpc_transport.h" + #include #include @@ -30,7 +31,8 @@ namespace erpc { /*! * @brief Types of messages that can be encoded. */ -typedef enum _message_type { +typedef enum _message_type +{ kInvocationMessage = 0, kOnewayMessage, kReplyMessage, diff --git a/erpc_c/infra/erpc_framed_transport.cpp b/erpc_c/infra/erpc_framed_transport.cpp index 2ae781101..2b67d26d7 100644 --- a/erpc_c/infra/erpc_framed_transport.cpp +++ b/erpc_c/infra/erpc_framed_transport.cpp @@ -9,6 +9,7 @@ #include "erpc_framed_transport.h" #include "erpc_message_buffer.h" + #include #include diff --git a/erpc_c/infra/erpc_framed_transport.h b/erpc_c/infra/erpc_framed_transport.h index bd5ac87dd..de77ec397 100644 --- a/erpc_c/infra/erpc_framed_transport.h +++ b/erpc_c/infra/erpc_framed_transport.h @@ -13,6 +13,7 @@ #include "erpc_config_internal.h" #include "erpc_message_buffer.h" #include "erpc_transport.h" + #include #if ERPC_THREADS diff --git a/erpc_c/infra/erpc_manually_constructed.h b/erpc_c/infra/erpc_manually_constructed.h index 297bee8c9..a096eacd1 100644 --- a/erpc_c/infra/erpc_manually_constructed.h +++ b/erpc_c/infra/erpc_manually_constructed.h @@ -52,11 +52,11 @@ class ManuallyConstructed T *get(void) { return reinterpret_cast(&m_storage); } const T *get(void) const { return reinterpret_cast(&m_storage); } T *operator->(void) { return get(); } - const T *operator->(void)const { return get(); } + const T *operator->(void) const { return get(); } T &operator*(void) { return *get(); } - const T &operator*(void)const { return *get(); } + const T &operator*(void) const { return *get(); } operator T *(void) { return get(); } - operator const T *(void)const { return get(); } + operator const T *(void) const { return get(); } //@} //! @name Explicit construction methods @@ -91,7 +91,7 @@ class ManuallyConstructed { new (m_storage) T(a1, a2, a3, a4, a5); } - + template void construct(const A1 &a1, const A2 &a2, const A3 &a3, const A4 &a4, const A5 &a5, const A6 &a6) { diff --git a/erpc_c/infra/erpc_message_buffer.cpp b/erpc_c/infra/erpc_message_buffer.cpp index f2c1cd96a..5549e6a1a 100644 --- a/erpc_c/infra/erpc_message_buffer.cpp +++ b/erpc_c/infra/erpc_message_buffer.cpp @@ -8,6 +8,7 @@ */ #include "erpc_message_buffer.h" + #include #include diff --git a/erpc_c/infra/erpc_message_buffer.h b/erpc_c/infra/erpc_message_buffer.h index 3a5f9e22e..79a4652f4 100644 --- a/erpc_c/infra/erpc_message_buffer.h +++ b/erpc_c/infra/erpc_message_buffer.h @@ -11,6 +11,7 @@ #define _EMBEDDED_RPC__MESSAGE_BUFFER_H_ #include "erpc_common.h" + #include #include @@ -166,7 +167,7 @@ class MessageBuffer /*! * @brief Casting operator return local buffer. */ - operator const uint8_t *(void)const { return m_buf; } + operator const uint8_t *(void) const { return m_buf; } /*! * @brief Array operator return value of buffer at given index. @@ -276,7 +277,7 @@ class MessageBuffer /*! * @brief Casting operator return local buffer. */ - operator const uint8_t *(void)const { return m_pos; } + operator const uint8_t *(void) const { return m_pos; } /*! * @brief Array operator return value of buffer at given index. diff --git a/erpc_c/infra/erpc_message_loggers.cpp b/erpc_c/infra/erpc_message_loggers.cpp index 7295c23a5..82e49d7fb 100644 --- a/erpc_c/infra/erpc_message_loggers.cpp +++ b/erpc_c/infra/erpc_message_loggers.cpp @@ -7,6 +7,7 @@ */ #include "erpc_message_loggers.h" + #include using namespace erpc; diff --git a/erpc_c/infra/erpc_pre_post_action.cpp b/erpc_c/infra/erpc_pre_post_action.cpp index eaa2619a8..7ab85fc26 100644 --- a/erpc_c/infra/erpc_pre_post_action.cpp +++ b/erpc_c/infra/erpc_pre_post_action.cpp @@ -8,6 +8,7 @@ */ #include "erpc_pre_post_action.h" + #include "erpc_config_internal.h" #if ERPC_PRE_POST_ACTION_DEFAULT #include "erpc_setup_extensions.h" diff --git a/erpc_c/infra/erpc_server.cpp b/erpc_c/infra/erpc_server.cpp index 08bade9ea..69963c07f 100644 --- a/erpc_c/infra/erpc_server.cpp +++ b/erpc_c/infra/erpc_server.cpp @@ -8,6 +8,7 @@ */ #include "erpc_server.h" + #include "assert.h" using namespace erpc; diff --git a/erpc_c/infra/erpc_server.h b/erpc_c/infra/erpc_server.h index 596987232..b0b602fd7 100644 --- a/erpc_c/infra/erpc_server.h +++ b/erpc_c/infra/erpc_server.h @@ -11,9 +11,9 @@ #ifndef _EMBEDDED_RPC__SERVER_H_ #define _EMBEDDED_RPC__SERVER_H_ +#include "erpc_client_server_common.h" #include "erpc_codec.h" #include "erpc_config_internal.h" -#include "erpc_client_server_common.h" #if ERPC_NESTED_CALLS #include "erpc_client_manager.h" #endif diff --git a/erpc_c/infra/erpc_static_queue.h b/erpc_c/infra/erpc_static_queue.h index c55f8683f..52d8ee3f5 100644 --- a/erpc_c/infra/erpc_static_queue.h +++ b/erpc_c/infra/erpc_static_queue.h @@ -103,12 +103,12 @@ class StaticQueue } protected: - uint64_t m_storage[elementCount][(sizeof(T) + sizeof(uint64_t) - 1) / - sizeof(uint64_t)]; /*!< Preallocated space based on data type size and elements - count. */ - uint32_t m_capacity; /*!< Capacity of queue */ - uint32_t volatile m_head; /*!< Index to free slot */ - uint32_t volatile m_tail; /*!< Index to slot with m_data */ + uint64_t m_storage[elementCount] + [(sizeof(T) + sizeof(uint64_t) - 1) / sizeof(uint64_t)]; /*!< Preallocated space based on data + type size and elements count. */ + uint32_t m_capacity; /*!< Capacity of queue */ + uint32_t volatile m_head; /*!< Index to free slot */ + uint32_t volatile m_tail; /*!< Index to slot with m_data */ }; } // namespace erpc diff --git a/erpc_c/infra/erpc_transport.h b/erpc_c/infra/erpc_transport.h index 255c0f884..a670ec79d 100644 --- a/erpc_c/infra/erpc_transport.h +++ b/erpc_c/infra/erpc_transport.h @@ -13,6 +13,7 @@ #include "erpc_common.h" #include "erpc_crc16.h" #include "erpc_message_buffer.h" + #include /*! diff --git a/erpc_c/infra/erpc_transport_arbitrator.cpp b/erpc_c/infra/erpc_transport_arbitrator.cpp index 56736f01d..07c5763da 100644 --- a/erpc_c/infra/erpc_transport_arbitrator.cpp +++ b/erpc_c/infra/erpc_transport_arbitrator.cpp @@ -7,7 +7,9 @@ * SPDX-License-Identifier: BSD-3-Clause */ #include "erpc_transport_arbitrator.h" + #include "erpc_config_internal.h" + #include #include #include @@ -56,16 +58,16 @@ erpc_status_t TransportArbitrator::receive(MessageBuffer *message) erpc_status_t err = m_sharedTransport->receive(message); if (err) { - // if we timeout, we must unblock all pending client(s) + // if we timeout, we must unblock all pending client(s) if (err == kErpcStatus_Timeout) - { + { PendingClientInfo *client = m_clientList; for (; client; client = client->m_next) { if (client->m_isValid) { client->m_sem.put(); - } + } } } return err; diff --git a/erpc_c/infra/erpc_version.h b/erpc_c/infra/erpc_version.h index f3d610ff3..65ca7397b 100644 --- a/erpc_c/infra/erpc_version.h +++ b/erpc_c/infra/erpc_version.h @@ -20,9 +20,9 @@ //////////////////////////////////////////////////////////////////////////////// //! @brief String version of eRPC. -#define ERPC_VERSION "1.7.4" +#define ERPC_VERSION "1.8.0" //! @brief Integer version of eRPC. -#define ERPC_VERSION_NUMBER 10704 +#define ERPC_VERSION_NUMBER 10800 /*! @} */ diff --git a/erpc_c/port/erpc_config_internal.h b/erpc_c/port/erpc_config_internal.h index f49cabbf2..cc992821c 100644 --- a/erpc_c/port/erpc_config_internal.h +++ b/erpc_c/port/erpc_config_internal.h @@ -29,6 +29,15 @@ #endif #endif +// Determine if we are targeting WIN32 environment +#if !defined(ERPC_HAS_WIN32) + #if defined(_WIN32) + #define ERPC_HAS_WIN32 (1) + #else + #define ERPC_HAS_WIN32 (0) + #endif +#endif + // Safely detect FreeRTOSConfig.h. #define ERPC_HAS_FREERTOSCONFIG_H (0) #if defined(__has_include) @@ -46,7 +55,7 @@ #elif ERPC_HAS_FREERTOSCONFIG_H // Use FreeRTOS if we can auto detect it. #define ERPC_THREADS (ERPC_THREADS_FREERTOS) - #elif defined(WIN32) + #elif ERPC_HAS_WIN32 #define ERPC_THREADS (ERPC_THREADS_WIN32) #else // Otherwise default to no threads. diff --git a/erpc_c/port/erpc_port_freertos.cpp b/erpc_c/port/erpc_port_freertos.cpp index 984396a05..1849e3b16 100644 --- a/erpc_c/port/erpc_port_freertos.cpp +++ b/erpc_c/port/erpc_port_freertos.cpp @@ -8,6 +8,7 @@ */ #include "erpc_port.h" + #include extern "C" { @@ -40,7 +41,7 @@ void *operator new[](std::size_t count, const std::nothrow_t &tag) THROW return p; } -void operator delete(void *ptr) THROW +void operator delete(void *ptr)THROW { erpc_free(ptr); } diff --git a/erpc_c/port/erpc_port_memmanager.cpp b/erpc_c/port/erpc_port_memmanager.cpp index 353b8f9df..aa23feafa 100644 --- a/erpc_c/port/erpc_port_memmanager.cpp +++ b/erpc_c/port/erpc_port_memmanager.cpp @@ -7,6 +7,7 @@ */ #include "erpc_port.h" + #include extern "C" { @@ -42,7 +43,7 @@ void *operator new[](std::size_t count, const std::nothrow_t &tag) THROW NOEXCEP return p; } -void operator delete(void *ptr) THROW +void operator delete(void *ptr)THROW { erpc_free(ptr); } diff --git a/erpc_c/port/erpc_port_mqx.cpp b/erpc_c/port/erpc_port_mqx.cpp index eecc40a8e..6311f3c75 100644 --- a/erpc_c/port/erpc_port_mqx.cpp +++ b/erpc_c/port/erpc_port_mqx.cpp @@ -8,6 +8,7 @@ */ #include "erpc_port.h" + #include extern "C" { @@ -40,7 +41,7 @@ void *operator new[](std::size_t count, const std::nothrow_t &tag) THROW return p; } -void operator delete(void *ptr) THROW +void operator delete(void *ptr)THROW { erpc_free(ptr); } diff --git a/erpc_c/port/erpc_port_stdlib.cpp b/erpc_c/port/erpc_port_stdlib.cpp index 2a7e76248..a03e35904 100644 --- a/erpc_c/port/erpc_port_stdlib.cpp +++ b/erpc_c/port/erpc_port_stdlib.cpp @@ -8,6 +8,7 @@ */ #include "erpc_port.h" + #include #include @@ -39,12 +40,12 @@ void *operator new[](size_t count, const nothrow_t &tag) THROW NOEXCEPT return p; } -void operator delete(void *ptr) THROW NOEXCEPT +void operator delete(void *ptr)THROW NOEXCEPT { erpc_free(ptr); } -void operator delete(void* ptr, std::size_t count) THROW NOEXCEPT +void operator delete(void *ptr, std::size_t count)THROW NOEXCEPT { (void)count; erpc_free(ptr); @@ -55,7 +56,7 @@ void operator delete[](void *ptr) THROW NOEXCEPT erpc_free(ptr); } -void operator delete[](void* ptr, std::size_t count) THROW NOEXCEPT +void operator delete[](void *ptr, std::size_t count) THROW NOEXCEPT { (void)count; erpc_free(ptr); diff --git a/erpc_c/port/erpc_port_zephyr.cpp b/erpc_c/port/erpc_port_zephyr.cpp index 6990bb976..b13e02efe 100644 --- a/erpc_c/port/erpc_port_zephyr.cpp +++ b/erpc_c/port/erpc_port_zephyr.cpp @@ -7,6 +7,7 @@ */ #include "erpc_port.h" + #include extern "C" { @@ -39,7 +40,7 @@ void *operator new[](std::size_t count, const std::nothrow_t &tag) THROW return p; } -void operator delete(void *ptr) THROW +void operator delete(void *ptr)THROW { erpc_free(ptr); } diff --git a/erpc_c/port/erpc_serial.cpp b/erpc_c/port/erpc_serial.cpp index 51d06d858..14d05bf2f 100644 --- a/erpc_c/port/erpc_serial.cpp +++ b/erpc_c/port/erpc_serial.cpp @@ -38,39 +38,53 @@ #include "erpc_serial.h" +#ifdef _WIN32 +static OVERLAPPED s_writeOverlap; +static OVERLAPPED s_readOverlap; +#define TX_BUF_BYTES 1024U +#define RX_BUF_BYTES 1024U +#endif + int serial_setup(int fd, speed_t speed) { -#ifdef WIN32 +#ifdef _WIN32 COMMTIMEOUTS timeouts; DCB dcb = { 0 }; HANDLE hCom = (HANDLE)fd; - dcb.DCBlength = sizeof(dcb); + DWORD errors; + COMSTAT status; + + ClearCommError(hCom, &errors, &status); + PurgeComm(hCom, PURGE_TXABORT | PURGE_RXABORT | PURGE_TXCLEAR | PURGE_RXCLEAR); - dcb.BaudRate = speed; + memset(&timeouts, 0, sizeof(timeouts)); + timeouts.ReadIntervalTimeout = MAXDWORD; + timeouts.WriteTotalTimeoutConstant = 500; + + if (!SetCommTimeouts(hCom, &timeouts)) + { + return -1; + } + + dcb.DCBlength = sizeof(dcb); + dcb.BaudRate = 115200; dcb.ByteSize = 8; dcb.Parity = NOPARITY; dcb.StopBits = ONESTOPBIT; + dcb.fBinary = TRUE; + dcb.fDtrControl = DTR_CONTROL_ENABLE; + dcb.fRtsControl = RTS_CONTROL_ENABLE; if (!SetCommState(hCom, &dcb)) { return -1; } - // These timeouts mean: - // read: return immediately with whatever data is available, if any - // write: timeouts not used - // reference: http://www.robbayer.com/files/serial-win.pdf - timeouts.ReadIntervalTimeout = MAXDWORD; - timeouts.ReadTotalTimeoutMultiplier = 0; - timeouts.ReadTotalTimeoutConstant = 0; - timeouts.WriteTotalTimeoutMultiplier = 0; - timeouts.WriteTotalTimeoutConstant = 0; + s_writeOverlap.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); + s_readOverlap.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); - if (!SetCommTimeouts(hCom, &timeouts)) - { - return -1; - } + SetCommMask(hCom, EV_RXCHAR); #else (void)speed; struct termios tty; @@ -83,7 +97,7 @@ int serial_setup(int fd, speed_t speed) tty.c_oflag = 0; tty.c_lflag = 0; -#ifdef LINUX +#ifdef __linux__ switch (speed) { case 9600: @@ -119,56 +133,18 @@ int serial_setup(int fd, speed_t speed) return -1; } -#ifdef MACOSX +#ifdef __APPLE__ return ioctl(fd, IOSSIOSPEED, &speed); -#endif //#ifdef MACOSX +#endif //#ifdef __APPLE__ -#endif // WIN32 +#endif // _WIN32 return 0; } int serial_set_read_timeout(int fd, uint8_t vtime, uint8_t vmin) { -#ifdef WIN32 - COMMTIMEOUTS timeouts; - HANDLE hCom = (HANDLE)fd; - - // These timeouts mean: - // read: return if: - // 1. Inter-character timeout exceeds ReadIntervalTimeout - // 2. Total timeout exceeds (ReadIntervalTimeout*ReadTotalTimeoutMultiplier*number of characters) + - // ReadTotalTimeoutConstant - // In practice it seems that no matter how many characters you ask for, if no characters appear on the interface - // then - // only ReadTotalTimeoutConstant applies. - // write: timeouts not used - // reference: http://www.robbayer.com/files/serial-win.pdf - if (timeoutMs != 0) - { - timeouts.ReadIntervalTimeout = 1000; - timeouts.ReadTotalTimeoutMultiplier = 10; - timeouts.ReadTotalTimeoutConstant = timeoutMs; - timeouts.WriteTotalTimeoutMultiplier = 0; - timeouts.WriteTotalTimeoutConstant = 0; - } - else - { - // Need a separate case for timeoutMs == 0 - // setting all these values to 0 results in no timeout - // so set them to a minimum value, this will return immediately - // if there is no data available - timeouts.ReadIntervalTimeout = 1; - timeouts.ReadTotalTimeoutMultiplier = 1; - timeouts.ReadTotalTimeoutConstant = 1; - timeouts.WriteTotalTimeoutMultiplier = 0; - timeouts.WriteTotalTimeoutConstant = 0; - } - - if (!SetCommTimeouts(hCom, &timeouts)) - { - return -1; - } - +#ifdef _WIN32 + // TODO #else struct termios tty; /*memset(&tty, 0x00, sizeof(tty)); @@ -191,24 +167,37 @@ int serial_set_read_timeout(int fd, uint8_t vtime, uint8_t vmin) return -1; } -#endif // WIN32 +#endif // _WIN32 return 0; } int serial_write(int fd, char *buf, int size) { -#ifdef WIN32 +#ifdef _WIN32 HANDLE hCom = (HANDLE)fd; + DWORD errors; + COMSTAT status; unsigned long bwritten = 0; - if (!WriteFile(hCom, buf, size, &bwritten, NULL)) - { - return 0; - } - else + ClearCommError(hCom, &errors, &status); + if (!WriteFile(hCom, buf, size, &bwritten, &s_writeOverlap)) { - return bwritten; + if (GetLastError() == ERROR_IO_PENDING) + { + if (!GetOverlappedResult(hCom, &s_writeOverlap, &bwritten, TRUE)) + { + return 0; + } + } + else + { + return 0; + ; + } } + ClearCommError(hCom, &errors, &status); + + return bwritten; #else return write(fd, buf, size); #endif @@ -216,18 +205,61 @@ int serial_write(int fd, char *buf, int size) int serial_read(int fd, char *buf, int size) { -#ifdef WIN32 +#ifdef _WIN32 HANDLE hCom = (HANDLE)fd; unsigned long bread = 0; + char temp[RX_BUF_BYTES] = { 0 }; + DWORD errors; + DWORD bytesToRead = 0; + DWORD bytesRead = 0; + DWORD ret = 0; - if (!ReadFile(hCom, buf, size, &bread, NULL)) - { - return 0; - } - else + while (bytesToRead != size) { - return bread; + do + { + + ClearCommError(hCom, &errors, NULL); + + if (!ReadFile(hCom, temp, RX_BUF_BYTES - bytesToRead, &bytesRead, &s_readOverlap)) + { + if (GetLastError() == ERROR_IO_PENDING) + { + ret = WaitForSingleObject(s_readOverlap.hEvent, INFINITE); + + if (WAIT_OBJECT_0 == ret) + { + if (!GetOverlappedResult(hCom, &s_readOverlap, &bytesRead, FALSE)) + { + bytesRead = 0; + bytesToRead = 0; + } + } + else + { + bytesRead = 0; + bytesToRead = 0; + } + } + else + { + bytesRead = 0; + bytesToRead = 0; + } + } + + bytesToRead += bytesRead; + + if (bytesRead) + { + memcpy(buf, temp, bytesRead); + buf += bytesRead; + } + + } while ((bytesRead > 0) && (RX_BUF_BYTES >= bytesToRead)); } + + return bytesToRead; #else int len = 0; int ret = 0; @@ -263,19 +295,21 @@ int serial_read(int fd, char *buf, int size) int serial_open(const char *port) { int fd; -#ifdef WIN32 +#ifdef _WIN32 static char full_path[32] = { 0 }; HANDLE hCom = NULL; - if (port[0] != '\\') + if (memcmp(port, "\\\\.\\", 4)) { _snprintf(full_path, sizeof(full_path) - 1, "\\\\.\\%s", port); - port = full_path; + } + else + { + memcpy(full_path, port, strnlen_s(port, sizeof(full_path) - 1)); } -#pragma warning(suppress : 6053) - hCom = CreateFileA(port, GENERIC_WRITE | GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); + hCom = CreateFileA(full_path, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL); if (!hCom || hCom == INVALID_HANDLE_VALUE) { @@ -298,7 +332,7 @@ int serial_open(const char *port) int serial_close(int fd) { -#ifdef WIN32 +#ifdef _WIN32 HANDLE hCom = (HANDLE)fd; CloseHandle(hCom); diff --git a/erpc_c/port/erpc_serial.h b/erpc_c/port/erpc_serial.h index 2b5a996a2..ee9d40efe 100644 --- a/erpc_c/port/erpc_serial.h +++ b/erpc_c/port/erpc_serial.h @@ -23,7 +23,7 @@ #ifndef MYSERIAL_H_ #define MYSERIAL_H_ -#ifdef MACOSX +#ifdef __APPLE__ #include #include @@ -34,7 +34,7 @@ #include -#ifdef WIN32 +#ifdef _WIN32 #include #include diff --git a/erpc_c/port/erpc_setup_extensions.h b/erpc_c/port/erpc_setup_extensions.h index d7666eda3..8b1c2060f 100644 --- a/erpc_c/port/erpc_setup_extensions.h +++ b/erpc_c/port/erpc_setup_extensions.h @@ -12,6 +12,8 @@ #include "erpc_config_internal.h" +#include + #if ERPC_THREADS #if ERPC_THREADS_IS(FREERTOS) diff --git a/erpc_c/port/erpc_setup_extensions_freertos.cpp b/erpc_c/port/erpc_setup_extensions_freertos.cpp index f71e653e2..983451da3 100644 --- a/erpc_c/port/erpc_setup_extensions_freertos.cpp +++ b/erpc_c/port/erpc_setup_extensions_freertos.cpp @@ -19,9 +19,11 @@ static TimerHandle_t s_erpc_call_timer_cb = NULL; void erpc::erpc_pre_cb_default() { - assert(s_erpc_call_in_progress && "If you want use default pre cb action, do not forget call erpc_init_call_progress_detection_default."); + assert(s_erpc_call_in_progress && + "If you want use default pre cb action, do not forget call erpc_init_call_progress_detection_default."); s_erpc_call_in_progress->get(s_erpc_call_in_progress->kWaitForever); - assert(s_erpc_call_timer_cb && "If you want use default pre cb action, do not forget call erpc_init_call_progress_detection_default."); + assert(s_erpc_call_timer_cb && + "If you want use default pre cb action, do not forget call erpc_init_call_progress_detection_default."); xTimerStart(s_erpc_call_timer_cb, 0); } @@ -36,24 +38,26 @@ void erpc_call_timer_cb_default(TimerHandle_t xTimer) assert(1 != 1 && "eRPC task freezed."); } -void erpc_init_call_progress_detection_default(erpc_call_timer_cb_default_t erpc_call_timer_cb = erpc_call_timer_cb_default, uint32_t waitTimeMs = 5 * 60 * 1000) +void erpc_init_call_progress_detection_default( + erpc_call_timer_cb_default_t erpc_call_timer_cb = erpc_call_timer_cb_default, uint32_t waitTimeMs = 5 * 60 * 1000) { s_erpc_call_in_progress = new Semaphore(1); assert(s_erpc_call_in_progress && "Creating eRPC semaphore failed."); - s_erpc_call_timer_cb = xTimerCreate("Erpc client call timer", waitTimeMs / portTICK_PERIOD_MS, pdFALSE, NULL, erpc_call_timer_cb); + s_erpc_call_timer_cb = + xTimerCreate("Erpc client call timer", waitTimeMs / portTICK_PERIOD_MS, pdFALSE, NULL, erpc_call_timer_cb); assert(s_erpc_call_timer_cb && "Creating eRPC timer failed."); } void erpc_deinit_call_progress_detection_default() { - if(s_erpc_call_in_progress) + if (s_erpc_call_in_progress) { delete s_erpc_call_in_progress; s_erpc_call_in_progress = NULL; } - if(s_erpc_call_timer_cb) + if (s_erpc_call_timer_cb) { xTimerDelete(s_erpc_call_timer_cb, 0); s_erpc_call_timer_cb = NULL; @@ -62,7 +66,8 @@ void erpc_deinit_call_progress_detection_default() bool erpc_is_call_in_progress_default() { - assert(s_erpc_call_in_progress && "If you want use default pre cb action, do not forget call erpc_init_call_progress_detection_default."); + assert(s_erpc_call_in_progress && + "If you want use default pre cb action, do not forget call erpc_init_call_progress_detection_default."); if (s_erpc_call_in_progress->get(0)) { s_erpc_call_in_progress->put(); @@ -74,10 +79,12 @@ bool erpc_is_call_in_progress_default() void erpc_reset_in_progress_state_default() { - assert(s_erpc_call_in_progress && "If you want use default pre cb action, do not forget call erpc_init_call_progress_detection_default."); + assert(s_erpc_call_in_progress && + "If you want use default pre cb action, do not forget call erpc_init_call_progress_detection_default."); s_erpc_call_in_progress->get(0); s_erpc_call_in_progress->put(); - assert(s_erpc_call_timer_cb && "If you want use default pre cb action, do not forget call erpc_init_call_progress_detection_default."); + assert(s_erpc_call_timer_cb && + "If you want use default pre cb action, do not forget call erpc_init_call_progress_detection_default."); xTimerStop(s_erpc_call_timer_cb, 0); } diff --git a/erpc_c/port/erpc_spidev.cpp b/erpc_c/port/erpc_spidev.cpp new file mode 100644 index 000000000..4adfbd131 --- /dev/null +++ b/erpc_c/port/erpc_spidev.cpp @@ -0,0 +1,82 @@ +/* + * Copyright 2020 NXP + * All rights reserved. + * + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include "erpc_spidev.h" + +#include +#include +#include +#include +#include +#include +#include + +int spidev_open(const char *port) +{ + int fd; + + fd = open(port, O_RDWR); + if (-1 == fd) + { + fprintf(stderr, "Could not open spidev port (%d).\r\n", errno); + } + return fd; +} + +int spidev_set_mode(int fd, unsigned char mode) +{ + if (-1 == ioctl(fd, SPI_IOC_WR_MODE, &mode)) + { + fprintf(stderr, "Could not set mode for spidev port (%d).\r\n", errno); + return ERPC_SPIDEV_STATUS_FAIL; + } + return ERPC_SPIDEV_STATUS_SUCCESS; +} + +int spidev_set_speed(int fd, unsigned int speed_hz) +{ + if (-1 == ioctl(fd, SPI_IOC_WR_MAX_SPEED_HZ, &speed_hz)) + { + fprintf(stderr, "Could not set max speed for spidev port (%d).\r\n", errno); + return ERPC_SPIDEV_STATUS_FAIL; + } + return ERPC_SPIDEV_STATUS_SUCCESS; +} + +int spidev_set_wordbits(int fd, unsigned char bits) +{ + if (-1 == ioctl(fd, SPI_IOC_WR_BITS_PER_WORD, &bits)) + { + fprintf(stderr, "Could not set bits per word for spidev port (%d).\r\n", errno); + return ERPC_SPIDEV_STATUS_FAIL; + } + return ERPC_SPIDEV_STATUS_SUCCESS; +} + +int spidev_transfer(int fd, unsigned char *tx_buf, unsigned char *rx_buf, unsigned int len) +{ + struct spi_ioc_transfer spi_message; + + memset(&spi_message, 0, sizeof(spi_message)); + spi_message.tx_buf = (unsigned long)tx_buf; + spi_message.rx_buf = (unsigned long)rx_buf; + spi_message.len = len; + + if (-1 == ioctl(fd, SPI_IOC_MESSAGE(1), &spi_message)) + { + fprintf(stderr, "Could not transfer data on spidev port (%d).\r\n", errno); + return ERPC_SPIDEV_STATUS_FAIL; + } + return ERPC_SPIDEV_STATUS_SUCCESS; +} + +int spidev_close(int fd) +{ + close(fd); + return ERPC_SPIDEV_STATUS_SUCCESS; +} diff --git a/erpc_c/port/erpc_spidev.h b/erpc_c/port/erpc_spidev.h new file mode 100644 index 000000000..6726a9db3 --- /dev/null +++ b/erpc_c/port/erpc_spidev.h @@ -0,0 +1,30 @@ +/* + * Copyright 2020 NXP + * All rights reserved. + * + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef _ERPC_SPIDEV_H_ +#define _ERPC_SPIDEV_H_ + +#if __cplusplus +extern "C" { +#endif + +#define ERPC_SPIDEV_STATUS_SUCCESS 0 +#define ERPC_SPIDEV_STATUS_FAIL -1 + +int spidev_open(const char *port); +int spidev_set_mode(int fd, unsigned char mode); +int spidev_set_speed(int fd, unsigned int speed_hz); +int spidev_set_wordbits(int fd, unsigned char bits); +int spidev_transfer(int fd, unsigned char *tx_buf, unsigned char *rx_buf, unsigned int len); +int spidev_close(int fd); + +#if __cplusplus +} +#endif + +#endif /* _ERPC_SPIDEV_H_ */ diff --git a/erpc_c/port/erpc_sysgpio.c b/erpc_c/port/erpc_sysgpio.c new file mode 100644 index 000000000..608f6e6c2 --- /dev/null +++ b/erpc_c/port/erpc_sysgpio.c @@ -0,0 +1,209 @@ +/* + * Copyright 2020 NXP + * All rights reserved. + * + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include "erpc_sysgpio.h" + +#include +#include +#include +#include +#include +#include +#include + +int gpio_export(int gpio) +{ + int fd; + char sysgpio[64]; + + /* Check if the gpio has already been exported */ + sprintf(sysgpio, "/sys/class/gpio/gpio%d/value", gpio); + fd = open(sysgpio, O_WRONLY); + if (-1 != fd) + { + close(fd); + return ERPC_SYSGPIO_STATUS_SUCCESS; + } + + fd = open("/sys/class/gpio/export", O_WRONLY | O_SYNC); + if (-1 == fd) + { + fprintf(stderr, "Could not open gpio export file (%d).\r\n", errno); + return -1; + } + else + { + sprintf(sysgpio, "%d", gpio); + if (strlen(sysgpio) != write(fd, sysgpio, strlen(sysgpio))) + { + fprintf(stderr, "Could not export gpio (%d) (%d).\r\n", gpio, errno); + close(fd); + return -2; + } + } + + close(fd); + return ERPC_SYSGPIO_STATUS_SUCCESS; +} + +int gpio_direction(int gpio, int direction) +{ + int fd; + char sysgpio[64]; + int ret = ERPC_SYSGPIO_STATUS_SUCCESS; + + sprintf(sysgpio, "/sys/class/gpio/gpio%d/direction", gpio); + fd = open(sysgpio, O_WRONLY | O_SYNC); + if (-1 == fd) + { + fprintf(stderr, "Could not open gpio (%d) direction file (%d).\r\n", gpio, errno); + return -1; + } + + else if (0 == direction) + { + if (3 != write(fd, "out", 3)) + { + fprintf(stderr, "Could not set gpio (%d) direction to out (low) (%d).\r\n", gpio, errno); + ret = -2; + } + } + else if (1 == direction) + { + if (2 != write(fd, "in", 2)) + { + fprintf(stderr, "Could not set gpio (%d) direction to in (%d).\r\n", gpio, errno); + ret = -3; + } + } + else if (2 == direction) + { + if (4 != write(fd, "high", 4)) + { + fprintf(stderr, "Could not set gpio (%d) direction to out (high) (%d).\r\n", gpio, errno); + ret = -4; + } + } + + close(fd); + return ret; +} + +int gpio_set_edge(int gpio, char *edge) +{ + int fd; + char sysgpio[64]; + unsigned char len = 0; + + sprintf(sysgpio, "/sys/class/gpio/gpio%d/edge", gpio); + fd = open(sysgpio, O_WRONLY | O_SYNC); + if (-1 == fd) + { + fprintf(stderr, "Could not open gpio (%d) edge file (%d).\r\n", gpio, errno); + return -1; + } + + len = strlen(edge) + 1; + if (len != write(fd, edge, len)) + { + fprintf(stderr, "Could not set gpio (%d) edge (%d).\r\n", gpio, errno); + close(fd); + return -2; + } + + close(fd); + return ERPC_SYSGPIO_STATUS_SUCCESS; +} + +int gpio_read(int gpio) +{ + int fd; + char sysgpio[64]; + char in; + + sprintf(sysgpio, "/sys/class/gpio/gpio%d/value", gpio); + fd = open(sysgpio, O_RDWR | O_SYNC); + if (-1 == fd) + { + fprintf(stderr, "Could not open gpio (%d) value file (%d).\r\n", gpio, errno); + return -1; + } + + if (1 != read(fd, &in, 1)) + { + fprintf(stderr, "Could not read gpio (%d) value (%d).\r\n", gpio, errno); + close(fd); + return -2; + } + + close(fd); + return atoi(&in); +} + +int gpio_open(int gpio) +{ + int fd; + char sysgpio[64]; + char in; + + sprintf(sysgpio, "/sys/class/gpio/gpio%d/value", gpio); + fd = open(sysgpio, O_RDWR | O_SYNC); + if (-1 == fd) + { + fprintf(stderr, "Could not open gpio (%d) value file (%d).\r\n", gpio, errno); + return -1; + } + + /* perform a dummy read to clean the events */ + if (1 != read(fd, &in, 1)) + { + fprintf(stderr, "Could not read gpio (%d) value (%d).\r\n", gpio, errno); + close(fd); + return -2; + } + + return fd; +} + +int gpio_close(int fd) +{ + return close(fd); +} + +int gpio_poll(int fd, int timeout) +{ + int pollr; + struct pollfd fds; + + fds.fd = fd; + fds.events = POLLPRI | POLLERR; + ; + pollr = poll(&fds, 1, timeout); + + if (pollr < 0) + { + fprintf(stderr, "Could not poll gpio (%d).\r\n", errno); + return -1; + } + + if (fds.revents & POLLPRI) + { + /* perform a dummy read to clean the events */ + char val; + lseek(fds.fd, 0, SEEK_SET); + read(fds.fd, &val, 1); + return 1; + } + else if (fds.revents & POLLERR) + { + fprintf(stderr, "Error while polling gpio (%d).\r\n", errno); + return -2; + } + + return ERPC_SYSGPIO_STATUS_SUCCESS; +} diff --git a/erpc_c/port/erpc_sysgpio.h b/erpc_c/port/erpc_sysgpio.h new file mode 100644 index 000000000..3012e98ce --- /dev/null +++ b/erpc_c/port/erpc_sysgpio.h @@ -0,0 +1,31 @@ +/* + * Copyright 2020 NXP + * All rights reserved. + * + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef _ERPC_SYSGPIO_H_ +#define _ERPC_SYSGPIO_H_ + +#if __cplusplus +extern "C" { +#endif + +#define ERPC_SYSGPIO_STATUS_SUCCESS 0 + +int gpio_export(int gpio); +int gpio_direction(int gpio, int direction); +int gpio_set_edge(int gpio, char *edge); +int gpio_read(int gpio); + +int gpio_open(int gpio); +int gpio_close(int fd); +int gpio_poll(int fd, int timeout); + +#if __cplusplus +} +#endif + +#endif /* _ERPC_SYSGPIO_H_ */ diff --git a/erpc_c/port/erpc_threading.h b/erpc_c/port/erpc_threading.h index 2c0b9e058..caa8fe8fd 100644 --- a/erpc_c/port/erpc_threading.h +++ b/erpc_c/port/erpc_threading.h @@ -11,6 +11,7 @@ #define __embedded_rpc__thread__ #include "erpc_config_internal.h" + #include // Exclude the rest of the file if threading is disabled. @@ -272,10 +273,10 @@ class Thread #elif ERPC_THREADS_IS(WIN32) /*! - * @brief This function execute threadEntryPoint function. - * - * @param[in] arg Thread to execute. - */ + * @brief This function execute threadEntryPoint function. + * + * @param[in] arg Thread to execute. + */ static unsigned WINAPI threadEntryPointStub(void *arg); #endif @@ -470,7 +471,7 @@ class Semaphore rtos::Semaphore *m_sem; /*!< Semaphore. */ int m_count; /*!< Semaphore count number. */ #elif ERPC_THREADS_IS(WIN32) - Mutex m_mutex; /*!< Mutext. */ + Mutex m_mutex; /*!< Mutext. */ int m_count; HANDLE m_sem; #endif diff --git a/erpc_c/port/erpc_threading_freertos.cpp b/erpc_c/port/erpc_threading_freertos.cpp index c00775080..f01b6f71c 100644 --- a/erpc_c/port/erpc_threading_freertos.cpp +++ b/erpc_c/port/erpc_threading_freertos.cpp @@ -8,6 +8,7 @@ */ #include "erpc_threading.h" + #include #include diff --git a/erpc_c/port/erpc_threading_pthreads.cpp b/erpc_c/port/erpc_threading_pthreads.cpp index 023b6b094..d3833a09b 100644 --- a/erpc_c/port/erpc_threading_pthreads.cpp +++ b/erpc_c/port/erpc_threading_pthreads.cpp @@ -8,6 +8,7 @@ */ #include "erpc_threading.h" + #include #include #include diff --git a/erpc_c/port/erpc_threading_win32.cpp b/erpc_c/port/erpc_threading_win32.cpp index 12a8cff7a..708ffa129 100644 --- a/erpc_c/port/erpc_threading_win32.cpp +++ b/erpc_c/port/erpc_threading_win32.cpp @@ -8,7 +8,11 @@ */ #include "erpc_threading.h" + +#include #include +#include +#include using namespace erpc; @@ -68,13 +72,7 @@ void Thread::start(void *arg) m_arg = arg; EnterCriticalSection(&m_critical_section); - m_thread = (HANDLE)_beginthreadex( - NULL, - m_stackSize, - threadEntryPointStub, - this, - 0, - &m_thrdaddr); + m_thread = (HANDLE)_beginthreadex(NULL, m_stackSize, threadEntryPointStub, this, 0, &m_thrdaddr); // Link in this thread to the list. if (NULL != s_first) @@ -111,7 +109,21 @@ Thread *Thread::getCurrentThread(void) void Thread::sleep(uint32_t usecs) { - Sleep(usecs); + LARGE_INTEGER startTime; + LARGE_INTEGER currTick; + LARGE_INTEGER freq; + uint32_t elapsedTimeMicroSeconds; + + QueryPerformanceFrequency(&freq); + QueryPerformanceCounter(&startTime); + + do + { + QueryPerformanceCounter(&currTick); + + elapsedTimeMicroSeconds = + static_cast(((currTick.QuadPart - startTime.QuadPart) * 1000000) / freq.QuadPart); + } while (elapsedTimeMicroSeconds < usecs); } void Thread::threadEntryPoint(void) diff --git a/erpc_c/port/erpc_threading_zephyr.cpp b/erpc_c/port/erpc_threading_zephyr.cpp index 312ff892e..ba084cfe4 100644 --- a/erpc_c/port/erpc_threading_zephyr.cpp +++ b/erpc_c/port/erpc_threading_zephyr.cpp @@ -7,6 +7,7 @@ */ #include "erpc_threading.h" + #include #if ERPC_THREADS_IS(ZEPHYR) diff --git a/erpc_c/port/port.dox b/erpc_c/port/port.dox index 2966f6089..9ee43cca0 100644 --- a/erpc_c/port/port.dox +++ b/erpc_c/port/port.dox @@ -20,3 +20,15 @@ @brief Serial port @ingroup port */ + +/*! +@defgroup port_spidev SPIdev +@brief SPIdev port +@ingroup port +*/ + +/*! +@defgroup port_sysgpio SysGPIO +@brief SysGPIO port +@ingroup port +*/ \ No newline at end of file diff --git a/erpc_c/setup/erpc_arbitrated_client_setup.cpp b/erpc_c/setup/erpc_arbitrated_client_setup.cpp index a40278373..d81cfbea9 100644 --- a/erpc_c/setup/erpc_arbitrated_client_setup.cpp +++ b/erpc_c/setup/erpc_arbitrated_client_setup.cpp @@ -1,117 +1,118 @@ -/* - * Copyright (c) 2016, Freescale Semiconductor, Inc. - * Copyright 2016-2020 NXP - * Copyright 2020 ACRIOS Systems s.r.o. - * All rights reserved. - * - * - * SPDX-License-Identifier: BSD-3-Clause - */ - -#include "erpc_arbitrated_client_setup.h" -#include "erpc_arbitrated_client_manager.h" -#include "erpc_basic_codec.h" -#include "erpc_manually_constructed.h" -#include "erpc_message_buffer.h" -#include "erpc_transport_arbitrator.h" -#if ERPC_NESTED_CALLS -#include "erpc_threading.h" -#endif -#include - -#if ERPC_THREADS_IS(NONE) -#error "Arbitrator code does not work in no-threading configuration." -#endif - -using namespace erpc; - -//////////////////////////////////////////////////////////////////////////////// -// Variables -//////////////////////////////////////////////////////////////////////////////// - -// global client variables -static ManuallyConstructed s_client; -ClientManager *g_client = NULL; - -static ManuallyConstructed s_codecFactory; -static ManuallyConstructed s_arbitrator; -static ManuallyConstructed s_codec; -static ManuallyConstructed s_crc16; - -//////////////////////////////////////////////////////////////////////////////// -// Code -//////////////////////////////////////////////////////////////////////////////// - -erpc_transport_t erpc_arbitrated_client_init(erpc_transport_t transport, erpc_mbf_t message_buffer_factory) -{ - assert(transport); - - // Init factories. - s_codecFactory.construct(); - - // Create codec used by the arbitrator. - s_codec.construct(); - - // Init the arbitrator using the passed in transport. - s_arbitrator.construct(); - Transport *castedTransport = reinterpret_cast(transport); - s_crc16.construct(); - castedTransport->setCrc16(s_crc16.get()); - s_arbitrator->setSharedTransport(castedTransport); - s_arbitrator->setCodec(s_codec); - - // Init the client manager. - s_client.construct(); - s_client->setArbitrator(s_arbitrator); - s_client->setCodecFactory(s_codecFactory); - s_client->setMessageBufferFactory(reinterpret_cast(message_buffer_factory)); - g_client = s_client; - - return reinterpret_cast(s_arbitrator.get()); -} - -void erpc_arbitrated_client_set_error_handler(client_error_handler_t error_handler) -{ - if (g_client != NULL) - { - g_client->setErrorHandler(error_handler); - } -} - -void erpc_arbitrated_client_set_crc(uint32_t crcStart) -{ - s_crc16->setCrcStart(crcStart); -} - -#if ERPC_NESTED_CALLS -void erpc_arbitrated_client_set_server(erpc_server_t server) -{ - if (g_client != NULL) - { - g_client->setServer(reinterpret_cast(server)); - } -} - -void erpc_arbitrated_client_set_server_thread_id(void *serverThreadId) -{ - if (g_client != NULL) - { - g_client->setServerThreadId(reinterpret_cast(serverThreadId)); - } -} -#endif - -#if ERPC_MESSAGE_LOGGING -bool erpc_arbitrated_client_add_message_logger(erpc_transport_t transport) -{ - if (g_client != NULL) - { - return g_client->addMessageLogger(reinterpret_cast(transport)); - } - return false; -} -#endif - +/* + * Copyright (c) 2016, Freescale Semiconductor, Inc. + * Copyright 2016-2020 NXP + * Copyright 2020 ACRIOS Systems s.r.o. + * All rights reserved. + * + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include "erpc_arbitrated_client_setup.h" + +#include "erpc_arbitrated_client_manager.h" +#include "erpc_basic_codec.h" +#include "erpc_manually_constructed.h" +#include "erpc_message_buffer.h" +#include "erpc_transport_arbitrator.h" +#if ERPC_NESTED_CALLS +#include "erpc_threading.h" +#endif +#include + +#if ERPC_THREADS_IS(NONE) +#error "Arbitrator code does not work in no-threading configuration." +#endif + +using namespace erpc; + +//////////////////////////////////////////////////////////////////////////////// +// Variables +//////////////////////////////////////////////////////////////////////////////// + +// global client variables +static ManuallyConstructed s_client; +ClientManager *g_client = NULL; + +static ManuallyConstructed s_codecFactory; +static ManuallyConstructed s_arbitrator; +static ManuallyConstructed s_codec; +static ManuallyConstructed s_crc16; + +//////////////////////////////////////////////////////////////////////////////// +// Code +//////////////////////////////////////////////////////////////////////////////// + +erpc_transport_t erpc_arbitrated_client_init(erpc_transport_t transport, erpc_mbf_t message_buffer_factory) +{ + assert(transport); + + // Init factories. + s_codecFactory.construct(); + + // Create codec used by the arbitrator. + s_codec.construct(); + + // Init the arbitrator using the passed in transport. + s_arbitrator.construct(); + Transport *castedTransport = reinterpret_cast(transport); + s_crc16.construct(); + castedTransport->setCrc16(s_crc16.get()); + s_arbitrator->setSharedTransport(castedTransport); + s_arbitrator->setCodec(s_codec); + + // Init the client manager. + s_client.construct(); + s_client->setArbitrator(s_arbitrator); + s_client->setCodecFactory(s_codecFactory); + s_client->setMessageBufferFactory(reinterpret_cast(message_buffer_factory)); + g_client = s_client; + + return reinterpret_cast(s_arbitrator.get()); +} + +void erpc_arbitrated_client_set_error_handler(client_error_handler_t error_handler) +{ + if (g_client != NULL) + { + g_client->setErrorHandler(error_handler); + } +} + +void erpc_arbitrated_client_set_crc(uint32_t crcStart) +{ + s_crc16->setCrcStart(crcStart); +} + +#if ERPC_NESTED_CALLS +void erpc_arbitrated_client_set_server(erpc_server_t server) +{ + if (g_client != NULL) + { + g_client->setServer(reinterpret_cast(server)); + } +} + +void erpc_arbitrated_client_set_server_thread_id(void *serverThreadId) +{ + if (g_client != NULL) + { + g_client->setServerThreadId(reinterpret_cast(serverThreadId)); + } +} +#endif + +#if ERPC_MESSAGE_LOGGING +bool erpc_arbitrated_client_add_message_logger(erpc_transport_t transport) +{ + if (g_client != NULL) + { + return g_client->addMessageLogger(reinterpret_cast(transport)); + } + return false; +} +#endif + #if ERPC_PRE_POST_ACTION void erpc_arbitrated_client_add_pre_cb_action(pre_post_action_cb preCB) { @@ -128,11 +129,11 @@ void erpc_arbitrated_client_add_post_cb_action(pre_post_action_cb postCB) } #endif -void erpc_arbitrated_client_deinit(void) -{ - s_client.destroy(); - s_codecFactory.destroy(); - s_codec.destroy(); - s_arbitrator.destroy(); - g_client = NULL; -} +void erpc_arbitrated_client_deinit(void) +{ + s_client.destroy(); + s_codecFactory.destroy(); + s_codec.destroy(); + s_arbitrator.destroy(); + g_client = NULL; +} diff --git a/erpc_c/setup/erpc_client_setup.cpp b/erpc_c/setup/erpc_client_setup.cpp index d9823ec76..fabc3966a 100644 --- a/erpc_c/setup/erpc_client_setup.cpp +++ b/erpc_c/setup/erpc_client_setup.cpp @@ -1,121 +1,123 @@ -/* - * Copyright (c) 2014-2016, Freescale Semiconductor, Inc. - * Copyright 2016-2017 NXP +/* + * Copyright (c) 2014-2016, Freescale Semiconductor, Inc. + * Copyright 2016-2017 NXP * Copyright 2020 ACRIOS Systems s.r.o. - * All rights reserved. - * - * - * SPDX-License-Identifier: BSD-3-Clause - */ - -#include "erpc_client_setup.h" -#include "erpc_basic_codec.h" -#include "erpc_client_manager.h" -#include "erpc_crc16.h" -#include "erpc_manually_constructed.h" -#include "erpc_message_buffer.h" -#include "erpc_transport.h" -#include -#if ERPC_NESTED_CALLS -#include "erpc_threading.h" -#endif - -using namespace erpc; - -//////////////////////////////////////////////////////////////////////////////// -// Variables -//////////////////////////////////////////////////////////////////////////////// - -// global client variables -static ManuallyConstructed s_client; -ClientManager *g_client = NULL; -static ManuallyConstructed s_codecFactory; -static ManuallyConstructed s_crc16; - -//////////////////////////////////////////////////////////////////////////////// -// Code -//////////////////////////////////////////////////////////////////////////////// - -void erpc_client_init(erpc_transport_t transport, erpc_mbf_t message_buffer_factory) -{ - assert(transport); - - // Init factories. - s_codecFactory.construct(); - - // Init client manager with the provided transport. - s_client.construct(); - Transport *castedTransport = reinterpret_cast(transport); - s_crc16.construct(); - castedTransport->setCrc16(s_crc16.get()); - s_client->setTransport(castedTransport); - s_client->setCodecFactory(s_codecFactory); - s_client->setMessageBufferFactory(reinterpret_cast(message_buffer_factory)); - g_client = s_client; -} - -void erpc_client_set_error_handler(client_error_handler_t error_handler) -{ - if (g_client != NULL) - { - g_client->setErrorHandler(error_handler); - } -} - -void erpc_client_set_crc(uint32_t crcStart) -{ - s_crc16->setCrcStart(crcStart); -} - -#if ERPC_NESTED_CALLS -void erpc_client_set_server(erpc_server_t server) -{ - if (g_client != NULL) - { - g_client->setServer(reinterpret_cast(server)); - } -} - -void erpc_client_set_server_thread_id(void *serverThreadId) -{ - if (g_client != NULL) - { - g_client->setServerThreadId(reinterpret_cast(serverThreadId)); - } -} -#endif - -#if ERPC_MESSAGE_LOGGING -bool erpc_client_add_message_logger(erpc_transport_t transport) -{ - if (g_client != NULL) - { - return g_client->addMessageLogger(reinterpret_cast(transport)); - } - return false; -} -#endif - -#if ERPC_PRE_POST_ACTION -void erpc_client_add_pre_cb_action(pre_post_action_cb preCB) -{ - assert(g_client); - - g_client->addPreCB(preCB); -} - -void erpc_client_add_post_cb_action(pre_post_action_cb postCB) -{ - assert(g_client); - - g_client->addPostCB(postCB); -} -#endif - -void erpc_client_deinit(void) -{ - s_crc16.destroy(); - s_client.destroy(); - s_codecFactory.destroy(); - g_client = NULL; -} + * All rights reserved. + * + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include "erpc_client_setup.h" + +#include "erpc_basic_codec.h" +#include "erpc_client_manager.h" +#include "erpc_crc16.h" +#include "erpc_manually_constructed.h" +#include "erpc_message_buffer.h" +#include "erpc_transport.h" + +#include +#if ERPC_NESTED_CALLS +#include "erpc_threading.h" +#endif + +using namespace erpc; + +//////////////////////////////////////////////////////////////////////////////// +// Variables +//////////////////////////////////////////////////////////////////////////////// + +// global client variables +static ManuallyConstructed s_client; +ClientManager *g_client = NULL; +static ManuallyConstructed s_codecFactory; +static ManuallyConstructed s_crc16; + +//////////////////////////////////////////////////////////////////////////////// +// Code +//////////////////////////////////////////////////////////////////////////////// + +void erpc_client_init(erpc_transport_t transport, erpc_mbf_t message_buffer_factory) +{ + assert(transport); + + // Init factories. + s_codecFactory.construct(); + + // Init client manager with the provided transport. + s_client.construct(); + Transport *castedTransport = reinterpret_cast(transport); + s_crc16.construct(); + castedTransport->setCrc16(s_crc16.get()); + s_client->setTransport(castedTransport); + s_client->setCodecFactory(s_codecFactory); + s_client->setMessageBufferFactory(reinterpret_cast(message_buffer_factory)); + g_client = s_client; +} + +void erpc_client_set_error_handler(client_error_handler_t error_handler) +{ + if (g_client != NULL) + { + g_client->setErrorHandler(error_handler); + } +} + +void erpc_client_set_crc(uint32_t crcStart) +{ + s_crc16->setCrcStart(crcStart); +} + +#if ERPC_NESTED_CALLS +void erpc_client_set_server(erpc_server_t server) +{ + if (g_client != NULL) + { + g_client->setServer(reinterpret_cast(server)); + } +} + +void erpc_client_set_server_thread_id(void *serverThreadId) +{ + if (g_client != NULL) + { + g_client->setServerThreadId(reinterpret_cast(serverThreadId)); + } +} +#endif + +#if ERPC_MESSAGE_LOGGING +bool erpc_client_add_message_logger(erpc_transport_t transport) +{ + if (g_client != NULL) + { + return g_client->addMessageLogger(reinterpret_cast(transport)); + } + return false; +} +#endif + +#if ERPC_PRE_POST_ACTION +void erpc_client_add_pre_cb_action(pre_post_action_cb preCB) +{ + assert(g_client); + + g_client->addPreCB(preCB); +} + +void erpc_client_add_post_cb_action(pre_post_action_cb postCB) +{ + assert(g_client); + + g_client->addPostCB(postCB); +} +#endif + +void erpc_client_deinit(void) +{ + s_crc16.destroy(); + s_client.destroy(); + s_codecFactory.destroy(); + g_client = NULL; +} diff --git a/erpc_c/setup/erpc_server_setup.cpp b/erpc_c/setup/erpc_server_setup.cpp index e3379f0be..48d8729a8 100644 --- a/erpc_c/setup/erpc_server_setup.cpp +++ b/erpc_c/setup/erpc_server_setup.cpp @@ -9,12 +9,14 @@ */ #include "erpc_server_setup.h" + #include "erpc_basic_codec.h" #include "erpc_crc16.h" #include "erpc_manually_constructed.h" #include "erpc_message_buffer.h" #include "erpc_simple_server.h" #include "erpc_transport.h" + #include using namespace erpc; diff --git a/erpc_c/setup/erpc_setup_mbf_dynamic.cpp b/erpc_c/setup/erpc_setup_mbf_dynamic.cpp index 14ece5e90..a50192d25 100644 --- a/erpc_c/setup/erpc_setup_mbf_dynamic.cpp +++ b/erpc_c/setup/erpc_setup_mbf_dynamic.cpp @@ -11,6 +11,7 @@ #include "erpc_manually_constructed.h" #include "erpc_mbf_setup.h" #include "erpc_message_buffer.h" + #include #include diff --git a/erpc_c/setup/erpc_setup_mbf_rpmsg.cpp b/erpc_c/setup/erpc_setup_mbf_rpmsg.cpp index 9b1bb0407..8c80bf957 100644 --- a/erpc_c/setup/erpc_setup_mbf_rpmsg.cpp +++ b/erpc_c/setup/erpc_setup_mbf_rpmsg.cpp @@ -12,7 +12,9 @@ #include "erpc_mbf_setup.h" #include "erpc_message_buffer.h" #include "erpc_rpmsg_lite_base_transport.h" + #include "rpmsg_lite.h" + #include using namespace erpc; diff --git a/erpc_c/setup/erpc_setup_mbf_rpmsg_tty.cpp b/erpc_c/setup/erpc_setup_mbf_rpmsg_tty.cpp index 56752976c..f9fe37c61 100644 --- a/erpc_c/setup/erpc_setup_mbf_rpmsg_tty.cpp +++ b/erpc_c/setup/erpc_setup_mbf_rpmsg_tty.cpp @@ -13,7 +13,9 @@ #include "erpc_mbf_setup.h" #include "erpc_message_buffer.h" #include "erpc_rpmsg_lite_base_transport.h" + #include "rpmsg_lite.h" + #include using namespace erpc; diff --git a/erpc_c/setup/erpc_setup_mbf_static.cpp b/erpc_c/setup/erpc_setup_mbf_static.cpp index cd554405e..0bfaa83b1 100644 --- a/erpc_c/setup/erpc_setup_mbf_static.cpp +++ b/erpc_c/setup/erpc_setup_mbf_static.cpp @@ -11,6 +11,7 @@ #include "erpc_manually_constructed.h" #include "erpc_mbf_setup.h" #include "erpc_message_buffer.h" + #include #if !ERPC_THREADS_IS(ERPC_THREADS_NONE) diff --git a/erpc_c/setup/erpc_setup_spidev_master.cpp b/erpc_c/setup/erpc_setup_spidev_master.cpp new file mode 100644 index 000000000..2c7054118 --- /dev/null +++ b/erpc_c/setup/erpc_setup_spidev_master.cpp @@ -0,0 +1,30 @@ +/* + * Copyright 2020 NXP + * All rights reserved. + * + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include "erpc_manually_constructed.h" +#include "erpc_spidev_master_transport.h" +#include "erpc_transport_setup.h" + +using namespace erpc; + +//////////////////////////////////////////////////////////////////////////////// +// Variables +//////////////////////////////////////////////////////////////////////////////// + +static ManuallyConstructed s_transport; + +//////////////////////////////////////////////////////////////////////////////// +// Code +//////////////////////////////////////////////////////////////////////////////// + +erpc_transport_t erpc_transport_spidev_master_init(const char *spidev, uint32_t speed_Hz) +{ + s_transport.construct(spidev, speed_Hz); + s_transport->init(); + return reinterpret_cast(s_transport.get()); +} diff --git a/erpc_c/setup/erpc_setup_tcp.cpp b/erpc_c/setup/erpc_setup_tcp.cpp index 607f41dba..9532aa0d0 100644 --- a/erpc_c/setup/erpc_setup_tcp.cpp +++ b/erpc_c/setup/erpc_setup_tcp.cpp @@ -7,8 +7,8 @@ */ #include "erpc_manually_constructed.h" -#include "erpc_transport_setup.h" #include "erpc_tcp_transport.h" +#include "erpc_transport_setup.h" using namespace erpc; @@ -25,11 +25,11 @@ static ManuallyConstructed s_transport; erpc_transport_t erpc_transport_tcp_init(const char *host, uint16_t port, bool isServer) { s_transport.construct(host, port, isServer); - if (kErpcStatus_Success == s_transport->open()) + if (kErpcStatus_Success == s_transport->open()) { return reinterpret_cast(s_transport.get()); - } - return NULL; + } + return NULL; } void erpc_transport_tcp_close(void) diff --git a/erpc_c/setup/erpc_setup_usb_cdc.cpp b/erpc_c/setup/erpc_setup_usb_cdc.cpp new file mode 100644 index 000000000..7e361f2c5 --- /dev/null +++ b/erpc_c/setup/erpc_setup_usb_cdc.cpp @@ -0,0 +1,36 @@ +/* + * Copyright 2020 NXP + * All rights reserved. + * + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include "erpc_manually_constructed.h" +#include "erpc_transport_setup.h" +#include "erpc_usb_cdc_transport.h" + +using namespace erpc; + +//////////////////////////////////////////////////////////////////////////////// +// Variables +//////////////////////////////////////////////////////////////////////////////// + +static ManuallyConstructed s_usb_transport; + +//////////////////////////////////////////////////////////////////////////////// +// Code +//////////////////////////////////////////////////////////////////////////////// + +erpc_transport_t erpc_transport_usb_cdc_init(void *serialHandle, void *serialConfig, void *usbCdcConfig, + uint8_t *usbRingBuffer, uint32_t usbRingBufferLength) +{ + s_usb_transport.construct((serial_handle_t)serialHandle, (serial_manager_config_t *)serialConfig, + (serial_port_usb_cdc_config_t *)usbCdcConfig, (uint8_t *)usbRingBuffer, + (uint32_t)usbRingBufferLength); + if (s_usb_transport->init() == kErpcStatus_Success) + { + return reinterpret_cast(s_usb_transport.get()); + } + return NULL; +} diff --git a/erpc_c/setup/erpc_transport_setup.h b/erpc_c/setup/erpc_transport_setup.h index c2894006b..3d9daf9dd 100644 --- a/erpc_c/setup/erpc_transport_setup.h +++ b/erpc_c/setup/erpc_transport_setup.h @@ -34,8 +34,8 @@ typedef void (*rpmsg_ready_cb)(void); extern "C" { #endif -#include #include +#include //! @name Transport setup //@{ @@ -132,6 +132,22 @@ erpc_transport_t erpc_transport_dspi_master_init(void *baseAddr, uint32_t baudRa erpc_transport_t erpc_transport_dspi_slave_init(void *baseAddr, uint32_t baudRate, uint32_t srcClock_Hz); //@} +//! @name SPIdev transport setup +//@{ + +/*! + * @brief Create a SPIdev transport. + * + * Create SPIdev master transport instance, to be used at master core. + * + * @param[in] spidev SPI device name. + * @param[in] speed_Hz SPI clock speed in Hz. + * + * @return Return NULL or erpc_transport_t instance pointer. + */ +erpc_transport_t erpc_transport_spidev_master_init(const char *spidev, uint32_t speed_Hz); +//@} + //! @name MU transport setup //@{ @@ -286,7 +302,7 @@ void erpc_transport_rpmsg_linux_deinit(void); //! @name TCP transport setup //@{ - + /*! * @brief Create and open TCP transport * @@ -304,11 +320,11 @@ erpc_transport_t erpc_transport_tcp_init(const char *host, uint16_t port, bool i /*! * @brief Close TCP connection * - * For server, stop listening and close all sockets. Note that the server mode + * For server, stop listening and close all sockets. Note that the server mode * uses and accept() which is a not-recommended blocking method so we can't exit * until a connection attempts is made. This is a deadlock but assuming that TCP * code is supposed to be for test, I assume it's acceptable. Otherwise a non-blocking - * socket or select() shoudl be used + * socket or select() shoudl be used * For client, close server connection * * @return Return TRUE if listen/connection successful @@ -316,6 +332,32 @@ erpc_transport_t erpc_transport_tcp_init(const char *host, uint16_t port, bool i void erpc_transport_tcp_close(void); //@} +//! @name USB CDC transport setup +//@{ + +/*! + * @brief Create an USB CDC transport. + * + * Create an USB CDC transport instance. + * + * @param[in] serialHandle Pointer to point to a memory space of size #SERIAL_MANAGER_HANDLE_SIZE allocated by the + * caller, see serial manager header file. + * @param[in] serialConfig Pointer to user-defined configuration structure allocated by the caller, see serial manager + * header file. + * @param[in] usbCdcConfig Pointer to serial port usb config structure allocated by the caller, see serial manager + * header file. + * @param[in] usbRingBuffer Pointer to point serial manager ring buffer allocated by the caller, see serial manager + * header file. + * @param[in] usbRingBufferLength Serial manager ring buffer size. + * + * @return Return NULL or erpc_transport_t instance pointer. + */ +erpc_transport_t erpc_transport_usb_cdc_init(void *serialHandle, void *serialConfig, void *usbCdcConfig, + uint8_t *usbRingBuffer, uint32_t usbRingBufferLength); +//@} + +//@} + #ifdef __cplusplus } #endif diff --git a/erpc_c/setup/setup.dox b/erpc_c/setup/setup.dox index d0793ce72..bfaa43d71 100644 --- a/erpc_c/setup/setup.dox +++ b/erpc_c/setup/setup.dox @@ -15,8 +15,20 @@ @brief Client side setup functions. */ +/*! +@defgroup message_buffer_factory_setup Message Buffer Factory Setup +@ingroup setup +@brief Message Buffer Factory setup functions. +*/ + /*! @defgroup transport_setup Transport Setup @ingroup setup @brief Transport layer initialization. */ + +/*! +@defgroup port_setup_extensions Extension Setup +@ingroup setup +@brief Extension setup functions. +*/ diff --git a/erpc_c/transports/erpc_dspi_master_transport.cpp b/erpc_c/transports/erpc_dspi_master_transport.cpp index 9dfa08d46..e740b70a3 100644 --- a/erpc_c/transports/erpc_dspi_master_transport.cpp +++ b/erpc_c/transports/erpc_dspi_master_transport.cpp @@ -8,10 +8,12 @@ */ #include "erpc_dspi_master_transport.h" + #include "board.h" #include "fsl_dspi.h" #include "fsl_gpio.h" #include "fsl_port.h" + #include using namespace erpc; diff --git a/erpc_c/transports/erpc_dspi_master_transport.h b/erpc_c/transports/erpc_dspi_master_transport.h index a7cdcda0a..77914e725 100644 --- a/erpc_c/transports/erpc_dspi_master_transport.h +++ b/erpc_c/transports/erpc_dspi_master_transport.h @@ -11,7 +11,9 @@ #define _EMBEDDED_RPC__DSPI_MASTER_TRANSPORT_H_ #include "erpc_framed_transport.h" + #include "fsl_dspi.h" + #include /*! diff --git a/erpc_c/transports/erpc_dspi_slave_transport.cpp b/erpc_c/transports/erpc_dspi_slave_transport.cpp index 2f797456b..2f6f55db5 100644 --- a/erpc_c/transports/erpc_dspi_slave_transport.cpp +++ b/erpc_c/transports/erpc_dspi_slave_transport.cpp @@ -8,9 +8,11 @@ */ #include "erpc_dspi_slave_transport.h" + #include "board.h" #include "fsl_dspi.h" #include "fsl_gpio.h" + #include using namespace erpc; diff --git a/erpc_c/transports/erpc_dspi_slave_transport.h b/erpc_c/transports/erpc_dspi_slave_transport.h index 4fbd79c51..ab8e9f8e1 100644 --- a/erpc_c/transports/erpc_dspi_slave_transport.h +++ b/erpc_c/transports/erpc_dspi_slave_transport.h @@ -11,7 +11,9 @@ #define _EMBEDDED_RPC__DSPI_SLAVE_TRANSPORT_H_ #include "erpc_framed_transport.h" + #include "fsl_dspi.h" + #include /*! diff --git a/erpc_c/transports/erpc_inter_thread_buffer_transport.cpp b/erpc_c/transports/erpc_inter_thread_buffer_transport.cpp index 940d80d35..724382d30 100644 --- a/erpc_c/transports/erpc_inter_thread_buffer_transport.cpp +++ b/erpc_c/transports/erpc_inter_thread_buffer_transport.cpp @@ -8,6 +8,7 @@ */ #include "erpc_inter_thread_buffer_transport.h" + #include using namespace erpc; diff --git a/erpc_c/transports/erpc_mu_transport.cpp b/erpc_c/transports/erpc_mu_transport.cpp index bb332d772..6012294c7 100644 --- a/erpc_c/transports/erpc_mu_transport.cpp +++ b/erpc_c/transports/erpc_mu_transport.cpp @@ -7,7 +7,9 @@ */ #include "erpc_mu_transport.h" + #include "erpc_config_internal.h" + #include "board.h" using namespace erpc; diff --git a/erpc_c/transports/erpc_mu_transport.h b/erpc_c/transports/erpc_mu_transport.h index 60b040e64..25e1581df 100644 --- a/erpc_c/transports/erpc_mu_transport.h +++ b/erpc_c/transports/erpc_mu_transport.h @@ -15,6 +15,7 @@ #endif #include "erpc_message_buffer.h" #include "erpc_transport.h" + #include "fsl_device_registers.h" #include "fsl_mu.h" diff --git a/erpc_c/transports/erpc_rpmsg_linux_transport.cpp b/erpc_c/transports/erpc_rpmsg_linux_transport.cpp index 72d00af48..c49810a4e 100644 --- a/erpc_c/transports/erpc_rpmsg_linux_transport.cpp +++ b/erpc_c/transports/erpc_rpmsg_linux_transport.cpp @@ -7,6 +7,7 @@ */ #include "erpc_rpmsg_linux_transport.h" + #include #include diff --git a/erpc_c/transports/erpc_rpmsg_lite_base_transport.h b/erpc_c/transports/erpc_rpmsg_lite_base_transport.h index 7a9ba2ed5..b0dc9ccb7 100644 --- a/erpc_c/transports/erpc_rpmsg_lite_base_transport.h +++ b/erpc_c/transports/erpc_rpmsg_lite_base_transport.h @@ -11,6 +11,7 @@ #define _EMBEDDED_RPC__RPMSG_LITE_BASE_TRANSPORT_H_ #include "erpc_transport.h" + #include "rpmsg_lite.h" /*! diff --git a/erpc_c/transports/erpc_rpmsg_lite_rtos_transport.cpp b/erpc_c/transports/erpc_rpmsg_lite_rtos_transport.cpp index ead30f804..21fe33666 100644 --- a/erpc_c/transports/erpc_rpmsg_lite_rtos_transport.cpp +++ b/erpc_c/transports/erpc_rpmsg_lite_rtos_transport.cpp @@ -8,8 +8,11 @@ */ #include "erpc_rpmsg_lite_rtos_transport.h" + #include "erpc_config_internal.h" + #include "rpmsg_ns.h" + #include using namespace erpc; diff --git a/erpc_c/transports/erpc_rpmsg_lite_rtos_transport.h b/erpc_c/transports/erpc_rpmsg_lite_rtos_transport.h index ba3351f74..c23b90743 100644 --- a/erpc_c/transports/erpc_rpmsg_lite_rtos_transport.h +++ b/erpc_c/transports/erpc_rpmsg_lite_rtos_transport.h @@ -12,6 +12,7 @@ #include "erpc_message_buffer.h" #include "erpc_rpmsg_lite_base_transport.h" + #include "rpmsg_lite.h" #include "rpmsg_queue.h" diff --git a/erpc_c/transports/erpc_rpmsg_lite_transport.cpp b/erpc_c/transports/erpc_rpmsg_lite_transport.cpp index d4e259d66..21a625019 100644 --- a/erpc_c/transports/erpc_rpmsg_lite_transport.cpp +++ b/erpc_c/transports/erpc_rpmsg_lite_transport.cpp @@ -7,7 +7,9 @@ * SPDX-License-Identifier: BSD-3-Clause */ #include "erpc_rpmsg_lite_transport.h" + #include "erpc_config_internal.h" + #include "rpmsg_ns.h" using namespace erpc; diff --git a/erpc_c/transports/erpc_rpmsg_lite_transport.h b/erpc_c/transports/erpc_rpmsg_lite_transport.h index 429838555..22b627076 100644 --- a/erpc_c/transports/erpc_rpmsg_lite_transport.h +++ b/erpc_c/transports/erpc_rpmsg_lite_transport.h @@ -14,6 +14,7 @@ #include "erpc_message_buffer.h" #include "erpc_rpmsg_lite_base_transport.h" #include "erpc_static_queue.h" + #include "rpmsg_lite.h" /*! diff --git a/erpc_c/transports/erpc_rpmsg_tty_rtos_transport.cpp b/erpc_c/transports/erpc_rpmsg_tty_rtos_transport.cpp index d71870ff4..7d14fa151 100644 --- a/erpc_c/transports/erpc_rpmsg_tty_rtos_transport.cpp +++ b/erpc_c/transports/erpc_rpmsg_tty_rtos_transport.cpp @@ -9,9 +9,12 @@ */ #include "erpc_rpmsg_tty_rtos_transport.h" + #include "erpc_config_internal.h" #include "erpc_framed_transport.h" + #include "rpmsg_ns.h" + #include using namespace erpc; diff --git a/erpc_c/transports/erpc_rpmsg_tty_rtos_transport.h b/erpc_c/transports/erpc_rpmsg_tty_rtos_transport.h index 1c27edde1..9960d6db0 100644 --- a/erpc_c/transports/erpc_rpmsg_tty_rtos_transport.h +++ b/erpc_c/transports/erpc_rpmsg_tty_rtos_transport.h @@ -13,6 +13,7 @@ #include "erpc_crc16.h" #include "erpc_message_buffer.h" #include "erpc_rpmsg_lite_base_transport.h" + #include "rpmsg_lite.h" #include "rpmsg_queue.h" @@ -35,7 +36,7 @@ namespace erpc { * @brief Transport that uses RPMsg zero copy RTOS API for interprocessor * messaging. * - * @ingroup rpmsg_lite_rtos_transport + * @ingroup rpmsg_tty_rtos_transport */ class RPMsgTTYRTOSTransport : public RPMsgBaseTransport { diff --git a/erpc_c/transports/erpc_serial_transport.cpp b/erpc_c/transports/erpc_serial_transport.cpp index 0f7a11c1a..f2326fa51 100644 --- a/erpc_c/transports/erpc_serial_transport.cpp +++ b/erpc_c/transports/erpc_serial_transport.cpp @@ -8,11 +8,20 @@ */ #include "erpc_serial_transport.h" + #include "erpc_message_buffer.h" #include "erpc_serial.h" + #include #include + +#ifdef _WIN32 +#include +#include +#include +#else #include +#endif using namespace erpc; @@ -39,10 +48,14 @@ erpc_status_t SerialTransport::init(uint8_t vtime, uint8_t vmin) { return kErpcStatus_InitFailed; } +#ifdef _WIN32 + // TODO +#else if (!isatty(m_serialHandle)) { return kErpcStatus_InitFailed; } +#endif if (-1 == serial_setup(m_serialHandle, m_baudRate)) { return kErpcStatus_InitFailed; @@ -51,10 +64,14 @@ erpc_status_t SerialTransport::init(uint8_t vtime, uint8_t vmin) { return kErpcStatus_InitFailed; } +#ifdef _WIN32 + // TODO +#else if (-1 == tcflush(m_serialHandle, TCIOFLUSH)) { return kErpcStatus_InitFailed; } +#endif return kErpcStatus_Success; } diff --git a/erpc_c/transports/erpc_serial_transport.h b/erpc_c/transports/erpc_serial_transport.h index 6176bf8ab..85eb34312 100644 --- a/erpc_c/transports/erpc_serial_transport.h +++ b/erpc_c/transports/erpc_serial_transport.h @@ -11,8 +11,14 @@ #define _EMBEDDED_RPC__SERIAL_TRANSPORT_H_ #include "erpc_framed_transport.h" + #include + +#ifdef _WIN32 +typedef long speed_t; +#else #include +#endif /*! * @addtogroup serial_transport diff --git a/erpc_c/transports/erpc_spi_master_transport.cpp b/erpc_c/transports/erpc_spi_master_transport.cpp index f85eee5db..ad05f3e4e 100644 --- a/erpc_c/transports/erpc_spi_master_transport.cpp +++ b/erpc_c/transports/erpc_spi_master_transport.cpp @@ -1,6 +1,6 @@ /* * Copyright (c) 2014-2016, Freescale Semiconductor, Inc. - * Copyright 2016 NXP + * Copyright 2016-2020 NXP * All rights reserved. * * @@ -8,14 +8,29 @@ */ #include "erpc_spi_master_transport.h" + #include "board.h" #include "fsl_gpio.h" #include "fsl_port.h" #include "fsl_spi.h" + #include using namespace erpc; +//////////////////////////////////////////////////////////////////////////////// +// Definitions +//////////////////////////////////////////////////////////////////////////////// + +#ifndef ERPC_BOARD_SPI_SLAVE_READY_USE_GPIO +#define ERPC_BOARD_SPI_SLAVE_READY_MARKER1 0xAB +#define ERPC_BOARD_SPI_SLAVE_READY_MARKER2 0xCD +#else +#ifndef ERPC_BOARD_SPI_INT_GPIO +#error "Please define the ERPC_BOARD_SPI_INT_GPIO used to notify when the SPI Slave is ready to transmit" +#endif +#endif + //////////////////////////////////////////////////////////////////////////////// // Variables //////////////////////////////////////////////////////////////////////////////// @@ -26,6 +41,63 @@ static volatile bool s_isSlaveReady = false; // Code //////////////////////////////////////////////////////////////////////////////// +#ifdef ERPC_BOARD_SPI_SLAVE_READY_USE_GPIO +/* @brief Initialize the GPIO used to notify the SPI Master */ +static inline void SpiMasterTransport_NotifyTransferGpioInit() +{ + gpio_pin_config_t gpioConfig; + + gpioConfig.pinDirection = kGPIO_DigitalInput; + + PORT_SetPinInterruptConfig(ERPC_BOARD_SPI_INT_PORT, ERPC_BOARD_SPI_INT_PIN, kPORT_InterruptFallingEdge); + EnableIRQ(ERPC_BOARD_SPI_INT_PIN_IRQ); + + GPIO_PinInit(ERPC_BOARD_SPI_INT_GPIO, ERPC_BOARD_SPI_INT_PIN, &gpioConfig); + if (!GPIO_PinRead(ERPC_BOARD_SPI_INT_GPIO, ERPC_BOARD_SPI_INT_PIN)) + { + s_isSlaveReady = true; + } +} + +static inline void SpidevMasterTransport_WaitForSlaveReadyGpio() +{ + while (!s_isSlaveReady) + { + } +} +#else +static inline void SpidevMasterTransport_WaitForSlaveReadyMarker(SPI_Type *spiBaseAddr) +{ + uint8_t detected = 0; + uint8_t data; + spi_transfer_t masterXferSlaveReadyMarker; + + while (1) + { + masterXferSlaveReadyMarker.txData = NULL; + masterXferSlaveReadyMarker.rxData = &data; + masterXferSlaveReadyMarker.dataSize = 1; + + if (kStatus_Success == SPI_MasterTransferBlocking(spiBaseAddr, &masterXferSlaveReadyMarker)) + { + if (ERPC_BOARD_SPI_SLAVE_READY_MARKER1 == data) + { + detected = 1; + } + else if (detected && (ERPC_BOARD_SPI_SLAVE_READY_MARKER2 == data)) + { + break; + } + else + { + detected = 0; + // Thread::sleep(100); + } + } + } +} +#endif + SpiMasterTransport::SpiMasterTransport(SPI_Type *spiBaseAddr, uint32_t baudRate, uint32_t srcClock_Hz) : m_spiBaseAddr(spiBaseAddr) , m_baudRate(baudRate) @@ -41,22 +113,14 @@ SpiMasterTransport::~SpiMasterTransport(void) erpc_status_t SpiMasterTransport::init(void) { spi_master_config_t spiConfig; - gpio_pin_config_t gpioConfig; SPI_MasterGetDefaultConfig(&spiConfig); spiConfig.baudRate_Bps = m_baudRate; SPI_MasterInit(m_spiBaseAddr, &spiConfig, m_srcClock_Hz); - gpioConfig.pinDirection = kGPIO_DigitalInput; - - PORT_SetPinInterruptConfig(ERPC_BOARD_SPI_INT_PORT, ERPC_BOARD_SPI_INT_PIN, kPORT_InterruptFallingEdge); - EnableIRQ(ERPC_BOARD_SPI_INT_PIN_IRQ); - - GPIO_PinInit(ERPC_BOARD_SPI_INT_GPIO, ERPC_BOARD_SPI_INT_PIN, &gpioConfig); - if (!GPIO_PinRead(ERPC_BOARD_SPI_INT_GPIO, ERPC_BOARD_SPI_INT_PIN)) - { - s_isSlaveReady = true; - } +#ifdef ERPC_BOARD_SPI_SLAVE_READY_USE_GPIO + SpiMasterTransport_NotifyTransferGpioInit(); +#endif return kErpcStatus_Success; } @@ -70,12 +134,16 @@ erpc_status_t SpiMasterTransport::underlyingReceive(uint8_t *data, uint32_t size masterXfer.rxData = data; masterXfer.dataSize = size; - while (!s_isSlaveReady) - { - } +#ifdef ERPC_BOARD_SPI_SLAVE_READY_USE_GPIO + SpidevMasterTransport_WaitForSlaveReadyGpio(); +#else + SpidevMasterTransport_WaitForSlaveReadyMarker(m_spiBaseAddr); +#endif status = SPI_MasterTransferBlocking(m_spiBaseAddr, &masterXfer); +#ifdef ERPC_BOARD_SPI_SLAVE_READY_USE_GPIO s_isSlaveReady = false; +#endif return status != kStatus_Success ? kErpcStatus_ReceiveFailed : kErpcStatus_Success; } @@ -89,16 +157,19 @@ erpc_status_t SpiMasterTransport::underlyingSend(const uint8_t *data, uint32_t s masterXfer.rxData = NULL; masterXfer.dataSize = size; - while (!s_isSlaveReady) - { - } +#ifdef ERPC_BOARD_SPI_SLAVE_READY_USE_GPIO + SpidevMasterTransport_WaitForSlaveReadyGpio(); +#endif status = SPI_MasterTransferBlocking(m_spiBaseAddr, &masterXfer); +#ifdef ERPC_BOARD_SPI_SLAVE_READY_USE_GPIO s_isSlaveReady = false; +#endif return status != kStatus_Success ? kErpcStatus_SendFailed : kErpcStatus_Success; } +#ifdef ERPC_BOARD_SPI_SLAVE_READY_USE_GPIO extern "C" { void ERPC_BOARD_SPI_INT_PIN_IRQ_HANDLER(void) { @@ -107,3 +178,4 @@ void ERPC_BOARD_SPI_INT_PIN_IRQ_HANDLER(void) s_isSlaveReady = true; } } +#endif diff --git a/erpc_c/transports/erpc_spi_master_transport.h b/erpc_c/transports/erpc_spi_master_transport.h index 18fb091aa..47a60d813 100644 --- a/erpc_c/transports/erpc_spi_master_transport.h +++ b/erpc_c/transports/erpc_spi_master_transport.h @@ -11,7 +11,9 @@ #define _EMBEDDED_RPC__SPI_MASTER_TRANSPORT_H_ #include "erpc_framed_transport.h" + #include "fsl_spi.h" + #include #include diff --git a/erpc_c/transports/erpc_spi_slave_transport.cpp b/erpc_c/transports/erpc_spi_slave_transport.cpp index a5e492a1b..1ee3ad105 100644 --- a/erpc_c/transports/erpc_spi_slave_transport.cpp +++ b/erpc_c/transports/erpc_spi_slave_transport.cpp @@ -1,6 +1,6 @@ /* * Copyright (c) 2014-2016, Freescale Semiconductor, Inc. - * Copyright 2016 NXP + * Copyright 2016-2020 NXP * All rights reserved. * * @@ -8,13 +8,31 @@ */ #include "erpc_spi_slave_transport.h" + #include "board.h" #include "fsl_gpio.h" #include "fsl_spi.h" + #include +#include +using namespace std; using namespace erpc; +//////////////////////////////////////////////////////////////////////////////// +// Definitions +//////////////////////////////////////////////////////////////////////////////// + +#ifndef ERPC_BOARD_SPI_SLAVE_READY_USE_GPIO +#define ERPC_BOARD_SPI_SLAVE_READY_MARKER_LEN 2 +#define ERPC_BOARD_SPI_SLAVE_READY_MARKER1 0xAB +#define ERPC_BOARD_SPI_SLAVE_READY_MARKER2 0xCD +#else +#ifndef ERPC_BOARD_SPI_INT_GPIO +#error "Please define the ERPC_BOARD_SPI_INT_GPIO used to notify when the SPI Slave is ready to transmit" +#endif +#endif + //////////////////////////////////////////////////////////////////////////////// // Variables //////////////////////////////////////////////////////////////////////////////// @@ -26,9 +44,33 @@ static volatile bool s_isTransferCompleted = false; // Code //////////////////////////////////////////////////////////////////////////////// -void SPI_SlaveUserCallback(SPI_Type *base, spi_slave_handle_t *handle, erpc_status_t status, void *userData) +#ifdef ERPC_BOARD_SPI_SLAVE_READY_USE_GPIO +/* @brief Initialize the GPIO used to notify the SPI Master */ +static inline void SpiSlaveTransport_NotifyTransferGpioInit() +{ + gpio_pin_config_t gpioConfig; + + gpioConfig.pinDirection = kGPIO_DigitalOutput; + gpioConfig.outputLogic = 1U; + + GPIO_PinInit(ERPC_BOARD_SPI_INT_GPIO, ERPC_BOARD_SPI_INT_PIN, &gpioConfig); +} + +/* @brief Notify the SPI Master that the Slave is ready for a new transfer */ +static inline void SpiSlaveTransport_NotifyTransferGpioReady() +{ + GPIO_PortClear(ERPC_BOARD_SPI_INT_GPIO, 1U << ERPC_BOARD_SPI_INT_PIN); +} + +/* @brief Notify the SPI Master that the Slave has finished the transfer */ +static inline void SpiSlaveTransport_NotifyTransferGpioCompleted() { GPIO_PortSet(ERPC_BOARD_SPI_INT_GPIO, 1U << ERPC_BOARD_SPI_INT_PIN); +} +#endif + +void SPI_SlaveUserCallback(SPI_Type *base, spi_slave_handle_t *handle, erpc_status_t status, void *userData) +{ s_isTransferCompleted = true; } @@ -44,25 +86,27 @@ SpiSlaveTransport::~SpiSlaveTransport(void) { if (m_isInited) { - GPIO_PortClear(ERPC_BOARD_SPI_INT_GPIO, 1U << ERPC_BOARD_SPI_INT_PIN); +#ifdef ERPC_BOARD_SPI_SLAVE_READY_USE_GPIO + SpiSlaveTransport_NotifyTransferGpioCompleted(); +#endif + SPI_Deinit(m_spiBaseAddr); + m_isInited = false; } - SPI_Deinit(m_spiBaseAddr); } erpc_status_t SpiSlaveTransport::init(void) { spi_slave_config_t spiConfig; - gpio_pin_config_t gpioConfig; SPI_SlaveGetDefaultConfig(&spiConfig); SPI_SlaveInit(m_spiBaseAddr, &spiConfig); SPI_SlaveTransferCreateHandle(m_spiBaseAddr, &s_s_handle, SPI_SlaveUserCallback, NULL); - gpioConfig.pinDirection = kGPIO_DigitalOutput; - gpioConfig.outputLogic = 1U; +#ifdef ERPC_BOARD_SPI_SLAVE_READY_USE_GPIO + SpiSlaveTransport_NotifyTransferGpioInit(); +#endif - GPIO_PinInit(ERPC_BOARD_SPI_INT_GPIO, ERPC_BOARD_SPI_INT_PIN, &gpioConfig); m_isInited = true; return kErpcStatus_Success; } @@ -79,9 +123,17 @@ erpc_status_t SpiSlaveTransport::underlyingReceive(uint8_t *data, uint32_t size) status = SPI_SlaveTransferNonBlocking(m_spiBaseAddr, &s_s_handle, &slaveXfer); - GPIO_PortClear(ERPC_BOARD_SPI_INT_GPIO, 1U << ERPC_BOARD_SPI_INT_PIN); - while (!s_isTransferCompleted) + if (kStatus_Success == status) { +#ifdef ERPC_BOARD_SPI_SLAVE_READY_USE_GPIO + SpiSlaveTransport_NotifyTransferGpioReady(); +#endif + while (!s_isTransferCompleted) + { + } +#ifdef ERPC_BOARD_SPI_SLAVE_READY_USE_GPIO + SpiSlaveTransport_NotifyTransferGpioCompleted(); +#endif } return status != kStatus_Success ? kErpcStatus_ReceiveFailed : kErpcStatus_Success; @@ -91,18 +143,47 @@ erpc_status_t SpiSlaveTransport::underlyingSend(const uint8_t *data, uint32_t si { erpc_status_t status; spi_transfer_t slaveXfer; + s_isTransferCompleted = false; +#ifdef ERPC_BOARD_SPI_SLAVE_READY_USE_GPIO slaveXfer.txData = (uint8_t *)data; slaveXfer.rxData = NULL; slaveXfer.dataSize = size; - s_isTransferCompleted = false; +#else + uint8_t *spiData = new (nothrow) uint8_t[size + ERPC_BOARD_SPI_SLAVE_READY_MARKER_LEN]; + if (spiData != NULL) + { + spiData[0] = ERPC_BOARD_SPI_SLAVE_READY_MARKER1; + spiData[1] = ERPC_BOARD_SPI_SLAVE_READY_MARKER2; + memcpy(&spiData[ERPC_BOARD_SPI_SLAVE_READY_MARKER_LEN], data, size); + } + else + { + return kErpcStatus_SendFailed; + } + + slaveXfer.txData = spiData; + slaveXfer.rxData = NULL; + slaveXfer.dataSize = size + ERPC_BOARD_SPI_SLAVE_READY_MARKER_LEN; +#endif status = SPI_SlaveTransferNonBlocking(m_spiBaseAddr, &s_s_handle, &slaveXfer); - GPIO_PortClear(ERPC_BOARD_SPI_INT_GPIO, 1U << ERPC_BOARD_SPI_INT_PIN); - while (!s_isTransferCompleted) + if (kStatus_Success == status) { +#ifdef ERPC_BOARD_SPI_SLAVE_READY_USE_GPIO + SpiSlaveTransport_NotifyTransferGpioReady(); +#endif + while (!s_isTransferCompleted) + { + } +#ifdef ERPC_BOARD_SPI_SLAVE_READY_USE_GPIO + SpiSlaveTransport_NotifyTransferGpioCompleted(); +#endif } +#ifndef ERPC_BOARD_SPI_SLAVE_READY_USE_GPIO + delete[] spiData; +#endif return status != kStatus_Success ? kErpcStatus_SendFailed : kErpcStatus_Success; } diff --git a/erpc_c/transports/erpc_spi_slave_transport.h b/erpc_c/transports/erpc_spi_slave_transport.h index 6c7058fd9..39d21d87d 100644 --- a/erpc_c/transports/erpc_spi_slave_transport.h +++ b/erpc_c/transports/erpc_spi_slave_transport.h @@ -11,8 +11,10 @@ #define _EMBEDDED_RPC__SPI_SLAVE_TRANSPORT_H_ #include "erpc_framed_transport.h" + #include "fsl_gpio.h" #include "fsl_spi.h" + #include /*! diff --git a/erpc_c/transports/erpc_spidev_master_transport.cpp b/erpc_c/transports/erpc_spidev_master_transport.cpp new file mode 100644 index 000000000..e53f24023 --- /dev/null +++ b/erpc_c/transports/erpc_spidev_master_transport.cpp @@ -0,0 +1,187 @@ +/* + * Copyright 2020 NXP + * All rights reserved. + * + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include "erpc_spidev_master_transport.h" + +#include "erpc_message_buffer.h" +#include "erpc_spidev.h" +#include "erpc_sysgpio.h" + +#include + +using namespace erpc; + +//////////////////////////////////////////////////////////////////////////////// +// Definitions +//////////////////////////////////////////////////////////////////////////////// + +#ifndef ERPC_BOARD_SPI_SLAVE_READY_USE_GPIO +#define ERPC_BOARD_SPI_SLAVE_READY_MARKER1 0xAB +#define ERPC_BOARD_SPI_SLAVE_READY_MARKER2 0xCD +#else +#ifndef ERPC_BOARD_SPI_INT_PIN +#error "Please define the BOARD_SPI_INT_PIN used to notify when the SPI Slave is ready to transmit" +#endif +#endif + +//////////////////////////////////////////////////////////////////////////////// +// Variables +//////////////////////////////////////////////////////////////////////////////// + +#ifdef ERPC_BOARD_SPI_SLAVE_READY_USE_GPIO +static volatile int s_gpioHandle = 0; +#endif + +//////////////////////////////////////////////////////////////////////////////// +// Code +//////////////////////////////////////////////////////////////////////////////// + +#ifdef ERPC_BOARD_SPI_SLAVE_READY_USE_GPIO +static inline void SpidevMasterTransport_WaitForSlaveReadyGpio() +{ + while (1) + { + /* + * The GPIO pin has been configured to generate interrupts on edge event + * The poll() will return whenever the interrupt was triggered + */ + if (gpio_poll(s_gpioHandle, -1)) + { + break; + } + } +} +#else +static inline void SpidevMasterTransport_WaitForSlaveReadyMarker(int spi_fd) +{ + uint8_t detected = 0; + uint8_t data; + while (1) + { + spidev_transfer(spi_fd, NULL, &data, 1); + if (ERPC_BOARD_SPI_SLAVE_READY_MARKER1 == data) + { + detected = 1; + } + else if (detected && ERPC_BOARD_SPI_SLAVE_READY_MARKER2 == data) + { + break; + } + else + { + detected = 0; + usleep(100); + } + } +} +#endif + +SpidevMasterTransport::SpidevMasterTransport(const char *spidev, uint32_t speed_Hz) +: m_spidevHandle(0) +, m_spidev(spidev) +, m_speed_Hz(speed_Hz) +{ +} + +SpidevMasterTransport::~SpidevMasterTransport(void) +{ + if (m_spidevHandle > 0) + { + spidev_close(m_spidevHandle); + } + +#ifdef ERPC_BOARD_SPI_SLAVE_READY_USE_GPIO + if (s_gpioHandle > 0) + { + gpio_close(s_gpioHandle); + } +#endif +} + +erpc_status_t SpidevMasterTransport::init(void) +{ + /* Initialize the SPI device */ + /* Open SPI device file descriptor */ + m_spidevHandle = spidev_open(m_spidev); + if (m_spidevHandle < ERPC_SPIDEV_STATUS_SUCCESS) + { + return kErpcStatus_InitFailed; + } + + /* Set SPI mode to SPI_MODE_0 (CPOL = 0, CPHA = 0) */ + if (ERPC_SPIDEV_STATUS_SUCCESS != spidev_set_mode(m_spidevHandle, 0)) + { + return kErpcStatus_InitFailed; + } + /* Set SPI default max speed */ + if (ERPC_SPIDEV_STATUS_SUCCESS != spidev_set_speed(m_spidevHandle, m_speed_Hz)) + { + return kErpcStatus_InitFailed; + } + /* Set SPI device word length */ + if (ERPC_SPIDEV_STATUS_SUCCESS != spidev_set_wordbits(m_spidevHandle, 8)) + { + return kErpcStatus_InitFailed; + } + +#ifdef ERPC_BOARD_SPI_SLAVE_READY_USE_GPIO + /* Initialize the GPIO SPI_INT_PIN */ + /* Export GPIO */ + if (ERPC_SYSGPIO_STATUS_SUCCESS != gpio_export(ERPC_BOARD_SPI_INT_PIN)) + { + return kErpcStatus_InitFailed; + } + /* Set GPIO direction to input */ + if (ERPC_SYSGPIO_STATUS_SUCCESS != gpio_direction(ERPC_BOARD_SPI_INT_PIN, 1)) + { + return kErpcStatus_InitFailed; + } + /* Set GPIO edge interrupt trigger */ + if (ERPC_SYSGPIO_STATUS_SUCCESS != gpio_set_edge(ERPC_BOARD_SPI_INT_PIN, (char *)"falling")) + { + return kErpcStatus_InitFailed; + } + /* Open GPIO file descriptor */ + s_gpioHandle = gpio_open(ERPC_BOARD_SPI_INT_PIN); + if (s_gpioHandle < ERPC_SYSGPIO_STATUS_SUCCESS) + { + return kErpcStatus_InitFailed; + } +#endif + + return kErpcStatus_Success; +} + +erpc_status_t SpidevMasterTransport::underlyingSend(const uint8_t *data, uint32_t size) +{ +#ifdef ERPC_BOARD_SPI_SLAVE_READY_USE_GPIO + SpidevMasterTransport_WaitForSlaveReadyGpio(); +#endif + + if (ERPC_SPIDEV_STATUS_SUCCESS != spidev_transfer(m_spidevHandle, (unsigned char *)data, NULL, size)) + { + return kErpcStatus_SendFailed; + } + return kErpcStatus_Success; +} + +erpc_status_t SpidevMasterTransport::underlyingReceive(uint8_t *data, uint32_t size) +{ +#ifdef ERPC_BOARD_SPI_SLAVE_READY_USE_GPIO + SpidevMasterTransport_WaitForSlaveReadyGpio(); +#else + SpidevMasterTransport_WaitForSlaveReadyMarker(m_spidevHandle); +#endif + + if (ERPC_SPIDEV_STATUS_SUCCESS != spidev_transfer(m_spidevHandle, NULL, data, size)) + { + return kErpcStatus_SendFailed; + } + + return kErpcStatus_Success; +} diff --git a/erpc_c/transports/erpc_spidev_master_transport.h b/erpc_c/transports/erpc_spidev_master_transport.h new file mode 100644 index 000000000..49cf5761a --- /dev/null +++ b/erpc_c/transports/erpc_spidev_master_transport.h @@ -0,0 +1,86 @@ +/* + * Copyright 2020 NXP + * All rights reserved. + * + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef _EMBEDDED_RPC__SPIDEV_MASTER_TRANSPORT_H_ +#define _EMBEDDED_RPC__SPIDEV_MASTER_TRANSPORT_H_ + +#include "erpc_framed_transport.h" + +/*! + * @addtogroup spidev_master_transport + * @{ + * @file + */ + +//////////////////////////////////////////////////////////////////////////////// +// Classes +//////////////////////////////////////////////////////////////////////////////// + +namespace erpc { +/*! + * @brief Very basic transport to send/receive messages via SPIdev. + * + * @ingroup spidev_master_transport + */ +class SpidevMasterTransport : public FramedTransport +{ +public: + /*! + * @brief Constructor. + * + * @param[in] spidev SPI device name. + * @param[in] speed_Hz SPI clock speed in Hz. + */ + SpidevMasterTransport(const char *spidev, uint32_t speed_Hz); + + /*! + * @brief Destructor. + */ + virtual ~SpidevMasterTransport(void); + + /*! + * @brief Initialize SPI peripheral. + * + * @return Status of init function. + */ + erpc_status_t init(void); + +protected: + int m_spidevHandle; /*!< SPI handle id. */ + const char *m_spidev; /*!< SPI device name. */ + uint32_t m_speed_Hz; /*!< SPI clock speed in Hz. */ + +private: + /*! + * @brief Receive data from SPI peripheral. + * + * @param[inout] data Preallocated buffer for receiving data. + * @param[in] size Size of data to read. + * + * @retval kErpcStatus_ReceiveFailed SPI failed to receive data. + * @retval kErpcStatus_Success Successfully received all data. + */ + virtual erpc_status_t underlyingReceive(uint8_t *data, uint32_t size); + + /*! + * @brief Write data to SPI peripheral. + * + * @param[in] data Buffer to send. + * @param[in] size Size of data to send. + * + * @retval kErpcStatus_SendFailed SPI failed to send data. + * @retval kErpcStatus_Success Successfully sent all data. + */ + virtual erpc_status_t underlyingSend(const uint8_t *data, uint32_t size); +}; + +} // namespace erpc + +/*! @} */ + +#endif // _EMBEDDED_RPC__SPIDEV_MASTER_TRANSPORT_H_ diff --git a/erpc_c/transports/erpc_tcp_transport.cpp b/erpc_c/transports/erpc_tcp_transport.cpp index b54bc0977..aca968aec 100644 --- a/erpc_c/transports/erpc_tcp_transport.cpp +++ b/erpc_c/transports/erpc_tcp_transport.cpp @@ -7,17 +7,18 @@ * SPDX-License-Identifier: BSD-3-Clause */ #include "erpc_tcp_transport.h" + #include #if ERPC_HAS_POSIX #include #endif #include #include +#include #include #include #include #include -#include #include using namespace erpc; @@ -89,7 +90,7 @@ erpc_status_t TCPTransport::connectClient(void) } // Fill in hints structure for getaddrinfo. - struct addrinfo hints = { }; + struct addrinfo hints = {}; hints.ai_flags = AI_NUMERICSERV; hints.ai_family = PF_UNSPEC; hints.ai_socktype = SOCK_STREAM; @@ -143,7 +144,7 @@ erpc_status_t TCPTransport::connectClient(void) TCP_DEBUG_ERR("connecting failed"); return kErpcStatus_ConnectionFailure; } - + int set = 1; setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (void *)&set, sizeof(int)); @@ -321,7 +322,7 @@ void TCPTransport::serverThread(void) TCP_DEBUG_ERR("accept failed"); } } - + ::close(serverSocket); } diff --git a/erpc_c/transports/erpc_uart_cmsis_transport.cpp b/erpc_c/transports/erpc_uart_cmsis_transport.cpp index 30022e4f8..2cc328166 100644 --- a/erpc_c/transports/erpc_uart_cmsis_transport.cpp +++ b/erpc_c/transports/erpc_uart_cmsis_transport.cpp @@ -1,6 +1,6 @@ /* * Copyright (c) 2014-2016, Freescale Semiconductor, Inc. - * Copyright 2016 NXP + * Copyright 2016-2020 NXP * All rights reserved. * * @@ -8,6 +8,7 @@ */ #include "erpc_uart_cmsis_transport.h" + #include using namespace erpc; @@ -18,6 +19,7 @@ using namespace erpc; static volatile bool s_isTransferReceiveCompleted = false; static volatile bool s_isTransferSendCompleted = false; +static UartTransport *s_uart_instance = NULL; //////////////////////////////////////////////////////////////////////////////// // Code @@ -25,7 +27,12 @@ static volatile bool s_isTransferSendCompleted = false; UartTransport::UartTransport(ARM_DRIVER_USART *uartDrv) : m_uartDrv(uartDrv) +#if ERPC_THREADS +, m_rxSemaphore() +, m_txSemaphore() +#endif { + s_uart_instance = this; } UartTransport::~UartTransport(void) @@ -33,17 +40,37 @@ UartTransport::~UartTransport(void) (*m_uartDrv).Uninitialize(); } +void UartTransport::tx_cb(void) +{ +#if ERPC_THREADS + m_txSemaphore.putFromISR(); +#else + s_isTransferSendCompleted = true; +#endif +} + +void UartTransport::rx_cb(void) +{ +#if ERPC_THREADS + m_rxSemaphore.putFromISR(); +#else + s_isTransferReceiveCompleted = true; +#endif +} + /* Transfer callback */ void TransferCallback(uint32_t event) { + UartTransport *transport = s_uart_instance; + if (event == ARM_USART_EVENT_SEND_COMPLETE) { - s_isTransferSendCompleted = true; + transport->tx_cb(); } if (event == ARM_USART_EVENT_RECEIVE_COMPLETE) { - s_isTransferReceiveCompleted = true; + transport->rx_cb(); } } @@ -77,9 +104,14 @@ erpc_status_t UartTransport::underlyingReceive(uint8_t *data, uint32_t size) int32_t status = (*m_uartDrv).Receive(data, size); if (status == ARM_DRIVER_OK) { +/* wait until the receiving is finished */ +#if ERPC_THREADS + m_rxSemaphore.get(); +#else while (!s_isTransferReceiveCompleted) { } +#endif return kErpcStatus_Success; } @@ -93,9 +125,14 @@ erpc_status_t UartTransport::underlyingSend(const uint8_t *data, uint32_t size) int32_t status = (*m_uartDrv).Send(data, size); if (status == ARM_DRIVER_OK) { +/* wait until the sending is finished */ +#if ERPC_THREADS + m_txSemaphore.get(); +#else while (!s_isTransferSendCompleted) { } +#endif return kErpcStatus_Success; } diff --git a/erpc_c/transports/erpc_uart_cmsis_transport.h b/erpc_c/transports/erpc_uart_cmsis_transport.h index f680b14c3..c65f2983b 100644 --- a/erpc_c/transports/erpc_uart_cmsis_transport.h +++ b/erpc_c/transports/erpc_uart_cmsis_transport.h @@ -1,6 +1,6 @@ /* * Copyright (c) 2014-2016, Freescale Semiconductor, Inc. - * Copyright 2016 NXP + * Copyright 2016-2020 NXP * All rights reserved. * * @@ -10,8 +10,14 @@ #ifndef _EMBEDDED_RPC__UART_TRANSPORT_H_ #define _EMBEDDED_RPC__UART_TRANSPORT_H_ +#include "erpc_config_internal.h" +#if ERPC_THREADS +#include "erpc_threading.h" +#endif #include "erpc_framed_transport.h" + #include "Driver_USART.h" + #include /*! @@ -54,9 +60,26 @@ class UartTransport : public FramedTransport */ virtual erpc_status_t init(void); + /*! + * @brief Function called from ARM_USART_SignalEvent when ARM_USART_EVENT_RECEIVE_COMPLETE event is asserted + * + * Unblocks the receive function. + */ + void rx_cb(void); + + /*! + * @brief Function called from ARM_USART_SignalEvent when ARM_USART_EVENT_SEND_COMPLETE event is asserted + * + * Unblocks the send function. + */ + void tx_cb(void); + protected: ARM_DRIVER_USART *m_uartDrv; /*!< Access structure of the USART Driver */ - +#if ERPC_THREADS + Semaphore m_rxSemaphore; /*!< Semaphore used by RTOS to block task until the receiving is not complete */ + Semaphore m_txSemaphore; /*!< Semaphore used by RTOS to block task until the sending is not complete */ +#endif private: /*! * @brief Receive data from UART peripheral. diff --git a/erpc_c/transports/erpc_usb_cdc_transport.cpp b/erpc_c/transports/erpc_usb_cdc_transport.cpp new file mode 100644 index 000000000..f05fb5784 --- /dev/null +++ b/erpc_c/transports/erpc_usb_cdc_transport.cpp @@ -0,0 +1,182 @@ +/* + * Copyright 2020 NXP + * All rights reserved. + * + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include "erpc_usb_cdc_transport.h" + +#include + +using namespace erpc; + +//////////////////////////////////////////////////////////////////////////////// +// Variables +//////////////////////////////////////////////////////////////////////////////// + +static volatile bool s_isTransferReceiveCompleted = false; +static volatile bool s_isTransferSendCompleted = false; +static UsbCdcTransport *s_usbcdc_instance = NULL; + +SDK_ALIGN(static uint8_t s_serialWriteHandleBuffer[SERIAL_MANAGER_WRITE_HANDLE_SIZE], 4); +static serial_write_handle_t s_serialWriteHandle = &s_serialWriteHandleBuffer[0]; /*!< serial manager write handle */ + +SDK_ALIGN(static uint8_t s_serialReadHandleBuffer[SERIAL_MANAGER_READ_HANDLE_SIZE], 4); +static serial_read_handle_t s_serialReadHandle = &s_serialReadHandleBuffer[0]; /*!< serial manager read handle */ +//////////////////////////////////////////////////////////////////////////////// +// Code +//////////////////////////////////////////////////////////////////////////////// + +static void ERPC_SerialManagerTxCallback(void *callbackParam, serial_manager_callback_message_t *message, + serial_manager_status_t status) +{ + UsbCdcTransport *transport = s_usbcdc_instance; + if ((NULL == callbackParam) || (NULL == message)) + { + return; + } + + if (kStatus_SerialManager_Success == status) + { + transport->tx_cb(); + } + else + { + /* Handle other status if needed */ + } +} + +static void ERPC_SerialManagerRxCallback(void *callbackParam, serial_manager_callback_message_t *message, + serial_manager_status_t status) +{ + UsbCdcTransport *transport = s_usbcdc_instance; + if ((NULL == callbackParam) || (NULL == message)) + { + return; + } + + if (kStatus_SerialManager_Success == status) + { + transport->rx_cb(); + } + else + { + /* Handle other status if needed */ + } +} + +void UsbCdcTransport::tx_cb(void) +{ +#if ERPC_THREADS + m_txSemaphore.putFromISR(); +#else + s_isTransferSendCompleted = true; +#endif +} + +void UsbCdcTransport::rx_cb(void) +{ +#if ERPC_THREADS + m_rxSemaphore.putFromISR(); +#else + s_isTransferReceiveCompleted = true; +#endif +} + +UsbCdcTransport::UsbCdcTransport(serial_handle_t serialHandle, serial_manager_config_t *serialConfig, + serial_port_usb_cdc_config_t *usbCdcConfig, uint8_t *usbRingBuffer, + uint32_t usbRingBufferLength) +: m_serialHandle(serialHandle) +, m_serialConfig(serialConfig) +, m_usbCdcConfig(usbCdcConfig) +, m_usbRingBuffer(usbRingBuffer) +, m_usbRingBufferLength(usbRingBufferLength) +#if ERPC_THREADS +, m_rxSemaphore() +, m_txSemaphore() +#endif +{ + s_usbcdc_instance = this; +} + +UsbCdcTransport::~UsbCdcTransport(void) +{ + /* Cleanup */ + SerialManager_CloseWriteHandle(s_serialWriteHandle); + SerialManager_CloseReadHandle(s_serialReadHandle); + SerialManager_Deinit(m_serialHandle); +} + +erpc_status_t UsbCdcTransport::init(void) +{ + /* Init Serial Manager for USB CDC */ + m_serialConfig->type = kSerialPort_UsbCdc; + m_serialConfig->ringBuffer = m_usbRingBuffer; + m_serialConfig->ringBufferSize = m_usbRingBufferLength; + m_serialConfig->portConfig = m_usbCdcConfig; + + if (kStatus_SerialManager_Success == SerialManager_Init(m_serialHandle, m_serialConfig)) + { + if (kStatus_SerialManager_Success == SerialManager_OpenWriteHandle(m_serialHandle, s_serialWriteHandle)) + { + if (kStatus_SerialManager_Success == SerialManager_OpenReadHandle(m_serialHandle, s_serialReadHandle)) + { + if (kStatus_SerialManager_Success == SerialManager_InstallTxCallback(s_serialWriteHandle, + ERPC_SerialManagerTxCallback, + s_serialWriteHandle)) + { + if (kStatus_SerialManager_Success == SerialManager_InstallRxCallback(s_serialReadHandle, + ERPC_SerialManagerRxCallback, + s_serialReadHandle)) + { + return kErpcStatus_Success; + } + } + } + } + } + + return kErpcStatus_InitFailed; +} + +erpc_status_t UsbCdcTransport::underlyingReceive(uint8_t *data, uint32_t size) +{ + s_isTransferReceiveCompleted = false; + + if (kStatus_SerialManager_Success == SerialManager_ReadNonBlocking(s_serialReadHandle, data, size)) + { +/* wait until the receiving is finished */ +#if ERPC_THREADS + m_rxSemaphore.get(); +#else + while (!s_isTransferReceiveCompleted) + { + } +#endif + return kErpcStatus_Success; + } + + return kErpcStatus_ReceiveFailed; +} + +erpc_status_t UsbCdcTransport::underlyingSend(const uint8_t *data, uint32_t size) +{ + s_isTransferSendCompleted = false; + + if (kStatus_SerialManager_Success == SerialManager_WriteNonBlocking(s_serialWriteHandle, (uint8_t *)data, size)) + { +/* wait until the sending is finished */ +#if ERPC_THREADS + m_txSemaphore.get(); +#else + while (!s_isTransferSendCompleted) + { + } +#endif + return kErpcStatus_Success; + } + + return kErpcStatus_SendFailed; +} diff --git a/erpc_c/transports/erpc_usb_cdc_transport.h b/erpc_c/transports/erpc_usb_cdc_transport.h new file mode 100644 index 000000000..403a20785 --- /dev/null +++ b/erpc_c/transports/erpc_usb_cdc_transport.h @@ -0,0 +1,124 @@ +/* + * Copyright 2020 NXP + * All rights reserved. + * + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef _EMBEDDED_RPC__USB_CDC_TRANSPORT_H_ +#define _EMBEDDED_RPC__USB_CDC_TRANSPORT_H_ + +#include "erpc_config_internal.h" +#if ERPC_THREADS +#include "erpc_threading.h" +#endif + +#include "erpc_framed_transport.h" + +#include "fsl_component_serial_manager.h" + +#include + +/*! + * @addtogroup USB_CDC_transport + * @{ + * @file + */ + +//////////////////////////////////////////////////////////////////////////////// +// Classes +//////////////////////////////////////////////////////////////////////////////// + +namespace erpc { +/*! + * @brief Very basic transport to send/receive messages via virtual USB CDC port. + * + * @ingroup USB_CDC_transport + */ +class UsbCdcTransport : public FramedTransport +{ +public: + /*! + * @brief Constructor. + * + * @param[in] serialHandle Pointer to point to a memory space of size #SERIAL_MANAGER_HANDLE_SIZE allocated by the + * caller, see serial manager header file. + * @param[in] serialConfig Pointer to user-defined configuration structure allocated by the caller, see serial + * manager header file. + * @param[in] usbCdcConfig Pointer to serial port usb config structure allocated by the caller, see serial manager + * header file. + * @param[in] usbRingBuffer Pointer to point serial manager ring buffer allocated by the caller, see serial manager + * header file. + * @param[in] usbRingBufferLength Serial manager ring buffer size. + */ + UsbCdcTransport(serial_handle_t serialHandle, serial_manager_config_t *serialConfig, + serial_port_usb_cdc_config_t *usbCdcConfig, uint8_t *usbRingBuffer, uint32_t usbRingBufferLength); + + /*! + * @brief Destructor. + */ + virtual ~UsbCdcTransport(void); + + /*! + * @brief Initialize USB CDC peripheral configuration structure with values specified in UsbCdcTransport + * constructor. + * + * @retval kErpcStatus_InitFailed When USB CDC init function failed. + * @retval kErpcStatus_Success When USB CDC init function was executed successfully. + */ + virtual erpc_status_t init(void); + + /*! + * @brief Function called from Serial Manager Rx Callback to unblock the receive function + * + * Unblocks the receive function. + */ + void rx_cb(void); + + /*! + * @brief Function called from Serial Manager Tx Callback to unblock the send function + * + * Unblocks the send function. + */ + void tx_cb(void); + +protected: +#if ERPC_THREADS + Semaphore m_rxSemaphore; /*!< Semaphore used by RTOS to block task until the receiving is not complete */ + Semaphore m_txSemaphore; /*!< Semaphore used by RTOS to block task until the sending is not complete */ +#endif +private: + serial_handle_t m_serialHandle; + serial_manager_config_t *m_serialConfig; + serial_port_usb_cdc_config_t *m_usbCdcConfig; + uint8_t *m_usbRingBuffer; + uint32_t m_usbRingBufferLength; + + /*! + * @brief Receive data from USB CDC peripheral. + * + * @param[inout] data Preallocated buffer for receiving data. + * @param[in] size Size of data to read. + * + * @retval kErpcStatus_ReceiveFailed USB CDC failed to receive data. + * @retval kErpcStatus_Success Successfully received all data. + */ + virtual erpc_status_t underlyingReceive(uint8_t *data, uint32_t size); + + /*! + * @brief Write data to USB CDC peripheral. + * + * @param[in] data Buffer to send. + * @param[in] size Size of data to send. + * + * @retval kErpcStatus_Success Always returns success status. + */ + virtual erpc_status_t underlyingSend(const uint8_t *data, uint32_t size); +}; + +} // namespace erpc + +/*! @} */ + +#endif /* _EMBEDDED_RPC__USB_CDC_TRANSPORT_H_ */ diff --git a/erpc_c/transports/transports.dox b/erpc_c/transports/transports.dox index 9aea8a751..67e20c961 100644 --- a/erpc_c/transports/transports.dox +++ b/erpc_c/transports/transports.dox @@ -27,6 +27,12 @@ @brief Kinetis SDK SPI slave driver transport. */ +/*! +@defgroup spidev_master_transport SPIdev Linux Master +@ingroup transports +@brief SPIdev Linux transport. +*/ + /*! @defgroup itbp_transport Inter-thread @ingroup transports @@ -56,6 +62,12 @@ @brief RPMsg-Lite zero copy transport. */ +/*! +@defgroup rpmsg_tty_rtos_transport RPMsg TTY RTOS +@ingroup transports +@brief RPMsg TTY RTOS transport. +*/ + /*! @defgroup tcp_transport TCP/IP @ingroup transports @@ -73,3 +85,9 @@ @ingroup transports @brief RPMsg endpoints linux transport. */ + +/*! +@defgroup USB_CDC_transport USB CDC +@ingroup transports +@brief USB CDC transport. +*/ diff --git a/erpc_python/erpc/erpc_version.py b/erpc_python/erpc/erpc_version.py index 1a49ff352..11675c637 100644 --- a/erpc_python/erpc/erpc_version.py +++ b/erpc_python/erpc/erpc_version.py @@ -6,4 +6,4 @@ # SPDX-License-Identifier: BSD-3-Clause #Should be same as in erpc_version.h -ERPC_VERSION = "1.7.4" +ERPC_VERSION = "1.8.0" diff --git a/erpcgen/src/AstNode.cpp b/erpcgen/src/AstNode.cpp index c278b1317..eff76d2a4 100644 --- a/erpcgen/src/AstNode.cpp +++ b/erpcgen/src/AstNode.cpp @@ -8,8 +8,10 @@ */ #include "AstNode.h" + #include "ErpcLexer.h" #include "format_string.h" + #include #include @@ -218,8 +220,7 @@ string AstNode::getDescription() const case TOK_ARRAY: case TOK_UNION_CASE: break; - default: - { + default: { output += " " + valToString + " "; if (valToString.size() == 1) { diff --git a/erpcgen/src/AstNode.h b/erpcgen/src/AstNode.h index 9d285acca..25a062721 100644 --- a/erpcgen/src/AstNode.h +++ b/erpcgen/src/AstNode.h @@ -12,6 +12,7 @@ #include "Token.h" #include "smart_ptr.h" + #include #include #include diff --git a/erpcgen/src/AstWalker.cpp b/erpcgen/src/AstWalker.cpp index 9f51c1a36..d2af18126 100644 --- a/erpcgen/src/AstWalker.cpp +++ b/erpcgen/src/AstWalker.cpp @@ -8,6 +8,7 @@ */ #include "AstWalker.h" + #include "ErpcLexer.h" #include "Logging.h" diff --git a/erpcgen/src/AstWalker.h b/erpcgen/src/AstWalker.h index 207a00b8c..172c14172 100644 --- a/erpcgen/src/AstWalker.h +++ b/erpcgen/src/AstWalker.h @@ -118,23 +118,91 @@ class AstWalker */ //@{ virtual void handleRoot(AstNode *node, top_down) { (void)node; }; - virtual AstNode *handleProgram(AstNode *node, top_down) { (void)node; return nullptr; } - virtual AstNode *handleConst(AstNode *node, top_down) { (void)node; return nullptr; } - virtual AstNode *handleChildren(AstNode *node, top_down) { (void)node; return nullptr; } - virtual AstNode *handleType(AstNode *node, top_down) { (void)node; return nullptr; } - virtual AstNode *handleEnum(AstNode *node, top_down) { (void)node; return nullptr; } - virtual AstNode *handleEnumMember(AstNode *node, top_down) { (void)node; return nullptr; } - virtual AstNode *handleStruct(AstNode *node, top_down) { (void)node; return nullptr; } - virtual AstNode *handleStructMember(AstNode *node, top_down) { (void)node; return nullptr; } - virtual AstNode *handleUnion(AstNode *node, top_down) { (void)node; return nullptr; } - virtual AstNode *handleUnionCase(AstNode *node, top_down) { (void)node; return nullptr; } - virtual AstNode *handleInterface(AstNode *node, top_down) { (void)node; return nullptr; } - virtual AstNode *handleFunction(AstNode *node, top_down) { (void)node; return nullptr; } - virtual AstNode *handleParam(AstNode *node, top_down) { (void)node; return nullptr; } - virtual AstNode *handleExpr(AstNode *node, top_down) { (void)node; return nullptr; } - virtual AstNode *handleBinaryOp(AstNode *node, top_down) { (void)node; return nullptr; } - virtual AstNode *handleUnaryOp(AstNode *node, top_down) { (void)node; return nullptr; } - virtual AstNode *handleAnnotation(AstNode *node, top_down) { (void)node; return nullptr; } + virtual AstNode *handleProgram(AstNode *node, top_down) + { + (void)node; + return nullptr; + } + virtual AstNode *handleConst(AstNode *node, top_down) + { + (void)node; + return nullptr; + } + virtual AstNode *handleChildren(AstNode *node, top_down) + { + (void)node; + return nullptr; + } + virtual AstNode *handleType(AstNode *node, top_down) + { + (void)node; + return nullptr; + } + virtual AstNode *handleEnum(AstNode *node, top_down) + { + (void)node; + return nullptr; + } + virtual AstNode *handleEnumMember(AstNode *node, top_down) + { + (void)node; + return nullptr; + } + virtual AstNode *handleStruct(AstNode *node, top_down) + { + (void)node; + return nullptr; + } + virtual AstNode *handleStructMember(AstNode *node, top_down) + { + (void)node; + return nullptr; + } + virtual AstNode *handleUnion(AstNode *node, top_down) + { + (void)node; + return nullptr; + } + virtual AstNode *handleUnionCase(AstNode *node, top_down) + { + (void)node; + return nullptr; + } + virtual AstNode *handleInterface(AstNode *node, top_down) + { + (void)node; + return nullptr; + } + virtual AstNode *handleFunction(AstNode *node, top_down) + { + (void)node; + return nullptr; + } + virtual AstNode *handleParam(AstNode *node, top_down) + { + (void)node; + return nullptr; + } + virtual AstNode *handleExpr(AstNode *node, top_down) + { + (void)node; + return nullptr; + } + virtual AstNode *handleBinaryOp(AstNode *node, top_down) + { + (void)node; + return nullptr; + } + virtual AstNode *handleUnaryOp(AstNode *node, top_down) + { + (void)node; + return nullptr; + } + virtual AstNode *handleAnnotation(AstNode *node, top_down) + { + (void)node; + return nullptr; + } //@} /* @@ -143,24 +211,92 @@ class AstWalker * @brief Bottom-up handlers types, which can be called. */ //@{ - virtual void handleRoot(AstNode *node, bottom_up){ (void)node; }; - virtual AstNode *handleProgram(AstNode *node, bottom_up) { (void)node; return nullptr; } - virtual AstNode *handleConst(AstNode *node, bottom_up) { (void)node; return nullptr; } - virtual AstNode *handleChildren(AstNode *node, bottom_up) { (void)node; return nullptr; } - virtual AstNode *handleType(AstNode *node, bottom_up) { (void)node; return nullptr; } - virtual AstNode *handleEnum(AstNode *node, bottom_up) { (void)node; return nullptr; } - virtual AstNode *handleEnumMember(AstNode *node, bottom_up) { (void)node; return nullptr; } - virtual AstNode *handleStruct(AstNode *node, bottom_up) { (void)node; return nullptr; } - virtual AstNode *handleStructMember(AstNode *node, bottom_up) { (void)node; return nullptr; } - virtual AstNode *handleUnion(AstNode *node, bottom_up) { (void)node; return nullptr; } - virtual AstNode *handleUnionCase(AstNode *node, bottom_up) { (void)node; return nullptr; } - virtual AstNode *handleInterface(AstNode *node, bottom_up) { (void)node; return nullptr; } - virtual AstNode *handleFunction(AstNode *node, bottom_up) { (void)node; return nullptr; } - virtual AstNode *handleParam(AstNode *node, bottom_up) { (void)node; return nullptr; } - virtual AstNode *handleExpr(AstNode *node, bottom_up) { (void)node; return nullptr; } - virtual AstNode *handleBinaryOp(AstNode *node, bottom_up) { (void)node; return nullptr; } - virtual AstNode *handleUnaryOp(AstNode *node, bottom_up) { (void)node; return nullptr; } - virtual AstNode *handleAnnotation(AstNode *node, bottom_up) { (void)node; return nullptr; } + virtual void handleRoot(AstNode *node, bottom_up) { (void)node; }; + virtual AstNode *handleProgram(AstNode *node, bottom_up) + { + (void)node; + return nullptr; + } + virtual AstNode *handleConst(AstNode *node, bottom_up) + { + (void)node; + return nullptr; + } + virtual AstNode *handleChildren(AstNode *node, bottom_up) + { + (void)node; + return nullptr; + } + virtual AstNode *handleType(AstNode *node, bottom_up) + { + (void)node; + return nullptr; + } + virtual AstNode *handleEnum(AstNode *node, bottom_up) + { + (void)node; + return nullptr; + } + virtual AstNode *handleEnumMember(AstNode *node, bottom_up) + { + (void)node; + return nullptr; + } + virtual AstNode *handleStruct(AstNode *node, bottom_up) + { + (void)node; + return nullptr; + } + virtual AstNode *handleStructMember(AstNode *node, bottom_up) + { + (void)node; + return nullptr; + } + virtual AstNode *handleUnion(AstNode *node, bottom_up) + { + (void)node; + return nullptr; + } + virtual AstNode *handleUnionCase(AstNode *node, bottom_up) + { + (void)node; + return nullptr; + } + virtual AstNode *handleInterface(AstNode *node, bottom_up) + { + (void)node; + return nullptr; + } + virtual AstNode *handleFunction(AstNode *node, bottom_up) + { + (void)node; + return nullptr; + } + virtual AstNode *handleParam(AstNode *node, bottom_up) + { + (void)node; + return nullptr; + } + virtual AstNode *handleExpr(AstNode *node, bottom_up) + { + (void)node; + return nullptr; + } + virtual AstNode *handleBinaryOp(AstNode *node, bottom_up) + { + (void)node; + return nullptr; + } + virtual AstNode *handleUnaryOp(AstNode *node, bottom_up) + { + (void)node; + return nullptr; + } + virtual AstNode *handleAnnotation(AstNode *node, bottom_up) + { + (void)node; + return nullptr; + } //@} }; diff --git a/erpcgen/src/CGenerator.cpp b/erpcgen/src/CGenerator.cpp index 88b575c64..a71caf864 100644 --- a/erpcgen/src/CGenerator.cpp +++ b/erpcgen/src/CGenerator.cpp @@ -1,6 +1,6 @@ /* * Copyright (c) 2014-2016, Freescale Semiconductor, Inc. - * Copyright 2016-2017 NXP + * Copyright 2016-2020 NXP * All rights reserved. * * @@ -8,10 +8,12 @@ */ #include "CGenerator.h" + #include "Logging.h" #include "ParseErrors.h" #include "annotations.h" #include "format_string.h" + #include #include #include @@ -163,22 +165,19 @@ DataType *CGenerator::findChildDataType(set &dataTypes, DataType *da switch (dataType->getDataType()) { - case DataType::kAliasType: - { + case DataType::kAliasType: { AliasType *aliasType = dynamic_cast(dataType); assert(aliasType); aliasType->setElementType(findChildDataType(dataTypes, aliasType->getElementType())); break; } - case DataType::kArrayType: - { + case DataType::kArrayType: { ArrayType *arrayType = dynamic_cast(dataType); assert(arrayType); arrayType->setElementType(findChildDataType(dataTypes, arrayType->getElementType())); break; } - case DataType::kBuiltinType: - { + case DataType::kBuiltinType: { if (dataType->isBinary()) { // check if binary data type was replaced with structure wrapper @@ -209,8 +208,7 @@ DataType *CGenerator::findChildDataType(set &dataTypes, DataType *da dataTypes.insert(dataType); break; } - case DataType::kFunctionType: - { + case DataType::kFunctionType: { FunctionType *funcType = dynamic_cast(dataType); assert(funcType); @@ -233,8 +231,7 @@ DataType *CGenerator::findChildDataType(set &dataTypes, DataType *da } break; } - case DataType::kListType: - { + case DataType::kListType: { // The only child node of a list node is the element type. ListType *listType = dynamic_cast(dataType); DataType *trueContainerDataType = listType->getTrueContainerDataType(); @@ -326,8 +323,7 @@ DataType *CGenerator::findChildDataType(set &dataTypes, DataType *da break; } } - case DataType::kStructType: - { + case DataType::kStructType: { StructType *structType = dynamic_cast(dataType); assert(structType); @@ -346,8 +342,7 @@ DataType *CGenerator::findChildDataType(set &dataTypes, DataType *da } break; } - case DataType::kUnionType: - { + case DataType::kUnionType: { // Keil need extra pragma option when unions are used. m_templateData["usedUnionType"] = true; UnionType *currentUnion = dynamic_cast(dataType); @@ -361,8 +356,7 @@ DataType *CGenerator::findChildDataType(set &dataTypes, DataType *da } break; } - default: - { + default: { break; } } @@ -811,8 +805,7 @@ void CGenerator::makeAliasesTemplateData() aliasInfo["unnamedName"] = getOutputName(aliasType); switch (elementDataType->getDataType()) { - case DataType::kStructType: - { + case DataType::kStructType: { StructType *structType = dynamic_cast(elementDataType); assert(structType); aliasInfo["unnamed"] = getStructDefinitionTemplateData( @@ -820,8 +813,7 @@ void CGenerator::makeAliasesTemplateData() aliasInfo["unnamedType"] = "struct"; break; } - case DataType::kEnumType: - { + case DataType::kEnumType: { EnumType *enumType = dynamic_cast(elementDataType); assert(enumType); aliasInfo["unnamed"] = getEnumTemplateData(enumType); @@ -870,8 +862,7 @@ void CGenerator::makeSymbolsDeclarationTemplateData() switch ((*it)->getSymbolType()) { - case DataType::kStructTypeSymbol: - { + case DataType::kStructTypeSymbol: { StructType *structType = dynamic_cast(*it); assert(structType); @@ -882,8 +873,7 @@ void CGenerator::makeSymbolsDeclarationTemplateData() break; } - case DataType::kUnionTypeSymbol: - { + case DataType::kUnionTypeSymbol: { UnionType *unionType = dynamic_cast(*it); assert(unionType); @@ -936,8 +926,7 @@ data_map CGenerator::makeGroupSymbolsTemplateData(Group *group) { switch (symbol->getSymbolType()) { - case DataType::kStructTypeSymbol: - { + case DataType::kStructTypeSymbol: { StructType *structType = dynamic_cast(symbol); assert(structType); @@ -973,8 +962,7 @@ data_map CGenerator::makeGroupSymbolsTemplateData(Group *group) } break; } - case DataType::kUnionTypeSymbol: - { + case DataType::kUnionTypeSymbol: { UnionType *unionType = dynamic_cast(symbol); assert(unionType); @@ -1757,8 +1745,7 @@ void CGenerator::setSymbolDataToSide(const Symbol *symbolType, const set<_param_ { case Symbol::kStructTypeSymbol: case Symbol::kUnionTypeSymbol: - case Symbol::kFunctionTypeSymbol: - { + case Symbol::kFunctionTypeSymbol: { bool in = directions.count(kInDirection); bool out = directions.count(kOutDirection); bool inOut = directions.count(kInoutDirection); @@ -1783,32 +1770,27 @@ void CGenerator::setSymbolDataToSide(const Symbol *symbolType, const set<_param_ break; } - case Symbol::kStructMemberSymbol: - { + case Symbol::kStructMemberSymbol: { const StructMember *structMember = dynamic_cast(symbolType); assert(structMember); switch (structMember->getDirection()) { case kOutDirection: - case kInoutDirection: - { + case kInoutDirection: { direction = kInOut; break; } - case kInDirection: - { + case kInDirection: { direction = kIn; break; } - default: - { + default: { throw internal_error("Unsupported direction type of structure member."); } } break; } - default: - { + default: { throw internal_error(format_string("Symbol: %s is not structure or function parameter.", symbolType->getDescription().c_str())); } @@ -1816,18 +1798,15 @@ void CGenerator::setSymbolDataToSide(const Symbol *symbolType, const set<_param_ switch (direction) { - case kIn: - { + case kIn: { toServer.push_back(dataMap); break; } - case kOut: - { + case kOut: { toClient.push_back(dataMap); break; } - case kInOut: - { + case kInOut: { toServer.push_back(dataMap); toClient.push_back(dataMap); break; @@ -1888,28 +1867,22 @@ string CGenerator::getErrorReturnValue(FunctionBase *fn) assert(builtinType); switch (builtinType->getBuiltinType()) { - case BuiltinType::kBoolType: - { + case BuiltinType::kBoolType: { return "false"; } - case BuiltinType::kUInt8Type: - { + case BuiltinType::kUInt8Type: { return "0xFFU"; } - case BuiltinType::kUInt16Type: - { + case BuiltinType::kUInt16Type: { return "0xFFFFU"; } - case BuiltinType::kUInt32Type: - { + case BuiltinType::kUInt32Type: { return "0xFFFFFFFFU"; } - case BuiltinType::kUInt64Type: - { + case BuiltinType::kUInt64Type: { return "0xFFFFFFFFFFFFFFFFU"; } - default: - { + default: { return "-1"; } } @@ -2148,8 +2121,7 @@ string CGenerator::getTypenameName(DataType *t, const string &name) string returnName; switch (t->getDataType()) { - case DataType::kArrayType: - { + case DataType::kArrayType: { // Array type requires the array element count to come after the variable/member name. returnName = name; ArrayType *a = dynamic_cast(t); @@ -2159,8 +2131,7 @@ string CGenerator::getTypenameName(DataType *t, const string &name) returnName = getTypenameName(a->getElementType(), returnName); break; } - case DataType::kBuiltinType: - { + case DataType::kBuiltinType: { assert(nullptr != dynamic_cast(t)); returnName = getBuiltinTypename(dynamic_cast(t)); if (!(t->isString() && name != "" && name[0] == '*')) @@ -2170,16 +2141,14 @@ string CGenerator::getTypenameName(DataType *t, const string &name) returnName += name; break; } - case DataType::kListType: - { + case DataType::kListType: { const ListType *a = dynamic_cast(t); assert(a); returnName = "* " + name; returnName = getTypenameName(a->getElementType(), returnName); break; } - case DataType::kUnionType: - { + case DataType::kUnionType: { UnionType *unionType = dynamic_cast(t); assert(unionType); if (unionType->isNonEncapsulatedUnion()) @@ -2195,8 +2164,7 @@ string CGenerator::getTypenameName(DataType *t, const string &name) } break; } - case DataType::kVoidType: - { + case DataType::kVoidType: { returnName = "void"; returnName += returnSpaceWhenNotEmpty(name) + name; break; @@ -2204,8 +2172,7 @@ string CGenerator::getTypenameName(DataType *t, const string &name) case DataType::kAliasType: case DataType::kEnumType: case DataType::kFunctionType: - case DataType::kStructType: - { + case DataType::kStructType: { returnName = getOutputName(t); returnName += returnSpaceWhenNotEmpty(name) + name; break; @@ -2246,7 +2213,7 @@ string CGenerator::getBuiltinTypename(const BuiltinType *t) case BuiltinType::kStringType: return "char *"; case BuiltinType::kUStringType: - return "unsigned char*"; + return "unsigned char*"; case BuiltinType::kBinaryType: return "uint8_t *"; default: @@ -2420,15 +2387,13 @@ data_map CGenerator::getEncodeDecodeCall(const string &name, Group *group, DataT switch (t->getDataType()) { - case DataType::kAliasType: - { + case DataType::kAliasType: { AliasType *aliasType = dynamic_cast(t); assert(aliasType); return getEncodeDecodeCall(name, group, aliasType->getElementType(), structType, inDataContainer, structMember, needTempVariable, isFunctionParam); } - case DataType::kArrayType: - { + case DataType::kArrayType: { static uint8_t arrayCounter; ArrayType *arrayType = dynamic_cast(t); assert(arrayType); @@ -2461,13 +2426,11 @@ data_map CGenerator::getEncodeDecodeCall(const string &name, Group *group, DataT --arrayCounter; break; } - case DataType::kBuiltinType: - { + case DataType::kBuiltinType: { getEncodeDecodeBuiltin(group, (BuiltinType *)t, templateData, structType, structMember, isFunctionParam); break; } - case DataType::kEnumType: - { + case DataType::kEnumType: { needTempVariable = true; templateData["decode"] = m_templateData["decodeEnumType"]; templateData["encode"] = m_templateData["encodeEnumType"]; @@ -2482,8 +2445,7 @@ data_map CGenerator::getEncodeDecodeCall(const string &name, Group *group, DataT } break; } - case DataType::kFunctionType: - { + case DataType::kFunctionType: { FunctionType *funType = dynamic_cast(t); assert(funType); const FunctionType::c_function_list_t &callbacks = funType->getCallbackFuns(); @@ -2508,8 +2470,7 @@ data_map CGenerator::getEncodeDecodeCall(const string &name, Group *group, DataT templateData["decode"] = m_templateData["decodeFunctionType"]; break; } - case DataType::kListType: - { + case DataType::kListType: { ListType *listType = dynamic_cast(t); assert(listType); DataType *elementType = listType->getElementType(); @@ -2653,8 +2614,7 @@ data_map CGenerator::getEncodeDecodeCall(const string &name, Group *group, DataT structMember, needTempVariable, isFunctionParam); break; } - case DataType::kStructType: - { + case DataType::kStructType: { // needDealloc(templateData, t, structType, structMember); string typeName = getOutputName(t); if (typeName != "") @@ -2674,8 +2634,7 @@ data_map CGenerator::getEncodeDecodeCall(const string &name, Group *group, DataT } break; } - case DataType::kUnionType: - { + case DataType::kUnionType: { UnionType *unionType = dynamic_cast(t); assert(unionType); @@ -2789,8 +2748,7 @@ data_map CGenerator::getEncodeDecodeCall(const string &name, Group *group, DataT } break; } - default: - { + default: { throw internal_error("unknown member type"); } } @@ -2925,32 +2883,27 @@ bool CGenerator::isNeedCallFree(DataType *dataType) DataType *trueDataType = dataType->getTrueDataType(); switch (trueDataType->getDataType()) { - case DataType::kArrayType: - { + case DataType::kArrayType: { ArrayType *arrayType = dynamic_cast(trueDataType); assert(arrayType); return isNeedCallFree(arrayType->getElementType()); } - case DataType::kBuiltinType: - { + case DataType::kBuiltinType: { BuiltinType *builtinType = dynamic_cast(trueDataType); assert(builtinType); return builtinType->isString() || builtinType->isBinary(); } - case DataType::kListType: - { + case DataType::kListType: { return true; } - case DataType::kStructType: - { + case DataType::kStructType: { StructType *structType = dynamic_cast(trueDataType); assert(structType); set loopDetection; return structType->containListMember() || structType->containStringMember() || containsByrefParamToFree(structType, loopDetection); } - case DataType::kUnionType: - { + case DataType::kUnionType: { UnionType *unionType = dynamic_cast(trueDataType); assert(unionType); for (auto unionCase : unionType->getCases()) @@ -2987,18 +2940,12 @@ void CGenerator::setCallingFreeFunctions(Symbol *symbol, data_map &info, bool re { if (!returnType) { - switch (trueDataType->getDataType()) + if (trueDataType->isStruct() || trueDataType->isUnion() || + (trueDataType->isFunction() && ((structMember->getDirection() == kOutDirection)))) { - case DataType::kStructType: - case DataType::kUnionType: - { - string name = getOutputName(structMember, false); - firstFreeingCall1["firstFreeingCall"] = m_templateData["freeData"]; - firstFreeingCall1["freeName"] = name; - break; - } - default: - break; + string name = getOutputName(structMember, false); + firstFreeingCall1["firstFreeingCall"] = m_templateData["freeData"]; + firstFreeingCall1["freeName"] = name; } } else @@ -3091,14 +3038,12 @@ bool CGenerator::containsString(DataType *dataType) DataType *trueDataType = dataType->getTrueContainerDataType(); switch (trueDataType->getDataType()) { - case DataType::kStructType: - { + case DataType::kStructType: { StructType *s = dynamic_cast(trueDataType); assert(s); return s->containStringMember(); } - case DataType::kUnionType: - { + case DataType::kUnionType: { UnionType *u = dynamic_cast(trueDataType); assert(u); for (UnionCase *unionCase : u->getUniqueCases()) @@ -3117,8 +3062,7 @@ bool CGenerator::containsString(DataType *dataType) } return false; } - default: - { + default: { if (trueDataType->isString()) { return true; @@ -3137,14 +3081,12 @@ bool CGenerator::containsList(DataType *dataType) DataType *trueDataType = dataType->getTrueContainerDataType(); switch (trueDataType->getDataType()) { - case DataType::kStructType: - { + case DataType::kStructType: { StructType *s = dynamic_cast(trueDataType); assert(s); return s->containListMember(); } - case DataType::kUnionType: - { + case DataType::kUnionType: { UnionType *u = dynamic_cast(trueDataType); assert(u); for (UnionCase *unionCase : u->getUniqueCases()) @@ -3163,8 +3105,7 @@ bool CGenerator::containsList(DataType *dataType) } return false; } - default: - { + default: { return false; } } diff --git a/erpcgen/src/CGenerator.h b/erpcgen/src/CGenerator.h index c6c329f20..36c7e02a8 100644 --- a/erpcgen/src/CGenerator.h +++ b/erpcgen/src/CGenerator.h @@ -13,6 +13,7 @@ #include "Generator.h" #include "cpptempl.h" #include "types/Group.h" + #include //////////////////////////////////////////////////////////////////////////////// diff --git a/erpcgen/src/ErpcLexer.cpp b/erpcgen/src/ErpcLexer.cpp index 5ff096513..fd26dac1a 100644 --- a/erpcgen/src/ErpcLexer.cpp +++ b/erpcgen/src/ErpcLexer.cpp @@ -7,11 +7,14 @@ * SPDX-License-Identifier: BSD-3-Clause */ #include "ErpcLexer.h" + #include "erpc_crc16.h" #include "erpc_version.h" + #include "Generator.h" #include "HexValues.h" #include "SearchPath.h" + #include #include #include @@ -76,16 +79,14 @@ int ErpcLexer::processStringEscapes(const char *in, char *out) { switch (*in) { - case '\\': - { + case '\\': { // start of an escape sequence char c = *++in; switch (c) { case 0: // end of the string, bail break; - case 'x': - { + case 'x': { // start of a hex char escape sequence // read high and low nibbles, checking for end of string diff --git a/erpcgen/src/ErpcLexer.h b/erpcgen/src/ErpcLexer.h index f4fb2a368..c896217a1 100644 --- a/erpcgen/src/ErpcLexer.h +++ b/erpcgen/src/ErpcLexer.h @@ -16,6 +16,7 @@ #undef yyFlexLexer #include "AstNode.h" #include "ParseErrors.h" + #include #include #include diff --git a/erpcgen/src/Generator.cpp b/erpcgen/src/Generator.cpp index 1346c4dd7..8a278858b 100644 --- a/erpcgen/src/Generator.cpp +++ b/erpcgen/src/Generator.cpp @@ -8,11 +8,14 @@ */ #include "Generator.h" + #include "erpc_version.h" + #include "Logging.h" #include "ParseErrors.h" #include "annotations.h" #include "format_string.h" + #include #include #include @@ -134,14 +137,12 @@ Generator::Generator(InterfaceDefinition *def, generator_type_t generatorType) // set codec information switch (m_def->getCodecType()) { - case InterfaceDefinition::kBasicCodec: - { + case InterfaceDefinition::kBasicCodec: { m_templateData["codecClass"] = "BasicCodec"; m_templateData["codecHeader"] = "erpc_basic_codec.h"; break; } - default: - { + default: { m_templateData["codecClass"] = "Codec"; m_templateData["codecHeader"] = "erpc_codec.h"; break; @@ -298,8 +299,7 @@ DataType *Generator::findChildDataType(set &dataTypes, DataType *dat switch (dataType->getDataType()) { - case DataType::kAliasType: - { + case DataType::kAliasType: { AliasType *aliasType = dynamic_cast(dataType); if (aliasType != nullptr) { @@ -307,8 +307,7 @@ DataType *Generator::findChildDataType(set &dataTypes, DataType *dat } break; } - case DataType::kArrayType: - { + case DataType::kArrayType: { ArrayType *arrayType = dynamic_cast(dataType); if (arrayType != nullptr) { @@ -316,8 +315,7 @@ DataType *Generator::findChildDataType(set &dataTypes, DataType *dat } break; } - case DataType::kListType: - { + case DataType::kListType: { ListType *listType = dynamic_cast(dataType); if (listType != nullptr) { @@ -325,8 +323,7 @@ DataType *Generator::findChildDataType(set &dataTypes, DataType *dat } break; } - case DataType::kStructType: - { + case DataType::kStructType: { StructType *structType = dynamic_cast(dataType); if (structType != nullptr) { @@ -337,8 +334,7 @@ DataType *Generator::findChildDataType(set &dataTypes, DataType *dat } break; } - case DataType::kUnionType: - { + case DataType::kUnionType: { // Keil need extra pragma option when unions are used. m_templateData["usedUnionType"] = true; UnionType *unionType = dynamic_cast(dataType); @@ -351,8 +347,7 @@ DataType *Generator::findChildDataType(set &dataTypes, DataType *dat } break; } - default: - { + default: { break; } } diff --git a/erpcgen/src/Generator.h b/erpcgen/src/Generator.h index 5c2e52cc0..0da93eeda 100644 --- a/erpcgen/src/Generator.h +++ b/erpcgen/src/Generator.h @@ -28,6 +28,7 @@ #include "types/StructType.h" #include "types/UnionType.h" #include "types/VoidType.h" + #include #include diff --git a/erpcgen/src/HexValues.cpp b/erpcgen/src/HexValues.cpp index 950d27f54..da6ab78e1 100644 --- a/erpcgen/src/HexValues.cpp +++ b/erpcgen/src/HexValues.cpp @@ -8,6 +8,7 @@ */ #include "HexValues.h" + #include bool isHexDigit(char c) diff --git a/erpcgen/src/InterfaceDefinition.cpp b/erpcgen/src/InterfaceDefinition.cpp index 762f5a635..6ecde745e 100644 --- a/erpcgen/src/InterfaceDefinition.cpp +++ b/erpcgen/src/InterfaceDefinition.cpp @@ -8,6 +8,7 @@ */ #include "InterfaceDefinition.h" + #include "AstNode.h" #include "AstWalker.h" #include "ErpcLexer.h" diff --git a/erpcgen/src/InterfaceDefinition.h b/erpcgen/src/InterfaceDefinition.h index 5c147d40c..60a34a777 100644 --- a/erpcgen/src/InterfaceDefinition.h +++ b/erpcgen/src/InterfaceDefinition.h @@ -13,6 +13,7 @@ #include "AstNode.h" #include "types/Program.h" #include "types/SymbolScope.h" + #include #include diff --git a/erpcgen/src/Logging.cpp b/erpcgen/src/Logging.cpp index 1ad5bd0c6..8cd18cc2e 100644 --- a/erpcgen/src/Logging.cpp +++ b/erpcgen/src/Logging.cpp @@ -8,6 +8,7 @@ */ #include "Logging.h" + #include #include #include diff --git a/erpcgen/src/ParseErrors.h b/erpcgen/src/ParseErrors.h index 8dd2a66a7..a1372b9f3 100644 --- a/erpcgen/src/ParseErrors.h +++ b/erpcgen/src/ParseErrors.h @@ -13,6 +13,7 @@ #include "Logging.h" #include "Token.h" #include "os_config.h" + #include //////////////////////////////////////////////////////////////////////////////// diff --git a/erpcgen/src/PythonGenerator.cpp b/erpcgen/src/PythonGenerator.cpp index 703403432..0fe7c4202 100644 --- a/erpcgen/src/PythonGenerator.cpp +++ b/erpcgen/src/PythonGenerator.cpp @@ -8,10 +8,12 @@ */ #include "PythonGenerator.h" + #include "Logging.h" #include "ParseErrors.h" #include "annotations.h" #include "format_string.h" + #include #include #include @@ -136,7 +138,7 @@ void PythonGenerator::generate() makeIncludesTemplateData(); - //makeAliasesTemplateData(); + // makeAliasesTemplateData(); makeConstTemplateData(); @@ -419,8 +421,7 @@ data_map PythonGenerator::makeGroupSymbolsTemplateData(Group *group) switch (symbol->getSymbolType()) { - case DataType::kStructTypeSymbol: - { + case DataType::kStructTypeSymbol: { StructType *structType = dynamic_cast(symbol); if (structType == nullptr) { @@ -444,8 +445,7 @@ data_map PythonGenerator::makeGroupSymbolsTemplateData(Group *group) } break; } - case DataType::kUnionTypeSymbol: - { + case DataType::kUnionTypeSymbol: { UnionType *unionType = dynamic_cast(symbol); if (unionType == nullptr) { @@ -455,7 +455,8 @@ data_map PythonGenerator::makeGroupSymbolsTemplateData(Group *group) Log::info("%s\n", unionType->getDescription().c_str()); string name = filterName(getOutputName(unionType)); - if(name.find('$') != string::npos) { + if (name.find('$') != string::npos) + { Log::debug("%s is inside struct!\n", name.c_str()); break; } @@ -474,8 +475,7 @@ data_map PythonGenerator::makeGroupSymbolsTemplateData(Group *group) } break; } - case DataType::kAliasTypeSymbol: - { + case DataType::kAliasTypeSymbol: { AliasType *aliasType = dynamic_cast(symbol); if (aliasType == nullptr) break; @@ -597,13 +597,11 @@ data_map PythonGenerator::getTypeInfo(DataType *t) info["isNonEncapsulatedUnion"] = false; switch (t->getDataType()) { - case DataType::kAliasType: - { + case DataType::kAliasType: { info = getTypeInfo(t->getTrueDataType()); break; } - case DataType::kArrayType: - { + case DataType::kArrayType: { // Array type requires the array element count to come after the variable/member name. ArrayType *a = dynamic_cast(t); assert(a); @@ -612,19 +610,16 @@ data_map PythonGenerator::getTypeInfo(DataType *t) info["elementType"] = getTypeInfo(a->getElementType()); break; } - case DataType::kBuiltinType: - { + case DataType::kBuiltinType: { assert(dynamic_cast(t)); info["type"] = getBuiltinTypename(dynamic_cast(t)); break; } - case DataType::kEnumType: - { + case DataType::kEnumType: { info["type"] = "enum"; break; } - case DataType::kFunctionType: - { + case DataType::kFunctionType: { info["type"] = "function"; FunctionType *funType = dynamic_cast(t); assert(funType); @@ -646,21 +641,18 @@ data_map PythonGenerator::getTypeInfo(DataType *t) } break; } - case DataType::kListType: - { + case DataType::kListType: { const ListType *a = dynamic_cast(t); assert(a); info["type"] = "list"; info["elementType"] = getTypeInfo(a->getElementType()); break; } - case DataType::kStructType: - { + case DataType::kStructType: { info["type"] = "struct"; break; } - case DataType::kUnionType: - { + case DataType::kUnionType: { UnionType *unionType = dynamic_cast(t); assert(unionType); info["type"] = "union"; @@ -728,8 +720,7 @@ data_map PythonGenerator::getTypeInfo(DataType *t) info["cases"] = unionCases; break; } - case DataType::kVoidType: - { + case DataType::kVoidType: { info["type"] = "void"; break; } diff --git a/erpcgen/src/PythonGenerator.h b/erpcgen/src/PythonGenerator.h index 6dc1d50c7..2cf51bfb9 100644 --- a/erpcgen/src/PythonGenerator.h +++ b/erpcgen/src/PythonGenerator.h @@ -12,6 +12,7 @@ #include "Generator.h" #include "cpptempl.h" + #include #include diff --git a/erpcgen/src/SearchPath.cpp b/erpcgen/src/SearchPath.cpp index 39e23f777..c03565e03 100644 --- a/erpcgen/src/SearchPath.cpp +++ b/erpcgen/src/SearchPath.cpp @@ -8,6 +8,7 @@ */ #include "SearchPath.h" + #include #if __WIN32__ diff --git a/erpcgen/src/SymbolScanner.cpp b/erpcgen/src/SymbolScanner.cpp index 89cb92bb7..9ff18b484 100644 --- a/erpcgen/src/SymbolScanner.cpp +++ b/erpcgen/src/SymbolScanner.cpp @@ -9,6 +9,7 @@ */ #include "SymbolScanner.h" + #include "ErpcLexer.h" #include "Logging.h" #include "annotations.h" @@ -19,6 +20,7 @@ #include "types/FunctionType.h" #include "types/ListType.h" #include "types/VoidType.h" + #include #include @@ -1354,8 +1356,7 @@ DataType *SymbolScanner::lookupDataType(const AstNode *typeNode) case TOK_LIST: return createListType(typeNode); - case TOK_UNION: - { + case TOK_UNION: { assert(nullptr != m_currentStruct); return lookupDataTypeByName(typeNode->getChild(3)->getToken(), &(m_currentStruct->getScope()), false); break; diff --git a/erpcgen/src/Token.cpp b/erpcgen/src/Token.cpp index 9d36e92d5..f6b09672a 100644 --- a/erpcgen/src/Token.cpp +++ b/erpcgen/src/Token.cpp @@ -8,6 +8,7 @@ */ #include "Token.h" + #include "ErpcLexer.h" #include "ParseErrors.h" diff --git a/erpcgen/src/UniqueIdChecker.cpp b/erpcgen/src/UniqueIdChecker.cpp index b03f06ece..c8be73388 100644 --- a/erpcgen/src/UniqueIdChecker.cpp +++ b/erpcgen/src/UniqueIdChecker.cpp @@ -8,6 +8,7 @@ */ #include "UniqueIdChecker.h" + #include "Annotation.h" #include "Logging.h" #include "ParseErrors.h" diff --git a/erpcgen/src/UniqueIdChecker.h b/erpcgen/src/UniqueIdChecker.h index 518f96a78..c4e6b131d 100644 --- a/erpcgen/src/UniqueIdChecker.h +++ b/erpcgen/src/UniqueIdChecker.h @@ -9,16 +9,16 @@ #ifndef _EMBEDDED_RPC__UNIQUEIDCHECKER_H_ #define _EMBEDDED_RPC__UNIQUEIDCHECKER_H_ +#include "Interface.h" +#include "InterfaceDefinition.h" +#include "SymbolScope.h" + #include #include #include #include #include -#include "Interface.h" -#include "InterfaceDefinition.h" -#include "SymbolScope.h" - //////////////////////////////////////////////////////////////////////////////// // Classes //////////////////////////////////////////////////////////////////////////////// diff --git a/erpcgen/src/Value.h b/erpcgen/src/Value.h index ac13a971a..2774061a1 100644 --- a/erpcgen/src/Value.h +++ b/erpcgen/src/Value.h @@ -10,10 +10,16 @@ #define _Value_h_ #include "format_string.h" + #include #include -typedef enum { kIntegerValue, kStringValue, kFloatValue } value_type_t; /*!< Value types */ +typedef enum +{ + kIntegerValue, + kStringValue, + kFloatValue +} value_type_t; /*!< Value types */ /*! * @brief Abstract base class for values of arbitrary types. @@ -82,7 +88,13 @@ class IntegerValue : public Value { public: //! Supported sizes of integers. - typedef enum { kSigned, kSignedLong, kUnsigned, kUnsignedLong } int_type_t; //!< The integer type. + typedef enum + { + kSigned, + kSignedLong, + kUnsigned, + kUnsignedLong + } int_type_t; //!< The integer type. /*! * @brief Constructor. diff --git a/erpcgen/src/cpptemplate/unit_testing.h b/erpcgen/src/cpptemplate/unit_testing.h index bcd6d9bed..47a9dd28b 100644 --- a/erpcgen/src/cpptemplate/unit_testing.h +++ b/erpcgen/src/cpptemplate/unit_testing.h @@ -29,6 +29,7 @@ #else #include "windows.h" #include "winnls.h" // unicode-multibyte conversion + #include #endif diff --git a/erpcgen/src/erpcgen.cpp b/erpcgen/src/erpcgen.cpp index 7ea5af5fc..4aa68ef38 100644 --- a/erpcgen/src/erpcgen.cpp +++ b/erpcgen/src/erpcgen.cpp @@ -8,6 +8,7 @@ */ #include "erpc_version.h" + #include "CGenerator.h" #include "ErpcLexer.h" #include "InterfaceDefinition.h" @@ -17,6 +18,7 @@ #include "UniqueIdChecker.h" #include "options.h" #include "types/Program.h" + #include #include #include @@ -191,8 +193,7 @@ class erpcgenTool PathSearcher::getGlobalSearcher().addSearchPath(optarg); break; - case 'g': - { + case 'g': { string lang = optarg; if (lang == "c") { @@ -210,8 +211,7 @@ class erpcgenTool break; } - case 'c': - { + case 'c': { string codec = optarg; if (codec.compare("basic") == 0) { diff --git a/erpcgen/src/format_string.cpp b/erpcgen/src/format_string.cpp index a5fb078e9..694c39079 100644 --- a/erpcgen/src/format_string.cpp +++ b/erpcgen/src/format_string.cpp @@ -8,7 +8,9 @@ */ #include "format_string.h" + #include "smart_ptr.h" + #include #include #include diff --git a/erpcgen/src/options.cpp b/erpcgen/src/options.cpp index b6c6c578c..be73c3896 100644 --- a/erpcgen/src/options.cpp +++ b/erpcgen/src/options.cpp @@ -40,12 +40,12 @@ // - Added PARSE_POS control flag and POSITIONAL return value. // ^^************************************************************************** +#include "options.h" + #include #include #include -#include "options.h" - using namespace std; // static const char indent[] = "@(#)Options 1.05" ; @@ -203,7 +203,7 @@ void OptStrTokIter::rewind(void) cur = ::strtok(tokstr, seps); } - // ************************************************************* OptIstreamIter +// ************************************************************* OptIstreamIter #ifdef vms enum @@ -633,7 +633,7 @@ unsigned OptionSpec::Format(char *buf, unsigned optctrls) const #endif /* USE_STDIO */ } - // ******************************************************************* Options +// ******************************************************************* Options #if (defined(MSWIN) || defined(OS2) || defined(MSDOS)) #define DIR_SEP_CHAR '\\' diff --git a/erpcgen/src/types/AliasType.h b/erpcgen/src/types/AliasType.h index 4584af798..b6f864313 100644 --- a/erpcgen/src/types/AliasType.h +++ b/erpcgen/src/types/AliasType.h @@ -11,6 +11,7 @@ #define _EMBEDDED_RPC__ALIASTYPE_H_ #include "DataType.h" + #include //////////////////////////////////////////////////////////////////////////////// diff --git a/erpcgen/src/types/Annotation.h b/erpcgen/src/types/Annotation.h index 37aaa748d..944a17cd9 100644 --- a/erpcgen/src/types/Annotation.h +++ b/erpcgen/src/types/Annotation.h @@ -13,6 +13,7 @@ #include "AstNode.h" #include "Token.h" #include "Value.h" + #include //////////////////////////////////////////////////////////////////////////////// diff --git a/erpcgen/src/types/ArrayType.h b/erpcgen/src/types/ArrayType.h index a488eb390..9ea550fed 100644 --- a/erpcgen/src/types/ArrayType.h +++ b/erpcgen/src/types/ArrayType.h @@ -11,6 +11,7 @@ #define _EMBEDDED_RPC__ARRAYTYPE_H_ #include "DataType.h" + #include //////////////////////////////////////////////////////////////////////////////// diff --git a/erpcgen/src/types/BuiltinType.h b/erpcgen/src/types/BuiltinType.h index 17d456547..4984247be 100644 --- a/erpcgen/src/types/BuiltinType.h +++ b/erpcgen/src/types/BuiltinType.h @@ -11,6 +11,7 @@ #define _EMBEDDED_RPC__BUILTINTYPE_H_ #include "DataType.h" + #include //////////////////////////////////////////////////////////////////////////////// @@ -113,7 +114,7 @@ class BuiltinType : public DataType * @retval false When builtin type isn't string or ustring. */ virtual bool isString() const { return m_builtinType == kStringType || m_builtinType == kUStringType; } - + /*! * @brief This function return true/false value for identify ustring type. * diff --git a/erpcgen/src/types/ConstType.h b/erpcgen/src/types/ConstType.h index 600dd53b7..4d7b3c98f 100644 --- a/erpcgen/src/types/ConstType.h +++ b/erpcgen/src/types/ConstType.h @@ -12,6 +12,7 @@ #include "DataType.h" #include "Symbol.h" + #include //////////////////////////////////////////////////////////////////////////////// diff --git a/erpcgen/src/types/DataType.h b/erpcgen/src/types/DataType.h index 3f1bac5c7..52f20afd7 100644 --- a/erpcgen/src/types/DataType.h +++ b/erpcgen/src/types/DataType.h @@ -11,6 +11,7 @@ #define _EMBEDDED_RPC__DATATYPE_H_ #include "Symbol.h" + #include //////////////////////////////////////////////////////////////////////////////// @@ -193,7 +194,7 @@ class DataType : public Symbol * @retval false Always return false. */ virtual bool isString() const { return false; } - + /*! * @brief This function return "false" value as default for identify ustring type. * diff --git a/erpcgen/src/types/EnumMember.h b/erpcgen/src/types/EnumMember.h index e2bfa9061..9d64d8713 100644 --- a/erpcgen/src/types/EnumMember.h +++ b/erpcgen/src/types/EnumMember.h @@ -11,6 +11,7 @@ #define _EMBEDDED_RPC__ENUMMEBER_H_ #include "Symbol.h" + #include //////////////////////////////////////////////////////////////////////////////// diff --git a/erpcgen/src/types/EnumType.h b/erpcgen/src/types/EnumType.h index b81330435..5ef65e133 100644 --- a/erpcgen/src/types/EnumType.h +++ b/erpcgen/src/types/EnumType.h @@ -12,6 +12,7 @@ #include "DataType.h" #include "EnumMember.h" + #include #include diff --git a/erpcgen/src/types/Function.h b/erpcgen/src/types/Function.h index 4d2f91671..fd96f2aa5 100644 --- a/erpcgen/src/types/Function.h +++ b/erpcgen/src/types/Function.h @@ -13,6 +13,7 @@ #include "DataType.h" #include "StructType.h" #include "Symbol.h" + #include //////////////////////////////////////////////////////////////////////////////// diff --git a/erpcgen/src/types/FunctionType.h b/erpcgen/src/types/FunctionType.h index a9ad304cf..d464d02db 100644 --- a/erpcgen/src/types/FunctionType.h +++ b/erpcgen/src/types/FunctionType.h @@ -14,6 +14,7 @@ #include "Function.h" #include "StructType.h" #include "Symbol.h" + #include //////////////////////////////////////////////////////////////////////////////// diff --git a/erpcgen/src/types/Group.h b/erpcgen/src/types/Group.h index ff5772a14..146c9cb1f 100644 --- a/erpcgen/src/types/Group.h +++ b/erpcgen/src/types/Group.h @@ -11,6 +11,7 @@ #include "Interface.h" #include "cpptempl.h" + #include #include #include diff --git a/erpcgen/src/types/Interface.h b/erpcgen/src/types/Interface.h index 66771924e..7193c040e 100644 --- a/erpcgen/src/types/Interface.h +++ b/erpcgen/src/types/Interface.h @@ -13,6 +13,7 @@ #include "Function.h" #include "Symbol.h" #include "SymbolScope.h" + #include #include diff --git a/erpcgen/src/types/ListType.h b/erpcgen/src/types/ListType.h index 37cdff746..25504a447 100644 --- a/erpcgen/src/types/ListType.h +++ b/erpcgen/src/types/ListType.h @@ -11,6 +11,7 @@ #define _EMBEDDED_RPC__LISTTYPE_H_ #include "DataType.h" + #include //////////////////////////////////////////////////////////////////////////////// diff --git a/erpcgen/src/types/Program.h b/erpcgen/src/types/Program.h index 6ea1ac1fb..65676d6ea 100644 --- a/erpcgen/src/types/Program.h +++ b/erpcgen/src/types/Program.h @@ -12,6 +12,7 @@ #include "DataType.h" #include "Symbol.h" + #include //////////////////////////////////////////////////////////////////////////////// diff --git a/erpcgen/src/types/StructMember.h b/erpcgen/src/types/StructMember.h index a890138b5..b224b3f03 100644 --- a/erpcgen/src/types/StructMember.h +++ b/erpcgen/src/types/StructMember.h @@ -12,6 +12,7 @@ #include "DataType.h" #include "Symbol.h" + #include //////////////////////////////////////////////////////////////////////////////// diff --git a/erpcgen/src/types/StructType.h b/erpcgen/src/types/StructType.h index 7c7a3add4..f0aef1d43 100644 --- a/erpcgen/src/types/StructType.h +++ b/erpcgen/src/types/StructType.h @@ -13,6 +13,7 @@ #include "DataType.h" #include "StructMember.h" #include "SymbolScope.h" + #include #include diff --git a/erpcgen/src/types/Symbol.h b/erpcgen/src/types/Symbol.h index edfc9557a..43b870552 100644 --- a/erpcgen/src/types/Symbol.h +++ b/erpcgen/src/types/Symbol.h @@ -13,6 +13,7 @@ #include "Annotation.h" #include "AstNode.h" #include "Token.h" + #include //////////////////////////////////////////////////////////////////////////////// diff --git a/erpcgen/src/types/SymbolScope.h b/erpcgen/src/types/SymbolScope.h index 7469b581f..41d654af7 100644 --- a/erpcgen/src/types/SymbolScope.h +++ b/erpcgen/src/types/SymbolScope.h @@ -11,6 +11,7 @@ #define _EMBEDDED_RPC__SYMBOLSCOPE_H_ #include "Symbol.h" + #include #include #include diff --git a/erpcgen/src/types/Type.cpp b/erpcgen/src/types/Type.cpp index dd4d2abeb..bc92c2cfe 100644 --- a/erpcgen/src/types/Type.cpp +++ b/erpcgen/src/types/Type.cpp @@ -28,6 +28,7 @@ #include "UnionType.h" #include "annotations.h" #include "cpptempl.h" + #include using namespace erpcgen; @@ -475,14 +476,12 @@ DataType *DataType::getTrueContainerDataType() DataType *trueDataType = this->getTrueDataType(); switch (trueDataType->getDataType()) { - case DataType::kListType: - { + case DataType::kListType: { ListType *l = dynamic_cast(trueDataType); assert(l); return l->getElementType()->getTrueContainerDataType(); } - case DataType::kArrayType: - { + case DataType::kArrayType: { ArrayType *a = dynamic_cast(trueDataType); assert(a); return a->getElementType()->getTrueContainerDataType(); diff --git a/erpcgen/src/types/UnionType.h b/erpcgen/src/types/UnionType.h index 2e7a51775..6af6c5cae 100644 --- a/erpcgen/src/types/UnionType.h +++ b/erpcgen/src/types/UnionType.h @@ -13,6 +13,7 @@ #include "DataType.h" #include "StructType.h" #include "UnionCase.h" + #include //////////////////////////////////////////////////////////////////////////////// diff --git a/erpcgen/src/types/VoidType.h b/erpcgen/src/types/VoidType.h index a980729f5..016ab53d1 100644 --- a/erpcgen/src/types/VoidType.h +++ b/erpcgen/src/types/VoidType.h @@ -11,6 +11,7 @@ #define _EMBEDDED_RPC__VOIDTYPE_H_ #include "DataType.h" + #include //////////////////////////////////////////////////////////////////////////////// diff --git a/erpcgen/test/test_forward_declaration_c.yml b/erpcgen/test/test_forward_declaration_c.yml index 2eb92822d..c39f0594a 100644 --- a/erpcgen/test/test_forward_declaration_c.yml +++ b/erpcgen/test/test_forward_declaration_c.yml @@ -1,6 +1,10 @@ --- name: struct before function desc: forward declaration of structure before function which is using type. +params: + dir: + - "in" + - "out" idl: struct forwardStruct; @@ -13,7 +17,7 @@ idl: interface foo { - myFun(in forwardCallback_t pCallback1_t) -> void + myFun({dir} forwardCallback_t pCallback1_t) -> void forwardCallback_t forwardCallback; } @@ -26,6 +30,12 @@ test.h: - "{" - forwardCallback_t pCallback; - "};" +test_server.cpp: + - if: dir == 'in' + then: + - not: erpc_free(pCallback1_t); + else: + - erpc_free(pCallback1_t); --- name: struct before struct diff --git a/erpcgen/test/test_nullable_c.yml b/erpcgen/test/test_nullable_c.yml index 63967ef36..f73990a90 100644 --- a/erpcgen/test/test_nullable_c.yml +++ b/erpcgen/test/test_nullable_c.yml @@ -16,10 +16,10 @@ test_client.cpp: - codec->writeNullFlag(true) - if: dir in ('in', 'inout') then: - - codec->writeString(strlen(a), a); + - codec->writeString(strlen((const char*)a), (const char*)a); - if: dir == 'out' then: - - not: codec->writeString(strlen(a), a); + - not: codec->writeString(strlen((const char*)a), (const char*)a); - if: dir in ('out', 'inout') then: - if (a != NULL) @@ -41,7 +41,51 @@ test_server.cpp: - if: dir in ('out', 'inout') then: - if (a != NULL) - - codec->writeString(strlen(a), a); + - codec->writeString(strlen((const char*)a), (const char*)a); +--- +name: param ustring +desc: +params: + dir: + - "in" + - "out" + - "inout" +idl: | + interface foo { + bar({dir} ustring a @nullable @max_length(8)) -> void + } +test_client.cpp: + - re: void bar\(\w*\s*unsigned\s*char\s*\* a\) + - if (a == NULL) + - codec->writeNullFlag(true) + - if: dir in ('in', 'inout') + then: + - codec->writeString(strlen((const char*)a), (const char*)a); + - if: dir == 'out' + then: + - not: codec->writeString(strlen((const char*)a), (const char*)a); + - if: dir in ('out', 'inout') + then: + - if (a != NULL) + - codec->readString(&a_len, &a_local); +test_server.cpp: + - ::bar_shim + - unsigned char* a = NULL; + - bool isNull; + - codec->readNullFlag(&isNull) + - if (!isNull) + - if: dir in ('in', 'inout') + then: + - codec->readString(&a_len, &a_local) + - if: dir == 'out' + then: + - not: codec->readString(&a_len, &a_local) + - else + - a = NULL; + - if: dir in ('out', 'inout') + then: + - if (a != NULL) + - codec->writeString(strlen((const char*)a), (const char*)a); --- name: in param struct desc: @@ -167,7 +211,7 @@ test_client.cpp: - codec->writeNullFlag(true); - else - codec->writeNullFlag(false); - - codec->writeString(strlen(data->a), data->a); + - codec->writeString(strlen((const char*)data->a), (const char*)data->a); - if: dir in ('out', 'inout') then: - void read_erpc_pair_struct @@ -196,7 +240,7 @@ test_server.cpp: - codec->writeNullFlag(true); - else - codec->writeNullFlag(false); - - codec->writeString(strlen(data->a), data->a); + - codec->writeString(strlen((const char*)data->a), (const char*)data->a); --- name: return struct diff --git a/erpcsniffer/src/Sniffer.cpp b/erpcsniffer/src/Sniffer.cpp index 158c0b41c..02936a29c 100644 --- a/erpcsniffer/src/Sniffer.cpp +++ b/erpcsniffer/src/Sniffer.cpp @@ -7,9 +7,12 @@ */ #include "Sniffer.h" + #include "erpc_c/infra/erpc_message_buffer.h" + #include "Logging.h" #include "annotations.h" + #include #include #include @@ -187,8 +190,7 @@ erpc_status_t Sniffer::parseDataType(DataType *dataType, string &parsedDataInfo) erpc_status_t err; switch (dataType->getDataType()) { - case DataType::_data_type::kAliasType: - { + case DataType::_data_type::kAliasType: { AliasType *aliasType = dynamic_cast(dataType); assert(aliasType); string parseDataInfo; @@ -202,8 +204,7 @@ erpc_status_t Sniffer::parseDataType(DataType *dataType, string &parsedDataInfo) addSpaces(parsedDataInfo, 2); break; } - case DataType::_data_type::kArrayType: - { + case DataType::_data_type::kArrayType: { ArrayType *arrayType = dynamic_cast(dataType); assert(arrayType); uint32_t arraySize = arrayType->getElementCount(); @@ -226,15 +227,13 @@ erpc_status_t Sniffer::parseDataType(DataType *dataType, string &parsedDataInfo) } break; } - case DataType::_data_type::kBuiltinType: - { + case DataType::_data_type::kBuiltinType: { parsedDataInfo = " value: "; BuiltinType *builtinType = dynamic_cast(dataType); assert(builtinType); switch (builtinType->getBuiltinType()) { - case BuiltinType::_builtin_type::kBoolType: - { + case BuiltinType::_builtin_type::kBoolType: { bool value; m_codec->read(&value); if ((err = m_codec->getStatus())) @@ -244,8 +243,7 @@ erpc_status_t Sniffer::parseDataType(DataType *dataType, string &parsedDataInfo) parsedDataInfo = "bool" + parsedDataInfo + ((value) ? "true" : "false"); break; } - case BuiltinType::_builtin_type::kInt8Type: - { + case BuiltinType::_builtin_type::kInt8Type: { int8_t value; m_codec->read(&value); if ((err = m_codec->getStatus())) @@ -255,8 +253,7 @@ erpc_status_t Sniffer::parseDataType(DataType *dataType, string &parsedDataInfo) parsedDataInfo = "int8_t" + parsedDataInfo + format_string("%d", value); break; } - case BuiltinType::_builtin_type::kInt16Type: - { + case BuiltinType::_builtin_type::kInt16Type: { int16_t value; m_codec->read(&value); if ((err = m_codec->getStatus())) @@ -266,8 +263,7 @@ erpc_status_t Sniffer::parseDataType(DataType *dataType, string &parsedDataInfo) parsedDataInfo = "int16_t" + parsedDataInfo + format_string("%d", value); break; } - case BuiltinType::_builtin_type::kInt32Type: - { + case BuiltinType::_builtin_type::kInt32Type: { int32_t value; m_codec->read(&value); if ((err = m_codec->getStatus())) @@ -277,8 +273,7 @@ erpc_status_t Sniffer::parseDataType(DataType *dataType, string &parsedDataInfo) parsedDataInfo = "int32_t" + parsedDataInfo + format_string("%d", value); break; } - case BuiltinType::_builtin_type::kInt64Type: - { + case BuiltinType::_builtin_type::kInt64Type: { int64_t value; m_codec->read(&value); if ((err = m_codec->getStatus())) @@ -288,8 +283,7 @@ erpc_status_t Sniffer::parseDataType(DataType *dataType, string &parsedDataInfo) parsedDataInfo = "int64_t" + parsedDataInfo + format_string("%ld", value); break; } - case BuiltinType::_builtin_type::kUInt8Type: - { + case BuiltinType::_builtin_type::kUInt8Type: { uint8_t value; m_codec->read(&value); if ((err = m_codec->getStatus())) @@ -299,8 +293,7 @@ erpc_status_t Sniffer::parseDataType(DataType *dataType, string &parsedDataInfo) parsedDataInfo = "uint8_t" + parsedDataInfo + format_string("%u", value); break; } - case BuiltinType::_builtin_type::kUInt16Type: - { + case BuiltinType::_builtin_type::kUInt16Type: { uint16_t value; m_codec->read(&value); if ((err = m_codec->getStatus())) @@ -310,8 +303,7 @@ erpc_status_t Sniffer::parseDataType(DataType *dataType, string &parsedDataInfo) parsedDataInfo = "uint16_t" + parsedDataInfo + format_string("%u", value); break; } - case BuiltinType::_builtin_type::kUInt32Type: - { + case BuiltinType::_builtin_type::kUInt32Type: { uint32_t value; m_codec->read(&value); if ((err = m_codec->getStatus())) @@ -321,8 +313,7 @@ erpc_status_t Sniffer::parseDataType(DataType *dataType, string &parsedDataInfo) parsedDataInfo = "uint32_t" + parsedDataInfo + format_string("%u", value); break; } - case BuiltinType::_builtin_type::kUInt64Type: - { + case BuiltinType::_builtin_type::kUInt64Type: { uint64_t value; m_codec->read(&value); if ((err = m_codec->getStatus())) @@ -332,8 +323,7 @@ erpc_status_t Sniffer::parseDataType(DataType *dataType, string &parsedDataInfo) parsedDataInfo = "uint64_t" + parsedDataInfo + format_string("%lu", value); break; } - case BuiltinType::_builtin_type::kFloatType: - { + case BuiltinType::_builtin_type::kFloatType: { float value; m_codec->read(&value); if ((err = m_codec->getStatus())) @@ -343,8 +333,7 @@ erpc_status_t Sniffer::parseDataType(DataType *dataType, string &parsedDataInfo) parsedDataInfo = "float" + parsedDataInfo + format_string("%f", value); break; } - case BuiltinType::_builtin_type::kDoubleType: - { + case BuiltinType::_builtin_type::kDoubleType: { double value; m_codec->read(&value); if ((err = m_codec->getStatus())) @@ -354,8 +343,7 @@ erpc_status_t Sniffer::parseDataType(DataType *dataType, string &parsedDataInfo) parsedDataInfo = "double" + parsedDataInfo + format_string("%f", value); break; } - case BuiltinType::_builtin_type::kStringType: - { + case BuiltinType::_builtin_type::kStringType: { char *value; uint32_t length; m_codec->readString(&length, &value); @@ -366,8 +354,7 @@ erpc_status_t Sniffer::parseDataType(DataType *dataType, string &parsedDataInfo) parsedDataInfo = "string" + parsedDataInfo + format_string("%.*s", length, value); break; } - case BuiltinType::_builtin_type::kBinaryType: - { + case BuiltinType::_builtin_type::kBinaryType: { uint8_t *value; uint32_t length; m_codec->readBinary(&length, &value); @@ -383,15 +370,13 @@ erpc_status_t Sniffer::parseDataType(DataType *dataType, string &parsedDataInfo) parsedDataInfo = "binary" + parsedDataInfo + binaryValue; break; } - default: - { + default: { throw runtime_error("Unrecognized builtin type.\n"); } } break; } - case DataType::_data_type::kEnumType: - { + case DataType::_data_type::kEnumType: { EnumType *e = dynamic_cast(dataType); assert(e); uint32_t value; @@ -416,8 +401,7 @@ erpc_status_t Sniffer::parseDataType(DataType *dataType, string &parsedDataInfo) parsedDataInfo = format_string("%s value: %s", e->getName().c_str(), enumMemberName.c_str()); break; } - case DataType::_data_type::kFunctionType: - { + case DataType::_data_type::kFunctionType: { FunctionType *f = dynamic_cast(dataType); assert(f); int32_t value; @@ -437,8 +421,7 @@ erpc_status_t Sniffer::parseDataType(DataType *dataType, string &parsedDataInfo) } break; } - case DataType::_data_type::kListType: - { + case DataType::_data_type::kListType: { ListType *listType = dynamic_cast(dataType); assert(listType); uint32_t listSize; @@ -468,8 +451,7 @@ erpc_status_t Sniffer::parseDataType(DataType *dataType, string &parsedDataInfo) } break; } - case DataType::_data_type::kStructType: - { + case DataType::_data_type::kStructType: { StructType *structType = dynamic_cast(dataType); assert(structType); parsedDataInfo = "struct " + structType->getName() + ":\n"; @@ -494,8 +476,7 @@ erpc_status_t Sniffer::parseDataType(DataType *dataType, string &parsedDataInfo) addSpaces(parsedDataInfo, 2); break; } - case DataType::_data_type::kUnionType: - { + case DataType::_data_type::kUnionType: { UnionType *unionType = dynamic_cast(dataType); assert(unionType); int32_t discriminator; @@ -545,13 +526,11 @@ erpc_status_t Sniffer::parseDataType(DataType *dataType, string &parsedDataInfo) addSpaces(parsedDataInfo, 2); break; } - case DataType::_data_type::kVoidType: - { + case DataType::_data_type::kVoidType: { parsedDataInfo = "void"; break; } - default: - { + default: { throw runtime_error("Unrecognized data type.\n"); } } @@ -670,14 +649,12 @@ string Sniffer::getDataTypeName(DataType *dataType) { switch (dataType->getDataType()) { - case DataType::kListType: - { + case DataType::kListType: { ListType *listType = dynamic_cast(dataType); assert(listType); return "list<" + getDataTypeName(listType->getElementType()) + ">"; } - case DataType::kArrayType: - { + case DataType::kArrayType: { string returnVal; while (dataType->isArray()) { @@ -688,8 +665,7 @@ string Sniffer::getDataTypeName(DataType *dataType) } return getDataTypeName(dataType) + returnVal; } - case DataType::kVoidType: - { + case DataType::kVoidType: { return "void"; } default: diff --git a/erpcsniffer/src/Sniffer.h b/erpcsniffer/src/Sniffer.h index 155cf5fe7..bf19d423e 100644 --- a/erpcsniffer/src/Sniffer.h +++ b/erpcsniffer/src/Sniffer.h @@ -11,7 +11,9 @@ #include "erpc_c/infra/erpc_basic_codec.h" #include "erpc_c/infra/erpc_transport.h" + #include "CGenerator.h" + #include //////////////////////////////////////////////////////////////////////////////// // Classes diff --git a/erpcsniffer/src/erpcsniffer.cpp b/erpcsniffer/src/erpcsniffer.cpp index 60bda31ae..348fd15fb 100644 --- a/erpcsniffer/src/erpcsniffer.cpp +++ b/erpcsniffer/src/erpcsniffer.cpp @@ -11,6 +11,7 @@ #include "erpc_transport.h" #include "erpc_transport_setup.h" #include "erpc_version.h" + #include "ErpcLexer.h" #include "InterfaceDefinition.h" #include "Logging.h" @@ -19,6 +20,7 @@ #include "UniqueIdChecker.h" #include "annotations.h" #include "options.h" + #include #include #include @@ -183,26 +185,22 @@ class erpcsnifferTool { switch (optchar) { - case '?': - { + case '?': { printUsage(options); return 0; } - case 'V': - { + case 'V': { printf("%s %s\n%s\n", k_toolName, k_version, k_copyright); return 0; } - case 'o': - { + case 'o': { m_outputFilePath = optarg; break; } - case 'v': - { + case 'v': { if (m_verboseType != kExtraDebug) { m_verboseType = (verbose_type_t)(((int)m_verboseType) + 1); @@ -210,14 +208,12 @@ class erpcsnifferTool break; } - case 'I': - { + case 'I': { PathSearcher::getGlobalSearcher().addSearchPath(optarg); break; } - case 't': - { + case 't': { string transport = optarg; if (transport == "tcp") { @@ -235,32 +231,27 @@ class erpcsnifferTool break; } - case 'q': - { + case 'q': { m_quantity = strtoul(optarg, NULL, 10); break; } - case 'b': - { + case 'b': { m_baudrate = strtoul(optarg, NULL, 10); break; } - case 'p': - { + case 'p': { m_port = optarg; break; } - case 'h': - { + case 'h': { m_host = optarg; break; } - default: - { + default: { Log::error("error: unrecognized option\n\n"); printUsage(options); return 0; @@ -345,8 +336,7 @@ class erpcsnifferTool Transport *_transport; switch (m_transport) { - case kTcpTransport: - { + case kTcpTransport: { uint16_t portNumber = strtoul(m_port, NULL, 10); TCPTransport *tcpTransport = new TCPTransport(m_host, portNumber, true); if (erpc_status_t err = tcpTransport->open()) @@ -357,16 +347,14 @@ class erpcsnifferTool break; } - case kSerialTransport: - { + case kSerialTransport: { erpc_transport_t transport = erpc_transport_serial_init(m_port, m_baudrate); _transport = reinterpret_cast(transport); assert(_transport); break; } - default: - { + default: { break; } } diff --git a/examples/matrix_multiply_tcp_python/service/__init__.py b/examples/matrix_multiply_tcp_python/service/__init__.py index 9f8092a1d..ad482727f 100644 --- a/examples/matrix_multiply_tcp_python/service/__init__.py +++ b/examples/matrix_multiply_tcp_python/service/__init__.py @@ -5,7 +5,7 @@ # SPDX-License-Identifier: BSD-3-Clause # -# Generated by erpcgen 1.7.4 on Thu Apr 16 10:59:26 2020. +# Generated by erpcgen 1.8.0 on Thu Oct 8 16:38:36 2020. # # AUTOGENERATED - DO NOT EDIT # diff --git a/examples/matrix_multiply_tcp_python/service/erpc_matrix_multiply/__init__.py b/examples/matrix_multiply_tcp_python/service/erpc_matrix_multiply/__init__.py index cbe9f0c34..8188e5c91 100644 --- a/examples/matrix_multiply_tcp_python/service/erpc_matrix_multiply/__init__.py +++ b/examples/matrix_multiply_tcp_python/service/erpc_matrix_multiply/__init__.py @@ -5,7 +5,7 @@ # SPDX-License-Identifier: BSD-3-Clause # -# Generated by erpcgen 1.7.4 on Thu Apr 16 10:59:26 2020. +# Generated by erpcgen 1.8.0 on Thu Oct 8 16:38:36 2020. # # AUTOGENERATED - DO NOT EDIT # @@ -15,8 +15,8 @@ version = erpc_version.ERPC_VERSION except ImportError: version = "unknown" -if version != "1.7.4": - raise ValueError("The generated shim code version (1.7.4) is different to the rest of eRPC code (%s). \ +if version != "1.8.0": + raise ValueError("The generated shim code version (1.8.0) is different to the rest of eRPC code (%s). \ Install newer version by running \"python setup.py install\" in folder erpc/erpc_python/." % repr(version)) from . import common diff --git a/examples/matrix_multiply_tcp_python/service/erpc_matrix_multiply/client.py b/examples/matrix_multiply_tcp_python/service/erpc_matrix_multiply/client.py index ac494b594..ef2798bf0 100644 --- a/examples/matrix_multiply_tcp_python/service/erpc_matrix_multiply/client.py +++ b/examples/matrix_multiply_tcp_python/service/erpc_matrix_multiply/client.py @@ -5,7 +5,7 @@ # SPDX-License-Identifier: BSD-3-Clause # -# Generated by erpcgen 1.7.4 on Thu Apr 16 10:59:26 2020. +# Generated by erpcgen 1.8.0 on Thu Oct 8 16:38:36 2020. # # AUTOGENERATED - DO NOT EDIT # diff --git a/examples/matrix_multiply_tcp_python/service/erpc_matrix_multiply/common.py b/examples/matrix_multiply_tcp_python/service/erpc_matrix_multiply/common.py index 1e8f6a5ae..0947097fb 100644 --- a/examples/matrix_multiply_tcp_python/service/erpc_matrix_multiply/common.py +++ b/examples/matrix_multiply_tcp_python/service/erpc_matrix_multiply/common.py @@ -5,7 +5,7 @@ # SPDX-License-Identifier: BSD-3-Clause # -# Generated by erpcgen 1.7.4 on Thu Apr 16 10:59:26 2020. +# Generated by erpcgen 1.8.0 on Thu Oct 8 16:38:36 2020. # # AUTOGENERATED - DO NOT EDIT # @@ -18,4 +18,3 @@ #matrix size is changed in the erpc file matrix_size = 5 - diff --git a/examples/matrix_multiply_tcp_python/service/erpc_matrix_multiply/interface.py b/examples/matrix_multiply_tcp_python/service/erpc_matrix_multiply/interface.py index b6ec9db4e..42830a7db 100644 --- a/examples/matrix_multiply_tcp_python/service/erpc_matrix_multiply/interface.py +++ b/examples/matrix_multiply_tcp_python/service/erpc_matrix_multiply/interface.py @@ -5,7 +5,7 @@ # SPDX-License-Identifier: BSD-3-Clause # -# Generated by erpcgen 1.7.4 on Thu Apr 16 10:59:26 2020. +# Generated by erpcgen 1.8.0 on Thu Oct 8 16:38:36 2020. # # AUTOGENERATED - DO NOT EDIT # diff --git a/examples/matrix_multiply_tcp_python/service/erpc_matrix_multiply/server.py b/examples/matrix_multiply_tcp_python/service/erpc_matrix_multiply/server.py index 782c7c99d..b9ee6ba65 100644 --- a/examples/matrix_multiply_tcp_python/service/erpc_matrix_multiply/server.py +++ b/examples/matrix_multiply_tcp_python/service/erpc_matrix_multiply/server.py @@ -5,7 +5,7 @@ # SPDX-License-Identifier: BSD-3-Clause # -# Generated by erpcgen 1.7.4 on Thu Apr 16 10:59:26 2020. +# Generated by erpcgen 1.8.0 on Thu Oct 8 16:38:36 2020. # # AUTOGENERATED - DO NOT EDIT # diff --git a/run_clang_format.py b/run_clang_format.py index 16b17bde7..db9c3c339 100644 --- a/run_clang_format.py +++ b/run_clang_format.py @@ -53,5 +53,5 @@ print("Ignored: ", file) else: print("Formatting: ", file) - subprocess.call(["clang-format-5.0", "-i", file]) + subprocess.call(["clang-format-10.0", "-i", file]) print('*****************************************************************************\n') diff --git a/test/common/unit_test_arbitrator_app0.cpp b/test/common/unit_test_arbitrator_app0.cpp index 7aadad367..a3b92f5a0 100644 --- a/test/common/unit_test_arbitrator_app0.cpp +++ b/test/common/unit_test_arbitrator_app0.cpp @@ -6,21 +6,18 @@ * SPDX-License-Identifier: BSD-3-Clause */ -#include "unit_test.h" - #include "erpc_arbitrated_client_setup.h" #include "erpc_mbf_setup.h" #include "erpc_server_setup.h" #include "erpc_transport_setup.h" #include "FreeRTOS.h" +#include "gtest.h" #include "semphr.h" #include "task.h" - -#include "gtest.h" - #include "test_firstInterface.h" #include "test_secondInterface_server.h" +#include "unit_test.h" #ifdef __cplusplus extern "C" { diff --git a/test/common/unit_test_arbitrator_app1.cpp b/test/common/unit_test_arbitrator_app1.cpp index 69259e6e4..ca1bf46a1 100644 --- a/test/common/unit_test_arbitrator_app1.cpp +++ b/test/common/unit_test_arbitrator_app1.cpp @@ -6,19 +6,17 @@ * SPDX-License-Identifier: BSD-3-Clause */ -#include "unit_test.h" - #include "erpc_arbitrated_client_setup.h" #include "erpc_mbf_setup.h" #include "erpc_server_setup.h" #include "erpc_transport_setup.h" -#include "test_firstInterface_server.h" -#include "test_secondInterface.h" - #include "FreeRTOS.h" #include "semphr.h" #include "task.h" +#include "test_firstInterface_server.h" +#include "test_secondInterface.h" +#include "unit_test.h" #ifdef __cplusplus extern "C" { diff --git a/test/common/unit_test_client.cpp b/test/common/unit_test_client.cpp index 711eff05d..9a070ab50 100644 --- a/test/common/unit_test_client.cpp +++ b/test/common/unit_test_client.cpp @@ -9,6 +9,7 @@ #include "erpc_client_setup.h" #include "erpc_mbf_setup.h" #include "erpc_transport_setup.h" + #include "board.h" #include "gtest.h" #include "gtestListener.h" diff --git a/test/common/unit_test_serial_client.cpp b/test/common/unit_test_serial_client.cpp index 8efa01911..890a4185a 100644 --- a/test/common/unit_test_serial_client.cpp +++ b/test/common/unit_test_serial_client.cpp @@ -9,6 +9,7 @@ #include "erpc_basic_codec.h" #include "erpc_client_manager.h" #include "erpc_serial_transport.h" + #include "Logging.h" #include "gtest.h" #include "gtestListener.h" diff --git a/test/common/unit_test_serial_server.cpp b/test/common/unit_test_serial_server.cpp index 131565bc4..5892b16dd 100644 --- a/test/common/unit_test_serial_server.cpp +++ b/test/common/unit_test_serial_server.cpp @@ -9,10 +9,12 @@ #include "erpc_basic_codec.h" #include "erpc_serial_transport.h" #include "erpc_simple_server.h" + #include "Logging.h" #include "myAlloc.h" #include "test_unit_test_common_server.h" #include "unit_test.h" + #include using namespace erpc; diff --git a/test/common/unit_test_server.cpp b/test/common/unit_test_server.cpp index 54f347a20..bb15903d7 100644 --- a/test/common/unit_test_server.cpp +++ b/test/common/unit_test_server.cpp @@ -10,6 +10,7 @@ #include "erpc_server_setup.h" #include "erpc_simple_server.h" #include "erpc_transport_setup.h" + #include "board.h" #include "myAlloc.h" #include "test_unit_test_common_server.h" @@ -65,6 +66,8 @@ void SystemInitHook(void) int main(int argc, const char *argv[]) { + BOARD_InitHardware(); + #if (defined(RPMSG) || defined(MU)) uint32_t startupData; mcmgr_status_t status; diff --git a/test/common/unit_test_tcp_arbitrator_client.cpp b/test/common/unit_test_tcp_arbitrator_client.cpp index 0296e06b8..36bc9ed14 100644 --- a/test/common/unit_test_tcp_arbitrator_client.cpp +++ b/test/common/unit_test_tcp_arbitrator_client.cpp @@ -11,11 +11,13 @@ #include "erpc_simple_server.h" #include "erpc_tcp_transport.h" #include "erpc_transport_arbitrator.h" + #include "Logging.h" #include "gtest.h" #include "test_firstInterface.h" #include "test_secondInterface.h" #include "unit_test.h" + #include using namespace erpc; diff --git a/test/common/unit_test_tcp_arbitrator_server.cpp b/test/common/unit_test_tcp_arbitrator_server.cpp index d6296857b..7295117ce 100644 --- a/test/common/unit_test_tcp_arbitrator_server.cpp +++ b/test/common/unit_test_tcp_arbitrator_server.cpp @@ -11,11 +11,13 @@ #include "erpc_simple_server.h" #include "erpc_tcp_transport.h" #include "erpc_transport_arbitrator.h" + #include "Logging.h" #include "myAlloc.h" #include "test_firstInterface.h" #include "test_secondInterface.h" #include "unit_test.h" + #include using namespace erpc; diff --git a/test/common/unit_test_tcp_client.cpp b/test/common/unit_test_tcp_client.cpp index dd814d7a1..1d4db5ca5 100644 --- a/test/common/unit_test_tcp_client.cpp +++ b/test/common/unit_test_tcp_client.cpp @@ -9,6 +9,7 @@ #include "erpc_basic_codec.h" #include "erpc_client_manager.h" #include "erpc_tcp_transport.h" + #include "Logging.h" #include "gtest.h" #include "gtestListener.h" diff --git a/test/common/unit_test_tcp_server.cpp b/test/common/unit_test_tcp_server.cpp index 008a3431c..e79557cc3 100644 --- a/test/common/unit_test_tcp_server.cpp +++ b/test/common/unit_test_tcp_server.cpp @@ -9,6 +9,7 @@ #include "erpc_basic_codec.h" #include "erpc_simple_server.h" #include "erpc_tcp_transport.h" + #include "Logging.h" #include "myAlloc.h" #include "test_unit_test_common_server.h" diff --git a/test/skeleton/server_skeleton.cpp b/test/skeleton/server_skeleton.cpp index fc69ec08e..561aa281c 100644 --- a/test/skeleton/server_skeleton.cpp +++ b/test/skeleton/server_skeleton.cpp @@ -9,6 +9,7 @@ #include "Logging.h" #include "out.h" #include "unit_test.h" + #include //////////////////////////////////////////////////////////////////////////////// //// Implementation of functions here @@ -21,8 +22,8 @@ void add_services(erpc::SimpleServer *server) { /* Define services to add using dynamic memory allocation - * Exapmle:ArithmeticService_service * svc = new ArithmeticService_service(); - */ // NOTE: possible memory leak? not ever deleting + * Exapmle:ArithmeticService_service * svc = new ArithmeticService_service(); + */ // NOTE: possible memory leak? not ever deleting /* Add services * Example: server->addService(svc); diff --git a/test/test_annotations/external.h b/test/test_annotations/external.h index 83ead35e2..2ccab8a7f 100644 --- a/test/test_annotations/external.h +++ b/test/test_annotations/external.h @@ -15,7 +15,12 @@ //////////////////////////////////////////////////////////////////////////////// // Enumerators data types declarations -typedef enum myEnum { one = 0, two = 1, three = 2 } myEnum; +typedef enum myEnum +{ + one = 0, + two = 1, + three = 2 +} myEnum; // Aliases data types declarations typedef int32_t myInt; diff --git a/test/test_annotations/test_annotations_server_impl.cpp b/test/test_annotations/test_annotations_server_impl.cpp index 68d9441c3..bcf466659 100644 --- a/test/test_annotations/test_annotations_server_impl.cpp +++ b/test/test_annotations/test_annotations_server_impl.cpp @@ -7,10 +7,12 @@ */ #include "erpc_server_setup.h" + #include "test_server.h" #include "test_unit_test_common_server.h" #include "unit_test.h" #include "unit_test_wrapped.h" + #include AnnotateTest_service *svc; diff --git a/test/test_arbitrator/test_arbitrator_client_impl.cpp b/test/test_arbitrator/test_arbitrator_client_impl.cpp index 861542800..3e498de81 100644 --- a/test/test_arbitrator/test_arbitrator_client_impl.cpp +++ b/test/test_arbitrator/test_arbitrator_client_impl.cpp @@ -7,6 +7,7 @@ */ #include "erpc_simple_server.h" + #include "gtest.h" #include "test_firstInterface.h" #include "test_secondInterface_server.h" diff --git a/test/test_arbitrator/test_arbitrator_server_impl.cpp b/test/test_arbitrator/test_arbitrator_server_impl.cpp index c3bcf7367..a9d52b2e5 100644 --- a/test/test_arbitrator/test_arbitrator_server_impl.cpp +++ b/test/test_arbitrator/test_arbitrator_server_impl.cpp @@ -7,6 +7,7 @@ */ #include "erpc_simple_server.h" + #include "test_firstInterface_server.h" #include "test_secondInterface.h" diff --git a/test/test_arrays/test_arrays_client_impl.cpp b/test/test_arrays/test_arrays_client_impl.cpp index ab2907ffa..1db0d3a68 100644 --- a/test/test_arrays/test_arrays_client_impl.cpp +++ b/test/test_arrays/test_arrays_client_impl.cpp @@ -8,6 +8,7 @@ #include "gtest.h" #include "test.h" + #include //////////////////////////////////////////////////////////////////////////////// diff --git a/test/test_arrays/test_arrays_server_impl.cpp b/test/test_arrays/test_arrays_server_impl.cpp index 0e4e0143c..8e37c85af 100644 --- a/test/test_arrays/test_arrays_server_impl.cpp +++ b/test/test_arrays/test_arrays_server_impl.cpp @@ -7,10 +7,12 @@ */ #include "erpc_server_setup.h" + #include "test_server.h" #include "test_unit_test_common_server.h" #include "unit_test.h" #include "unit_test_wrapped.h" + #include #include @@ -46,7 +48,7 @@ int32_t (*sendReceived2Int32(int32_t arrayNumbers[12][10]))[12][10] char *(*sendReceivedString(char *arrayStrings[12]))[12] { - char *(*sendArrays)[12] = (char *(*)[12])erpc_malloc(sizeof(char * [12])); + char *(*sendArrays)[12] = (char *(*)[12])erpc_malloc(sizeof(char *[12])); for (int32_t i = 0; i < 12; ++i) { uint32_t textLen = strlen(arrayStrings[i]); @@ -58,7 +60,7 @@ char *(*sendReceivedString(char *arrayStrings[12]))[12] char *(*sendReceived2String(char *arrayStrings[3][5]))[3][5] { - char *(*sendArrays)[3][5] = (char *(*)[3][5])erpc_malloc(sizeof(char * [3][5])); + char *(*sendArrays)[3][5] = (char *(*)[3][5])erpc_malloc(sizeof(char *[3][5])); for (int32_t i = 0; i < 3; ++i) { for (int32_t j = 0; j < 5; ++j) diff --git a/test/test_binary/test_binary_server_impl.cpp b/test/test_binary/test_binary_server_impl.cpp index 74e73f3bf..93d6f52ec 100644 --- a/test/test_binary/test_binary_server_impl.cpp +++ b/test/test_binary/test_binary_server_impl.cpp @@ -7,10 +7,12 @@ */ #include "erpc_server_setup.h" + #include "test_server.h" #include "test_unit_test_common_server.h" #include "unit_test.h" #include "unit_test_wrapped.h" + #include Binary_service *svc; diff --git a/test/test_builtin/test_builtin_client_impl.cpp b/test/test_builtin/test_builtin_client_impl.cpp index 322b7a7e5..47bc8a0a2 100644 --- a/test/test_builtin/test_builtin_client_impl.cpp +++ b/test/test_builtin/test_builtin_client_impl.cpp @@ -8,6 +8,7 @@ #include "gtest.h" #include "test.h" + #include using namespace std; diff --git a/test/test_builtin/test_builtin_server_impl.cpp b/test/test_builtin/test_builtin_server_impl.cpp index bc67f9653..25e86e046 100644 --- a/test/test_builtin/test_builtin_server_impl.cpp +++ b/test/test_builtin/test_builtin_server_impl.cpp @@ -7,10 +7,12 @@ */ #include "erpc_server_setup.h" + #include "test_server.h" #include "test_unit_test_common_server.h" #include "unit_test.h" #include "unit_test_wrapped.h" + #include #include diff --git a/test/test_callbacks/test_callbacks_server_impl.cpp b/test/test_callbacks/test_callbacks_server_impl.cpp index 6850c1683..657c00478 100644 --- a/test/test_callbacks/test_callbacks_server_impl.cpp +++ b/test/test_callbacks/test_callbacks_server_impl.cpp @@ -6,11 +6,13 @@ */ #include "erpc_server_setup.h" + #include "test_core0_server.h" #include "test_core1.h" #include "test_unit_test_common_server.h" #include "unit_test.h" #include "unit_test_wrapped.h" + #include ClientCore0Services_service *svc; @@ -74,7 +76,8 @@ int32_t my_mul(int32_t arg1, int32_t arg2) int32_t my_div(int32_t arg1, int32_t arg2) { - if(arg2) { + if (arg2) + { return arg1 / arg2; } return 0; diff --git a/test/test_const/test_const_server_impl.cpp b/test/test_const/test_const_server_impl.cpp index 9c8961b67..0cecb8a1d 100644 --- a/test/test_const/test_const_server_impl.cpp +++ b/test/test_const/test_const_server_impl.cpp @@ -7,10 +7,12 @@ */ #include "erpc_server_setup.h" + #include "test_server.h" #include "test_unit_test_common_server.h" #include "unit_test.h" #include "unit_test_wrapped.h" + #include //////////////////////////////////////////////////////////////////////////////// diff --git a/test/test_enums/test_enums_server_impl.cpp b/test/test_enums/test_enums_server_impl.cpp index 87bccee43..579584da9 100644 --- a/test/test_enums/test_enums_server_impl.cpp +++ b/test/test_enums/test_enums_server_impl.cpp @@ -7,10 +7,12 @@ */ #include "erpc_server_setup.h" + #include "test_server.h" #include "test_unit_test_common_server.h" #include "unit_test.h" #include "unit_test_wrapped.h" + #include EnumsService_service *svc; diff --git a/test/test_lists/test_lists_client_impl.cpp b/test/test_lists/test_lists_client_impl.cpp index f5bca8b5e..5c8a2e376 100644 --- a/test/test_lists/test_lists_client_impl.cpp +++ b/test/test_lists/test_lists_client_impl.cpp @@ -8,6 +8,7 @@ #include "gtest.h" #include "test.h" + #include using namespace std; diff --git a/test/test_lists/test_lists_server_impl.cpp b/test/test_lists/test_lists_server_impl.cpp index cad77fd08..9990d8aff 100644 --- a/test/test_lists/test_lists_server_impl.cpp +++ b/test/test_lists/test_lists_server_impl.cpp @@ -7,10 +7,12 @@ */ #include "erpc_server_setup.h" + #include "test_server.h" #include "test_unit_test_common_server.h" #include "unit_test.h" #include "unit_test_wrapped.h" + #include #include diff --git a/test/test_shared/test_shared_server_impl.cpp b/test/test_shared/test_shared_server_impl.cpp index 772dfd901..fb4388b8d 100644 --- a/test/test_shared/test_shared_server_impl.cpp +++ b/test/test_shared/test_shared_server_impl.cpp @@ -6,10 +6,12 @@ */ #include "erpc_server_setup.h" + #include "test_server.h" #include "test_unit_test_common_server.h" #include "unit_test.h" #include "unit_test_wrapped.h" + #include SharedService_service *svc; diff --git a/test/test_struct/test_struct_client_impl.cpp b/test/test_struct/test_struct_client_impl.cpp index 6eb54fc64..3a99fc4aa 100644 --- a/test/test_struct/test_struct_client_impl.cpp +++ b/test/test_struct/test_struct_client_impl.cpp @@ -8,6 +8,7 @@ #include "gtest.h" #include "test_ArithmeticService.h" + #include using namespace std; diff --git a/test/test_struct/test_struct_server_impl.cpp b/test/test_struct/test_struct_server_impl.cpp index 12c894403..be0b27160 100644 --- a/test/test_struct/test_struct_server_impl.cpp +++ b/test/test_struct/test_struct_server_impl.cpp @@ -7,10 +7,12 @@ */ #include "erpc_server_setup.h" + #include "test_ArithmeticService_server.h" #include "test_unit_test_common_server.h" #include "unit_test.h" #include "unit_test_wrapped.h" + #include #include diff --git a/test/test_typedef/test_typedef_client_impl.cpp b/test/test_typedef/test_typedef_client_impl.cpp index 44c5df4cb..6ab651523 100644 --- a/test/test_typedef/test_typedef_client_impl.cpp +++ b/test/test_typedef/test_typedef_client_impl.cpp @@ -8,6 +8,7 @@ #include "gtest.h" #include "test.h" + #include //////////////////////////////////////////////////////////////////////////////// diff --git a/test/test_typedef/test_typedef_server_impl.cpp b/test/test_typedef/test_typedef_server_impl.cpp index 722279293..fbc04b456 100644 --- a/test/test_typedef/test_typedef_server_impl.cpp +++ b/test/test_typedef/test_typedef_server_impl.cpp @@ -7,10 +7,12 @@ */ #include "erpc_server_setup.h" + #include "test_server.h" #include "test_unit_test_common_server.h" #include "unit_test.h" #include "unit_test_wrapped.h" + #include #include diff --git a/test/test_unions/test_unions_client_impl.cpp b/test/test_unions/test_unions_client_impl.cpp index cc754a912..5d955d124 100644 --- a/test/test_unions/test_unions_client_impl.cpp +++ b/test/test_unions/test_unions_client_impl.cpp @@ -8,6 +8,7 @@ #include "gtest.h" #include "test.h" + #include using namespace std; diff --git a/test/test_unions/test_unions_server_impl.cpp b/test/test_unions/test_unions_server_impl.cpp index 5dbde4d30..7c4f3907f 100644 --- a/test/test_unions/test_unions_server_impl.cpp +++ b/test/test_unions/test_unions_server_impl.cpp @@ -7,10 +7,12 @@ */ #include "erpc_server_setup.h" + #include "test_server.h" #include "test_unit_test_common_server.h" #include "unit_test.h" #include "unit_test_wrapped.h" + #include #include @@ -25,8 +27,7 @@ gapGenericEvent_t *testGenericCallback(const gapGenericEvent_t *event) gapGenericEvent_t *newEvent = (gapGenericEvent_t *)erpc_malloc(sizeof(gapGenericEvent_t)); switch (event->eventType) { - case gInternalError_c: - { + case gInternalError_c: { if (event->eventData.internalError.errorCode == gBleSuccess_c && event->eventData.internalError.errorSource == gHciCommandStatus_c && event->eventData.internalError.hciCommandOpcode == 5) @@ -39,8 +40,7 @@ gapGenericEvent_t *testGenericCallback(const gapGenericEvent_t *event) } break; } - case gRandomAddressReady_c: - { + case gRandomAddressReady_c: { int x = 0xAA; int success = 1; int i = 0; @@ -63,8 +63,7 @@ gapGenericEvent_t *testGenericCallback(const gapGenericEvent_t *event) } break; } - case gWhiteListSizeReady_c: - { + case gWhiteListSizeReady_c: { newEvent->eventType = gTestCaseReturn_c; if (100 == event->eventData.whiteListSize) { @@ -79,8 +78,7 @@ gapGenericEvent_t *testGenericCallback(const gapGenericEvent_t *event) case gPublicAddressRead_c: case gAdvertisingSetupFailed_c: case gAdvTxPowerLevelRead_c: - default: - { + default: { } } return newEvent; @@ -91,8 +89,7 @@ foo *sendMyFoo(const foo *f) foo *newFoo = (foo *)erpc_malloc(sizeof(foo)); switch (f->discriminator) { - case apple: - { + case apple: { for (uint32_t i = 0; i < f->bing.myFoobar.rawString.dataLength; ++i) { if ((i + 1) != f->bing.myFoobar.rawString.data[i]) @@ -107,8 +104,7 @@ foo *sendMyFoo(const foo *f) erpc_free(f->bing.myFoobar.rawString.data); break; } - case banana: - { + case banana: { if ((f->bing.x == 3) && (f->bing.y == 4.0)) { newFoo->discriminator = papaya; @@ -123,8 +119,7 @@ foo *sendMyFoo(const foo *f) } break; } - case orange: - { + case orange: { for (uint32_t i = 1; i <= f->bing.a.elementsCount; ++i) { // If data sent across is incorrect, return 0x55 @@ -141,8 +136,7 @@ foo *sendMyFoo(const foo *f) erpc_free(f->bing.a.elements); break; } - default: - { + default: { break; } } @@ -155,8 +149,7 @@ foo *sendMyUnion(fruit discriminator, const unionType *unionVariable) foo *newFoo = (foo *)erpc_malloc(sizeof(foo)); switch (discriminator) { - case apple: - { + case apple: { for (uint32_t i = 0; i < unionVariable->myFoobar.rawString.dataLength; ++i) { if ((i + 1) != unionVariable->myFoobar.rawString.data[i]) @@ -170,8 +163,7 @@ foo *sendMyUnion(fruit discriminator, const unionType *unionVariable) newFoo->bing.ret = 0xAA; break; } - case banana: - { + case banana: { if ((unionVariable->x == 3) && (unionVariable->y == 4.0)) { newFoo->discriminator = papaya; @@ -186,8 +178,7 @@ foo *sendMyUnion(fruit discriminator, const unionType *unionVariable) } break; } - case orange: - { + case orange: { for (uint32_t i = 1; i <= unionVariable->a.elementsCount; ++i) { // If data sent across is incorrect, return 0x55 @@ -203,8 +194,7 @@ foo *sendMyUnion(fruit discriminator, const unionType *unionVariable) newFoo->bing.ret = 0xAA; break; } - default: - { + default: { break; } } From 99afd4915cafe143562295021ac925c7b7cbf305 Mon Sep 17 00:00:00 2001 From: "Michal Princ (nxa17570)" Date: Wed, 16 Dec 2020 17:53:12 +0100 Subject: [PATCH 94/96] Fix minor typo in greetings.yml --- .github/workflows/greetings.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/greetings.yml b/.github/workflows/greetings.yml index ec766b0d9..9ca791ea4 100644 --- a/.github/workflows/greetings.yml +++ b/.github/workflows/greetings.yml @@ -9,5 +9,5 @@ jobs: - uses: actions/first-interaction@v1 with: repo-token: ${{ secrets.GITHUB_TOKEN }} - issue-message: 'Hi eRPC user. Thank you for your interest and welcomme. We hope you will enjoy this framework well.' + issue-message: 'Hi eRPC user. Thank you for your interest and welcome. We hope you will enjoy this framework well.' pr-message: 'Hi eRPC user. Thank you for your PR. We are appreciating that and we will try to review it as soon as possible. We hope you are enjoying this framework so far.' From 6a571caf6d5042af5d63ff8745f2e4b24e14bc9f Mon Sep 17 00:00:00 2001 From: "Michal Princ (nxa17570)" Date: Tue, 5 Jan 2021 17:07:02 +0100 Subject: [PATCH 95/96] eRPC updates 01/2021 -- Update/correct erpc README.md. -- Several MISRA C-2012 violations addressed. -- Add missing GPIO-less support into the erpc DSPI transport layer to be aligned with the SPI transport. --- README.md | 44 +++++-- erpc_c/config/erpc_config.h | 4 +- erpc_c/infra/erpc_client_manager.h | 4 +- erpc_c/infra/erpc_client_server_common.h | 2 +- erpc_c/infra/erpc_framed_transport.cpp | 8 +- erpc_c/infra/erpc_framed_transport.h | 6 +- erpc_c/infra/erpc_pre_post_action.h | 6 +- erpc_c/infra/erpc_server.cpp | 1 + erpc_c/infra/erpc_server.h | 4 +- erpc_c/infra/erpc_simple_server.cpp | 2 +- erpc_c/port/erpc_config_internal.h | 4 +- erpc_c/port/erpc_port_freertos.cpp | 2 +- erpc_c/port/erpc_port_memmanager.cpp | 2 +- erpc_c/port/erpc_port_mqx.cpp | 2 +- erpc_c/port/erpc_port_stdlib.cpp | 2 +- erpc_c/port/erpc_port_zephyr.cpp | 2 +- erpc_c/port/erpc_setup_extensions.h | 2 +- .../port/erpc_setup_extensions_freertos.cpp | 12 +- erpc_c/port/erpc_threading.h | 2 +- erpc_c/port/erpc_threading_freertos.cpp | 2 +- erpc_c/setup/erpc_arbitrated_client_setup.cpp | 1 + erpc_c/setup/erpc_client_setup.cpp | 1 + erpc_c/setup/erpc_server_setup.cpp | 1 + erpc_c/setup/erpc_setup_mbf_dynamic.cpp | 2 +- erpc_c/setup/erpc_setup_mbf_static.cpp | 16 +-- .../erpc_setup_rpmsg_lite_rtos_master.cpp | 4 +- .../erpc_setup_rpmsg_tty_rtos_remote.cpp | 2 +- erpc_c/setup/erpc_transport_setup.h | 2 +- .../transports/erpc_dspi_master_transport.cpp | 107 +++++++++++++++--- .../transports/erpc_dspi_slave_transport.cpp | 106 ++++++++++++++--- erpc_c/transports/erpc_mu_transport.cpp | 16 +-- erpc_c/transports/erpc_mu_transport.h | 8 +- .../transports/erpc_rpmsg_linux_transport.h | 4 +- .../transports/erpc_spi_slave_transport.cpp | 2 +- .../transports/erpc_uart_cmsis_transport.cpp | 12 +- erpc_c/transports/erpc_uart_cmsis_transport.h | 4 +- erpc_c/transports/erpc_usb_cdc_transport.cpp | 10 +- erpc_c/transports/erpc_usb_cdc_transport.h | 4 +- 38 files changed, 294 insertions(+), 121 deletions(-) diff --git a/README.md b/README.md index 298ef96af..31ab66619 100644 --- a/README.md +++ b/README.md @@ -26,7 +26,8 @@ Client side usage: void example_client(void) { // Initialize client running over UART. erpc_client_init( - erpc_transport_cmsis_uart_init(Driver_USART0); + erpc_transport_cmsis_uart_init(Driver_USART0), + erpc_mbf_dynamic_init()); // Now we can call the remote function to turn on the green LED. set_led(kGreen, true); @@ -43,7 +44,8 @@ void set_led(LEDName whichLed, bool onOrOff) { void example_server(void) { // Initialize server running over UART. erpc_server_init( - erpc_transport_cmsis_uart_init(Driver_USART0); + erpc_transport_cmsis_uart_init(Driver_USART0), + erpc_mbf_dynamic_init()); // Add the IO service. erpc_add_service_to_server(create_IO_service()); @@ -61,9 +63,12 @@ Supported transports: * NXP Kinetis SPI and DSPI * POSIX and Windows serial port * TCP/IP (mostly for testing) -* [NXP RPMsg-Lite](https://github.com/NXPmicro/rpmsg-lite) +* [NXP RPMsg-Lite / RPMsg TTY](https://github.com/NXPmicro/rpmsg-lite) +* SPIdev Linux +* USB CDC +* NXP Messaging Unit -eRPC is available with an unrestrictive BSD 3-clause license. See the LICENSE file for the full license text. +eRPC is available with an unrestrictive BSD 3-clause license. See the [LICENSE file](https://github.com/EmbeddedRPC/erpc/blob/develop/LICENSE) for the full license text. ## Releases @@ -71,10 +76,19 @@ eRPC is available with an unrestrictive BSD 3-clause license. See the LICENSE fi ## Documentation -[Documentation](https://github.com/EmbeddedRPC/erpc/wiki) is in the `wiki` section. Commit sha in wiki repository: 431cba8. +[Documentation](https://github.com/EmbeddedRPC/erpc/wiki) is in the `wiki` section. + +[eRPC Infrastructure documentation](https://embeddedrpc.github.io/) + +## Examples [Example IDL](examples/README.md) is available in the `examples/` folder. +Plenty of eRPC multicore and multiprocessor examples can be also found in NXP MCUXpressoSDK packages. Visit [https://mcuxpresso.nxp.com](https://mcuxpresso.nxp.com) to configure, build and download these packages.
    +To get the board list with multicore support (eRPC included) use filtering based on Middleware and search for 'multicore' string. Once the selected package with the multicore middleware is downloaded, see
    +/boards//multicore_examples for eRPC multicore examples (RPMsg_Lite or Messaging Unit transports used) or
    +/boards//multiprocessor_examples for eRPC multiprocessor examples (UART or SPI transports used).
    +eRPC examples use 'erpc_' name prefix. ## Directories @@ -88,12 +102,16 @@ eRPC is available with an unrestrictive BSD 3-clause license. See the LICENSE fi `erpcgen` - Holds source code for erpcgen and makefiles or project files to build erpcgen on Windows, Linux, and OS X. +`erpcsniffer` - Holds source code for erpcsniffer application. + `examples` - Several example IDL files. `mk` - Contains common makefiles for building eRPC components. `test` - Client/server tests. These tests verify the entire communications path from client to server and back. +`utilities` - Holds utilities which bring additional benefit to eRPC apps developers. + ## Building and installing @@ -117,11 +135,11 @@ Steps are described in [`erpcgen/VisualStudio_v14/readme_erpcgen.txt`](erpcgen/V Install these packages: * bison: GNU yacc-compatible parser generator * flex: A fast lexical analyzer generator -* libboost-dev, libboost-filesystem-dev, libboost-system-dev: Boost C++ libraries (Linux needs to use libboost version 1.67.0) +* libboost-dev, libboost-filesystem-dev, libboost-system-dev: Boost C++ libraries (Linux needs to use libboost version 1.65.0) * make: the GNU version of the 'make' utility * python: Python language interpreter (either 2.7 or 3.5+ work) -* gcc-core: GNU Compiler Collection (C, OpenMP) -* gcc-g++: GNU Compiler Collection (C++) +* gcc-7: GNU C compiler (recommended version) +* g++-7: GNU C++ compiler (recommended version) Mandatory for case, when build for different architecture is needed * gcc-multilib, g++-multilib @@ -130,9 +148,9 @@ Mandatory for case, when build for different architecture is needed #### Mac OS X Install these packages with [homebrew](http://brew.sh/): -* bison: GNU yacc-compatible parser generator -* flex: A fast lexical analyzer generator -* boost: Boost C++ libraries +* bison: GNU yacc-compatible parser generator (version 3.7.3 is recommended) +* flex: A fast lexical analyzer generator (version 2.6.4 is recommended) +* boost: Boost C++ libraries (version 1.74 is recommended) ### Building @@ -157,6 +175,8 @@ List of top level Makefile targets: - `all`: build all of the above - `install`: install liberpc.a, erpcgen, and include files +eRPC code is validated with respect to the C++ 11 standard. + ### Installing for Python To install the Python infrastructure for eRPC, first change to the `erpc_python/` directory. Then run the setup.py script like this: @@ -165,7 +185,7 @@ To install the Python infrastructure for eRPC, first change to the `erpc_python/ After installation, the `erpc` package is available via normal import statements. See the [erpc_python folder readme](erpc_python/readme.md) for more. -## Code providing: +## Code providing Repository on Github contains two main branches. __Master__ and __develop__. Code is developed on __develop__ branch. Release version is created via merging __develop__ branch into __master__ branch. diff --git a/erpc_c/config/erpc_config.h b/erpc_c/config/erpc_config.h index c8da1592d..fbde2753b 100644 --- a/erpc_c/config/erpc_config.h +++ b/erpc_c/config/erpc_config.h @@ -71,13 +71,13 @@ //! Uncomment to change the size of buffers allocated by one of MessageBufferFactory. //! (@ref client_setup and @ref server_setup). The default size is set to 256. //! For RPMsg transport layer, ERPC_DEFAULT_BUFFER_SIZE must be 2^n - 16. -//#define ERPC_DEFAULT_BUFFER_SIZE (256) +//#define ERPC_DEFAULT_BUFFER_SIZE (256U) //! @def ERPC_DEFAULT_BUFFERS_COUNT //! //! Uncomment to change the count of buffers allocated by one of statically allocated messages. //! Default value is set to 2. -//#define ERPC_DEFAULT_BUFFERS_COUNT (2) +//#define ERPC_DEFAULT_BUFFERS_COUNT (2U) //! @def ERPC_NOEXCEPT //! diff --git a/erpc_c/infra/erpc_client_manager.h b/erpc_c/infra/erpc_client_manager.h index 851aa14d4..4c333c3e8 100644 --- a/erpc_c/infra/erpc_client_manager.h +++ b/erpc_c/infra/erpc_client_manager.h @@ -200,8 +200,8 @@ class ClientManager : public ClientServerCommon Codec *createBufferAndCodec(void); private: - ClientManager(const ClientManager &); //!< Disable copy ctor. - ClientManager &operator=(const ClientManager &); //!< Disable copy ctor. + ClientManager(const ClientManager &other); //!< Disable copy ctor. + ClientManager &operator=(const ClientManager &other); //!< Disable copy ctor. }; /*! diff --git a/erpc_c/infra/erpc_client_server_common.h b/erpc_c/infra/erpc_client_server_common.h index e47571cb9..08d720bf5 100644 --- a/erpc_c/infra/erpc_client_server_common.h +++ b/erpc_c/infra/erpc_client_server_common.h @@ -79,7 +79,7 @@ class ClientServerCommon #define ERPC_OTHER_INHERITANCE 1 : #endif - PrePostAction() + PrePostAction(void) #endif {}; diff --git a/erpc_c/infra/erpc_framed_transport.cpp b/erpc_c/infra/erpc_framed_transport.cpp index 2b67d26d7..9b865d229 100644 --- a/erpc_c/infra/erpc_framed_transport.cpp +++ b/erpc_c/infra/erpc_framed_transport.cpp @@ -1,6 +1,6 @@ /* * Copyright (c) 2014-2016, Freescale Semiconductor, Inc. - * Copyright 2016-2017 NXP + * Copyright 2016-2020 NXP * All rights reserved. * * @@ -22,7 +22,7 @@ using namespace erpc; FramedTransport::FramedTransport(void) : Transport() , m_crcImpl(NULL) -#if ERPC_THREADS +#if !ERPC_THREADS_IS(NONE) , m_sendLock() , m_receiveLock() #endif @@ -43,7 +43,7 @@ erpc_status_t FramedTransport::receive(MessageBuffer *message) Header h; { -#if ERPC_THREADS +#if !ERPC_THREADS_IS(NONE) Mutex::Guard lock(m_receiveLock); #endif @@ -88,7 +88,7 @@ erpc_status_t FramedTransport::receive(MessageBuffer *message) erpc_status_t FramedTransport::send(MessageBuffer *message) { assert(m_crcImpl && "Uninitialized Crc16 object."); -#if ERPC_THREADS +#if !ERPC_THREADS_IS(NONE) Mutex::Guard lock(m_sendLock); #endif diff --git a/erpc_c/infra/erpc_framed_transport.h b/erpc_c/infra/erpc_framed_transport.h index de77ec397..52139d186 100644 --- a/erpc_c/infra/erpc_framed_transport.h +++ b/erpc_c/infra/erpc_framed_transport.h @@ -1,6 +1,6 @@ /* * Copyright (c) 2014-2016, Freescale Semiconductor, Inc. - * Copyright 2016-2017 NXP + * Copyright 2016-2020 NXP * All rights reserved. * * @@ -16,7 +16,7 @@ #include -#if ERPC_THREADS +#if !ERPC_THREADS_IS(NONE) #include "erpc_threading.h" #endif @@ -111,7 +111,7 @@ class FramedTransport : public Transport protected: Crc16 *m_crcImpl; /*!< CRC object. */ -#if ERPC_THREADS +#if !ERPC_THREADS_IS(NONE) Mutex m_sendLock; //!< Mutex protecting send. Mutex m_receiveLock; //!< Mutex protecting receive. #endif diff --git a/erpc_c/infra/erpc_pre_post_action.h b/erpc_c/infra/erpc_pre_post_action.h index bedb0679d..f38a0be9b 100644 --- a/erpc_c/infra/erpc_pre_post_action.h +++ b/erpc_c/infra/erpc_pre_post_action.h @@ -42,7 +42,7 @@ class PrePostAction /*! * @brief PrePostAction constructor. */ - PrePostAction() + PrePostAction(void) : m_preCB(NULL) , m_postCB(NULL){}; @@ -67,14 +67,14 @@ class PrePostAction * * @return preCB Pointer for callback function. */ - pre_post_action_cb getPreCB() { return m_preCB; } + pre_post_action_cb getPreCB(void) { return m_preCB; } /*! * @brief This function returns "after eRPC call finish" callback function. * * @return postCB Pointer for callback function. */ - pre_post_action_cb getPostCB() { return m_postCB; } + pre_post_action_cb getPostCB(void) { return m_postCB; } /*! * @brief PrePostAction destructor diff --git a/erpc_c/infra/erpc_server.cpp b/erpc_c/infra/erpc_server.cpp index 69963c07f..86097cf9b 100644 --- a/erpc_c/infra/erpc_server.cpp +++ b/erpc_c/infra/erpc_server.cpp @@ -18,6 +18,7 @@ using namespace erpc; //////////////////////////////////////////////////////////////////////////////// #if ERPC_NESTED_CALLS_DETECTION +extern bool nestingDetection; bool nestingDetection = false; #endif diff --git a/erpc_c/infra/erpc_server.h b/erpc_c/infra/erpc_server.h index b0b602fd7..0712b970f 100644 --- a/erpc_c/infra/erpc_server.h +++ b/erpc_c/infra/erpc_server.h @@ -226,8 +226,8 @@ class Server : public ClientServerCommon private: // Disable copy ctor. - Server(const Server &); /*!< Disable copy ctor. */ - Server &operator=(const Server &); /*!< Disable copy ctor. */ + Server(const Server &other); /*!< Disable copy ctor. */ + Server &operator=(const Server &other); /*!< Disable copy ctor. */ }; } // namespace erpc diff --git a/erpc_c/infra/erpc_simple_server.cpp b/erpc_c/infra/erpc_simple_server.cpp index 5972ce38f..c9a90b8d6 100644 --- a/erpc_c/infra/erpc_simple_server.cpp +++ b/erpc_c/infra/erpc_simple_server.cpp @@ -64,7 +64,7 @@ erpc_status_t SimpleServer::runInternalBegin(Codec **codec, MessageBuffer &buff, erpc_status_t err = m_transport->receive(&buff); #if ERPC_PRE_POST_ACTION - pre_post_action_cb preCB = this->getPreCB(); + pre_post_action_cb preCB = this->getPreCB(void); if (preCB) { preCB(); diff --git a/erpc_c/port/erpc_config_internal.h b/erpc_c/port/erpc_config_internal.h index cc992821c..9205bd2d5 100644 --- a/erpc_c/port/erpc_config_internal.h +++ b/erpc_c/port/erpc_config_internal.h @@ -70,13 +70,13 @@ // Set default buffer size. #if !defined(ERPC_DEFAULT_BUFFER_SIZE) //! @brief Size of buffers allocated by BasicMessageBufferFactory in setup functions. - #define ERPC_DEFAULT_BUFFER_SIZE (256) + #define ERPC_DEFAULT_BUFFER_SIZE (256U) #endif // Set default buffers count. #if !defined(ERPC_DEFAULT_BUFFERS_COUNT) //! @brief Count of buffers allocated by StaticMessageBufferFactory. - #define ERPC_DEFAULT_BUFFERS_COUNT (2) + #define ERPC_DEFAULT_BUFFERS_COUNT (2U) #endif // Disable/enable noexcept. diff --git a/erpc_c/port/erpc_port_freertos.cpp b/erpc_c/port/erpc_port_freertos.cpp index 1849e3b16..884c0f376 100644 --- a/erpc_c/port/erpc_port_freertos.cpp +++ b/erpc_c/port/erpc_port_freertos.cpp @@ -64,7 +64,7 @@ void erpc_free(void *ptr) /* Provide function for pure virtual call to avoid huge demangling code being linked in ARM GCC */ #if ((defined(__GNUC__)) && (defined(__arm__))) -extern "C" void __cxa_pure_virtual() +extern "C" void __cxa_pure_virtual(void) { while (1) ; diff --git a/erpc_c/port/erpc_port_memmanager.cpp b/erpc_c/port/erpc_port_memmanager.cpp index aa23feafa..7c60ba43f 100644 --- a/erpc_c/port/erpc_port_memmanager.cpp +++ b/erpc_c/port/erpc_port_memmanager.cpp @@ -66,7 +66,7 @@ void erpc_free(void *ptr) /* Provide function for pure virtual call to avoid huge demangling code being linked in ARM GCC */ #if ((defined(__GNUC__)) && (defined(__arm__))) -extern "C" void __cxa_pure_virtual() +extern "C" void __cxa_pure_virtual(void) { while (1) ; diff --git a/erpc_c/port/erpc_port_mqx.cpp b/erpc_c/port/erpc_port_mqx.cpp index 6311f3c75..709bd9d8b 100644 --- a/erpc_c/port/erpc_port_mqx.cpp +++ b/erpc_c/port/erpc_port_mqx.cpp @@ -64,7 +64,7 @@ void erpc_free(void *ptr) /* Provide function for pure virtual call to avoid huge demangling code being linked in ARM GCC */ #if ((defined(__GNUC__)) && (defined(__arm__))) -extern "C" void __cxa_pure_virtual() +extern "C" void __cxa_pure_virtual(void) { while (1) ; diff --git a/erpc_c/port/erpc_port_stdlib.cpp b/erpc_c/port/erpc_port_stdlib.cpp index a03e35904..6d5a3e4b0 100644 --- a/erpc_c/port/erpc_port_stdlib.cpp +++ b/erpc_c/port/erpc_port_stdlib.cpp @@ -75,7 +75,7 @@ void erpc_free(void *ptr) /* Provide function for pure virtual call to avoid huge demangling code being linked in ARM GCC */ #if ((defined(__GNUC__)) && (defined(__arm__))) -extern "C" void __cxa_pure_virtual() +extern "C" void __cxa_pure_virtual(void) { while (1) ; diff --git a/erpc_c/port/erpc_port_zephyr.cpp b/erpc_c/port/erpc_port_zephyr.cpp index b13e02efe..5e894a696 100644 --- a/erpc_c/port/erpc_port_zephyr.cpp +++ b/erpc_c/port/erpc_port_zephyr.cpp @@ -63,7 +63,7 @@ void erpc_free(void *ptr) /* Provide function for pure virtual call to avoid huge demangling code being linked in ARM GCC */ #if ((defined(__GNUC__)) && (defined(__arm__))) -extern "C" void __cxa_pure_virtual() +extern "C" void __cxa_pure_virtual(void) { while (1) ; diff --git a/erpc_c/port/erpc_setup_extensions.h b/erpc_c/port/erpc_setup_extensions.h index 8b1c2060f..d49dbe8b3 100644 --- a/erpc_c/port/erpc_setup_extensions.h +++ b/erpc_c/port/erpc_setup_extensions.h @@ -14,7 +14,7 @@ #include -#if ERPC_THREADS +#if !ERPC_THREADS_IS(NONE) #if ERPC_THREADS_IS(FREERTOS) #include "FreeRTOS.h" diff --git a/erpc_c/port/erpc_setup_extensions_freertos.cpp b/erpc_c/port/erpc_setup_extensions_freertos.cpp index 983451da3..585e6d5f6 100644 --- a/erpc_c/port/erpc_setup_extensions_freertos.cpp +++ b/erpc_c/port/erpc_setup_extensions_freertos.cpp @@ -17,7 +17,7 @@ using namespace erpc; static Semaphore *s_erpc_call_in_progress = NULL; static TimerHandle_t s_erpc_call_timer_cb = NULL; -void erpc::erpc_pre_cb_default() +void erpc::erpc_pre_cb_default(void) { assert(s_erpc_call_in_progress && "If you want use default pre cb action, do not forget call erpc_init_call_progress_detection_default."); @@ -27,13 +27,13 @@ void erpc::erpc_pre_cb_default() xTimerStart(s_erpc_call_timer_cb, 0); } -void erpc::erpc_post_cb_default() +void erpc::erpc_post_cb_default(void) { xTimerStop(s_erpc_call_timer_cb, 0); s_erpc_call_in_progress->put(); } -void erpc_call_timer_cb_default(TimerHandle_t xTimer) +static void erpc_call_timer_cb_default(TimerHandle_t xTimer) { assert(1 != 1 && "eRPC task freezed."); } @@ -49,7 +49,7 @@ void erpc_init_call_progress_detection_default( assert(s_erpc_call_timer_cb && "Creating eRPC timer failed."); } -void erpc_deinit_call_progress_detection_default() +void erpc_deinit_call_progress_detection_default(void) { if (s_erpc_call_in_progress) { @@ -64,7 +64,7 @@ void erpc_deinit_call_progress_detection_default() } } -bool erpc_is_call_in_progress_default() +bool erpc_is_call_in_progress_default(void) { assert(s_erpc_call_in_progress && "If you want use default pre cb action, do not forget call erpc_init_call_progress_detection_default."); @@ -76,7 +76,7 @@ bool erpc_is_call_in_progress_default() return true; } -void erpc_reset_in_progress_state_default() +void erpc_reset_in_progress_state_default(void) { assert(s_erpc_call_in_progress && diff --git a/erpc_c/port/erpc_threading.h b/erpc_c/port/erpc_threading.h index caa8fe8fd..dd2130177 100644 --- a/erpc_c/port/erpc_threading.h +++ b/erpc_c/port/erpc_threading.h @@ -15,7 +15,7 @@ #include // Exclude the rest of the file if threading is disabled. -#if ERPC_THREADS +#if !ERPC_THREADS_IS(NONE) #if ERPC_THREADS_IS(PTHREADS) #include diff --git a/erpc_c/port/erpc_threading_freertos.cpp b/erpc_c/port/erpc_threading_freertos.cpp index f01b6f71c..2401974bd 100644 --- a/erpc_c/port/erpc_threading_freertos.cpp +++ b/erpc_c/port/erpc_threading_freertos.cpp @@ -87,7 +87,7 @@ bool Thread::operator==(Thread &o) return m_task == o.m_task; } -Thread *Thread::getCurrentThread() +Thread *Thread::getCurrentThread(void) { TaskHandle_t thisTask = xTaskGetCurrentTaskHandle(); diff --git a/erpc_c/setup/erpc_arbitrated_client_setup.cpp b/erpc_c/setup/erpc_arbitrated_client_setup.cpp index d81cfbea9..e9f0da010 100644 --- a/erpc_c/setup/erpc_arbitrated_client_setup.cpp +++ b/erpc_c/setup/erpc_arbitrated_client_setup.cpp @@ -32,6 +32,7 @@ using namespace erpc; // global client variables static ManuallyConstructed s_client; +extern ClientManager *g_client; ClientManager *g_client = NULL; static ManuallyConstructed s_codecFactory; diff --git a/erpc_c/setup/erpc_client_setup.cpp b/erpc_c/setup/erpc_client_setup.cpp index fabc3966a..2fb0b9536 100644 --- a/erpc_c/setup/erpc_client_setup.cpp +++ b/erpc_c/setup/erpc_client_setup.cpp @@ -30,6 +30,7 @@ using namespace erpc; // global client variables static ManuallyConstructed s_client; +extern ClientManager *g_client; ClientManager *g_client = NULL; static ManuallyConstructed s_codecFactory; static ManuallyConstructed s_crc16; diff --git a/erpc_c/setup/erpc_server_setup.cpp b/erpc_c/setup/erpc_server_setup.cpp index 48d8729a8..8057f301e 100644 --- a/erpc_c/setup/erpc_server_setup.cpp +++ b/erpc_c/setup/erpc_server_setup.cpp @@ -27,6 +27,7 @@ using namespace erpc; // global server variables static ManuallyConstructed s_server; +extern SimpleServer *g_server; SimpleServer *g_server = NULL; static ManuallyConstructed s_codecFactory; static ManuallyConstructed s_crc16; diff --git a/erpc_c/setup/erpc_setup_mbf_dynamic.cpp b/erpc_c/setup/erpc_setup_mbf_dynamic.cpp index a50192d25..d559b28e3 100644 --- a/erpc_c/setup/erpc_setup_mbf_dynamic.cpp +++ b/erpc_c/setup/erpc_setup_mbf_dynamic.cpp @@ -28,7 +28,7 @@ using namespace erpc; class DynamicMessageBufferFactory : public MessageBufferFactory { public: - virtual MessageBuffer create() + virtual MessageBuffer create(void) { uint8_t *buf = new (nothrow) uint8_t[ERPC_DEFAULT_BUFFER_SIZE]; return MessageBuffer(buf, ERPC_DEFAULT_BUFFER_SIZE); diff --git a/erpc_c/setup/erpc_setup_mbf_static.cpp b/erpc_c/setup/erpc_setup_mbf_static.cpp index 0bfaa83b1..a97ecf12f 100644 --- a/erpc_c/setup/erpc_setup_mbf_static.cpp +++ b/erpc_c/setup/erpc_setup_mbf_static.cpp @@ -1,6 +1,6 @@ /* * Copyright (c) 2014-2016, Freescale Semiconductor, Inc. - * Copyright 2016 NXP + * Copyright 2016-2020 NXP * All rights reserved. * * @@ -14,7 +14,7 @@ #include -#if !ERPC_THREADS_IS(ERPC_THREADS_NONE) +#if !ERPC_THREADS_IS(NONE) #include "erpc_threading.h" #endif @@ -34,7 +34,7 @@ class StaticMessageBufferFactory : public MessageBufferFactory * @brief Constructor. */ StaticMessageBufferFactory(void) -#if !ERPC_THREADS_IS(ERPC_THREADS_NONE) +#if !ERPC_THREADS_IS(NONE) : m_semaphore(1) #endif { @@ -58,7 +58,7 @@ class StaticMessageBufferFactory : public MessageBufferFactory virtual MessageBuffer create(void) { uint8_t idx = 0; -#if !ERPC_THREADS_IS(ERPC_THREADS_NONE) +#if !ERPC_THREADS_IS(NONE) m_semaphore.get(); #endif while (((m_freeBufferBitmap[idx >> 3] & (1 << (idx & 0x7))) == 0) && (idx < ERPC_DEFAULT_BUFFERS_COUNT)) @@ -69,7 +69,7 @@ class StaticMessageBufferFactory : public MessageBufferFactory assert(idx < ERPC_DEFAULT_BUFFERS_COUNT); m_freeBufferBitmap[idx >> 3] &= ~(1 << (idx & 0x7)); -#if !ERPC_THREADS_IS(ERPC_THREADS_NONE) +#if !ERPC_THREADS_IS(NONE) m_semaphore.put(); #endif @@ -92,7 +92,7 @@ class StaticMessageBufferFactory : public MessageBufferFactory if (tmp) { uint8_t idx = 0; -#if !ERPC_THREADS_IS(ERPC_THREADS_NONE) +#if !ERPC_THREADS_IS(NONE) m_semaphore.get(); #endif while ((tmp != (uint8_t *)m_buffers[idx]) && (idx < ERPC_DEFAULT_BUFFERS_COUNT)) @@ -103,7 +103,7 @@ class StaticMessageBufferFactory : public MessageBufferFactory { m_freeBufferBitmap[idx >> 3] |= 1 << (idx & 0x7); } -#if !ERPC_THREADS_IS(ERPC_THREADS_NONE) +#if !ERPC_THREADS_IS(NONE) m_semaphore.put(); #endif } @@ -113,7 +113,7 @@ class StaticMessageBufferFactory : public MessageBufferFactory uint8_t m_freeBufferBitmap[(ERPC_DEFAULT_BUFFERS_COUNT >> 3) + 1]; /*!< Bitmat of used/not used buffers. */ uint64_t m_buffers[ERPC_DEFAULT_BUFFERS_COUNT] [(ERPC_DEFAULT_BUFFER_SIZE + sizeof(uint64_t) - 1) / sizeof(uint64_t)]; /*!< Static buffers. */ -#if !ERPC_THREADS_IS(ERPC_THREADS_NONE) +#if !ERPC_THREADS_IS(NONE) Semaphore m_semaphore; /*!< Semaphore.*/ #endif }; diff --git a/erpc_c/setup/erpc_setup_rpmsg_lite_rtos_master.cpp b/erpc_c/setup/erpc_setup_rpmsg_lite_rtos_master.cpp index 43d8fe0cf..fc2de7618 100644 --- a/erpc_c/setup/erpc_setup_rpmsg_lite_rtos_master.cpp +++ b/erpc_c/setup/erpc_setup_rpmsg_lite_rtos_master.cpp @@ -17,7 +17,7 @@ using namespace erpc; //////////////////////////////////////////////////////////////////////////////// #if !defined(SH_MEM_TOTAL_SIZE) -#define SH_MEM_TOTAL_SIZE (6144) +#define SH_MEM_TOTAL_SIZE (6144U) #endif #if defined(__ICCARM__) /* IAR Workbench */ @@ -25,7 +25,7 @@ using namespace erpc; char rpmsg_lite_base[SH_MEM_TOTAL_SIZE]; #elif defined(__CC_ARM) || defined(__ARMCC_VERSION) /* Keil MDK */ char rpmsg_lite_base[SH_MEM_TOTAL_SIZE] __attribute__((section("rpmsg_sh_mem_section"))); -#elif defined(__GNUC__) /* LPCXpresso */ +#elif defined(__GNUC__) char rpmsg_lite_base[SH_MEM_TOTAL_SIZE] __attribute__((section(".noinit.$rpmsg_sh_mem"))); #else #error "RPMsg: Please provide your definition of rpmsg_lite_base[]!" diff --git a/erpc_c/setup/erpc_setup_rpmsg_tty_rtos_remote.cpp b/erpc_c/setup/erpc_setup_rpmsg_tty_rtos_remote.cpp index a3a1662e5..19c93f86e 100644 --- a/erpc_c/setup/erpc_setup_rpmsg_tty_rtos_remote.cpp +++ b/erpc_c/setup/erpc_setup_rpmsg_tty_rtos_remote.cpp @@ -37,7 +37,7 @@ erpc_transport_t erpc_transport_rpmsg_lite_tty_rtos_remote_init(uint32_t src_add return NULL; } -void erpc_transport_rpmsg_lite_tty_rtos_deinit() +void erpc_transport_rpmsg_lite_tty_rtos_deinit(void) { s_transport.destroy(); } diff --git a/erpc_c/setup/erpc_transport_setup.h b/erpc_c/setup/erpc_transport_setup.h index 3d9daf9dd..27b020fb9 100644 --- a/erpc_c/setup/erpc_transport_setup.h +++ b/erpc_c/setup/erpc_transport_setup.h @@ -279,7 +279,7 @@ void erpc_transport_rpmsg_lite_tty_rtos_deinit(void); * @brief Create an Linux RPMSG endpoint transport. * * This function is using RPMSG endpoints based on this implementation: - * https://github.com/NXPmicro/rpmsg-sysfs/tree/0aa1817545a765c200b1b2f9b6680a420dcf9171 . + * github.com/NXPmicro/rpmsg-sysfs/tree/0aa1817545a765c200b1b2f9b6680a420dcf9171 . * * When local/remote address is set to '-1', then default addresses will be used. * When type is set to '0', then Datagram model will be used, else Stream. diff --git a/erpc_c/transports/erpc_dspi_master_transport.cpp b/erpc_c/transports/erpc_dspi_master_transport.cpp index e740b70a3..0266feeb0 100644 --- a/erpc_c/transports/erpc_dspi_master_transport.cpp +++ b/erpc_c/transports/erpc_dspi_master_transport.cpp @@ -1,6 +1,6 @@ /* * Copyright (c) 2014-2016, Freescale Semiconductor, Inc. - * Copyright 2016 NXP + * Copyright 2016-2020 NXP * All rights reserved. * * @@ -18,6 +18,19 @@ using namespace erpc; +//////////////////////////////////////////////////////////////////////////////// +// Definitions +//////////////////////////////////////////////////////////////////////////////// + +#ifndef ERPC_BOARD_SPI_SLAVE_READY_USE_GPIO +#define ERPC_BOARD_SPI_SLAVE_READY_MARKER1 0xAB +#define ERPC_BOARD_SPI_SLAVE_READY_MARKER2 0xCD +#else +#ifndef ERPC_BOARD_DSPI_INT_GPIO +#error "Please define the ERPC_BOARD_DSPI_INT_GPIO used to notify when the DSPI Slave is ready to transmit" +#endif +#endif + //////////////////////////////////////////////////////////////////////////////// // Variables //////////////////////////////////////////////////////////////////////////////// @@ -28,6 +41,64 @@ static volatile bool s_isSlaveReady = false; // Code //////////////////////////////////////////////////////////////////////////////// +#ifdef ERPC_BOARD_SPI_SLAVE_READY_USE_GPIO +/* @brief Initialize the GPIO used to notify the SPI Master */ +static inline void DSpiMasterTransport_NotifyTransferGpioInit(void) +{ + gpio_pin_config_t gpioConfig; + + gpioConfig.pinDirection = kGPIO_DigitalInput; + + PORT_SetPinInterruptConfig(ERPC_BOARD_DSPI_INT_PORT, ERPC_BOARD_DSPI_INT_PIN, kPORT_InterruptFallingEdge); + EnableIRQ(ERPC_BOARD_DSPI_INT_PIN_IRQ); + + GPIO_PinInit(ERPC_BOARD_DSPI_INT_GPIO, ERPC_BOARD_DSPI_INT_PIN, &gpioConfig); + if (!GPIO_PinRead(ERPC_BOARD_DSPI_INT_GPIO, ERPC_BOARD_DSPI_INT_PIN)) + { + s_isSlaveReady = true; + } +} + +static inline void DSpidevMasterTransport_WaitForSlaveReadyGpio(void) +{ + while (!s_isSlaveReady) + { + } +} +#else +static inline void DSpidevMasterTransport_WaitForSlaveReadyMarker(SPI_Type *spiBaseAddr) +{ + uint8_t detected = 0; + uint8_t data; + dspi_transfer_t masterXferSlaveReadyMarker; + + while (1) + { + masterXferSlaveReadyMarker.txData = NULL; + masterXferSlaveReadyMarker.rxData = &data; + masterXferSlaveReadyMarker.dataSize = 1; + masterXferSlaveReadyMarker.configFlags = kDSPI_MasterCtar0 | kDSPI_MasterPcs0; + + if (kStatus_Success == DSPI_MasterTransferBlocking(spiBaseAddr, &masterXferSlaveReadyMarker)) + { + if (ERPC_BOARD_SPI_SLAVE_READY_MARKER1 == data) + { + detected = 1; + } + else if (detected && (ERPC_BOARD_SPI_SLAVE_READY_MARKER2 == data)) + { + break; + } + else + { + detected = 0; + // Thread::sleep(100); + } + } + } +} +#endif + DspiMasterTransport::DspiMasterTransport(SPI_Type *spiBaseAddr, uint32_t baudRate, uint32_t srcClock_Hz) : m_spiBaseAddr(spiBaseAddr) , m_baudRate(baudRate) @@ -43,22 +114,14 @@ DspiMasterTransport::~DspiMasterTransport(void) erpc_status_t DspiMasterTransport::init(void) { dspi_master_config_t dspiConfig; - gpio_pin_config_t gpioConfig; DSPI_MasterGetDefaultConfig(&dspiConfig); dspiConfig.ctarConfig.baudRate = m_baudRate; DSPI_MasterInit(m_spiBaseAddr, &dspiConfig, m_srcClock_Hz); - gpioConfig.pinDirection = kGPIO_DigitalInput; - - PORT_SetPinInterruptConfig(ERPC_BOARD_DSPI_INT_PORT, ERPC_BOARD_DSPI_INT_PIN, kPORT_InterruptFallingEdge); - EnableIRQ(ERPC_BOARD_DSPI_INT_PIN_IRQ); - - GPIO_PinInit(ERPC_BOARD_DSPI_INT_GPIO, ERPC_BOARD_DSPI_INT_PIN, &gpioConfig); - if (!GPIO_PinRead(ERPC_BOARD_DSPI_INT_GPIO, ERPC_BOARD_DSPI_INT_PIN)) - { - s_isSlaveReady = true; - } +#ifdef ERPC_BOARD_SPI_SLAVE_READY_USE_GPIO + DSpiMasterTransport_NotifyTransferGpioInit(); +#endif return kErpcStatus_Success; } @@ -73,12 +136,16 @@ erpc_status_t DspiMasterTransport::underlyingReceive(uint8_t *data, uint32_t siz masterXfer.dataSize = size; masterXfer.configFlags = kDSPI_MasterCtar0 | kDSPI_MasterPcs0; - while (!s_isSlaveReady) - { - } +#ifdef ERPC_BOARD_SPI_SLAVE_READY_USE_GPIO + DSpidevMasterTransport_WaitForSlaveReadyGpio(); +#else + DSpidevMasterTransport_WaitForSlaveReadyMarker(m_spiBaseAddr); +#endif status = DSPI_MasterTransferBlocking(m_spiBaseAddr, &masterXfer); +#ifdef ERPC_BOARD_SPI_SLAVE_READY_USE_GPIO s_isSlaveReady = false; +#endif return status != kStatus_Success ? kErpcStatus_ReceiveFailed : kErpcStatus_Success; } @@ -93,16 +160,19 @@ erpc_status_t DspiMasterTransport::underlyingSend(const uint8_t *data, uint32_t masterXfer.dataSize = size; masterXfer.configFlags = kDSPI_MasterCtar0 | kDSPI_MasterPcs0; - while (!s_isSlaveReady) - { - } +#ifdef ERPC_BOARD_SPI_SLAVE_READY_USE_GPIO + DSpidevMasterTransport_WaitForSlaveReadyGpio(); +#endif status = DSPI_MasterTransferBlocking(m_spiBaseAddr, &masterXfer); +#ifdef ERPC_BOARD_SPI_SLAVE_READY_USE_GPIO s_isSlaveReady = false; +#endif return status != kStatus_Success ? kErpcStatus_SendFailed : kErpcStatus_Success; } +#ifdef ERPC_BOARD_SPI_SLAVE_READY_USE_GPIO extern "C" { void ERPC_BOARD_DSPI_INT_PIN_IRQ_HANDLER(void) { @@ -111,3 +181,4 @@ void ERPC_BOARD_DSPI_INT_PIN_IRQ_HANDLER(void) s_isSlaveReady = true; } } +#endif diff --git a/erpc_c/transports/erpc_dspi_slave_transport.cpp b/erpc_c/transports/erpc_dspi_slave_transport.cpp index 2f6f55db5..7fde066a9 100644 --- a/erpc_c/transports/erpc_dspi_slave_transport.cpp +++ b/erpc_c/transports/erpc_dspi_slave_transport.cpp @@ -1,6 +1,6 @@ /* * Copyright (c) 2014-2016, Freescale Semiconductor, Inc. - * Copyright 2016 NXP + * Copyright 2016-2020 NXP * All rights reserved. * * @@ -14,9 +14,24 @@ #include "fsl_gpio.h" #include +#include +using namespace std; using namespace erpc; +//////////////////////////////////////////////////////////////////////////////// +// Definitions +//////////////////////////////////////////////////////////////////////////////// +#ifndef ERPC_BOARD_SPI_SLAVE_READY_USE_GPIO +#define ERPC_BOARD_SPI_SLAVE_READY_MARKER_LEN 2 +#define ERPC_BOARD_SPI_SLAVE_READY_MARKER1 0xAB +#define ERPC_BOARD_SPI_SLAVE_READY_MARKER2 0xCD +#else +#ifndef ERPC_BOARD_DSPI_INT_GPIO +#error "Please define the ERPC_BOARD_DSPI_INT_GPIO used to notify when the DSPI Slave is ready to transmit" +#endif +#endif + //////////////////////////////////////////////////////////////////////////////// // Variables //////////////////////////////////////////////////////////////////////////////// @@ -28,9 +43,33 @@ static volatile bool s_isTransferCompleted = false; // Code //////////////////////////////////////////////////////////////////////////////// -void DSPI_SlaveUserCallback(SPI_Type *base, dspi_slave_handle_t *handle, erpc_status_t status, void *userData) +#ifdef ERPC_BOARD_SPI_SLAVE_READY_USE_GPIO +/* @brief Initialize the GPIO used to notify the SPI Master */ +static inline void DSpiSlaveTransport_NotifyTransferGpioInit(void) +{ + gpio_pin_config_t gpioConfig; + + gpioConfig.pinDirection = kGPIO_DigitalOutput; + gpioConfig.outputLogic = 1U; + + GPIO_PinInit(ERPC_BOARD_DSPI_INT_GPIO, ERPC_BOARD_DSPI_INT_PIN, &gpioConfig); +} + +/* @brief Notify the SPI Master that the Slave is ready for a new transfer */ +static inline void DSpiSlaveTransport_NotifyTransferGpioReady(void) +{ + GPIO_PortClear(ERPC_BOARD_DSPI_INT_GPIO, 1U << ERPC_BOARD_DSPI_INT_PIN); +} + +/* @brief Notify the SPI Master that the Slave has finished the transfer */ +static inline void DSpiSlaveTransport_NotifyTransferGpioCompleted(void) { GPIO_PortSet(ERPC_BOARD_DSPI_INT_GPIO, 1U << ERPC_BOARD_DSPI_INT_PIN); +} +#endif + +static void DSPI_SlaveUserCallback(SPI_Type *base, dspi_slave_handle_t *handle, erpc_status_t status, void *userData) +{ s_isTransferCompleted = true; } @@ -46,25 +85,26 @@ DspiSlaveTransport::~DspiSlaveTransport(void) { if (m_isInited) { - GPIO_PortClear(ERPC_BOARD_DSPI_INT_GPIO, 1U << ERPC_BOARD_DSPI_INT_PIN); +#ifdef ERPC_BOARD_SPI_SLAVE_READY_USE_GPIO + DSpiSlaveTransport_NotifyTransferGpioCompleted(); +#endif + DSPI_Deinit(m_spiBaseAddr); + m_isInited = false; } - DSPI_Deinit(m_spiBaseAddr); } erpc_status_t DspiSlaveTransport::init(void) { dspi_slave_config_t dspiConfig; - gpio_pin_config_t gpioConfig; DSPI_SlaveGetDefaultConfig(&dspiConfig); DSPI_SlaveInit(m_spiBaseAddr, &dspiConfig); DSPI_SlaveTransferCreateHandle(m_spiBaseAddr, &g_s_handle, DSPI_SlaveUserCallback, NULL); - gpioConfig.pinDirection = kGPIO_DigitalOutput; - gpioConfig.outputLogic = 1U; - - GPIO_PinInit(ERPC_BOARD_DSPI_INT_GPIO, ERPC_BOARD_DSPI_INT_PIN, &gpioConfig); +#ifdef ERPC_BOARD_SPI_SLAVE_READY_USE_GPIO + DSpiSlaveTransport_NotifyTransferGpioInit(); +#endif m_isInited = true; return kErpcStatus_Success; @@ -83,9 +123,17 @@ erpc_status_t DspiSlaveTransport::underlyingReceive(uint8_t *data, uint32_t size status = DSPI_SlaveTransferNonBlocking(m_spiBaseAddr, &g_s_handle, &slaveXfer); - GPIO_PortClear(ERPC_BOARD_DSPI_INT_GPIO, 1U << ERPC_BOARD_DSPI_INT_PIN); - while (!s_isTransferCompleted) + if (kStatus_Success == status) { +#ifdef ERPC_BOARD_SPI_SLAVE_READY_USE_GPIO + DSpiSlaveTransport_NotifyTransferGpioReady(); +#endif + while (!s_isTransferCompleted) + { + } +#ifdef ERPC_BOARD_SPI_SLAVE_READY_USE_GPIO + DSpiSlaveTransport_NotifyTransferGpioCompleted(); +#endif } return status != kStatus_Success ? kErpcStatus_ReceiveFailed : kErpcStatus_Success; @@ -95,19 +143,49 @@ erpc_status_t DspiSlaveTransport::underlyingSend(const uint8_t *data, uint32_t s { erpc_status_t status; dspi_transfer_t slaveXfer; + s_isTransferCompleted = false; +#ifdef ERPC_BOARD_SPI_SLAVE_READY_USE_GPIO slaveXfer.txData = (uint8_t *)data; slaveXfer.rxData = NULL; slaveXfer.dataSize = size; slaveXfer.configFlags = kDSPI_SlaveCtar0; - s_isTransferCompleted = false; +#else + uint8_t *dspiData = new (nothrow) uint8_t[size + ERPC_BOARD_SPI_SLAVE_READY_MARKER_LEN]; + if (dspiData != NULL) + { + dspiData[0] = ERPC_BOARD_SPI_SLAVE_READY_MARKER1; + dspiData[1] = ERPC_BOARD_SPI_SLAVE_READY_MARKER2; + memcpy(&dspiData[ERPC_BOARD_SPI_SLAVE_READY_MARKER_LEN], data, size); + } + else + { + return kErpcStatus_SendFailed; + } + + slaveXfer.txData = dspiData; + slaveXfer.rxData = NULL; + slaveXfer.dataSize = size + ERPC_BOARD_SPI_SLAVE_READY_MARKER_LEN; + slaveXfer.configFlags = kDSPI_SlaveCtar0; +#endif status = DSPI_SlaveTransferNonBlocking(m_spiBaseAddr, &g_s_handle, &slaveXfer); - GPIO_PortClear(ERPC_BOARD_DSPI_INT_GPIO, 1U << ERPC_BOARD_DSPI_INT_PIN); - while (!s_isTransferCompleted) + if (kStatus_Success == status) { +#ifdef ERPC_BOARD_SPI_SLAVE_READY_USE_GPIO + DSpiSlaveTransport_NotifyTransferGpioReady(); +#endif + while (!s_isTransferCompleted) + { + } +#ifdef ERPC_BOARD_SPI_SLAVE_READY_USE_GPIO + DSpiSlaveTransport_NotifyTransferGpioCompleted(); +#endif } +#ifndef ERPC_BOARD_SPI_SLAVE_READY_USE_GPIO + delete[] dspiData; +#endif return status != kStatus_Success ? kErpcStatus_SendFailed : kErpcStatus_Success; } diff --git a/erpc_c/transports/erpc_mu_transport.cpp b/erpc_c/transports/erpc_mu_transport.cpp index 6012294c7..f86337b93 100644 --- a/erpc_c/transports/erpc_mu_transport.cpp +++ b/erpc_c/transports/erpc_mu_transport.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2017 NXP + * Copyright 2017-2020 NXP * All rights reserved. * * @@ -79,7 +79,7 @@ MUTransport::MUTransport(void) , m_txMsgSize(0) , m_txCntBytes(0) , m_txBuffer(NULL) -#if ERPC_THREADS +#if !ERPC_THREADS_IS(NONE) , m_rxSemaphore() , m_txSemaphore() , m_sendLock() @@ -146,7 +146,7 @@ void MUTransport::rx_cb(void) if (m_rxCntBytes >= m_rxMsgSize) { m_rxBuffer = NULL; -#if ERPC_THREADS +#if !ERPC_THREADS_IS(NONE) MU_DisableInterrupts(m_muBase, (1U << (MU_CR_RIEn_SHIFT + MU_RR_COUNT - MU_REG_COUNT))); m_rxSemaphore.putFromISR(); #endif @@ -177,7 +177,7 @@ void MUTransport::tx_cb(void) // unblock caller of the send function m_txBuffer = NULL; -#if ERPC_THREADS +#if !ERPC_THREADS_IS(NONE) m_txSemaphore.putFromISR(); #endif } @@ -190,7 +190,7 @@ erpc_status_t MUTransport::receive(MessageBuffer *message) return kErpcStatus_ReceiveFailed; } -#if ERPC_THREADS +#if !ERPC_THREADS_IS(NONE) Mutex::Guard lock(m_receiveLock); #endif @@ -202,7 +202,7 @@ erpc_status_t MUTransport::receive(MessageBuffer *message) MU_EnableInterrupts(m_muBase, (1U << (MU_CR_RIEn_SHIFT + MU_RR_COUNT - MU_REG_COUNT))); // wait until the receiving is not complete -#if ERPC_THREADS +#if !ERPC_THREADS_IS(NONE) m_rxSemaphore.get(); #else while (m_rxBuffer) @@ -223,7 +223,7 @@ erpc_status_t MUTransport::send(MessageBuffer *message) return kErpcStatus_SendFailed; } -#if ERPC_THREADS +#if !ERPC_THREADS_IS(NONE) Mutex::Guard lock(m_sendLock); #endif @@ -253,7 +253,7 @@ erpc_status_t MUTransport::send(MessageBuffer *message) // enable MU tx empty irq from the last mu tx reg MU_EnableInterrupts(m_muBase, (1U << (MU_CR_TIEn_SHIFT + MU_TR_COUNT - MU_REG_COUNT))); // wait until the sending is not complete -#if ERPC_THREADS +#if !ERPC_THREADS_IS(NONE) m_txSemaphore.get(); #else while (m_txBuffer) diff --git a/erpc_c/transports/erpc_mu_transport.h b/erpc_c/transports/erpc_mu_transport.h index 25e1581df..034e2e74d 100644 --- a/erpc_c/transports/erpc_mu_transport.h +++ b/erpc_c/transports/erpc_mu_transport.h @@ -1,5 +1,5 @@ /* - * Copyright 2017 NXP + * Copyright 2017-2020 NXP * All rights reserved. * * @@ -10,7 +10,7 @@ #define _EMBEDDED_RPC__MU_TRANSPORT_H_ #include "erpc_config_internal.h" -#if ERPC_THREADS +#if !ERPC_THREADS_IS(NONE) #include "erpc_threading.h" #endif #include "erpc_message_buffer.h" @@ -123,7 +123,7 @@ class MUTransport : public Transport * * @return True if exist new message, else false. */ - virtual bool hasMessage() { return m_newMessage; } + virtual bool hasMessage(void) { return m_newMessage; } #if ERPC_TRANSPORT_MU_USE_MCMGR /*! @@ -185,7 +185,7 @@ class MUTransport : public Transport uint32_t m_txCntBytes; /*!< Count of currently received bytes of message */ uint32_t *volatile m_txBuffer; /*!< Pointer to buffer from which is copied data to MU registers during sending */ -#if ERPC_THREADS +#if !ERPC_THREADS_IS(NONE) Semaphore m_rxSemaphore; /*!< Semaphore used by RTOS to block task until the receiving is not complete */ Semaphore m_txSemaphore; /*!< Semaphore used by RTOS to block task until the sending is not complete */ diff --git a/erpc_c/transports/erpc_rpmsg_linux_transport.h b/erpc_c/transports/erpc_rpmsg_linux_transport.h index ebc7c6a6b..74d6f0da7 100644 --- a/erpc_c/transports/erpc_rpmsg_linux_transport.h +++ b/erpc_c/transports/erpc_rpmsg_linux_transport.h @@ -7,7 +7,7 @@ */ /* Download "rpmsg_linux_endpoint.h/.cpp" from - * https://github.com/EmbeddedRPC/erpc-imx-demos/tree/master/middleware/rpmsg-cpp */ + * github.com/EmbeddedRPC/erpc-imx-demos/tree/master/middleware/rpmsg-cpp */ #include "erpc_rpmsg_linux_endpoint.h" #include "erpc_transport.h" @@ -19,7 +19,7 @@ namespace erpc { /*! * @brief RPMSG Linux transport to send/receive messages through RPMSG endpoints - * based on https://github.com/NXPmicro/rpmsg-sysfs/tree/0aa1817545a765c200b1b2f9b6680a420dcf9171 + * based on github.com/NXPmicro/rpmsg-sysfs/tree/0aa1817545a765c200b1b2f9b6680a420dcf9171 * implementation. * @ingroup rpmsg_linux_transport */ diff --git a/erpc_c/transports/erpc_spi_slave_transport.cpp b/erpc_c/transports/erpc_spi_slave_transport.cpp index 1ee3ad105..90b57db25 100644 --- a/erpc_c/transports/erpc_spi_slave_transport.cpp +++ b/erpc_c/transports/erpc_spi_slave_transport.cpp @@ -69,7 +69,7 @@ static inline void SpiSlaveTransport_NotifyTransferGpioCompleted() } #endif -void SPI_SlaveUserCallback(SPI_Type *base, spi_slave_handle_t *handle, erpc_status_t status, void *userData) +static void SPI_SlaveUserCallback(SPI_Type *base, spi_slave_handle_t *handle, erpc_status_t status, void *userData) { s_isTransferCompleted = true; } diff --git a/erpc_c/transports/erpc_uart_cmsis_transport.cpp b/erpc_c/transports/erpc_uart_cmsis_transport.cpp index 2cc328166..debfc16bc 100644 --- a/erpc_c/transports/erpc_uart_cmsis_transport.cpp +++ b/erpc_c/transports/erpc_uart_cmsis_transport.cpp @@ -27,7 +27,7 @@ static UartTransport *s_uart_instance = NULL; UartTransport::UartTransport(ARM_DRIVER_USART *uartDrv) : m_uartDrv(uartDrv) -#if ERPC_THREADS +#if !ERPC_THREADS_IS(NONE) , m_rxSemaphore() , m_txSemaphore() #endif @@ -42,7 +42,7 @@ UartTransport::~UartTransport(void) void UartTransport::tx_cb(void) { -#if ERPC_THREADS +#if !ERPC_THREADS_IS(NONE) m_txSemaphore.putFromISR(); #else s_isTransferSendCompleted = true; @@ -51,7 +51,7 @@ void UartTransport::tx_cb(void) void UartTransport::rx_cb(void) { -#if ERPC_THREADS +#if !ERPC_THREADS_IS(NONE) m_rxSemaphore.putFromISR(); #else s_isTransferReceiveCompleted = true; @@ -59,7 +59,7 @@ void UartTransport::rx_cb(void) } /* Transfer callback */ -void TransferCallback(uint32_t event) +static void TransferCallback(uint32_t event) { UartTransport *transport = s_uart_instance; @@ -105,7 +105,7 @@ erpc_status_t UartTransport::underlyingReceive(uint8_t *data, uint32_t size) if (status == ARM_DRIVER_OK) { /* wait until the receiving is finished */ -#if ERPC_THREADS +#if !ERPC_THREADS_IS(NONE) m_rxSemaphore.get(); #else while (!s_isTransferReceiveCompleted) @@ -126,7 +126,7 @@ erpc_status_t UartTransport::underlyingSend(const uint8_t *data, uint32_t size) if (status == ARM_DRIVER_OK) { /* wait until the sending is finished */ -#if ERPC_THREADS +#if !ERPC_THREADS_IS(NONE) m_txSemaphore.get(); #else while (!s_isTransferSendCompleted) diff --git a/erpc_c/transports/erpc_uart_cmsis_transport.h b/erpc_c/transports/erpc_uart_cmsis_transport.h index c65f2983b..efcecf5f7 100644 --- a/erpc_c/transports/erpc_uart_cmsis_transport.h +++ b/erpc_c/transports/erpc_uart_cmsis_transport.h @@ -11,7 +11,7 @@ #define _EMBEDDED_RPC__UART_TRANSPORT_H_ #include "erpc_config_internal.h" -#if ERPC_THREADS +#if !ERPC_THREADS_IS(NONE) #include "erpc_threading.h" #endif #include "erpc_framed_transport.h" @@ -76,7 +76,7 @@ class UartTransport : public FramedTransport protected: ARM_DRIVER_USART *m_uartDrv; /*!< Access structure of the USART Driver */ -#if ERPC_THREADS +#if !ERPC_THREADS_IS(NONE) Semaphore m_rxSemaphore; /*!< Semaphore used by RTOS to block task until the receiving is not complete */ Semaphore m_txSemaphore; /*!< Semaphore used by RTOS to block task until the sending is not complete */ #endif diff --git a/erpc_c/transports/erpc_usb_cdc_transport.cpp b/erpc_c/transports/erpc_usb_cdc_transport.cpp index f05fb5784..9e4afb267 100644 --- a/erpc_c/transports/erpc_usb_cdc_transport.cpp +++ b/erpc_c/transports/erpc_usb_cdc_transport.cpp @@ -69,7 +69,7 @@ static void ERPC_SerialManagerRxCallback(void *callbackParam, serial_manager_cal void UsbCdcTransport::tx_cb(void) { -#if ERPC_THREADS +#if !ERPC_THREADS_IS(NONE) m_txSemaphore.putFromISR(); #else s_isTransferSendCompleted = true; @@ -78,7 +78,7 @@ void UsbCdcTransport::tx_cb(void) void UsbCdcTransport::rx_cb(void) { -#if ERPC_THREADS +#if !ERPC_THREADS_IS(NONE) m_rxSemaphore.putFromISR(); #else s_isTransferReceiveCompleted = true; @@ -93,7 +93,7 @@ UsbCdcTransport::UsbCdcTransport(serial_handle_t serialHandle, serial_manager_co , m_usbCdcConfig(usbCdcConfig) , m_usbRingBuffer(usbRingBuffer) , m_usbRingBufferLength(usbRingBufferLength) -#if ERPC_THREADS +#if !ERPC_THREADS_IS(NONE) , m_rxSemaphore() , m_txSemaphore() #endif @@ -148,7 +148,7 @@ erpc_status_t UsbCdcTransport::underlyingReceive(uint8_t *data, uint32_t size) if (kStatus_SerialManager_Success == SerialManager_ReadNonBlocking(s_serialReadHandle, data, size)) { /* wait until the receiving is finished */ -#if ERPC_THREADS +#if !ERPC_THREADS_IS(NONE) m_rxSemaphore.get(); #else while (!s_isTransferReceiveCompleted) @@ -168,7 +168,7 @@ erpc_status_t UsbCdcTransport::underlyingSend(const uint8_t *data, uint32_t size if (kStatus_SerialManager_Success == SerialManager_WriteNonBlocking(s_serialWriteHandle, (uint8_t *)data, size)) { /* wait until the sending is finished */ -#if ERPC_THREADS +#if !ERPC_THREADS_IS(NONE) m_txSemaphore.get(); #else while (!s_isTransferSendCompleted) diff --git a/erpc_c/transports/erpc_usb_cdc_transport.h b/erpc_c/transports/erpc_usb_cdc_transport.h index 403a20785..0d6879307 100644 --- a/erpc_c/transports/erpc_usb_cdc_transport.h +++ b/erpc_c/transports/erpc_usb_cdc_transport.h @@ -10,7 +10,7 @@ #define _EMBEDDED_RPC__USB_CDC_TRANSPORT_H_ #include "erpc_config_internal.h" -#if ERPC_THREADS +#if !ERPC_THREADS_IS(NONE) #include "erpc_threading.h" #endif @@ -84,7 +84,7 @@ class UsbCdcTransport : public FramedTransport void tx_cb(void); protected: -#if ERPC_THREADS +#if !ERPC_THREADS_IS(NONE) Semaphore m_rxSemaphore; /*!< Semaphore used by RTOS to block task until the receiving is not complete */ Semaphore m_txSemaphore; /*!< Semaphore used by RTOS to block task until the sending is not complete */ #endif From ee2ec008b6b00f139c699d477215682e197c5594 Mon Sep 17 00:00:00 2001 From: farrenv Date: Fri, 12 Mar 2021 10:02:35 -0500 Subject: [PATCH 96/96] deletions for compatibility with mbed-rpc, update to 1.8.0 --- .../port/erpc_setup_extensions_freertos.cpp | 90 -------- erpc_c/port/erpc_spidev.cpp | 82 ------- erpc_c/port/erpc_spidev.h | 30 --- erpc_c/port/erpc_sysgpio.c | 209 ----------------- erpc_c/port/erpc_threading_win32.cpp | 211 ------------------ erpc_c/port/erpc_threading_zephyr.cpp | 145 ------------ 6 files changed, 767 deletions(-) delete mode 100644 erpc_c/port/erpc_setup_extensions_freertos.cpp delete mode 100644 erpc_c/port/erpc_spidev.cpp delete mode 100644 erpc_c/port/erpc_spidev.h delete mode 100644 erpc_c/port/erpc_sysgpio.c delete mode 100644 erpc_c/port/erpc_threading_win32.cpp delete mode 100644 erpc_c/port/erpc_threading_zephyr.cpp diff --git a/erpc_c/port/erpc_setup_extensions_freertos.cpp b/erpc_c/port/erpc_setup_extensions_freertos.cpp deleted file mode 100644 index 585e6d5f6..000000000 --- a/erpc_c/port/erpc_setup_extensions_freertos.cpp +++ /dev/null @@ -1,90 +0,0 @@ -/* - * Copyright 2020 NXP - * Copyright 2020 ACRIOS Systems s.r.o. - * All rights reserved. - * - * - * SPDX-License-Identifier: BSD-3-Clause - */ - -#include "erpc_setup_extensions.h" -#include "erpc_threading.h" - -#include - -using namespace erpc; - -static Semaphore *s_erpc_call_in_progress = NULL; -static TimerHandle_t s_erpc_call_timer_cb = NULL; - -void erpc::erpc_pre_cb_default(void) -{ - assert(s_erpc_call_in_progress && - "If you want use default pre cb action, do not forget call erpc_init_call_progress_detection_default."); - s_erpc_call_in_progress->get(s_erpc_call_in_progress->kWaitForever); - assert(s_erpc_call_timer_cb && - "If you want use default pre cb action, do not forget call erpc_init_call_progress_detection_default."); - xTimerStart(s_erpc_call_timer_cb, 0); -} - -void erpc::erpc_post_cb_default(void) -{ - xTimerStop(s_erpc_call_timer_cb, 0); - s_erpc_call_in_progress->put(); -} - -static void erpc_call_timer_cb_default(TimerHandle_t xTimer) -{ - assert(1 != 1 && "eRPC task freezed."); -} - -void erpc_init_call_progress_detection_default( - erpc_call_timer_cb_default_t erpc_call_timer_cb = erpc_call_timer_cb_default, uint32_t waitTimeMs = 5 * 60 * 1000) -{ - s_erpc_call_in_progress = new Semaphore(1); - assert(s_erpc_call_in_progress && "Creating eRPC semaphore failed."); - - s_erpc_call_timer_cb = - xTimerCreate("Erpc client call timer", waitTimeMs / portTICK_PERIOD_MS, pdFALSE, NULL, erpc_call_timer_cb); - assert(s_erpc_call_timer_cb && "Creating eRPC timer failed."); -} - -void erpc_deinit_call_progress_detection_default(void) -{ - if (s_erpc_call_in_progress) - { - delete s_erpc_call_in_progress; - s_erpc_call_in_progress = NULL; - } - - if (s_erpc_call_timer_cb) - { - xTimerDelete(s_erpc_call_timer_cb, 0); - s_erpc_call_timer_cb = NULL; - } -} - -bool erpc_is_call_in_progress_default(void) -{ - assert(s_erpc_call_in_progress && - "If you want use default pre cb action, do not forget call erpc_init_call_progress_detection_default."); - if (s_erpc_call_in_progress->get(0)) - { - s_erpc_call_in_progress->put(); - return false; - } - return true; -} - -void erpc_reset_in_progress_state_default(void) -{ - - assert(s_erpc_call_in_progress && - "If you want use default pre cb action, do not forget call erpc_init_call_progress_detection_default."); - s_erpc_call_in_progress->get(0); - s_erpc_call_in_progress->put(); - - assert(s_erpc_call_timer_cb && - "If you want use default pre cb action, do not forget call erpc_init_call_progress_detection_default."); - xTimerStop(s_erpc_call_timer_cb, 0); -} diff --git a/erpc_c/port/erpc_spidev.cpp b/erpc_c/port/erpc_spidev.cpp deleted file mode 100644 index 4adfbd131..000000000 --- a/erpc_c/port/erpc_spidev.cpp +++ /dev/null @@ -1,82 +0,0 @@ -/* - * Copyright 2020 NXP - * All rights reserved. - * - * - * SPDX-License-Identifier: BSD-3-Clause - */ - -#include "erpc_spidev.h" - -#include -#include -#include -#include -#include -#include -#include - -int spidev_open(const char *port) -{ - int fd; - - fd = open(port, O_RDWR); - if (-1 == fd) - { - fprintf(stderr, "Could not open spidev port (%d).\r\n", errno); - } - return fd; -} - -int spidev_set_mode(int fd, unsigned char mode) -{ - if (-1 == ioctl(fd, SPI_IOC_WR_MODE, &mode)) - { - fprintf(stderr, "Could not set mode for spidev port (%d).\r\n", errno); - return ERPC_SPIDEV_STATUS_FAIL; - } - return ERPC_SPIDEV_STATUS_SUCCESS; -} - -int spidev_set_speed(int fd, unsigned int speed_hz) -{ - if (-1 == ioctl(fd, SPI_IOC_WR_MAX_SPEED_HZ, &speed_hz)) - { - fprintf(stderr, "Could not set max speed for spidev port (%d).\r\n", errno); - return ERPC_SPIDEV_STATUS_FAIL; - } - return ERPC_SPIDEV_STATUS_SUCCESS; -} - -int spidev_set_wordbits(int fd, unsigned char bits) -{ - if (-1 == ioctl(fd, SPI_IOC_WR_BITS_PER_WORD, &bits)) - { - fprintf(stderr, "Could not set bits per word for spidev port (%d).\r\n", errno); - return ERPC_SPIDEV_STATUS_FAIL; - } - return ERPC_SPIDEV_STATUS_SUCCESS; -} - -int spidev_transfer(int fd, unsigned char *tx_buf, unsigned char *rx_buf, unsigned int len) -{ - struct spi_ioc_transfer spi_message; - - memset(&spi_message, 0, sizeof(spi_message)); - spi_message.tx_buf = (unsigned long)tx_buf; - spi_message.rx_buf = (unsigned long)rx_buf; - spi_message.len = len; - - if (-1 == ioctl(fd, SPI_IOC_MESSAGE(1), &spi_message)) - { - fprintf(stderr, "Could not transfer data on spidev port (%d).\r\n", errno); - return ERPC_SPIDEV_STATUS_FAIL; - } - return ERPC_SPIDEV_STATUS_SUCCESS; -} - -int spidev_close(int fd) -{ - close(fd); - return ERPC_SPIDEV_STATUS_SUCCESS; -} diff --git a/erpc_c/port/erpc_spidev.h b/erpc_c/port/erpc_spidev.h deleted file mode 100644 index 6726a9db3..000000000 --- a/erpc_c/port/erpc_spidev.h +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright 2020 NXP - * All rights reserved. - * - * - * SPDX-License-Identifier: BSD-3-Clause - */ - -#ifndef _ERPC_SPIDEV_H_ -#define _ERPC_SPIDEV_H_ - -#if __cplusplus -extern "C" { -#endif - -#define ERPC_SPIDEV_STATUS_SUCCESS 0 -#define ERPC_SPIDEV_STATUS_FAIL -1 - -int spidev_open(const char *port); -int spidev_set_mode(int fd, unsigned char mode); -int spidev_set_speed(int fd, unsigned int speed_hz); -int spidev_set_wordbits(int fd, unsigned char bits); -int spidev_transfer(int fd, unsigned char *tx_buf, unsigned char *rx_buf, unsigned int len); -int spidev_close(int fd); - -#if __cplusplus -} -#endif - -#endif /* _ERPC_SPIDEV_H_ */ diff --git a/erpc_c/port/erpc_sysgpio.c b/erpc_c/port/erpc_sysgpio.c deleted file mode 100644 index 608f6e6c2..000000000 --- a/erpc_c/port/erpc_sysgpio.c +++ /dev/null @@ -1,209 +0,0 @@ -/* - * Copyright 2020 NXP - * All rights reserved. - * - * - * SPDX-License-Identifier: BSD-3-Clause - */ - -#include "erpc_sysgpio.h" - -#include -#include -#include -#include -#include -#include -#include - -int gpio_export(int gpio) -{ - int fd; - char sysgpio[64]; - - /* Check if the gpio has already been exported */ - sprintf(sysgpio, "/sys/class/gpio/gpio%d/value", gpio); - fd = open(sysgpio, O_WRONLY); - if (-1 != fd) - { - close(fd); - return ERPC_SYSGPIO_STATUS_SUCCESS; - } - - fd = open("/sys/class/gpio/export", O_WRONLY | O_SYNC); - if (-1 == fd) - { - fprintf(stderr, "Could not open gpio export file (%d).\r\n", errno); - return -1; - } - else - { - sprintf(sysgpio, "%d", gpio); - if (strlen(sysgpio) != write(fd, sysgpio, strlen(sysgpio))) - { - fprintf(stderr, "Could not export gpio (%d) (%d).\r\n", gpio, errno); - close(fd); - return -2; - } - } - - close(fd); - return ERPC_SYSGPIO_STATUS_SUCCESS; -} - -int gpio_direction(int gpio, int direction) -{ - int fd; - char sysgpio[64]; - int ret = ERPC_SYSGPIO_STATUS_SUCCESS; - - sprintf(sysgpio, "/sys/class/gpio/gpio%d/direction", gpio); - fd = open(sysgpio, O_WRONLY | O_SYNC); - if (-1 == fd) - { - fprintf(stderr, "Could not open gpio (%d) direction file (%d).\r\n", gpio, errno); - return -1; - } - - else if (0 == direction) - { - if (3 != write(fd, "out", 3)) - { - fprintf(stderr, "Could not set gpio (%d) direction to out (low) (%d).\r\n", gpio, errno); - ret = -2; - } - } - else if (1 == direction) - { - if (2 != write(fd, "in", 2)) - { - fprintf(stderr, "Could not set gpio (%d) direction to in (%d).\r\n", gpio, errno); - ret = -3; - } - } - else if (2 == direction) - { - if (4 != write(fd, "high", 4)) - { - fprintf(stderr, "Could not set gpio (%d) direction to out (high) (%d).\r\n", gpio, errno); - ret = -4; - } - } - - close(fd); - return ret; -} - -int gpio_set_edge(int gpio, char *edge) -{ - int fd; - char sysgpio[64]; - unsigned char len = 0; - - sprintf(sysgpio, "/sys/class/gpio/gpio%d/edge", gpio); - fd = open(sysgpio, O_WRONLY | O_SYNC); - if (-1 == fd) - { - fprintf(stderr, "Could not open gpio (%d) edge file (%d).\r\n", gpio, errno); - return -1; - } - - len = strlen(edge) + 1; - if (len != write(fd, edge, len)) - { - fprintf(stderr, "Could not set gpio (%d) edge (%d).\r\n", gpio, errno); - close(fd); - return -2; - } - - close(fd); - return ERPC_SYSGPIO_STATUS_SUCCESS; -} - -int gpio_read(int gpio) -{ - int fd; - char sysgpio[64]; - char in; - - sprintf(sysgpio, "/sys/class/gpio/gpio%d/value", gpio); - fd = open(sysgpio, O_RDWR | O_SYNC); - if (-1 == fd) - { - fprintf(stderr, "Could not open gpio (%d) value file (%d).\r\n", gpio, errno); - return -1; - } - - if (1 != read(fd, &in, 1)) - { - fprintf(stderr, "Could not read gpio (%d) value (%d).\r\n", gpio, errno); - close(fd); - return -2; - } - - close(fd); - return atoi(&in); -} - -int gpio_open(int gpio) -{ - int fd; - char sysgpio[64]; - char in; - - sprintf(sysgpio, "/sys/class/gpio/gpio%d/value", gpio); - fd = open(sysgpio, O_RDWR | O_SYNC); - if (-1 == fd) - { - fprintf(stderr, "Could not open gpio (%d) value file (%d).\r\n", gpio, errno); - return -1; - } - - /* perform a dummy read to clean the events */ - if (1 != read(fd, &in, 1)) - { - fprintf(stderr, "Could not read gpio (%d) value (%d).\r\n", gpio, errno); - close(fd); - return -2; - } - - return fd; -} - -int gpio_close(int fd) -{ - return close(fd); -} - -int gpio_poll(int fd, int timeout) -{ - int pollr; - struct pollfd fds; - - fds.fd = fd; - fds.events = POLLPRI | POLLERR; - ; - pollr = poll(&fds, 1, timeout); - - if (pollr < 0) - { - fprintf(stderr, "Could not poll gpio (%d).\r\n", errno); - return -1; - } - - if (fds.revents & POLLPRI) - { - /* perform a dummy read to clean the events */ - char val; - lseek(fds.fd, 0, SEEK_SET); - read(fds.fd, &val, 1); - return 1; - } - else if (fds.revents & POLLERR) - { - fprintf(stderr, "Error while polling gpio (%d).\r\n", errno); - return -2; - } - - return ERPC_SYSGPIO_STATUS_SUCCESS; -} diff --git a/erpc_c/port/erpc_threading_win32.cpp b/erpc_c/port/erpc_threading_win32.cpp deleted file mode 100644 index 708ffa129..000000000 --- a/erpc_c/port/erpc_threading_win32.cpp +++ /dev/null @@ -1,211 +0,0 @@ -/* - * Copyright (c) 2014-2016, Freescale Semiconductor, Inc. - * Copyright 2016 NXP - * All rights reserved. - * - * - * SPDX-License-Identifier: BSD-3-Clause - */ - -#include "erpc_threading.h" - -#include -#include -#include -#include - -using namespace erpc; - -//////////////////////////////////////////////////////////////////////////////// -// Variables -//////////////////////////////////////////////////////////////////////////////// - -Thread *Thread::s_first = NULL; -BOOL Thread::m_critical_section_inited = FALSE; -CRITICAL_SECTION Thread::m_critical_section; - -//////////////////////////////////////////////////////////////////////////////// -// Code -//////////////////////////////////////////////////////////////////////////////// - -Thread::Thread(const char *name) -: m_name(name) -, m_entry(0) -, m_arg(0) -, m_stackSize(0) -, m_priority(0) -, m_thread(0) -, m_thrdaddr(0) -, m_next(0) -{ -} - -Thread::Thread(thread_entry_t entry, uint32_t priority, uint32_t stackSize, const char *name) -: m_name(name) -, m_entry(entry) -, m_arg(0) -, m_stackSize(stackSize) -, m_priority(priority) -, m_thread(0) -, m_thrdaddr(0) -, m_next(0) -{ -} - -Thread::~Thread(void) {} - -void Thread::init(thread_entry_t entry, uint32_t priority, uint32_t stackSize) -{ - m_entry = entry; - m_stackSize = stackSize; - m_priority = priority; - - if (m_critical_section_inited == FALSE) - { - InitializeCriticalSection(&m_critical_section); - m_critical_section_inited = TRUE; - } -} - -void Thread::start(void *arg) -{ - m_arg = arg; - - EnterCriticalSection(&m_critical_section); - m_thread = (HANDLE)_beginthreadex(NULL, m_stackSize, threadEntryPointStub, this, 0, &m_thrdaddr); - - // Link in this thread to the list. - if (NULL != s_first) - { - m_next = s_first; - } - s_first = this; - LeaveCriticalSection(&m_critical_section); -} - -bool Thread::operator==(Thread &o) -{ - return (m_thrdaddr == o.m_thrdaddr); -} - -Thread *Thread::getCurrentThread(void) -{ - unsigned int thisThrdaddr = GetCurrentThreadId(); - - // Walk the threads list to find the Thread object for the current task. - EnterCriticalSection(&m_critical_section); - Thread *it = s_first; - while (it) - { - if (it->m_thrdaddr == thisThrdaddr) - { - break; - } - it = it->m_next; - } - LeaveCriticalSection(&m_critical_section); - return it; -} - -void Thread::sleep(uint32_t usecs) -{ - LARGE_INTEGER startTime; - LARGE_INTEGER currTick; - LARGE_INTEGER freq; - uint32_t elapsedTimeMicroSeconds; - - QueryPerformanceFrequency(&freq); - QueryPerformanceCounter(&startTime); - - do - { - QueryPerformanceCounter(&currTick); - - elapsedTimeMicroSeconds = - static_cast(((currTick.QuadPart - startTime.QuadPart) * 1000000) / freq.QuadPart); - } while (elapsedTimeMicroSeconds < usecs); -} - -void Thread::threadEntryPoint(void) -{ - if (m_entry) - { - m_entry(m_arg); - } -} - -unsigned WINAPI Thread::threadEntryPointStub(void *arg) -{ - Thread *_this = reinterpret_cast(arg); - if (_this) - { - _this->threadEntryPoint(); - } - - return 0; -} - -Mutex::Mutex(void) -{ - m_mutex = CreateMutex(NULL, FALSE, ""); -} - -Mutex::~Mutex(void) -{ - CloseHandle(m_mutex); -} - -bool Mutex::tryLock(void) -{ - return (WAIT_OBJECT_0 == WaitForSingleObject(m_mutex, 0)); -} - -bool Mutex::lock(void) -{ - return (WAIT_OBJECT_0 == WaitForSingleObject(m_mutex, INFINITE)); -} - -bool Mutex::unlock(void) -{ - return ReleaseMutex(m_mutex); -} - -Semaphore::Semaphore(int count) -: m_count(count) -, m_sem() -, m_mutex() -{ - m_sem = CreateSemaphore(NULL, m_count, 1, ""); -} - -Semaphore::~Semaphore(void) -{ - CloseHandle(m_sem); -} - -void Semaphore::put(void) -{ - LONG precount; - ReleaseSemaphore(m_sem, 1, &precount); - m_mutex.lock(); - ++m_count; - m_mutex.unlock(); -} - -bool Semaphore::get(uint32_t timeout) -{ - DWORD ret = WaitForSingleObject(m_sem, timeout); - m_mutex.lock(); - --m_count; - m_mutex.unlock(); - return (WAIT_OBJECT_0 == ret); -} - -int Semaphore::getCount(void) const -{ - return m_count; -} - -//////////////////////////////////////////////////////////////////////////////// -// EOF -//////////////////////////////////////////////////////////////////////////////// diff --git a/erpc_c/port/erpc_threading_zephyr.cpp b/erpc_c/port/erpc_threading_zephyr.cpp deleted file mode 100644 index ba084cfe4..000000000 --- a/erpc_c/port/erpc_threading_zephyr.cpp +++ /dev/null @@ -1,145 +0,0 @@ -/* - * Copyright 2017 NXP - * All rights reserved. - * - * - * SPDX-License-Identifier: BSD-3-Clause - */ - -#include "erpc_threading.h" - -#include - -#if ERPC_THREADS_IS(ZEPHYR) - -using namespace erpc; - -//////////////////////////////////////////////////////////////////////////////// -// Code -//////////////////////////////////////////////////////////////////////////////// - -Thread::Thread(const char *name) -: m_name(name) -, m_entry(0) -, m_arg(0) -, m_stackSize(0) -, m_priority(0) -, m_thread(0) -, m_stack(0) -{ -} - -Thread::Thread(thread_entry_t entry, uint32_t priority, uint32_t stackSize, const char *name) -: m_name(name) -, m_entry(entry) -, m_arg(0) -, m_stackSize(stackSize) -, m_priority(priority) -, m_thread(0) -, m_stack(0) -{ -} - -Thread::~Thread(void) {} - -void Thread::init(thread_entry_t entry, uint32_t priority, uint32_t stackSize) -{ - m_entry = entry; - m_stackSize = stackSize; - m_priority = priority; -} - -void Thread::start(void *arg) -{ - m_arg = arg; - - assert(m_stack && "Set stack address"); - k_thread_create(&m_thread, m_stack, m_stackSize, threadEntryPointStub, this, NULL, NULL, m_priority, 0, K_NO_WAIT); -} - -bool Thread::operator==(Thread &o) -{ - return m_thread == o.m_thread; -} - -Thread *Thread::getCurrentThread(void) -{ - return reinterpret_cast(k_thread_custom_data_get()); -} - -void Thread::sleep(uint32_t usecs) -{ - k_sleep(usecs / 1000); -} - -void Thread::threadEntryPoint(void) -{ - if (m_entry) - { - m_entry(m_arg); - } -} - -void *Thread::threadEntryPointStub(void *arg1, void *arg2, void *arg3) -{ - Thread *_this = reinterpret_cast(arg1); - assert(_this && "Reinterpreting 'void *arg1' to 'Thread *' failed."); - k_thread_custom_data_set(arg1); - _this->threadEntryPoint(); - - // Handle a task returning from its function. - k_thread_abort(k_current_get()); -} - -Mutex::Mutex(void) -: m_mutex(0) -{ - k_mutex_init(&m_mutex); -} - -Mutex::~Mutex(void) {} - -bool Mutex::tryLock(void) -{ - return (k_mutex_lock(&m_mutex, K_NO_WAIT) == 0); -} - -bool Mutex::lock(void) -{ - return (k_mutex_lock(&m_mutex, K_FOREVER) == 0); -} - -bool Mutex::unlock(void) -{ - k_mutex_unlock(&m_mutex); - return true; -} - -Semaphore::Semaphore(int count) -: m_sem(0) -{ - // Set max count to highest signed int. - k_sem_init(&m_sem, count, 0x7fffffff); -} - -Semaphore::~Semaphore(void) {} - -void Semaphore::put(void) -{ - k_sem_give(&m_sem); -} - -bool Semaphore::get(uint32_t timeout) -{ - return (k_sem_take(&m_sem, timeout / 1000) == 0); -} - -int Semaphore::getCount(void) const -{ - return k_sem_count_get(m_sem)); -} -#endif /* ERPC_THREADS_IS(FREERTOS) */ - -//////////////////////////////////////////////////////////////////////////////// -// EOF -////////////////////////////////////////////////////////////////////////////////