blob: 96ebdb2763da7eece87d477bacdf7cadb69b87b8 [file] [log] [blame]
/*
* Copyright (c) 2022 Trackunit Corporation
*
* SPDX-License-Identifier: Apache-2.0
*/
/*************************************************************************************************/
/* Dependencies */
/*************************************************************************************************/
#include <zephyr/ztest.h>
#include <zephyr/kernel.h>
#include <zephyr/sys/atomic.h>
#include <zephyr/modem/backend/tty.h>
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <termios.h>
#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) == 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);
}
/*************************************************************************************************/
/* Tests */
/*************************************************************************************************/
ZTEST(modem_backend_tty_suite, test_close_open)
{
bool result;
zassert_ok(modem_pipe_close(tty_pipe), "Failed to close pipe");
zassert_ok(modem_pipe_close(tty_pipe), "Pipe should already be closed");
zassert_ok(modem_pipe_open(tty_pipe), "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), "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);