1 /*
2 * Copyright (c) 2022 Trackunit Corporation
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 /*************************************************************************************************/
8 /* Dependencies */
9 /*************************************************************************************************/
10 #include <zephyr/ztest.h>
11 #include <zephyr/kernel.h>
12 #include <zephyr/sys/atomic.h>
13
14 #include <zephyr/modem/backend/tty.h>
15
16 #include <stdio.h>
17 #include <stdlib.h>
18 #include <fcntl.h>
19 #include <unistd.h>
20 #include <string.h>
21 #include <termios.h>
22
23 #define TEST_MODEM_BACKEND_TTY_PIPE_EVENT_OPENED_BIT (0)
24 #define TEST_MODEM_BACKEND_TTY_PIPE_EVENT_RRDY_BIT (1)
25 #define TEST_MODEM_BACKEND_TTY_PIPE_EVENT_TIDLE_BIT (2)
26 #define TEST_MODEM_BACKEND_TTY_PIPE_EVENT_CLOSED_BIT (3)
27
28 #define TEST_MODEM_BACKEND_TTY_OP_DELAY (K_MSEC(1000))
29
30 /*************************************************************************************************/
31 /* Mock pipe */
32 /*************************************************************************************************/
33 static struct modem_backend_tty tty_backend;
34 static struct modem_pipe *tty_pipe;
35
36 /*************************************************************************************************/
37 /* Mock PTY */
38 /*************************************************************************************************/
39 static int primary_fd;
40
41 /*************************************************************************************************/
42 /* Buffers */
43 /*************************************************************************************************/
44 static uint8_t buffer1[1024];
45 K_KERNEL_STACK_DEFINE(tty_stack, 4096);
46
47 /*************************************************************************************************/
48 /* Helpers */
49 /*************************************************************************************************/
test_modem_backend_tty_cfmakeraw(struct termios * termios_p)50 static void test_modem_backend_tty_cfmakeraw(struct termios *termios_p)
51 {
52 termios_p->c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP | INLCR | IGNCR | ICRNL | IXON);
53 termios_p->c_oflag &= ~OPOST;
54 termios_p->c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN);
55 termios_p->c_cflag &= ~(CSIZE | PARENB);
56 termios_p->c_cflag |= CS8;
57 }
58
59 /*************************************************************************************************/
60 /* Modem pipe callback */
61 /*************************************************************************************************/
62 static atomic_t tty_pipe_events;
63
modem_pipe_callback_handler(struct modem_pipe * pipe,enum modem_pipe_event event,void * user_data)64 static void modem_pipe_callback_handler(struct modem_pipe *pipe, enum modem_pipe_event event,
65 void *user_data)
66 {
67 switch (event) {
68 case MODEM_PIPE_EVENT_OPENED:
69 atomic_set_bit(&tty_pipe_events, TEST_MODEM_BACKEND_TTY_PIPE_EVENT_OPENED_BIT);
70 break;
71
72 case MODEM_PIPE_EVENT_RECEIVE_READY:
73 atomic_set_bit(&tty_pipe_events, TEST_MODEM_BACKEND_TTY_PIPE_EVENT_RRDY_BIT);
74 break;
75
76 case MODEM_PIPE_EVENT_TRANSMIT_IDLE:
77 atomic_set_bit(&tty_pipe_events, TEST_MODEM_BACKEND_TTY_PIPE_EVENT_TIDLE_BIT);
78 break;
79
80 case MODEM_PIPE_EVENT_CLOSED:
81 atomic_set_bit(&tty_pipe_events, TEST_MODEM_BACKEND_TTY_PIPE_EVENT_CLOSED_BIT);
82 break;
83 }
84 }
85
86 /*************************************************************************************************/
87 /* Test setup */
88 /*************************************************************************************************/
test_modem_backend_tty_setup(void)89 static void *test_modem_backend_tty_setup(void)
90 {
91 const char *secondary_name;
92 struct termios tio;
93
94 primary_fd = posix_openpt(O_RDWR | O_NOCTTY);
95 __ASSERT_NO_MSG(primary_fd > -1);
96 __ASSERT_NO_MSG(grantpt(primary_fd) > -1);
97 __ASSERT_NO_MSG(unlockpt(primary_fd) > -1);
98 __ASSERT_NO_MSG(tcgetattr(primary_fd, &tio) > -1);
99 test_modem_backend_tty_cfmakeraw(&tio);
100 __ASSERT_NO_MSG(tcsetattr(primary_fd, TCSAFLUSH, &tio) > -1);
101 secondary_name = ptsname(primary_fd);
102
103 struct modem_backend_tty_config config = {
104 .tty_path = secondary_name,
105 .stack = tty_stack,
106 .stack_size = K_KERNEL_STACK_SIZEOF(tty_stack),
107 };
108
109 tty_pipe = modem_backend_tty_init(&tty_backend, &config);
110 modem_pipe_attach(tty_pipe, modem_pipe_callback_handler, NULL);
111 __ASSERT_NO_MSG(modem_pipe_open(tty_pipe) == 0);
112 return NULL;
113 }
114
test_modem_backend_tty_before(void * f)115 static void test_modem_backend_tty_before(void *f)
116 {
117 atomic_set(&tty_pipe_events, 0);
118 }
119
test_modem_backend_tty_teardown(void * f)120 static void test_modem_backend_tty_teardown(void *f)
121 {
122 modem_pipe_close(tty_pipe);
123 }
124
125 /*************************************************************************************************/
126 /* Tests */
127 /*************************************************************************************************/
ZTEST(modem_backend_tty_suite,test_close_open)128 ZTEST(modem_backend_tty_suite, test_close_open)
129 {
130 bool result;
131
132 zassert_ok(modem_pipe_close(tty_pipe), "Failed to close pipe");
133 zassert_ok(modem_pipe_close(tty_pipe), "Pipe should already be closed");
134 zassert_ok(modem_pipe_open(tty_pipe), "Failed to open pipe");
135 result = atomic_test_bit(&tty_pipe_events, TEST_MODEM_BACKEND_TTY_PIPE_EVENT_TIDLE_BIT);
136 zassert_true(result, "Transmit idle event should be set");
137 zassert_ok(modem_pipe_open(tty_pipe), "Pipe should already be open");
138 }
139
ZTEST(modem_backend_tty_suite,test_receive_ready_event_not_raised)140 ZTEST(modem_backend_tty_suite, test_receive_ready_event_not_raised)
141 {
142 bool result;
143
144 k_sleep(TEST_MODEM_BACKEND_TTY_OP_DELAY);
145
146 result = atomic_test_bit(&tty_pipe_events, TEST_MODEM_BACKEND_TTY_PIPE_EVENT_RRDY_BIT);
147 zassert_false(result, "Receive ready event should not be set");
148 }
149
ZTEST(modem_backend_tty_suite,test_receive_ready_event_raised)150 ZTEST(modem_backend_tty_suite, test_receive_ready_event_raised)
151 {
152 int ret;
153 bool result;
154 char msg[] = "Test me buddy";
155
156 ret = write(primary_fd, msg, sizeof(msg));
157 zassert_true(ret == sizeof(msg), "Failed to write to primary FD");
158
159 k_sleep(TEST_MODEM_BACKEND_TTY_OP_DELAY);
160
161 result = atomic_test_bit(&tty_pipe_events, TEST_MODEM_BACKEND_TTY_PIPE_EVENT_RRDY_BIT);
162 zassert_true(result == true, "Receive ready evennt not set");
163 }
164
ZTEST(modem_backend_tty_suite,test_receive)165 ZTEST(modem_backend_tty_suite, test_receive)
166 {
167 int ret;
168 char msg[] = "Test me buddy";
169
170 ret = write(primary_fd, msg, sizeof(msg));
171 zassert_true(ret == sizeof(msg), "Failed to write to primary FD");
172 k_sleep(TEST_MODEM_BACKEND_TTY_OP_DELAY);
173
174 ret = modem_pipe_receive(tty_pipe, buffer1, sizeof(buffer1));
175 zassert_true(ret == sizeof(msg), "Received incorrect number of bytes");
176 ret = memcmp(msg, buffer1, sizeof(msg));
177 zassert_true(ret == 0, "Received incorrect bytes");
178 }
179
ZTEST(modem_backend_tty_suite,test_transmit)180 ZTEST(modem_backend_tty_suite, test_transmit)
181 {
182 int ret;
183 char msg[] = "Test me buddy 2";
184 bool result;
185
186 result = atomic_test_bit(&tty_pipe_events, TEST_MODEM_BACKEND_TTY_PIPE_EVENT_TIDLE_BIT);
187 zassert_false(result, "Transmit idle event should not be set");
188
189 ret = modem_pipe_transmit(tty_pipe, msg, sizeof(msg));
190 zassert_true(ret == sizeof(msg), "Failed to transmit using pipe");
191
192 k_sleep(TEST_MODEM_BACKEND_TTY_OP_DELAY);
193
194 result = atomic_test_bit(&tty_pipe_events, TEST_MODEM_BACKEND_TTY_PIPE_EVENT_TIDLE_BIT);
195 zassert_true(result, "Transmit idle event should be set");
196
197 ret = read(primary_fd, buffer1, sizeof(buffer1));
198 zassert_true(ret == sizeof(msg), "Read incorrect number of bytes");
199 ret = memcmp(msg, buffer1, sizeof(msg));
200 zassert_true(ret == 0, "Read incorrect bytes");
201 }
202
203 ZTEST_SUITE(modem_backend_tty_suite, NULL, test_modem_backend_tty_setup,
204 test_modem_backend_tty_before, NULL, test_modem_backend_tty_teardown);
205