diff --git a/CMakeLists.txt b/CMakeLists.txt index 5ce1a276..8ab5ab52 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -99,6 +99,9 @@ add_subdirectory(core/essentials) add_subdirectory(core/utils) add_subdirectory(core/connectivity/cellular) +# Add Integration testing library +add_subdirectory(core/testing) + ## Add thirdparty libs add_subdirectory(thirdparty) diff --git a/core/testing/CMakeLists.txt b/core/testing/CMakeLists.txt new file mode 100644 index 00000000..eb7afcb4 --- /dev/null +++ b/core/testing/CMakeLists.txt @@ -0,0 +1,40 @@ +cmake_minimum_required(VERSION 3.6) + +project ("Kiso Testing" C) + +## Interface library +add_library(testing_int INTERFACE) +target_include_directories(testing_int +INTERFACE + include +) +target_link_libraries(testing_int INTERFACE essentials_int) + +## Enable static code analysis +# the checks will be executed as it would be on the desired compile step +if(${ENABLE_STATIC_CHECKS}) + set(CMAKE_C_CLANG_TIDY ${CLANG_TIDY} --extra-arg=--target=arm-none-eabi --extra-arg=--sysroot=${CMAKE_SYSROOT}) + set(CMAKE_CXX_CLANG_TIDY ${CLANG_TIDY} --extra-arg=--target=arm-none-eabi --extra-arg=--sysroot=${CMAKE_SYSROOT}) +endif() + +## Make sure we are only compiling them with the proper toolchain +if(${CMAKE_CROSSCOMPILING}) + + file(GLOB TESTING_SOURCES + ./source/*.c + ) + add_library(testing STATIC EXCLUDE_FROM_ALL ${TESTING_SOURCES}) + target_include_directories(testing + PUBLIC + include + PRIVATE + source/protected + ) + target_link_libraries(testing testing_int essentials utils ${KISO_OS_LIB}) + +endif(${CMAKE_CROSSCOMPILING}) + +## Add tests +if(${CMAKE_TESTING_ENABLED}) + #add_subdirectory(test) +endif() diff --git a/core/testing/include/Kiso_Testing.h b/core/testing/include/Kiso_Testing.h new file mode 100644 index 00000000..64080452 --- /dev/null +++ b/core/testing/include/Kiso_Testing.h @@ -0,0 +1,192 @@ +/********************************************************************************************************************** + * Copyright (c) 2010#2019 Robert Bosch GmbH + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl#2.0. + * + * SPDX#License#Identifier: EPL#2.0 + * + * Contributors: + * Robert Bosch GmbH # initial contribution + * + **********************************************************************************************************************/ + +/** + * @file + * @defgroup + * @ingroup + * @{ + * + * @brief This module manages the integration testing protocol and communication between the device under test + and the test coordinator + * + */ + +#ifndef KISO_TESTING_H_ +#define KISO_TESTING_H_ + +/*###################### INCLUDED HEADERS ############################################################################*/ + +#include "Kiso_Basics.h" +#include "Kiso_Retcode.h" +#include "Kiso_Assert.h" +#include "Kiso_Testing_Config.h" + +/*###################### MACROS DEFINITION ###########################################################################*/ + +/*###################### TYPE DEFINITIONS ############################################################################*/ +/** + * @brief Enumerates the internal units in the Kiso_Testing library which could return Retcode conform error + * codes. In case of error, one can refer to this enumeration to identify which source file has issued + * it. +*/ +enum KISO_TESTING_Modules_E +{ + KISO_MODULE_ID_TESTING = 1, + KISO_MODULE_ID_TESTING_TESTREGISTRY, /**< KISO_TESTS_MODULE_ID_TESTREGISTRY */ + KISO_MODULE_ID_TESTING_CCHANNEL, /**< KISO_TESTS_MODULE_ID_CCHANNEL */ + KISO_MODULE_ID_TESTING_SERIALMSGTRANSCEIVER, /**< KISO_TESTS_MODULE_ID_SERIALMSGTRANSCEIVER */ + KISO_MODULE_ID_TESTING_TESTRUNNER, /**< KISO_TESTS_MODULE_ID_TESTRUNNER */ + KISO_MODULE_ID_TESTING_SERIAL, /**< KISO_TESTS_MODULE_ID_SERIAL */ + KISO_MODULE_ID_TESTING_TESTENTRY, +}; + +/** + * @brief Enumerates the special return codes that could be returned from the different units in the + * Kiso_Testing library. +*/ +enum KISO_TESTING_Retcodes_E +{ + RETCODE_TESTING_SUITE_ALREADY_REGISTERED = RETCODE_FIRST_CUSTOM_CODE, + RETCODE_TESTING_CASE_ALREADY_REGISTERED, + RETCODE_TESTING_CCHANNEL_INITIALISATION_FAILED, + RETCODE_TESTING_INCOMPLETE_MESSAGE_RECEIVED, + RETCODE_TESTING_CRC_MISMATCH, + RETCODE_TESTING_VERSION_MISMATCH, + RETCODE_TESTING_TLVELEMENT_NOT_FOUND, + RETCODE_TESTING_REPORT_TIMEOUT, + RETCODE_TESTING_CCHANNEL_NOT_SPECIFIED, +}; + +/** + * @brief Enumerates the types of messages exchanged between the Test_Executor and the Test_Controller + */ +enum CCMsg_MessageType_E +{ + CCMSG_TYPE_COMMAND, + CCMSG_TYPE_REPORT, + CCMSG_TYPE_ACK, +}; + +/** + * @brief Encapsulates the elements composing the message header. + */ +typedef struct MessageHeader_S +{ + uint8_t messageInfo; /**< version is 2 bits, message type is 2 bits and the remaining 4 bits are reserved */ + uint8_t messageToken; + uint8_t messageType; + uint8_t errorCode; + uint8_t testEntry; + uint8_t testSuite; + uint8_t testCase; + uint8_t payloadLength; +} MsgHdr_T; + +/** + * @brief Encapsulates the elements composing a TLV object(type, length and value) + */ +typedef struct TlvElement_S +{ + uint8_t type; + uint8_t length; + char *value; +} TlvElt_T; + +/** + * @brief Encapsulates the elements composing a message.. + */ +typedef struct CCMsg_S +{ + MsgHdr_T header; /**< Header of the message */ + uint8_t payload[TEST_MAX_PAYLOAD_LENGTH]; + TlvElt_T tlvArray[CCHANNEL_MAX_NUMBER_OF_TLV_ELEMENTS]; /**< Parsed TLV array (from receive buffer) */ + uint8_t payloadIndex; + uint8_t tlvArrayIndex; + uint8_t numberOfTlvElements; /**< Number of TLV elements for the message */ + uint8_t rebootCounter; + bool isFree : 1; /**< This bit indicates whether the received message is processed by test runner or not */ +} CCMsg_T; + +/** + * @brief Defines a prototype type for the setup functions of the test suites and test cases. + */ +typedef Retcode_T (*SetupFct_T)(CCMsg_T *ccmsg); + +/** + * @brief Defines a prototype type for the tear down functions of the test suites and test cases. + */ +typedef Retcode_T (*TearDownFct_T)(CCMsg_T *ccmsg); + +/** + * @brief Sefines a prototype type for the run functions of the test cases. + */ +typedef void (*RunFct_T)(CCMsg_T *ccmsg); + +/*###################### EXPORTED FUNCTIONS PROTOTYPES ###############################################################*/ + +/** + * @brief Initializes the Testing Framework. + * @details this + * @param[in] eId Id of the Test Entry + * @return RETCODE_OK if initialized successfully error code otherwise + */ +Retcode_T Tests_Initialize(uint8_t eId, SetupFct_T setup, TearDownFct_T teardown); + +/** + * @brief Registers a Test Suite + * @details todo mak explain what the function does currently + * @param[in] sId The identifier of the TestSuite to register + * @param[in] setup A reference to the setup function of the TestSuite + * @param[in] teardown A reference to the tear down function of the TestSuite + * @note setup and tear down functions pointers can be null if nothing has to be done. + * @return RETCODE_OK in case of success, error code otherwise. + */ +Retcode_T Tests_RegisterTestSuite(uint8_t sId, SetupFct_T setup, TearDownFct_T teardown); + +/** + * @brief Registers a Test Case + * @details todo mak explain what the function does + * @param[in] sId identifier of the Test Suite the test to register + * @param[in] cId identifier of the Test Case to register + * @param[in] setup A reference to the setup function of the Test Suite + * @param[in] run A reference to the run function of the Test Suite + * @param[in] teardown A reference to the tear down function of the Test Suite + * @note setup and tear down functions pointers can be null if nothing has to be done. + * @return RETCODE_OK in case of success, error code otherwise. + */ +Retcode_T Tests_RegisterTestCase(uint8_t sId, uint8_t cId, SetupFct_T setup, RunFct_T run, TearDownFct_T teardown); + +/** + * @brief Sends a result of a test case execution. + * @details todo mak explain what the function does + * @param[in] result The test result code (0: success / otherwise: failure) + * @param[in] reason A 0-terminating string stating a reason. It can be NULL, if no reason should be sent. + */ +void Tests_SendReport(uint8_t result, char *reason); + +/** + * @brief Gets a tlv element using the type of the tlvElement input + * @details todo mak explain what the function does + * @param[in] ccmsg A reference to the message in which to look for the element + * @param[in,out] tlvElement A reference to where to store the element if found. + * tlvElement->type is used as input to find the element's value + * @return RETCODE_OK in case of success, error code otherwise. + * todo mak: make explicit the type search. interface is hiding information. + */ +Retcode_T Tests_GetTlvElement(CCMsg_T *ccmsg, TlvElt_T *tlvElement); + +#endif /* KISO_TESTING_H_ */ + +/** @} */ diff --git a/core/testing/include/Kiso_Testing_Config.h b/core/testing/include/Kiso_Testing_Config.h new file mode 100644 index 00000000..8e91d272 --- /dev/null +++ b/core/testing/include/Kiso_Testing_Config.h @@ -0,0 +1,54 @@ +/*----------------------------------------------------------------------------*/ +/* + * Copyright (C) Bosch Connected Devices and Solutions GmbH. + * All Rights Reserved. Confidential. + * + * Distribution only to people who need to know this information in + * order to do their job.(Need-to-know principle). + * Distribution to persons outside the company, only if these persons + * signed a non-disclosure agreement. + * Electronic transmission, e.g. via electronic mail, must be made in + * encrypted form. + */ +/*----------------------------------------------------------------------------*/ + +/** + * @file Add a brief description here. + * + * Put here the documentation of this header file. Explain the interface exposed + * by this header, e.g. what is the purpose of use, how to use it, etc. + */ + +#ifndef KISO_TESTING_CONFIG_H +#define KISO_TESTING_CONFIG_H + +#ifndef TEST_RUNNER_TASK_PRIO +#define TEST_RUNNER_TASK_PRIO 2 +#endif + +#ifndef TEST_RUNNER_TASK_STACK_DEPTH +#define TEST_RUNNER_TASK_STACK_DEPTH 1024 +#endif + +#ifndef TEST_RUNNER_QUEUE_SIZE +#define TEST_RUNNER_QUEUE_SIZE 5U +#endif + +#ifndef TEST_MAX_NUMBER_OF_TEST_SUITES +#define TEST_MAX_NUMBER_OF_TEST_SUITES 16 +#endif + +/** Macros defining the maximum number of Test Cases per Test Suite */ +#ifndef TEST_MAX_NUMBER_OF_TEST_CASES_PER_TEST_SUITE +#define TEST_MAX_NUMBER_OF_TEST_CASES_PER_TEST_SUITE 16 +#endif + +#ifndef CCHANNEL_MAX_NUMBER_OF_TLV_ELEMENTS +#define CCHANNEL_MAX_NUMBER_OF_TLV_ELEMENTS 2 +#endif + +#ifndef TEST_MAX_PAYLOAD_LENGTH +#define TEST_MAX_PAYLOAD_LENGTH 248U +#endif + +#endif /* KISO_TESTING_CONFIG_H */ diff --git a/core/testing/source/CChannel.c b/core/testing/source/CChannel.c new file mode 100644 index 00000000..e0732f0f --- /dev/null +++ b/core/testing/source/CChannel.c @@ -0,0 +1,328 @@ +/********************************************************************************************************************** + * Copyright (c) 2010#2019 Robert Bosch GmbH + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl#2.0. + * + * SPDX#License#Identifier: EPL#2.0 + * + * Contributors: + * Robert Bosch GmbH # initial contribution + * + **********************************************************************************************************************/ + +/** + * @file + * + * @brief + * This module is responsible for the transmission and reception of data through the communication medium, which can be + * UART / UDP / BLE and so on. + */ +/*###################### INCLUDED HEADERS ###########################################################################*/ + +#include "Kiso_Testing.h" +#include "CChannel.h" +#include "TestRunner.h" +#include "SerialCChannel.h" +#include "SerialMsgTransceiver.h" + +/*###################### MACROS DEFINITION ##########################################################################*/ + +#undef KISO_MODULE_ID +#define KISO_MODULE_ID KISO_MODULE_ID_TESTING_CCHANNEL + +#define MAX_NUMBER_OF_INCOMING_MESSAGE 2 + +#define CCHANNEL_TLV_TYPE_REASON 112 + +#define CCHANNEL_REPORT_TYPE 110 + +#define CCHANNEL_NUM_OF_SEND_RETRIES 4 + +/*###################### LOCAL_TYPES DEFINITION #####################################################################*/ + +/*###################### LOCAL FUNCTIONS DECLARATION ################################################################*/ + +static CCMsg_T *allocCCMessage(void); +static Retcode_T sendMessage(CCMsg_T *ccmsg); +static void parseTlvElements(CCMsg_T *ccmsg); +static void freeAllCCMsg(void); + +/*###################### VARIABLES DECLARATION ######################################################################*/ + +static CCMsg_T msgPool[MAX_NUMBER_OF_INCOMING_MESSAGE]; +static CCMsg_T ackMessage; +static CCMsg_T reportMessage; + +/*###################### EXPOSED FUNCTIONS IMPLEMENTATION ###########################################################*/ + +Retcode_T CChannel_Initialize(void) +{ + freeAllCCMsg(); + Retcode_T retcode = Serial_Initialize(); + + if (RETCODE_OK == retcode) + { + char msg[18] = "CCHANNEL INIT OK\r\n"; + retcode = Serial_Send((void *)msg, 18); + } + return retcode; +} + +Retcode_T CChannel_Deinitialize(void) +{ + return Serial_Deinitialize(); +} + +void CChannel_FreeCCMsg(CCMsg_T *ccmsg) +{ + (void)memset(ccmsg, 0, sizeof(CCMsg_T)); + + ccmsg->isFree = true; +} + +void CChannel_ReceiveEventHandler(uint8_t *buffer, uint8_t length) +{ + if (CCMSG_VERSION != ((buffer[0] & CCMSG_VERSION_MASK) >> 6)) + { + //if the framework version does not match we just ignore this message + return; + } + + CCMsg_T *ccmsg = allocCCMessage(); + + if (NULL == ccmsg) + { + Retcode_RaiseError(RETCODE(RETCODE_SEVERITY_ERROR, RETCODE_OUT_OF_RESOURCES)); + return; + } + + (void)memcpy(ccmsg, buffer, length); + + parseTlvElements(ccmsg); + + TestRunner_ProcessMessage(ccmsg); + + return; +} + +void CChannel_PrepareAck(CCMsg_T *ccmsg) +{ + (void)memset(&ackMessage, 0, sizeof(CCMsg_T)); + + (void)memcpy(&ackMessage, ccmsg, CCHANNEL_HEADER_LENGTH); + + ackMessage.header.messageInfo = CCMSG_CREATE_TYPE(CCHANNEL_MSG_TYPE_ACK); + ackMessage.header.payloadLength = 0; +} + +Retcode_T CChannel_SendAck(uint8_t result) +{ + ackMessage.header.errorCode = result; + + assert(ackMessage.header.messageInfo == CCMSG_CREATE_TYPE(CCHANNEL_MSG_TYPE_ACK)); + assert(ackMessage.header.payloadLength == 0); + + return sendMessage(&ackMessage); +} + +Retcode_T CChannel_ResendAck(void) +{ + return sendMessage(&ackMessage); +} + +void CChannel_PrepareReport(CCMsg_T *ccmsg) +{ + (void)memset(&reportMessage, 0, sizeof(CCMsg_T)); + + (void)memcpy(&reportMessage, ccmsg, CCHANNEL_HEADER_LENGTH); + + reportMessage.header.messageType = CCHANNEL_REPORT_TYPE; + reportMessage.header.messageInfo = CCMSG_CREATE_TYPE(CCHANNEL_MSG_TYPE_REPORT); + reportMessage.header.payloadLength = 0; +} + +Retcode_T CChannel_SendReport(uint8_t result, char *reason) +{ + Retcode_T retcode = RETCODE_OK; + + reportMessage.header.errorCode = result; + + assert(reportMessage.header.payloadLength == 0); + + if (NULL != reason) + { + TlvElt_T reasonTlv; + reasonTlv.type = CCHANNEL_TLV_TYPE_REASON; + reasonTlv.length = strlen(reason); + reasonTlv.value = reason; + + retcode = CChannel_AddTlvElement(&reportMessage, &reasonTlv); + + if ((strlen(reason) + 2) != reportMessage.header.payloadLength) + { + return RETCODE(RETCODE_SEVERITY_WARNING, (uint32_t)RETCODE_UNEXPECTED_BEHAVIOR); + } + } + + assert(reportMessage.header.messageInfo == CCMSG_CREATE_TYPE(CCHANNEL_MSG_TYPE_REPORT)); + + if (RETCODE_OK == retcode) + { + retcode = sendMessage(&reportMessage); + } + + return retcode; +} + +Retcode_T CChannel_ResendReport(void) +{ + Retcode_T retcode = RETCODE_OK; + + retcode = sendMessage(&reportMessage); + + return retcode; +} + +bool CChannel_DoesAckMatchReport(CCMsg_T *ccack) +{ + bool result = true; + MsgHdr_T msgHdr = reportMessage.header; + MsgHdr_T ackHdr = ccack->header; + + if ((ackHdr.messageToken != msgHdr.messageToken) || (ackHdr.testEntry != msgHdr.testEntry) || (ackHdr.testSuite != msgHdr.testSuite) || (ackHdr.testCase != msgHdr.testCase)) + { + result = false; + } + + return result; +} + +Retcode_T CChannel_GetTlvElement(CCMsg_T *ccmsg, TlvElt_T *tlvElement) +{ + + if ((NULL == ccmsg) || (NULL == tlvElement)) + { + return RETCODE(RETCODE_SEVERITY_ERROR, RETCODE_INVALID_PARAM); + } + else + { + for (uint32_t i = 0; i < ccmsg->numberOfTlvElements; i++) + { + if (tlvElement->type == ccmsg->tlvArray[i].type) + { + if (NULL == ccmsg->tlvArray[i].value) + { + return RETCODE(RETCODE_SEVERITY_ERROR, RETCODE_NULL_POINTER); + } + + tlvElement->value = ccmsg->tlvArray[i].value; + tlvElement->length = ccmsg->tlvArray[i].length; + return RETCODE_OK; + } + } + } + return RETCODE(RETCODE_SEVERITY_ERROR, RETCODE_TESTING_TLVELEMENT_NOT_FOUND); +} + +Retcode_T CChannel_AddTlvElement(CCMsg_T *ccmsg, TlvElt_T *tlvElement) +{ + if ((NULL == ccmsg) || (NULL == tlvElement) || (NULL == tlvElement->value)) + { + return (RETCODE(RETCODE_SEVERITY_ERROR, (uint32_t)RETCODE_NULL_POINTER)); + } + else + { + + if (CCHANNEL_MAX_NUMBER_OF_TLV_ELEMENTS == ccmsg->numberOfTlvElements) + { + //we allow only 20 TLV elements in a message + return RETCODE(RETCODE_SEVERITY_ERROR, (uint32_t)RETCODE_OUT_OF_RESOURCES); + } + + if (CCHANNEL_PAYLOAD_MAX_SIZE <= (ccmsg->payloadIndex + 2 + tlvElement->length)) + { + //we allow only 248 as the maximum paylaod size + return RETCODE(RETCODE_SEVERITY_ERROR, (uint32_t)RETCODE_OUT_OF_RESOURCES); + } + + TlvElt_T *currentTlvElement = &ccmsg->tlvArray[ccmsg->numberOfTlvElements]; + + currentTlvElement->type = tlvElement->type; + ccmsg->payload[ccmsg->payloadIndex++] = tlvElement->type; + currentTlvElement->length = tlvElement->length; + ccmsg->payload[ccmsg->payloadIndex++] = tlvElement->length; + + currentTlvElement->value = (char *)&(ccmsg->payload[ccmsg->payloadIndex]); + (void)memcpy(&ccmsg->payload[ccmsg->payloadIndex], tlvElement->value, tlvElement->length); + + ccmsg->payloadIndex += tlvElement->length; + + ccmsg->header.payloadLength += tlvElement->length + 2; + ccmsg->numberOfTlvElements++; + + return RETCODE_OK; + } +} + +/*###################### LOCAL FUNCTIONS IMPLEMENTATION #############################################################*/ + +static CCMsg_T *allocCCMessage(void) +{ + CCMsg_T *ccmsg = NULL; + + for (uint8_t i = 0; i < MAX_NUMBER_OF_INCOMING_MESSAGE; i++) + { + if (msgPool[i].isFree) + { + ccmsg = &msgPool[i]; + ccmsg->isFree = false; + break; + } + } + + return ccmsg; +} + +static Retcode_T sendMessage(CCMsg_T *ccmsg) +{ + Retcode_T retcode = RETCODE_OK; + uint32_t retries = CCHANNEL_NUM_OF_SEND_RETRIES; + do + { + retcode = SerialMsgTransceiver_Send((uint8_t *)ccmsg, CCHANNEL_HEADER_LENGTH + ccmsg->header.payloadLength); + retries--; + } while (retries > 0 && RETCODE_OK != retcode); + + return retcode; +} + +static void parseTlvElements(CCMsg_T *ccmsg) +{ + for (uint8_t i = 0; i < ccmsg->header.payloadLength;) + { + if (ccmsg->numberOfTlvElements == CCHANNEL_MAX_NUMBER_OF_TLV_ELEMENTS) + { + return; + } + + ccmsg->tlvArray[ccmsg->numberOfTlvElements].type = ccmsg->payload[i++]; + ccmsg->tlvArray[ccmsg->numberOfTlvElements].length = ccmsg->payload[i++]; + ccmsg->tlvArray[ccmsg->numberOfTlvElements].value = (char *)&(ccmsg->payload[i]); + i += ccmsg->tlvArray[ccmsg->numberOfTlvElements].length; + ccmsg->numberOfTlvElements++; + } + + return; +} + +static void freeAllCCMsg(void) +{ + (void)memset(msgPool, 0, sizeof(msgPool)); + + for (uint32_t i = 0; i < MAX_NUMBER_OF_INCOMING_MESSAGE; i++) + { + msgPool[i].isFree = true; + } +} diff --git a/core/testing/source/Serial.c b/core/testing/source/Serial.c new file mode 100644 index 00000000..d399bfba --- /dev/null +++ b/core/testing/source/Serial.c @@ -0,0 +1,219 @@ +/********************************************************************************************************************** + * Copyright (c) 2010#2019 Robert Bosch GmbH + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl#2.0. + * + * SPDX#License#Identifier: EPL#2.0 + * + * Contributors: + * Robert Bosch GmbH # initial contribution + * + **********************************************************************************************************************/ + +/** + * @file + * + * @brief + * todo add brief description Implements the following functionalities specified in template.h + */ +/*###################### INCLUDED HEADERS ###########################################################################*/ + +#include "Kiso_Testing.h" +#include "Kiso_Testing_Config.h" +#include "Kiso_BSP_TestInterface.h" +#include "Kiso_MCU_UART.h" +#include "Kiso_GuardedTask.h" +#include "Kiso_RingBuffer.h" +#include "FreeRTOS.h" +#include "semphr.h" +#include "SerialMsgTransceiver.h" +#include "SerialCChannel.h" + +/*###################### MACROS DEFINITION ##########################################################################*/ +#undef KISO_MODULE_ID +#define KISO_MODULE_ID KISO_MODULE_ID_TESTING_SERIAL + +#define WAIT_TIME_FOR_SINGLE_UART_TRANSMISSION UINT32_C(500) + +#define MAX_BUFFER_SIZE UINT16_C(300) + +#ifndef SERIAL_TASK_PRIO +#define SERIAL_TASK_PRIO (1UL) +#endif /* SERiAL_TASK_PRIO */ + +#ifndef SERIAL_TASK_STACK_DEPTH +#define SERIAL_TASK_STACK_DEPTH (128UL) +#endif /* SERIAL_TASK_STACK_DEPTH */ + +/*###################### LOCAL_TYPES DEFINITION #####################################################################*/ + +/*###################### LOCAL FUNCTIONS DECLARATION ################################################################*/ + +static void uartEventsCallbackFunc(UART_T uart, struct MCU_UART_Event_S event); + +/*###################### VARIABLES DECLARATION ######################################################################*/ + +static GuardedTask_T serialGuardedTask; +volatile uint32_t serialReceivedCnt = 0; +static SemaphoreHandle_t TransmitDataSemaphoreHandle = NULL; +static RingBuffer_T serialRingBuffer; +static uint8_t serialBuffer[MAX_BUFFER_SIZE]; +static uint8_t RxBuffer; +static UART_T TestInterfaceUart; +#ifndef NDEBUG +volatile uint32_t TestUartErrorCount = 0; /* number of errors post mortem */ +#endif /* NDEBUG */ + +/*###################### EXPOSED FUNCTIONS IMPLEMENTATION ###########################################################*/ + +/* The description is defined at function declaration */ +Retcode_T Serial_Initialize(void) +{ + Retcode_T rc = RETCODE_OK; + + rc = BSP_TestInterface_Connect(); + if (RETCODE_OK == rc) + { + TestInterfaceUart = (UART_T)BSP_TestInterface_GetUARTHandle(); + if (NULL == TestInterfaceUart) + { + rc = RETCODE(RETCODE_SEVERITY_ERROR, RETCODE_NULL_POINTER); + } + } + + if (RETCODE_OK == rc) + { + rc = MCU_UART_Initialize(TestInterfaceUart, uartEventsCallbackFunc); + } + + if (RETCODE_OK == rc) + { + rc = BSP_TestInterface_Enable(); + } + + if (RETCODE_OK == rc) + { + rc = GuardedTask_Initialize(&serialGuardedTask, SerialMsgTransceiver_Receive, "SERIAL_TASK", SERIAL_TASK_PRIO, SERIAL_TASK_STACK_DEPTH); + } + + if (RETCODE_OK == rc) + { + TransmitDataSemaphoreHandle = xSemaphoreCreateBinary(); + if (NULL == TransmitDataSemaphoreHandle) + { + rc = RETCODE(RETCODE_SEVERITY_WARNING, (uint32_t)RETCODE_OUT_OF_RESOURCES); + } + } + + if (RETCODE_OK == rc) + { + RingBuffer_Initialize(&serialRingBuffer, serialBuffer, MAX_BUFFER_SIZE); + } + + if (RETCODE_OK == rc) + { + /* start the receive process, this will enable UART interrupts and trigger a callback on receive */ + rc = MCU_UART_Receive(TestInterfaceUart, &RxBuffer, 1UL); + } + + return (rc); +} + +Retcode_T Serial_Deinitialize(void) +{ + Retcode_T rc = MCU_UART_Deinitialize(TestInterfaceUart); + if (RETCODE_OK == rc) + { + rc = BSP_TestInterface_Disable(); + } + + if (RETCODE_OK == rc) + { + rc = BSP_TestInterface_Disconnect(); + } + + if (RETCODE_OK == rc) + { + rc = GuardedTask_Deinitialize(&serialGuardedTask); + } + return rc; +} + +Retcode_T Serial_Send(void *data, uint32_t len) +{ + Retcode_T retCode; + retCode = MCU_UART_Send(TestInterfaceUart, (uint8_t *)data, len); + + if (RETCODE_OK == retCode) + { + /* Waiting here for the transmit complete event */ + if (pdTRUE != xSemaphoreTake(TransmitDataSemaphoreHandle, (WAIT_TIME_FOR_SINGLE_UART_TRANSMISSION / portTICK_RATE_MS))) + { + retCode = RETCODE(RETCODE_SEVERITY_WARNING, (uint32_t)RETCODE_SEMAPHORE_ERROR); + } + } + + return (retCode); +} + +Retcode_T Serial_Receive(void *data, uint32_t len) +{ + uint32_t numberOfReadBytes = 0; + Retcode_T retcode = RETCODE_OK; + + numberOfReadBytes = RingBuffer_Read(&serialRingBuffer, (uint8_t *)data, len); + + if (numberOfReadBytes != len) + { + retcode = RETCODE(RETCODE_SEVERITY_ERROR, RETCODE_UNEXPECTED_BEHAVIOR); + } + + return retcode; +} + +/*###################### LOCAL FUNCTIONS IMPLEMENTATION #############################################################*/ + +static void uartEventsCallbackFunc(UART_T uart, struct MCU_UART_Event_S event) +{ + KISO_UNUSED(uart); /* not used in One-Byte-Mode */ + + Retcode_T retcode = RETCODE_OK; + + /* Signal the guarded task to indicate that the receive is complete */ + if (event.RxComplete) + { + serialReceivedCnt++; + + if (1UL == RingBuffer_Write(&serialRingBuffer, (uint8_t *)&RxBuffer, 1UL)) + { + (void)GuardedTask_SignalFromIsr(&serialGuardedTask); + } + } + else if (event.TxComplete) + { + portBASE_TYPE xHigherPriorityTaskWoken = pdFALSE; + + if (pdTRUE == xSemaphoreGiveFromISR(TransmitDataSemaphoreHandle, &xHigherPriorityTaskWoken)) + { + portYIELD_FROM_ISR(xHigherPriorityTaskWoken); + } + else + { + /* ignore... semaphore has already been given */ + } + } + else if (event.RxError) + { + retcode = RETCODE(RETCODE_SEVERITY_ERROR, RETCODE_FAILURE); + } + else if (event.TxError) + { + retcode = RETCODE(RETCODE_SEVERITY_ERROR, RETCODE_FAILURE); + } + if (RETCODE_OK != retcode) + { + Retcode_RaiseErrorFromIsr(retcode); + } +} \ No newline at end of file diff --git a/core/testing/source/SerialMsgTransceiver.c b/core/testing/source/SerialMsgTransceiver.c new file mode 100644 index 00000000..17566b6b --- /dev/null +++ b/core/testing/source/SerialMsgTransceiver.c @@ -0,0 +1,270 @@ +/********************************************************************************************************************** + * Copyright (c) 2010#2019 Robert Bosch GmbH + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl#2.0. + * + * SPDX#License#Identifier: EPL#2.0 + * + * Contributors: + * Robert Bosch GmbH # initial contribution + * + **********************************************************************************************************************/ + +/** + * @file + * + * @brief + * Implements the following functionalities specified in template.h + */ +/*###################### INCLUDED HEADERS ############################################################################*/ + +#include "Kiso_Testing.h" +#include "SerialMsgTransceiver.h" +#include "SerialCChannel.h" +#include "CChannel.h" +#include "Kiso_GuardedTask.h" + +/*###################### MACROS DEFINITION ###########################################################################*/ +#undef KISO_MODULE_ID +#define KISO_MODULE_ID KISO_MODULE_ID_TESTING_SERIALMSGTRANSCEIVER + +#define PAYLOAD_LENGTH_INDEX 7 +#define RECEIVE_BUFFER_SIZE 256 + +#define START 0xC0 +#define ESC 0xDB +#define ESC_START 0xDC +#define ESC_ESC 0xDD + +#define CRC_DEFAULT UINT8_C(0) +#define CRC_BIT_SHIFT_4 UINT16_C(4) /** 4 bit shifting for CRC calculation */ +#define CRC_BIT_SHIFT_5 UINT16_C(5) /** 5 bit shifting for CRC calculation */ +#define CRC_BIT_SHIFT_8 UINT16_C(8) /** 8 bit shifting for CRC calculation */ +#define CRC_BIT_SHIFT_12 UINT16_C(12) /** 12 bit shifting for CRC calculation */ +#define CRC_INIT_VALUE UINT16_C(0) /** Default Initialize value for flag */ +#define CRC_BYTE_MASK UINT16_C(0xFF) + +/*###################### LOCAL_TYPES DEFINITION ######################################################################*/ + +enum Receiver_State_E +{ + WAITING_FOR_START, + RECEIVING_HEADER, + RECEIVING_PAYLOAD, + RECEIVED_DONE +}; + +/*###################### LOCAL FUNCTIONS DECLARATION #################################################################*/ + +static uint16_t calculateCRC(uint8_t *buffer, uint8_t length); + +/*###################### VARIABLES DECLARATION #######################################################################*/ + +static uint8_t receiveBuffer[RECEIVE_BUFFER_SIZE]; +static uint32_t serialConsumedCnt = 0; /* number of characters received */ +static uint32_t msgCnt = 0; /* diagnostic: number of messages received */ +static uint32_t msgOK = 0; /* diagnostic: number of messages received */ +static uint32_t msgNOK = 0; /* diagnostic: number of messages received */ + +/*###################### EXPOSED FUNCTIONS IMPLEMENTATION ############################################################*/ + +/*###################### LOCAL FUNCTIONS IMPLEMENTATION ##############################################################*/ + +Retcode_T SerialMsgTransceiver_Send(uint8_t *message, uint8_t length) +{ + Retcode_T ReturnValue; + uint8_t sendBuffer[length * 2]; //todo variable length array dangerous + uint8_t j = 0; + + uint16_t crc = calculateCRC(message, length); + + sendBuffer[j++] = START; + + if (((crc >> 8) & 0xFF) == START) + { + sendBuffer[j++] = ESC; + sendBuffer[j++] = ESC_START; + } + else if (((crc >> 8) & 0xFF) == ESC) + { + sendBuffer[j++] = ESC; + sendBuffer[j++] = ESC_ESC; + } + else + { + sendBuffer[j++] = (crc >> 8) & 0xFF; + } + + if ((crc & 0xFF) == START) + { + sendBuffer[j++] = ESC; + sendBuffer[j++] = ESC_START; + } + else if ((crc & 0xFF & 0xFF) == ESC) + { + sendBuffer[j++] = ESC; + sendBuffer[j++] = ESC_ESC; + } + else + { + sendBuffer[j++] = crc & 0xFF; + } + + for (uint32_t i = 0; i < length; i++) + { + if (message[i] == START) + { + sendBuffer[j++] = ESC; + sendBuffer[j++] = ESC_START; + } + else if (message[i] == ESC) + { + sendBuffer[j++] = ESC; + sendBuffer[j++] = ESC_ESC; + } + else + { + sendBuffer[j++] = message[i]; + } + } + + ReturnValue = Serial_Send(sendBuffer, j); + + return (ReturnValue); +} + +//@todo dei9bue: verify total length, limited to 256! what to do if exceeded? +/* The description is defined at function declaration */ +void SerialMsgTransceiver_Receive(void) +{ + static uint8_t receivingState = WAITING_FOR_START; + static uint8_t receivedByte; + static uint8_t nReceivedByte = 0; + static uint8_t payloadLength = 0; + static bool receivedEsc = false; + static uint8_t testCnt = 0; + + /* The serialReceivedCnt is incremented with every received byte in the ISR + The difference betweeb the serialReceivedCnt and serialConsumedCnt repflects the number of bytes available in the buffer + We consume characters while the difference is > 0 + There is no need to check overflows since both numbers are of uint32_t and the result will always state the difference. + */ + while ((serialReceivedCnt - serialConsumedCnt) > 0) + { + if (RETCODE_OK != Serial_Receive((uint8_t *)&receivedByte, UINT32_C(1))) + { + Retcode_RaiseError(RETCODE(RETCODE_SEVERITY_WARNING, RETCODE_FAILURE)); + return; + } + serialConsumedCnt++; + + if (WAITING_FOR_START == receivingState) + { + if (START == receivedByte) + { + nReceivedByte = 0; + (void)memset(receiveBuffer, 0, sizeof(receiveBuffer)); + receivingState = RECEIVING_HEADER; + } + } + else + { + if (START == receivedByte) + { + Retcode_RaiseError(RETCODE(RETCODE_SEVERITY_WARNING, RETCODE_TESTING_INCOMPLETE_MESSAGE_RECEIVED)); + nReceivedByte = 0; + (void)memset(receiveBuffer, 0, sizeof(receiveBuffer)); + msgNOK++; + receivingState = RECEIVING_HEADER; + } + else if (receivedEsc) + { + receivedEsc = false; + if (ESC_START == receivedByte) + { + receiveBuffer[nReceivedByte++] = START; + } + else if (ESC_ESC == receivedByte) + { + receiveBuffer[nReceivedByte++] = ESC; + } + else + { + // error should not happen + Retcode_RaiseError(RETCODE(RETCODE_SEVERITY_WARNING, RETCODE_INCONSITENT_STATE)); + receivingState = WAITING_FOR_START; + } + } + else if (ESC == receivedByte) + { + receivedEsc = true; + } + else + { + receiveBuffer[nReceivedByte++] = receivedByte; + } + + if (RECEIVING_HEADER == receivingState) + { + if (CCHANNEL_HEADER_LENGTH + 2 == nReceivedByte) + { + payloadLength = receiveBuffer[PAYLOAD_LENGTH_INDEX + 2]; + + if (0 == payloadLength) + { + receivingState = RECEIVED_DONE; + } + else + { + receivingState = RECEIVING_PAYLOAD; + } + } + } + else if (RECEIVING_PAYLOAD == receivingState) + { + if (payloadLength + CCHANNEL_HEADER_LENGTH + 2 == nReceivedByte) + { + receivingState = RECEIVED_DONE; + } + } + } + } + + if (RECEIVED_DONE == receivingState) + { + uint16_t calculatedCRC = calculateCRC(&receiveBuffer[2], CCHANNEL_HEADER_LENGTH + payloadLength); + uint16_t expectedCRC = ((receiveBuffer[0] & CRC_BYTE_MASK) << 8) + (receiveBuffer[1] & CRC_BYTE_MASK); + + msgCnt++; + if (calculatedCRC == expectedCRC) + { + CChannel_ReceiveEventHandler(&receiveBuffer[2], CCHANNEL_HEADER_LENGTH + payloadLength); + receivingState = WAITING_FOR_START; + msgOK++; + } + else + { + Retcode_RaiseError(RETCODE(RETCODE_SEVERITY_WARNING, RETCODE_TESTING_CRC_MISMATCH)); + receivingState = WAITING_FOR_START; + msgNOK++; + } + testCnt++; + } +} + +static uint16_t calculateCRC(uint8_t *buffer, uint8_t length) +{ + uint16_t crc = CRC_DEFAULT; + + for (uint8_t i = 0; i < length; i++) + { + crc = (crc >> (CRC_BIT_SHIFT_8)) | (crc << (CRC_BIT_SHIFT_8)); + crc ^= buffer[i]; + crc ^= (crc & (CRC_BYTE_MASK)) >> (CRC_BIT_SHIFT_4); + crc ^= crc << (CRC_BIT_SHIFT_12); + crc ^= (crc & (CRC_BYTE_MASK)) << (CRC_BIT_SHIFT_5); + } + return crc; +} \ No newline at end of file diff --git a/core/testing/source/TestRegistry.c b/core/testing/source/TestRegistry.c new file mode 100644 index 00000000..71a32c60 --- /dev/null +++ b/core/testing/source/TestRegistry.c @@ -0,0 +1,339 @@ +/********************************************************************************************************************** + * Copyright (c) 2010#2019 Robert Bosch GmbH + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl#2.0. + * + * SPDX#License#Identifier: EPL#2.0 + * + * Contributors: + * Robert Bosch GmbH # initial contribution + * + **********************************************************************************************************************/ + +/** + * @file + * + * @brief + */ +/*###################### INCLUDED HEADERS ############################################################################*/ + +#include "Kiso_Testing.h" +#include "TestRegistry.h" + +/*###################### MACROS DEFINITION ###########################################################################*/ + +#undef KISO_MODULE_ID +#define KISO_MODULE_ID KISO_MODULE_ID_TESTING_TESTREGISTRY + +/*###################### LOCAL_TYPES DEFINITION ######################################################################*/ + +/*###################### LOCAL FUNCTIONS DECLARATION #################################################################*/ + +static TstSte_T *lookupTestSuite(uint8_t sId); +static TstCse_T *lookupTestCase(TstSte_T *testSuite, uint8_t cId); + +/*###################### VARIABLES DECLARATION #######################################################################*/ + +static TstEnt_T testEntry; + +/*###################### EXPOSED FUNCTIONS IMPLEMENTATION ############################################################*/ + +/* @see TestRegistry.h for function description */ +void TestRegistry_Initialize(uint8_t eId, SetupFct_T setup, TearDownFct_T teardown) +{ + (void)memset(&testEntry, 0, sizeof(TstEnt_T)); + + testEntry.id = eId; + testEntry.setup = setup; + testEntry.teardown = teardown; +} + +/* @see TestRegistry.h for function description */ +Retcode_T TestRegistry_RegisterTestSuite(uint8_t sId, SetupFct_T setup, TearDownFct_T teardown) +{ + if (TEST_MAX_NUMBER_OF_TEST_SUITES <= testEntry.numTestSuites) + { + return RETCODE(RETCODE_SEVERITY_ERROR, (uint32_t)RETCODE_OUT_OF_RESOURCES); + } + + TstSte_T *suite = lookupTestSuite(sId); + + if (NULL != suite) + { + /* The test suite with the given ID is already registered */ + return RETCODE(RETCODE_SEVERITY_WARNING, (uint32_t)RETCODE_TESTING_SUITE_ALREADY_REGISTERED); + } + + suite = &testEntry.testSuites[testEntry.numTestSuites]; + testEntry.numTestSuites++; + + suite->id = sId; + suite->setup = setup; + suite->teardown = teardown; + + return RETCODE_OK; +} + +/* @see TestRegistry.h for function description */ +Retcode_T TestRegistry_RegisterTestCase(uint8_t sId, uint8_t cId, SetupFct_T setup, RunFct_T run, TearDownFct_T teardown) +{ + if (NULL == run) + { + return RETCODE(RETCODE_SEVERITY_ERROR, (uint32_t)RETCODE_INVALID_PARAM); + } + + TstSte_T *suite = lookupTestSuite(sId); + + if (NULL == suite) + { + /* The suite is not found */ + return RETCODE(RETCODE_SEVERITY_WARNING, (uint32_t)RETCODE_INVALID_PARAM); + } + + if (TEST_MAX_NUMBER_OF_TEST_CASES_PER_TEST_SUITE <= suite->numTestCases) + { + return RETCODE(RETCODE_SEVERITY_ERROR, (uint32_t)RETCODE_OUT_OF_RESOURCES); + } + + TstCse_T *testCase = lookupTestCase(suite, cId); + + if (NULL != testCase) + { + /* A test case with the given ID is already registered */ + return RETCODE(RETCODE_SEVERITY_WARNING, (uint32_t)RETCODE_TESTING_CASE_ALREADY_REGISTERED); + } + + testCase = &suite->testCases[suite->numTestCases]; + suite->numTestCases++; + + testCase->id = cId; + testCase->setup = setup; + testCase->run = run; + testCase->teardown = teardown; + + return RETCODE_OK; +} + +/* @see TestRegistry.h for function description */ +TstEnt_T *TestRegistry_LookupTestEntry(uint8_t eId) +{ + TstEnt_T *theTestEntry = NULL; + + if (eId == testEntry.id) + { + theTestEntry = &testEntry; + } + + return theTestEntry; +} + +/* @see TestRegistry.h for function description */ +TstSte_T *TestRegistry_LookupTestSuite(uint8_t eId, uint8_t sId) +{ + TstSte_T *testSuite = NULL; + + if (eId == testEntry.id) + { + testSuite = lookupTestSuite(sId); + } + + return testSuite; +} + +/* @see TestRegistry.h for function description */ +TstCse_T *TestRegistry_LookupTestCase(uint8_t eId, uint8_t sId, uint8_t cId) +{ + TstSte_T *testSuite = TestRegistry_LookupTestSuite(eId, sId); + TstCse_T *testCase = NULL; + + if (NULL != testSuite) + { + testCase = lookupTestCase(testSuite, cId); + } + + return testCase; +} + +/* @see TestRegistry.h for function description */ +Retcode_T TestEntry_Setup(TstEnt_T *theTestEntry, CCMsg_T *ccmsg) +{ + + Retcode_T retcode = RETCODE_OK; + if ((NULL == theTestEntry) || (NULL == ccmsg)) + { + /* The suite is not found */ + retcode = RETCODE(RETCODE_SEVERITY_WARNING, (uint32_t)RETCODE_NULL_POINTER); + return (retcode); + } + + /* If test section setup pointer are null, it means that there is nothing to be done and that we can just send an + Acknowledgement with status OK.*/ + if (NULL != theTestEntry->setup) + { + retcode = theTestEntry->setup(ccmsg); + } + return retcode; +} + +/* @see TestRegistry.h for function description */ +Retcode_T TestEntry_Teardown(TstEnt_T *theTestEntry, CCMsg_T *ccmsg) +{ + + Retcode_T retcode = RETCODE_OK; + + if ((NULL == theTestEntry) || (NULL == ccmsg)) + { + /* The suite is not found */ + retcode = RETCODE(RETCODE_SEVERITY_WARNING, (uint32_t)RETCODE_NULL_POINTER); + return (retcode); + } + + /* + If test section teardown pointer are null, it means that there is nothing to be done and that we can just send an + Acknowledgement with status OK.*/ + if (NULL != theTestEntry->teardown) + { + retcode = theTestEntry->teardown(ccmsg); + } + return retcode; +} + +/* @see TestRegistry.h for function description */ +Retcode_T TestSuite_Setup(TstSte_T *testSuite, CCMsg_T *ccmsg) +{ + + Retcode_T retcode = RETCODE_OK; + + if ((NULL == testSuite) || (NULL == ccmsg)) + { + /* The suite is not found */ + retcode = RETCODE(RETCODE_SEVERITY_WARNING, (uint32_t)RETCODE_NULL_POINTER); + return (retcode); + } + /* If test suite setup pointer are null, it means that there is nothing to be done and that we can just send an + Acknowledgement with status OK.*/ + if (NULL != testSuite->setup) + { + retcode = testSuite->setup(ccmsg); + } + + return retcode; +} + +/* @see TestRegistry.h for function description */ +Retcode_T TestSuite_Teardown(TstSte_T *testSuite, CCMsg_T *ccmsg) +{ + Retcode_T retcode = RETCODE_OK; + if ((NULL == testSuite) || (NULL == ccmsg)) + { + /* The suite is not found */ + retcode = RETCODE(RETCODE_SEVERITY_WARNING, (uint32_t)RETCODE_NULL_POINTER); + return (retcode); + } + /* If test suite teardown pointer are null, it means that there is nothing to be done and that we can just send an + Acknowledgement with status OK.*/ + if (NULL != testSuite->teardown) + { + retcode = testSuite->teardown(ccmsg); + } + + return retcode; +} + +/* @see TestRegistry.h for function description */ +Retcode_T TestCase_Setup(TstCse_T *testCase, CCMsg_T *ccmsg) +{ + + Retcode_T retcode = RETCODE_OK; + + if ((NULL == testCase) || (NULL == ccmsg)) + { + /* The suite is not found */ + retcode = RETCODE(RETCODE_SEVERITY_WARNING, (uint32_t)RETCODE_NULL_POINTER); + return (retcode); + } + if (NULL != testCase->setup) + { + retcode = testCase->setup(ccmsg); + } + + return retcode; +} + +/* @see TestRegistry.h for function description */ +void TestCase_Run(TstCse_T *testCase, CCMsg_T *ccmsg) +{ + + if ((NULL == testCase) || (NULL == ccmsg) || (NULL == testCase->run)) + { + Retcode_RaiseError(RETCODE(RETCODE_SEVERITY_ERROR, (uint32_t)RETCODE_NULL_POINTER)); + } + else + { + testCase->run(ccmsg); + } +} + +/* @see TestRegistry.h for function description */ +Retcode_T TestCase_Teardown(TstCse_T *testCase, CCMsg_T *ccmsg) +{ + + Retcode_T retcode = RETCODE_OK; + + if ((NULL == testCase) || (NULL == ccmsg)) + { + /* The suite is not found */ + retcode = RETCODE(RETCODE_SEVERITY_WARNING, (uint32_t)RETCODE_NULL_POINTER); + } + else + { + if (NULL != testCase->teardown) + { + retcode = testCase->teardown(ccmsg); + } + } + + return retcode; +} + +/*###################### LOCAL FUNCTIONS IMPLEMENTATION ##############################################################*/ + +/** + * @brief finds a test suite by suite Id in the test suites registry. +*/ +static TstSte_T *lookupTestSuite(uint8_t sId) +{ + TstSte_T *testSuite = NULL; + + for (uint32_t i = 0; i < testEntry.numTestSuites; i++) + { + if (sId == testEntry.testSuites[i].id) + { + testSuite = &testEntry.testSuites[i]; + break; + } + } + + return testSuite; +} + +/** + * @brief finds a test case by case Id in the test cases registry of the referenced test suite . +*/ +static TstCse_T *lookupTestCase(TstSte_T *testSuite, uint8_t cId) +{ + TstCse_T *testCase = NULL; + + for (uint32_t i = 0; i < testSuite->numTestCases; i++) + { + if (cId == testSuite->testCases[i].id) + { + testCase = &testSuite->testCases[i]; + break; + } + } + + return testCase; +} diff --git a/core/testing/source/TestRunner.c b/core/testing/source/TestRunner.c new file mode 100644 index 00000000..c5a62475 --- /dev/null +++ b/core/testing/source/TestRunner.c @@ -0,0 +1,385 @@ +/********************************************************************************************************************** + * Copyright (c) 2010#2019 Robert Bosch GmbH + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl#2.0. + * + * SPDX#License#Identifier: EPL#2.0 + * + * Contributors: + * Robert Bosch GmbH # initial contribution + * + **********************************************************************************************************************/ + +/** + * @file + * + * @brief + * The TestRunner dispatches the commands to the test sections and test suites and processes the acknowledgments + * received from the test controller. + */ +/*###################### INCLUDED HEADERS ############################################################################*/ + +#include "Kiso_Testing.h" +#include "TestRunner.h" +#include "Kiso_CmdProcessor.h" +#include "CChannel.h" +#include "TestRegistry.h" +#include "FreeRTOS.h" +#include "timers.h" + +/*###################### MACROS DEFINITION ###########################################################################*/ + +#undef KISO_MODULE_ID +#define KISO_MODULE_ID KISO_MODULE_ID_TESTING_TESTRUNNER + +#define TEST_ENTRY_SETUP 1 +#define TEST_SUITE_SETUP 2 +#define TEST_CASE_SETUP 3 +#define TEST_CASE_RUN 13 +#define TEST_ENTRY_TEARDOWN 21 +#define TEST_SUITE_TEARDOWN 22 +#define TEST_CASE_TEARDOWN 23 + +#define RUNNER_TIME_TO_WAIT_FOR_ACK_MS (UINT8_C(3000)) + +/*###################### LOCAL_TYPES DEFINITION ######################################################################*/ +/** Structure containing the handler for the Test Runner */ +struct TestRunner_S +{ + uint8_t id; /**< Message token corresponding to the message type */ + uint8_t numberOfRetries; + CmdProcessor_T cmdProcessor; + TimerHandle_t timer; + uint8_t lastReceivedMessageToken; + bool waitingForAck; +}; + +/*###################### LOCAL FUNCTIONS DECLARATION #################################################################*/ + +static void dispatcher(CCMsg_T *ccmsg, uint32_t unusedParameter); +static void processAck(CCMsg_T *ccmsg); +static void processCommand(CCMsg_T *ccmsg); +static void ackTimerCallbackFunction(TimerHandle_t timer); +static bool isMsgAnAck(CCMsg_T *ccmsg); +static bool isMsgACommand(CCMsg_T *ccmsg); + +/*###################### VARIABLES DECLARATION #######################################################################*/ + +static struct TestRunner_S testRunner; + +/*###################### EXPOSED FUNCTIONS IMPLEMENTATION ############################################################*/ + +/* @see TestRunner.h for function description */ +Retcode_T TestRunner_Initialize(void) +{ + Retcode_T retcode = RETCODE_OK; + testRunner.id = 0U; + + retcode = CmdProcessor_Initialize(&testRunner.cmdProcessor, + "Test Runner", + TEST_RUNNER_TASK_PRIO, + TEST_RUNNER_TASK_STACK_DEPTH, + TEST_RUNNER_QUEUE_SIZE); + + if (RETCODE_OK == retcode) + { + testRunner.timer = xTimerCreate((const char *const) "Test Runner Timer", + RUNNER_TIME_TO_WAIT_FOR_ACK_MS, + pdFALSE, + NULL, + ackTimerCallbackFunction); + if (NULL == testRunner.timer) + { + retcode = RETCODE(RETCODE_SEVERITY_ERROR, RETCODE_OUT_OF_RESOURCES); + } + } + if (RETCODE_OK == retcode) + { + retcode = CChannel_Initialize(); + } + return retcode; +} + +/* @see TestRunner.h for function description */ +void TestRunner_ProcessMessage(CCMsg_T *ccmsg) +{ + Retcode_T retcode = CmdProcessor_Enqueue(&testRunner.cmdProcessor, + (CmdProcessor_Func_T)dispatcher, + ccmsg, + 0); + + if (RETCODE_OK != retcode) + { + Retcode_RaiseError(retcode); + } +} + +/* @see TestRunner.h for function description */ +void TestRunner_SendReport(uint8_t result, char *reason) +{ + Retcode_T retcode = RETCODE_OK; + + retcode = CChannel_SendReport(result, reason); + + if (RETCODE_OK == retcode) + { + if (pdFAIL == xTimerStart(testRunner.timer, RUNNER_TIME_TO_WAIT_FOR_ACK_MS)) + { + Retcode_RaiseError(RETCODE(RETCODE_SEVERITY_ERROR, RETCODE_OUT_OF_RESOURCES)); + } + testRunner.numberOfRetries = 3; + testRunner.waitingForAck = true; + } + else + { + Retcode_RaiseError(retcode); + } + + return; +} + +/*###################### LOCAL FUNCTIONS IMPLEMENTATION ##############################################################*/ + +static void dispatcher(CCMsg_T *ccmsg, uint32_t unusedParameter) +{ + KISO_UNUSED(unusedParameter); + + if (isMsgAnAck(ccmsg)) + { + processAck(ccmsg); + } + else if (isMsgACommand(ccmsg)) + { + processCommand(ccmsg); + } + else + { + //@todo dei9bue: handle the fact that the type is not supported + // CChannel_PrepareAck(ccmsg); + // CChannel_SendAck(RETCODE_OK); + } + + CChannel_FreeCCMsg(ccmsg); + return; +} + +static void processAck(CCMsg_T *ccmsg) +{ + if (CChannel_DoesAckMatchReport(ccmsg)) + { + + if (pdFAIL == xTimerStop(testRunner.timer, 0)) + { + //@todo dei9bue: raise some error? + } + + testRunner.waitingForAck = false; + testRunner.numberOfRetries = 0; + } + else + { + //@todo dei9bue: do we just ignore it? or raise an error? + } + + return; +} + +static void processCommand(CCMsg_T *ccmsg) +{ + Retcode_T retcode = RETCODE(RETCODE_SEVERITY_ERROR, RETCODE_FAILURE); + + if (testRunner.waitingForAck) + { + /** + * this means the Test Coordinator did receive the Report but the ack was lost + * so we can jsut stop the timer and continue + */ + if (true != xTimerStop(testRunner.timer, 0)) + { + //@todo dei9bue: raise some error? + } + testRunner.waitingForAck = false; + testRunner.numberOfRetries = 0; + } + if (testRunner.lastReceivedMessageToken == ccmsg->header.messageToken) + { + /** + * if we receive again a command, we shouldn't do the associated action + * we should however resend the ack. + */ + retcode = CChannel_ResendAck(); + + if (RETCODE_OK != retcode) + { + Retcode_RaiseError(retcode); + } + return; + } + + uint8_t result = RETCODE_OK; + + TstEnt_T *testEntry = TestRegistry_LookupTestEntry(ccmsg->header.testEntry); + TstSte_T *testSuite = TestRegistry_LookupTestSuite(ccmsg->header.testEntry, ccmsg->header.testSuite); + TstCse_T *testCase = TestRegistry_LookupTestCase(ccmsg->header.testEntry, + ccmsg->header.testSuite, ccmsg->header.testCase); + + testRunner.lastReceivedMessageToken = ccmsg->header.messageToken; + + CChannel_PrepareAck(ccmsg); + + switch (ccmsg->header.messageType) + { + case TEST_ENTRY_SETUP: + if (NULL != testEntry) + { + retcode = TestEntry_Setup(testEntry, ccmsg); + } + else + { + /* @todo: The error code in Retcode_T occupies 16 bits. But, the argument type passed to CChannel_SendAck() is uint8_t. + * The test coordination protocol has an error code of 8 bits. This is a problem, as we would end up in overflow + * and due to the unsigned nature of the variable, we would wrap around. This needs to be fixed. + * This has a Jira issue: COSP-562. */ + result = (uint8_t)RETCODE_INVALID_PARAM; + } + break; + case TEST_SUITE_SETUP: + if (NULL != testSuite) + { + retcode = TestSuite_Setup(testSuite, ccmsg); + } + else + { + result = (uint8_t)RETCODE_INVALID_PARAM; + } + break; + case TEST_CASE_SETUP: + if (NULL != testCase) + { + retcode = TestCase_Setup(testCase, ccmsg); + } + else + { + result = (uint8_t)RETCODE_INVALID_PARAM; + } + break; + case TEST_CASE_RUN: + if (NULL != testCase) + { + retcode = CChannel_SendAck(RETCODE_OK); + + if (RETCODE_OK != retcode) + { + Retcode_RaiseError(retcode); + } + else + { + CChannel_PrepareReport(ccmsg); + + TestCase_Run(testCase, ccmsg); + } + return; + } + else + { + result = (uint8_t)RETCODE_INVALID_PARAM; + } + break; + case TEST_ENTRY_TEARDOWN: + if (NULL != testEntry) + { + retcode = TestEntry_Teardown(testEntry, ccmsg); + } + else + { + result = (uint8_t)RETCODE_INVALID_PARAM; + } + break; + case TEST_SUITE_TEARDOWN: + if (NULL != testSuite) + { + retcode = TestSuite_Teardown(testSuite, ccmsg); + } + else + { + result = (uint8_t)RETCODE_INVALID_PARAM; + } + break; + case TEST_CASE_TEARDOWN: + if (NULL != testCase) + { + retcode = TestCase_Teardown(testCase, ccmsg); + } + else + { + result = (uint8_t)RETCODE_INVALID_PARAM; + } + break; + default: + result = (uint8_t)RETCODE_INVALID_PARAM; + break; + } + + if ((uint8_t)RETCODE_INVALID_PARAM != result) + { + result = Retcode_GetCode(retcode); + } + + retcode = CChannel_SendAck(result); + + if (RETCODE_OK != retcode) + { + Retcode_RaiseError(retcode); + } + + return; +} + +static void ackTimerCallbackFunction(TimerHandle_t timer) +{ + KISO_UNUSED(timer); + Retcode_T retcode = RETCODE_OK; + + if (testRunner.numberOfRetries > 0) + { + testRunner.numberOfRetries--; + + retcode = CChannel_ResendReport(); + + if (RETCODE_OK == retcode) + { + if (true != xTimerStart(testRunner.timer, RUNNER_TIME_TO_WAIT_FOR_ACK_MS)) + { + Retcode_RaiseError(RETCODE(RETCODE_SEVERITY_ERROR, (uint32_t)RETCODE_OUT_OF_RESOURCES)); + } + } + else + { + Retcode_RaiseError(retcode); + } + } + else + { + testRunner.waitingForAck = false; + Retcode_RaiseError(RETCODE(RETCODE_SEVERITY_WARNING, RETCODE_TESTING_REPORT_TIMEOUT)); + } + return; +} + +/** + * @brief checks the type of the message and returns true if it is an acknowledgement message. + */ +static bool isMsgAnAck(CCMsg_T *ccmsg) +{ + return CCMSG_GET_TYPE(ccmsg) == CCHANNEL_MSG_TYPE_ACK; +} + +/** + * @brief checks the type of the message and returns true if it is a command message. + */ +static bool isMsgACommand(CCMsg_T *ccmsg) +{ + return CCMSG_GET_TYPE(ccmsg) == CCHANNEL_MSG_TYPE_COMMAND; +} \ No newline at end of file diff --git a/core/testing/source/Testing.c b/core/testing/source/Testing.c new file mode 100644 index 00000000..37f0503a --- /dev/null +++ b/core/testing/source/Testing.c @@ -0,0 +1,74 @@ + +/********************************************************************************************************************** + * Copyright (c) 2010#2019 Robert Bosch GmbH + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl#2.0. + * + * SPDX#License#Identifier: EPL#2.0 + * + * Contributors: + * Robert Bosch GmbH # initial contribution + * + **********************************************************************************************************************/ + +/** + * @file + * + * @brief + * This file implements the promised API functions in Kiso_Testing.h with help of the components TestRunner TestRegistry + * and CChannel. + */ +/*###################### INCLUDED HEADERS ############################################################################*/ + +#include "Kiso_Testing.h" +#include "TestRegistry.h" +#include "TestRunner.h" +#include "CChannel.h" + +/*###################### MACROS DEFINITION ###########################################################################*/ + +#undef KISO_MODULE_ID +#define KISO_MODULE_ID KISO_MODULE_ID_TESTING + +/*###################### LOCAL_TYPES DEFINITION ######################################################################*/ + +/*###################### LOCAL FUNCTIONS DECLARATION #################################################################*/ + +/*###################### VARIABLES DECLARATION #######################################################################*/ + +/*###################### EXPOSED FUNCTIONS IMPLEMENTATION ############################################################*/ + +/* @see Kiso_Testing.h for function description */ +Retcode_T Tests_Initialize(uint8_t eId, SetupFct_T setup, TearDownFct_T teardown) +{ + TestRegistry_Initialize(eId, setup, teardown); + return TestRunner_Initialize(); +} + +/* @see Kiso_Testing.h for function description */ +Retcode_T Tests_RegisterTestSuite(uint8_t sId, SetupFct_T setup, TearDownFct_T teardown) +{ + return TestRegistry_RegisterTestSuite(sId, setup, teardown); +} + +/* @see Kiso_Testing.h for function description */ +Retcode_T Tests_RegisterTestCase(uint8_t sId, uint8_t cId, SetupFct_T setup, RunFct_T run, TearDownFct_T teardown) +{ + return TestRegistry_RegisterTestCase(sId, cId, setup, run, teardown); +} + +/* @see Kiso_Testing.h for function description */ +void Tests_SendReport(uint8_t result, char *reason) +{ + TestRunner_SendReport(result, reason); +} + +/* @see Kiso_Testing.h for function description */ +Retcode_T Tests_GetTlvElement(CCMsg_T *ccmsg, TlvElt_T *tlvElement) +{ + return CChannel_GetTlvElement(ccmsg, tlvElement); +} + +/*###################### LOCAL FUNCTIONS IMPLEMENTATION ##############################################################*/ \ No newline at end of file diff --git a/core/testing/source/protected/CChannel.h b/core/testing/source/protected/CChannel.h new file mode 100644 index 00000000..d2367301 --- /dev/null +++ b/core/testing/source/protected/CChannel.h @@ -0,0 +1,169 @@ +/********************************************************************************************************************** + * Copyright (c) 2010#2019 Robert Bosch GmbH + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl#2.0. + * + * SPDX#License#Identifier: EPL#2.0 + * + * Contributors: + * Robert Bosch GmbH # initial contribution + * + **********************************************************************************************************************/ + +/** + * @file + * @defgroup + * @ingroup + * @{ + * + * @brief communication channel handling APIs. + * @details + * This file is part of the test executor software component in the integration testing framework. it provides + * internally used API functions managing the communication protocol between the test executor and the test controller. + * + */ + +#ifndef KISO_CCHANNEL_H_ +#define KISO_CCHANNEL_H_ + +/*###################### INCLUDED HEADERS ############################################################################*/ + +#include "Kiso_Testing.h" + +/*###################### MACROS DEFINITION ###########################################################################*/ + +#define CCMSG_VERSION 1 + +#define CCMSG_TYPE_MASK 0x30 +#define CCMSG_VERSION_MASK 0xC0 + +#define CCMSG_GET_VERSION(ccmsg) (((ccmsg->header.messageInfo & CCMSG_VERSION_MASK) >> 6) & 0x03) +#define CCMSG_GET_TYPE(ccmsg) (((ccmsg->header.messageInfo & CCMSG_TYPE_MASK) >> 4) & 0x03) + +#define CCMSG_CREATE_TYPE(type) ((((type << 4) & 0x30) + ((CCMSG_VERSION << 6) & CCMSG_VERSION_MASK)) & 0xFF) + +#define CCHANNEL_MSG_TYPE_COMMAND 0 +#define CCHANNEL_MSG_TYPE_REPORT 1 +#define CCHANNEL_MSG_TYPE_ACK 2 + +#define CCHANNEL_MESSAGE_MAX_LENGTH 256 +#define CCHANNEL_HEADER_LENGTH 8 +#define CCHANNEL_PAYLOAD_MAX_SIZE CCHANNEL_MESSAGE_MAX_LENGTH - CCHANNEL_HEADER_LENGTH + +#define NO_REBOOT 0 + +/*###################### TYPE DEFINITIONS ############################################################################*/ + +/*###################### EXPORTED FUNCTIONS PROTOTYPES ###############################################################*/ + +/** + * @brief Initializes the CChannel + * + * @return RETCODE_OK in case of success error code otherwise. + */ +Retcode_T CChannel_Initialize(void); + +/** + * @brief Frees the message after having been processed + * + * @param[in] ccmsg The reference to the message to free + */ +void CChannel_FreeCCMsg(CCMsg_T *ccmsg); + +/** + * @brief Prepares the Ack corresponding to the message + * + * @param[in] ccmsg The reference to the message we are preparing the ack for + */ +void CChannel_PrepareAck(CCMsg_T *ccmsg); + +/** + * @brief Sends the ack previously prepared + * + * @param[in] result error code to set in the ack before sending it + * + * @retcode RETCODE_OK (=0) on success. Any other value means a failure + */ +Retcode_T CChannel_SendAck(uint8_t result); + +/** + * @brief Resends the last ack. This is used in case we receive twice the same command + * + * @return RETCODE_OK on success. Any other value means a failure + */ +Retcode_T CChannel_ResendAck(void); + +/** + * @brief Prepares the report corresponding to the message + * + * @param[in] ccmsg The message we are preparing the report for + */ +void CChannel_PrepareReport(CCMsg_T *ccmsg); + +/** + * @brief Sends a Report. Function to be called within the run function implementation + * + * @param[in] result The test result code (0: success / otherwise: failure) + * @param[in] reason 0-terminating string stating a reason. It can be NULL, if no reason should be sent. + * + * @reurn RETCODE_OK on success. Any other value means a failure + */ +Retcode_T CChannel_SendReport(uint8_t result, char *reason); + +/** + * @brief Resends the last report. This is used in case we did not receive an ack for our report + * + * @return RETCODE_OK on success. Any other value means a failure + */ +Retcode_T CChannel_ResendReport(void); + +/** + * @brief Gets a tlv element using the type of the tlvElement input + * + * @param[in] ccmsg - message in which to look for the element + * @param[in, out] tlvElement - to store the element if found + * tlvElement->type used as input to find the element's value + * + * @return RETCODE_OK if found the TLV element, error code otherwise. + */ +Retcode_T CChannel_GetTlvElement(CCMsg_T *ccmsg, TlvElt_T *tlvElement); + +/** + * @brief Checks if the ack we received corresponds to the report we just sent + * + * @param[in] ccack ack message we received + * + * @return true if match, false if no match + */ +bool CChannel_DoesAckMatchReport(CCMsg_T *ccack); + +/** + * @brief Stops the CChannel + * + * @return RETCODE_OK on success. Any other value means a failure + */ +Retcode_T CChannel_Deinitialize(void); + +/** + * @brief Method triggered when a new message in received + * + * @param[in] buffer pointer to the message as a raw buffer + * @param[in] length length of the received message + */ +void CChannel_ReceiveEventHandler(uint8_t *buffer, uint8_t length); + +/** + * @brief Adds the tlv Element to the message + * + * @param[in] ccmsg Message to add the element to + * @param[in] tlvElement TLV element to add + * + * @return RETCODE_OK if successful error code otherwise + */ +Retcode_T CChannel_AddTlvElement(CCMsg_T *ccmsg, TlvElt_T *tlvElement); + +/*###################### GLOBAL VARIABLES ###########################################################################*/ + +#endif /* KISO_CCHANNEL_H_ */ \ No newline at end of file diff --git a/core/testing/source/protected/SerialCChannel.h b/core/testing/source/protected/SerialCChannel.h new file mode 100644 index 00000000..88e1b0eb --- /dev/null +++ b/core/testing/source/protected/SerialCChannel.h @@ -0,0 +1,77 @@ +/********************************************************************************************************************** + * Copyright (c) 2010#2019 Robert Bosch GmbH + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl#2.0. + * + * SPDX#License#Identifier: EPL#2.0 + * + * Contributors: + * Robert Bosch GmbH # initial contribution + * + **********************************************************************************************************************/ + +/** + * @file + * @defgroup + * @ingroup + * @{ + * + * @brief Serial Communication Channel Interface + * @details This header provides APIs to control uart communication line if this one is used as a communication + * channel between the Test executor and the test controller. + */ + +#ifndef SERIALCCHANNEL_H_ +#define SERIALCCHANNEL_H_ + +/*###################### INCLUDED HEADERS ############################################################################*/ + +#include "Kiso_Retcode.h" + +/*###################### MACROS DEFINITION ###########################################################################*/ + +/*###################### TYPE DEFINITIONS ############################################################################*/ + +/*###################### EXPORTED FUNCTIONS PROTOTYPES ###############################################################*/ + +/** + * @brief Initializes the serial interface + * + * @return RETCODE_OK if Initialized successfully error code otherwise. + */ +Retcode_T Serial_Initialize(void); + +/** + * @brief Deinitializes the serial interface + * + * @return RETCODE_OK if Deinitialized successfully error code otherwise. + */ +Retcode_T Serial_Deinitialize(void); + +/** + * @brief Receives data from the serial interface + * + * @param[in] data: A pointer to a data buffer. + * @param[in] len: Number of bytes to be received. + * + * @return RETCODE_OK if Receive successful error code otherwise. + */ +Retcode_T Serial_Receive(void *data, uint32_t len); + +/** + * @brief Sends data to the serial interface + * + * @param[in] data: A pointer to a data buffer. + * @param[in] len: Number of bytes to be sent. + * + * @return RETCODE_OK if Send successful error code otherwise + */ +Retcode_T Serial_Send(void *data, uint32_t len); + +/*###################### GLOBAL VARIABLES ###########################################################################*/ + +extern volatile uint32_t serialReceivedCnt; + +#endif /* SERIALCCHANNEL_H_ */ diff --git a/core/testing/source/protected/SerialMsgTransceiver.h b/core/testing/source/protected/SerialMsgTransceiver.h new file mode 100644 index 00000000..f1901bbe --- /dev/null +++ b/core/testing/source/protected/SerialMsgTransceiver.h @@ -0,0 +1,58 @@ +/********************************************************************************************************************** + * Copyright (c) 2010#2019 Robert Bosch GmbH + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl#2.0. + * + * SPDX#License#Identifier: EPL#2.0 + * + * Contributors: + * Robert Bosch GmbH # initial contribution + * + **********************************************************************************************************************/ + +/** + * @file + * @defgroup + * @ingroup + * @{ + * + * @brief Provides APIs for sending and receiving over serial line + * + */ + +#ifndef SERIALMSGTRANSCEIVER_H_ +#define SERIALMSGTRANSCEIVER_H_ + +/*###################### INCLUDED HEADERS ############################################################################*/ + +#include "Kiso_Retcode.h" + +/*###################### MACROS DEFINITION ###########################################################################*/ + +/*###################### TYPE DEFINITIONS ############################################################################*/ + +/*###################### EXPORTED FUNCTIONS PROTOTYPES ###############################################################*/ + +/** + * @brief Receive a message parses it and forwards it to CChannel for further processing + */ +void SerialMsgTransceiver_Receive(void); + +/** + * @brief Sends a message through the serial interface. + * @details This can be also used for building and sending the messages via other interfaces + * + * @param[in] message A reference to the message buffer to be sent. + * @param[in] length The Length of the message to be sent. + * + * @retval RETCODE_OK if the message transmitted successfully, error code otherwise. + */ +Retcode_T SerialMsgTransceiver_Send(uint8_t *message, uint8_t length); + +#endif /* SERIALMSGTRANSCEIVER_H_ */ + +/*###################### GLOBAL VARIABLES ###########################################################################*/ + +/** @} */ diff --git a/core/testing/source/protected/TestRegistry.h b/core/testing/source/protected/TestRegistry.h new file mode 100644 index 00000000..bf07f5d5 --- /dev/null +++ b/core/testing/source/protected/TestRegistry.h @@ -0,0 +1,197 @@ +/********************************************************************************************************************** + * Copyright (c) 2010#2019 Robert Bosch GmbH + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl#2.0. + * + * SPDX#License#Identifier: EPL#2.0 + * + * Contributors: + * Robert Bosch GmbH # initial contribution + * + **********************************************************************************************************************/ + +/** + * @file + * @defgroup + * @ingroup + * @{ + * + * @brief todo mak write brief here + * + */ + +#ifndef TESTREGISTRY_H_ +#define TESTREGISTRY_H_ + +/*###################### INCLUDED HEADERS ############################################################################*/ + +#include "Kiso_Testing.h" + +/*###################### MACROS DEFINITION ###########################################################################*/ + +#ifndef TEST_MAX_NUMBER_OF_TEST_CASES_PER_TEST_SUITE +#warning "config TEST_MAX_NUMBER_OF_TEST_CASES_PER_TEST_SUITE not set. The software will build with default value 1" +#define TEST_MAX_NUMBER_OF_TEST_CASES_PER_TEST_SUITE 1 +#endif +/*###################### TYPE DEFINITIONS ############################################################################*/ + +/** + * @brief Structure for the test case which contains the function pointers for setup, run and tear down. + */ +typedef struct TestCase_S +{ + uint8_t id; + SetupFct_T setup; + RunFct_T run; + TearDownFct_T teardown; +} TstCse_T, TstCse_T; + +/** + * @brief Structure for the test suite which contains the function pointers for setup and tear down. + * It also contains the test case structure with the number of test cases. + */ +typedef struct TestSuite_S +{ + uint8_t id; + uint8_t numTestCases; + SetupFct_T setup; + TearDownFct_T teardown; + TstCse_T testCases[TEST_MAX_NUMBER_OF_TEST_CASES_PER_TEST_SUITE]; +} TstSte_T; + +typedef struct TestEntry_S +{ + uint8_t id; + uint8_t numTestSuites; + SetupFct_T setup; + TearDownFct_T teardown; + TstSte_T testSuites[TEST_MAX_NUMBER_OF_TEST_SUITES]; +} TstEnt_T, TstEnt_T; + +/*###################### EXPORTED FUNCTIONS PROTOTYPES ###############################################################*/ + +/** + * @brief Initializes the Test Registry. + * @details This function Initializes the Test Registry by filling it with the Test Entry, Test Suites and Test Case arrays. + * @param[in] eId The Identifier of the Test Entry + * @param[in] setup A reference to the setup function of the Test Entry. + * @param[in] teardown A reference to the tear down function of the Test Entry. + * @note setup and tear down functions pointers can be null if nothing has to be done. + */ +void TestRegistry_Initialize(uint8_t eId, SetupFct_T setup, TearDownFct_T teardown); + +/** + * @brief Registers a Test Suite + * @param[in] sId The Identifier of the Test Suite to register + * @param[in] setup A reference to the setup function of the Test Suite + * @param[in] teardown A reference to the tear down function of the Test Suite + * @note setup and tear down functions pointers can be null if nothing has to be done. + * @return RETCODE_OK if the Test Suite registered successfully. + * @return RETCODE_OUT_OF_RESOURCES if Maximum number of Test Suites reached. + * @return RETCODE_TESTING_SUITE_ALREADY_REGISTERED if a test suite with this Id has already been registered. + */ +Retcode_T TestRegistry_RegisterTestSuite(uint8_t sId, SetupFct_T setup, TearDownFct_T teardown); + +/** + * @brief Registers a Test Case + * @param[in] sId Id of the Test Suite of the test to register + * @param[in] cId Id of the Test Case to register + * @param[in] setup A reference to the setup function of the Test Suite + * @param[in] run A reference to the run function of the Test Suite + * @param[in] teardown function pointer to the tear down function of the Test Suite + * @note setup and tear down functions pointers can be null if nothing has to be done. + * @note run method MUST NOT be NULL! + * @return RETCODE_OK The Test Case registered successfully + * @return RETCODE_INVALID_PARAM No Test Suite with the given Id has been found + * @return RETCODE_OUT_OF_RESOURCES Maximum number of Test Cases reached + * @return RETCODE_TESTING_CASE_ALREADY_REGISTERED A Test Case with this Id has already been registered + */ +Retcode_T TestRegistry_RegisterTestCase(uint8_t sId, uint8_t cId, SetupFct_T setup, RunFct_T run, TearDownFct_T teardown); + +/** + * @brief Looks up for a Test Entry by Id + * @param[in] eId Id of the Test Entry to look for. + * @return Reference to the Test Entry on SUCCESS NULL if not found + */ +TstEnt_T *TestRegistry_LookupTestEntry(uint8_t eId); + +/** + * @brief Looks up for a Test Suite + * + * @param[in] eId The identifier of the Test Suite the test to register + * @param[in] sId The identifier of the Test Suite the test to register + * @return Test Suite pointer on SUCCESS NULL if not found. + */ +TstSte_T *TestRegistry_LookupTestSuite(uint8_t eId, uint8_t sId); + +/** + * @brief Looks up for a Test Case + * + * @param[in] eId The identifier of the test entry register to look from + * @param[in] sId The identifier of the test suite register to look from + * @param[in] cId Id of the Test Case to look for. + * @return Test Case pointer on SUCCESS, NULL if not found + */ +TstCse_T *TestRegistry_LookupTestCase(uint8_t eId, uint8_t sId, uint8_t cId); + +/** + * @brief Calls the setup function of the Test Entry + * @param[in] testEntry Test Entry which setup function should be called + * @param[in] ccmsg Message to pass to the Test Entry setup function. + * @return Retcode of the Setup function to use for the Acknowledgment message + */ +Retcode_T TestEntry_Setup(TstEnt_T *testEntry, CCMsg_T *ccmsg); + +/** + * @brief Calls the teardown function of the Test Entry + * @param[in] testEntry Test Entry which teardown function should be called + * @param[in] ccmsg Message to pass to the Test Entry teardown function. + * @return Retcode of the Teardown function to use for the Acknowledgment message. + */ +Retcode_T TestEntry_Teardown(TstEnt_T *testEntry, CCMsg_T *ccmsg); + +/** + * @brief Calls the setup function of the Test Suite + * @param[in] testSuite Test Suite which setup function should be called + * @param[in] ccmsg Message to pass to the Test Suite setup function. * + * @return Retcode of the setup function to use for the Acknowledgment message + */ +Retcode_T TestSuite_Setup(TstSte_T *testSuite, CCMsg_T *ccmsg); + +/** + * @brief Calls the teardown function of the Test Suite + * @param[in] testSuite Test Suite which teardown function should be called + * @param[in] ccmsg Message to pass to the Test Suite teardown function. + * @return Retcode of the Teardown function to use for the Acknowledgment message + */ +Retcode_T TestSuite_Teardown(TstSte_T *testSuite, CCMsg_T *ccmsg); + +/** + * @brief Calls the setup function of the Test Case + * @param[in] testCase Test Case which setup function should be called + * @param[in] ccmsg Message to pass to the Test Case setup function. + * @return Retcode of the setup function to use for the Acknowledgment message + */ +Retcode_T TestCase_Setup(TstCse_T *testCase, CCMsg_T *ccmsg); + +/** + * @brief Calls the run function of the Test Case + * @param[in] testCase Test Case which run function should be called + * @param[in] ccmsg Message to pass to the Test Case run function. + */ +void TestCase_Run(TstCse_T *testCase, CCMsg_T *ccmsg); + +/** + * @brief Calls the teardown function of the Test Case + * + * @param[in] testCase Test Case which teardown function should be called + * @param[in] ccmsg Message to pass to the Test Case teardown function. + * @return Retcode of the Teardown function to use for the Acknowledgment message + */ +Retcode_T TestCase_Teardown(TstCse_T *testCase, CCMsg_T *ccmsg); + +/*###################### GLOBAL VARIABLES ###########################################################################*/ + +#endif /* TESTREGISTRY_H_ */ diff --git a/core/testing/source/protected/TestRunner.h b/core/testing/source/protected/TestRunner.h new file mode 100644 index 00000000..5b0ec3e1 --- /dev/null +++ b/core/testing/source/protected/TestRunner.h @@ -0,0 +1,62 @@ +/********************************************************************************************************************** + * Copyright (c) 2010#2019 Robert Bosch GmbH + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl#2.0. + * + * SPDX#License#Identifier: EPL#2.0 + * + * Contributors: + * Robert Bosch GmbH # initial contribution + * + **********************************************************************************************************************/ + +/** + * @file + * @defgroup + * @ingroup + * @{ + * + * @brief todo mak provide description of the module. + * + */ + +#ifndef TESTRUNNER_H_ +#define TESTRUNNER_H_ + +/*###################### INCLUDED HEADERS ############################################################################*/ + +#include "Kiso_Testing.h" +#include "Kiso_Retcode.h" + +/*###################### MACROS DEFINITION ###########################################################################*/ + +/*###################### TYPE DEFINITIONS ############################################################################*/ + +/*###################### EXPORTED FUNCTIONS PROTOTYPES ###############################################################*/ + +/** + * @brief Initializes the Test Runner + * @retval RETCODE_OK in case of success, error code otherwise. + */ +Retcode_T TestRunner_Initialize(void); + +/** + * @brief Processes an incoming message + * @param[in] ccmsg incoming message to process + */ +void TestRunner_ProcessMessage(CCMsg_T *ccmsg); + +/** + * @brief Sends a Report. + * + * @param[in] result test result code (0: success / otherwise: failure) + * @param[in] reason 0-terminating string stating a reason. It can be NULL, if no reason should be sent. + */ +void TestRunner_SendReport(uint8_t result, char *reason); + +/*###################### GLOBAL VARIABLES ###########################################################################*/ + +#endif /* TESTRUNNER_H_ */ +/** @} */