/* * Copyright (c) 2022 Trackunit Corporation * * SPDX-License-Identifier: Apache-2.0 */ /*************************************************************************************************/ /* Dependencies */ /*************************************************************************************************/ #include #include #include #include #include #include #include #include #include #include #define TEST_MODEM_BACKEND_TTY_PIPE_EVENT_OPENED_BIT (0) #define TEST_MODEM_BACKEND_TTY_PIPE_EVENT_RRDY_BIT (1) #define TEST_MODEM_BACKEND_TTY_PIPE_EVENT_TIDLE_BIT (2) #define TEST_MODEM_BACKEND_TTY_PIPE_EVENT_CLOSED_BIT (3) #define TEST_MODEM_BACKEND_TTY_OP_DELAY (K_MSEC(1000)) /*************************************************************************************************/ /* Mock pipe */ /*************************************************************************************************/ static struct modem_backend_tty tty_backend; static struct modem_pipe *tty_pipe; /*************************************************************************************************/ /* Mock PTY */ /*************************************************************************************************/ static int primary_fd; /*************************************************************************************************/ /* Buffers */ /*************************************************************************************************/ static uint8_t buffer1[1024]; K_KERNEL_STACK_DEFINE(tty_stack, 4096); /*************************************************************************************************/ /* Helpers */ /*************************************************************************************************/ static void test_modem_backend_tty_cfmakeraw(struct termios *termios_p) { termios_p->c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP | INLCR | IGNCR | ICRNL | IXON); termios_p->c_oflag &= ~OPOST; termios_p->c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN); termios_p->c_cflag &= ~(CSIZE | PARENB); termios_p->c_cflag |= CS8; } /*************************************************************************************************/ /* Modem pipe callback */ /*************************************************************************************************/ static atomic_t tty_pipe_events; static void modem_pipe_callback_handler(struct modem_pipe *pipe, enum modem_pipe_event event, void *user_data) { switch (event) { case MODEM_PIPE_EVENT_OPENED: atomic_set_bit(&tty_pipe_events, TEST_MODEM_BACKEND_TTY_PIPE_EVENT_OPENED_BIT); break; case MODEM_PIPE_EVENT_RECEIVE_READY: atomic_set_bit(&tty_pipe_events, TEST_MODEM_BACKEND_TTY_PIPE_EVENT_RRDY_BIT); break; case MODEM_PIPE_EVENT_TRANSMIT_IDLE: atomic_set_bit(&tty_pipe_events, TEST_MODEM_BACKEND_TTY_PIPE_EVENT_TIDLE_BIT); break; case MODEM_PIPE_EVENT_CLOSED: atomic_set_bit(&tty_pipe_events, TEST_MODEM_BACKEND_TTY_PIPE_EVENT_CLOSED_BIT); break; } } /*************************************************************************************************/ /* Test setup */ /*************************************************************************************************/ static void *test_modem_backend_tty_setup(void) { const char *secondary_name; struct termios tio; primary_fd = posix_openpt(O_RDWR | O_NOCTTY); __ASSERT_NO_MSG(primary_fd > -1); __ASSERT_NO_MSG(grantpt(primary_fd) > -1); __ASSERT_NO_MSG(unlockpt(primary_fd) > -1); __ASSERT_NO_MSG(tcgetattr(primary_fd, &tio) > -1); test_modem_backend_tty_cfmakeraw(&tio); __ASSERT_NO_MSG(tcsetattr(primary_fd, TCSAFLUSH, &tio) > -1); secondary_name = ptsname(primary_fd); struct modem_backend_tty_config config = { .tty_path = secondary_name, .stack = tty_stack, .stack_size = K_KERNEL_STACK_SIZEOF(tty_stack), }; tty_pipe = modem_backend_tty_init(&tty_backend, &config); modem_pipe_attach(tty_pipe, modem_pipe_callback_handler, NULL); __ASSERT_NO_MSG(modem_pipe_open(tty_pipe, K_SECONDS(10)) == 0); return NULL; } static void test_modem_backend_tty_before(void *f) { atomic_set(&tty_pipe_events, 0); } static void test_modem_backend_tty_teardown(void *f) { modem_pipe_close(tty_pipe, K_SECONDS(10)); } /*************************************************************************************************/ /* Tests */ /*************************************************************************************************/ ZTEST(modem_backend_tty_suite, test_close_open) { bool result; zassert_ok(modem_pipe_close(tty_pipe, K_SECONDS(10)), "Failed to close pipe"); zassert_ok(modem_pipe_close(tty_pipe, K_SECONDS(10)), "Pipe should already be closed"); zassert_ok(modem_pipe_open(tty_pipe, K_SECONDS(10)), "Failed to open pipe"); result = atomic_test_bit(&tty_pipe_events, TEST_MODEM_BACKEND_TTY_PIPE_EVENT_TIDLE_BIT); zassert_true(result, "Transmit idle event should be set"); zassert_ok(modem_pipe_open(tty_pipe, K_SECONDS(10)), "Pipe should already be open"); } ZTEST(modem_backend_tty_suite, test_receive_ready_event_not_raised) { bool result; k_sleep(TEST_MODEM_BACKEND_TTY_OP_DELAY); result = atomic_test_bit(&tty_pipe_events, TEST_MODEM_BACKEND_TTY_PIPE_EVENT_RRDY_BIT); zassert_false(result, "Receive ready event should not be set"); } ZTEST(modem_backend_tty_suite, test_receive_ready_event_raised) { int ret; bool result; char msg[] = "Test me buddy"; ret = write(primary_fd, msg, sizeof(msg)); zassert_true(ret == sizeof(msg), "Failed to write to primary FD"); k_sleep(TEST_MODEM_BACKEND_TTY_OP_DELAY); result = atomic_test_bit(&tty_pipe_events, TEST_MODEM_BACKEND_TTY_PIPE_EVENT_RRDY_BIT); zassert_true(result == true, "Receive ready evennt not set"); } ZTEST(modem_backend_tty_suite, test_receive) { int ret; char msg[] = "Test me buddy"; ret = write(primary_fd, msg, sizeof(msg)); zassert_true(ret == sizeof(msg), "Failed to write to primary FD"); k_sleep(TEST_MODEM_BACKEND_TTY_OP_DELAY); ret = modem_pipe_receive(tty_pipe, buffer1, sizeof(buffer1)); zassert_true(ret == sizeof(msg), "Received incorrect number of bytes"); ret = memcmp(msg, buffer1, sizeof(msg)); zassert_true(ret == 0, "Received incorrect bytes"); } ZTEST(modem_backend_tty_suite, test_transmit) { int ret; char msg[] = "Test me buddy 2"; bool result; result = atomic_test_bit(&tty_pipe_events, TEST_MODEM_BACKEND_TTY_PIPE_EVENT_TIDLE_BIT); zassert_false(result, "Transmit idle event should not be set"); ret = modem_pipe_transmit(tty_pipe, msg, sizeof(msg)); zassert_true(ret == sizeof(msg), "Failed to transmit using pipe"); k_sleep(TEST_MODEM_BACKEND_TTY_OP_DELAY); result = atomic_test_bit(&tty_pipe_events, TEST_MODEM_BACKEND_TTY_PIPE_EVENT_TIDLE_BIT); zassert_true(result, "Transmit idle event should be set"); ret = read(primary_fd, buffer1, sizeof(buffer1)); zassert_true(ret == sizeof(msg), "Read incorrect number of bytes"); ret = memcmp(msg, buffer1, sizeof(msg)); zassert_true(ret == 0, "Read incorrect bytes"); } ZTEST_SUITE(modem_backend_tty_suite, NULL, test_modem_backend_tty_setup, test_modem_backend_tty_before, NULL, test_modem_backend_tty_teardown);