Newer
Older
mbed-os / drivers / tests / TESTS / mbed_drivers / unbuffered_serial / main.cpp
@George Psimenos George Psimenos on 24 Mar 2021 5 KB Replace USBTX/RX everywhere else
/*
 * Copyright (c) 2019 Arm Limited and affiliates.
 * SPDX-License-Identifier: Apache-2.0
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
#if !DEVICE_SERIAL
#error [NOT_SUPPORTED] serial communication not supported for this target
#else

#include "mbed.h"
#include "utest/utest.h"
#include "unity/unity.h"
#include "greentea-client/test_env.h"


using namespace utest::v1;


/**
 * Macros for setting console flow control.
 */
#define CONSOLE_FLOWCONTROL_RTS                                               1
#define CONSOLE_FLOWCONTROL_CTS                                               2
#define CONSOLE_FLOWCONTROL_RTSCTS                                            3
#define mbed_console_concat_(x) CONSOLE_FLOWCONTROL_##x
#define mbed_console_concat(x) mbed_console_concat_(x)
#define CONSOLE_FLOWCONTROL mbed_console_concat(MBED_CONF_TARGET_CONSOLE_UART_FLOW_CONTROL)


#define MSG_KEY_ECHO_MESSAGE                                     "echo_message"
#define MSG_VALUE_HELLO_WORLD                                   "Hello, world!"

#define EXPECTED_ECHOED_STRING "{{" MSG_KEY_ECHO_MESSAGE ";" MSG_VALUE_HELLO_WORLD "}}"
// The target is expected to transmit Greentea messages with \n (or \r\n) or they are not detected by the host
#define STRING_TO_SEND EXPECTED_ECHOED_STRING "\n"


static UnbufferedSerial unbuffered_serial_obj(
    CONSOLE_TX, CONSOLE_RX, MBED_CONF_PLATFORM_STDIO_BAUD_RATE
);

static ssize_t unbuffered_serial_read(void *buffer, ssize_t length)
{
    if (length == 0) {
        return 0;
    }

    // Ignore the `\n` character previously sent to the host in the previous
    // key-value pair that may not have been removed from the FIFO.
    unsigned char *buf = static_cast<unsigned char *>(buffer);
    unbuffered_serial_obj.read(buf, 1);
    ssize_t i = (buf[0] == '{') ? 1 : 0;

    // Get the message sent by the host
    for (; i < length; i++) {
        TEST_ASSERT_EQUAL_UINT(1, unbuffered_serial_obj.read(buf + i, 1));
    }

    return length;
}


// Test that data sent using an UnbufferedSerial object is correctly sent.
// The test case sends a Greentea key-value pair message from the target to the
// host using an UnbufferedSerial object and expects the message
// to be echoed back by the host. The host response is received via the Greentea
// framework usual route using greentea_parse_kv(). Success is determined upon
// reception of the echoed message which indicates that the message was received
// by the host as it was sent by the target.
static void test_serial_write()
{
    char tx_msg[] = STRING_TO_SEND;

    TEST_ASSERT_EQUAL_UINT(
        strlen(tx_msg) + 1,
        unbuffered_serial_obj.write(tx_msg, strlen(tx_msg) + 1)
    );

    char rx_key[30] = {0};
    char rx_value[30] = {0};
    greentea_parse_kv(rx_key, rx_value, sizeof(rx_key), sizeof(rx_value));

    TEST_ASSERT_EQUAL_STRING(MSG_KEY_ECHO_MESSAGE, rx_key);
    TEST_ASSERT_EQUAL_STRING(MSG_VALUE_HELLO_WORLD, rx_value);
}


// Test that data received using an UnbufferedSerial object is correctly received.
// The test case sends a Greentea key-value pair message from the target to the
// host via the Greentea framework usual route using greentea_send_kv().
// It expects the message to be echoed back to the target. An UnbufferedSerial
// object is used to handle the received message. Succes is determined upon
// reception of a key-value pair matching the key-value pair sent by the target.
static void test_serial_read()
{
    greentea_send_kv(MSG_KEY_ECHO_MESSAGE, MSG_VALUE_HELLO_WORLD);

    char rx_msg[sizeof(EXPECTED_ECHOED_STRING)] = {0};
    // Exclude the null terminator which is not read
    ssize_t expected_rx_msg_length = sizeof(EXPECTED_ECHOED_STRING) - 1;

    unbuffered_serial_read(rx_msg, expected_rx_msg_length);

    TEST_ASSERT_EQUAL_STRING(EXPECTED_ECHOED_STRING, rx_msg);
}


utest::v1::status_t greentea_setup(const size_t number_of_cases)
{
    GREENTEA_SETUP(12, "serial_comms");

    return greentea_test_setup_handler(number_of_cases);
}


utest::v1::status_t greentea_failure_handler(
    const Case *const source, const failure_t reason
)
{
    greentea_case_failure_abort_handler(source, reason);
    return STATUS_CONTINUE;
}


Case cases[] = {
    Case(
        "Bytes are correctly sent",
        test_serial_write, greentea_failure_handler
    ),
    Case(
        "Bytes are correctly received",
        test_serial_read, greentea_failure_handler
    ),
};


Specification specification(
    greentea_setup, cases, greentea_test_teardown_handler
);


int main()
{
#if   CONSOLE_FLOWCONTROL == CONSOLE_FLOWCONTROL_RTS
    unbuffered_serial_obj.set_flow_control(
        SerialBase::RTS, STDIO_UART_RTS, NC
    );
#elif CONSOLE_FLOWCONTROL == CONSOLE_FLOWCONTROL_CTS
    unbuffered_serial_obj.set_flow_control(
        SerialBase::CTS, NC, STDIO_UART_CTS
    );
#elif CONSOLE_FLOWCONTROL == CONSOLE_FLOWCONTROL_RTSCTS
    unbuffered_serial_obj.set_flow_control(
        SerialBase::RTSCTS, STDIO_UART_RTS, STDIO_UART_CTS
    );
#endif
    return !Harness::run(specification);
}

#endif // !DEVICE_SERIAL