blob: 7280bdcd1e7d2df2c7b5379027848d9d80d5a683 [file] [log] [blame]
Vadim Yanitskiy9ef304d2023-11-14 20:46:01 +07001/*
2 * (C) 2023 by sysmocom - s.f.m.c. GmbH <info@sysmocom.de>
3 * Author: Vadim Yanitskiy <vyanitskiy@sysmocom.de>
4 *
5 * All Rights Reserved
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 */
18
Vadim Yanitskiy811638c2023-11-30 03:09:05 +070019#include <errno.h>
Vadim Yanitskiy9ef304d2023-11-14 20:46:01 +070020#include <stdio.h>
21#include <stdint.h>
22
23#include <osmocom/core/msgb.h>
24#include <osmocom/core/utils.h>
25#include <osmocom/core/soft_uart.h>
26
Vadim Yanitskiyd0b575c2023-12-09 04:26:51 +070027#define SUART_TEST_BEGIN \
28 do { \
29 printf("\nExecuting %s\n", __func__); \
30 } while (0)
31
Vadim Yanitskiy9ef304d2023-11-14 20:46:01 +070032static struct {
33 size_t data_len;
34 const uint8_t *data;
35} g_tx_cb_cfg;
36
37static void suart_rx_cb(void *priv, struct msgb *msg, unsigned int flags)
38{
39 fprintf(stdout, "%s(flags=%02x): %s\n",
40 __func__, flags, msgb_hexdump(msg));
41 msgb_free(msg);
42}
43
44static void suart_tx_cb(void *priv, struct msgb *msg)
45{
46 size_t n_bytes;
47
48 n_bytes = OSMO_MIN(g_tx_cb_cfg.data_len, msg->data_len);
49 if (g_tx_cb_cfg.data != NULL && n_bytes > 0)
50 memcpy(msgb_put(msg, n_bytes), g_tx_cb_cfg.data, n_bytes);
51
52 fprintf(stdout, "%s(len=%u/%u): %s\n",
53 __func__, msg->len, msg->data_len, msgb_hexdump(msg));
54}
55
Vadim Yanitskiy6587dd02023-11-30 03:04:32 +070056static void suart_status_change_cb(void *priv, unsigned int status)
57{
58 fprintf(stdout, "%s(status=0x%08x)\n", __func__, status);
59}
60
Vadim Yanitskiy9ef304d2023-11-14 20:46:01 +070061static const struct osmo_soft_uart_cfg suart_test_default_cfg = {
62 .num_data_bits = 8,
63 .num_stop_bits = 1,
64 .parity_mode = OSMO_SUART_PARITY_NONE,
65 .rx_buf_size = 128,
66 .rx_cb = &suart_rx_cb,
67 .tx_cb = &suart_tx_cb,
Vadim Yanitskiy6587dd02023-11-30 03:04:32 +070068 .status_change_cb = &suart_status_change_cb,
Vadim Yanitskiy9ef304d2023-11-14 20:46:01 +070069};
70
71static void test_rx_exec(struct osmo_soft_uart *suart,
72 const char *input)
73{
74 for (unsigned int i = 0; input[i] != '\0'; i++) {
75 ubit_t ubit;
Vadim Yanitskiyc460deb2023-12-09 02:44:59 +070076 int rc;
Vadim Yanitskiy9ef304d2023-11-14 20:46:01 +070077
78 switch (input[i]) {
79 case '0':
80 case '1':
81 ubit = input[i] - '0';
Vadim Yanitskiyc460deb2023-12-09 02:44:59 +070082 rc = osmo_soft_uart_rx_ubits(suart, &ubit, 1);
83 OSMO_ASSERT(rc == 0); /* 0 on success */
Vadim Yanitskiy9ef304d2023-11-14 20:46:01 +070084 break;
85 case 'F':
86 printf("%s() @ %u: flush the Rx buffer\n", __func__, i);
87 osmo_soft_uart_flush_rx(suart);
88 break;
89 case ' ': /* padding */
90 continue;
91 default:
92 printf("%s() @ %u: unknown opcode '%c'\n",
93 __func__, i, input[i]);
94 break;
95 }
96 }
97}
98
99static void test_rx(void)
100{
101 struct osmo_soft_uart_cfg cfg;
102 struct osmo_soft_uart *suart;
103
Vadim Yanitskiyd0b575c2023-12-09 04:26:51 +0700104 SUART_TEST_BEGIN;
105
Vadim Yanitskiy9ef304d2023-11-14 20:46:01 +0700106 suart = osmo_soft_uart_alloc(NULL, __func__, &suart_test_default_cfg);
107 OSMO_ASSERT(suart != NULL);
108
109 osmo_soft_uart_set_rx(suart, true);
110
Vadim Yanitskiyd0b575c2023-12-09 04:26:51 +0700111 printf("======== testing 8-N-1 (no data)\n");
Vadim Yanitskiy9ef304d2023-11-14 20:46:01 +0700112 test_rx_exec(suart, "F11111F11111F");
113
Vadim Yanitskiyd0b575c2023-12-09 04:26:51 +0700114 printf("======== testing 8-N-1 (fill up flush)\n");
Vadim Yanitskiy9ef304d2023-11-14 20:46:01 +0700115 cfg = suart_test_default_cfg;
116 cfg.rx_buf_size = 4;
117 osmo_soft_uart_configure(suart, &cfg);
118 test_rx_exec(suart, "11111" /* no data */
119 "0 01111011 1"
120 "0 10110101 1"
121 "0 01111101 1"
122 "0 11110111 1" /* filled up, expect flush */
123 "0 00000000 1"
124 "0 01010101 1"
125 "0 10101010 1"
126 "0 11111111 1" /* filled up, expect flush */
127 "F" /* flush! (for sanity) */
128 );
129
Vadim Yanitskiyd0b575c2023-12-09 04:26:51 +0700130 printf("======== testing 8-N-1 (HELLO)\n");
Vadim Yanitskiy9ef304d2023-11-14 20:46:01 +0700131 cfg = suart_test_default_cfg;
132 cfg.num_stop_bits = 1;
133 osmo_soft_uart_configure(suart, &cfg);
134 test_rx_exec(suart, "111111" /* no data */
135 "0 00010010 1F" /* 'H', flush! */
136 "0 10100010 1F" /* 'E', flush! */
137 "1111111111111" /* no data */
138 "0 00110010 1F" /* 'L', flush! */
139 "0 00110010 1F" /* 'L', flush! */
140 "1111111111111" /* no data */
141 "0 11110010 1F" /* 'O', flush! */
142 );
143
Vadim Yanitskiyd0b575c2023-12-09 04:26:51 +0700144 printf("======== testing 8-N-1 (framing errors)\n");
Vadim Yanitskiy9ef304d2023-11-14 20:46:01 +0700145 test_rx_exec(suart, "11111" /* no data */
146 "0 00000000 0" /* stop bit != 1, expect flush */
147 "0 01010101 0" /* stop bit != 1, expect flush */
148 "0 11111111 1" /* stop bit == 1, recovery */
149 "F" /* flush! */
150 );
151
Vadim Yanitskiyd0b575c2023-12-09 04:26:51 +0700152 printf("======== testing 8-N-2 (HELLO)\n");
Vadim Yanitskiy9ef304d2023-11-14 20:46:01 +0700153 cfg = suart_test_default_cfg;
154 cfg.num_stop_bits = 2;
155 osmo_soft_uart_configure(suart, &cfg);
156 test_rx_exec(suart, "11111111" /* no data */
157 "0 00010010 1F1F" /* 'H', flush! */
158 "0 10100010 1F1F" /* 'E', flush! */
159 "111111111111111" /* no data */
160 "0 00110010 1F1F" /* 'L', flush! */
161 "0 00110010 1F1F" /* 'L', flush! */
162 "111111111111111" /* no data */
163 "0 11110010 1F1F" /* 'O', flush! */
164 );
165
Vadim Yanitskiyd0b575c2023-12-09 04:26:51 +0700166 printf("======== testing 8-N-2 (framing errors)\n");
Vadim Yanitskiy9ef304d2023-11-14 20:46:01 +0700167 test_rx_exec(suart, "11111" /* no data */
168 "0 00000000 00" /* stop bit != 1, expect flush */
169 "0 01010101 01" /* stop bit != 1, expect flush */
170 "0 10101010 10" /* stop bit != 1, expect flush */
171 "0 11111111 11" /* stop bit == 1, recovery */
172 "F" /* flush! (for sanity) */
173 );
174
175
Vadim Yanitskiyd0b575c2023-12-09 04:26:51 +0700176 printf("======== testing 8-E-1 (invalid parity)\n");
Vadim Yanitskiy9ef304d2023-11-14 20:46:01 +0700177 cfg = suart_test_default_cfg;
178 cfg.parity_mode = OSMO_SUART_PARITY_EVEN;
179 osmo_soft_uart_configure(suart, &cfg);
180 test_rx_exec(suart, "1111111" /* no data */
181 "0 00000000 1 1" /* odd parity, expect flush */
182 "0 10000000 0 1" /* odd parity, expect flush */
183 "0 11111111 1 1" /* odd parity, expect flush */
184 "F" /* flush! (for sanity) */
185 );
Vadim Yanitskiyd0b575c2023-12-09 04:26:51 +0700186 printf("======== testing 8-E-1 (valid parity)\n");
Vadim Yanitskiy9ef304d2023-11-14 20:46:01 +0700187 test_rx_exec(suart, "1111111" /* no data */
188 "0 00000000 0 1"
189 "0 11111111 0 1"
190 "0 01010101 0 1"
191 "0 10101010 0 1"
192 "F" /* flush! */
193 "0 00000001 1 1"
194 "0 00000111 1 1"
195 "0 00011111 1 1"
196 "0 01111111 1 1"
197 "F" /* flush! */
198 );
199
Vadim Yanitskiyd0b575c2023-12-09 04:26:51 +0700200 printf("======== testing 8-O-1 (invalid parity)\n");
Vadim Yanitskiy9ef304d2023-11-14 20:46:01 +0700201 cfg = suart_test_default_cfg;
202 cfg.parity_mode = OSMO_SUART_PARITY_ODD;
203 osmo_soft_uart_configure(suart, &cfg);
204 test_rx_exec(suart,
205 "0 00000000 0 1" /* even parity, expect flush */
206 "0 10000000 1 1" /* even parity, expect flush */
207 "0 11111111 0 1" /* even parity, expect flush */
208 "F" /* flush! (for sanity) */
209 );
Vadim Yanitskiyd0b575c2023-12-09 04:26:51 +0700210 printf("======== testing 8-O-1 (valid parity)\n");
Vadim Yanitskiy9ef304d2023-11-14 20:46:01 +0700211 test_rx_exec(suart, "1111111" /* no data */
212 "0 00000000 1 1"
213 "0 11111111 1 1"
214 "0 01010101 1 1"
215 "0 10101010 1 1"
216 "F" /* flush! */
217 "0 00000001 0 1"
218 "0 00000111 0 1"
219 "0 00011111 0 1"
220 "0 01111111 0 1"
221 "F" /* flush! */
222 );
223
224 osmo_soft_uart_free(suart);
225}
226
Vadim Yanitskiyd76cc372023-12-09 04:38:14 +0700227static void test_rx_flush(void)
228{
Vadim Yanitskiyb3920992023-12-11 22:38:17 +0700229 struct osmo_soft_uart_cfg cfg;
Vadim Yanitskiyd76cc372023-12-09 04:38:14 +0700230 struct osmo_soft_uart *suart;
231
232 SUART_TEST_BEGIN;
233
234 suart = osmo_soft_uart_alloc(NULL, __func__, &suart_test_default_cfg);
235 OSMO_ASSERT(suart != NULL);
236
237 printf("calling osmo_soft_uart_flush_rx() while Rx disabled\n");
238 osmo_soft_uart_flush_rx(suart);
239
240 printf("enabling the receiver\n");
241 osmo_soft_uart_set_rx(suart, true);
242
243 printf("calling osmo_soft_uart_flush_rx() while Rx enabled, but no data\n");
244 osmo_soft_uart_flush_rx(suart);
245
Vadim Yanitskiyb3920992023-12-11 22:38:17 +0700246 /* FIXME: this scenario demonstrates a problem that may occur when the user
247 * flushes the Rx buffer manually while the soft-UART state reflects flags
248 * of an incomplete symbol, for which we're waiting the stop bit. */
249 printf("testing corner case: manual flushing during a parity error (8-E-1)\n");
250 cfg = suart_test_default_cfg;
251 cfg.parity_mode = OSMO_SUART_PARITY_EVEN;
252 osmo_soft_uart_configure(suart, &cfg);
253 test_rx_exec(suart, "1111111" /* no data */
254 "0 01010101 0 1" /* even parity, correct */
255 "0 10101010 0 1" /* even parity, correct */
256 "0 11111111 1" /* odd parity, incorrect, but stop bit is pending */
257 "F" /* manual flush happens before receiving the stop bit */
258 "1" /* finally, the stop bit is received */
259 );
260 /* test_rx_exec() @ 47: flush the Rx buffer
261 * suart_rx_cb(flags=02): aa 55 <--- this is wrong, should be flags=00
262 * suart_rx_cb(flags=02): ff <--- this is expected due to odd parity */
263
264
Vadim Yanitskiyd76cc372023-12-09 04:38:14 +0700265 osmo_soft_uart_free(suart);
266}
267
Vadim Yanitskiy9ef304d2023-11-14 20:46:01 +0700268static void test_tx_rx_exec_one(struct osmo_soft_uart *suart,
269 size_t n_bits_total, size_t n_bits_frame)
270{
271 ubit_t tx_buf[n_bits_total];
272 ubit_t *ptr = &tx_buf[0];
273 int rc;
274
275 rc = osmo_soft_uart_tx_ubits(suart, &tx_buf[0], n_bits_total);
Vadim Yanitskiyffb8d5e2023-12-04 03:17:26 +0700276 OSMO_ASSERT(rc == n_bits_total);
Vadim Yanitskiy9ef304d2023-11-14 20:46:01 +0700277
278 rc = osmo_soft_uart_rx_ubits(suart, &tx_buf[0], n_bits_total);
279 OSMO_ASSERT(rc == 0);
280 osmo_soft_uart_flush_rx(suart);
281
282 printf("%s(n_bits_total=%zu):", __func__, n_bits_total);
283 while (n_bits_total > 0) {
284 size_t n_bits = OSMO_MIN(n_bits_frame, n_bits_total);
285 printf(" %s", osmo_ubit_dump(ptr, n_bits));
286 n_bits_total -= n_bits;
287 ptr += n_bits;
288 }
289 printf("\n");
290}
291
292static void test_tx_rx_exec(struct osmo_soft_uart *suart, size_t n_bits_frame)
293{
294 const uint8_t tx_data[][4] = {
295 { 0xde, 0xad, 0xbe, 0xef },
296 { 0x00, 0xaa, 0x55, 0xff },
297 { 0x01, 0x02, 0x04, 0x08 },
298 { 0x10, 0x20, 0x40, 0x80 },
299 };
300
301 for (size_t i = 0; i < ARRAY_SIZE(tx_data); i++) {
302 g_tx_cb_cfg.data_len = 4;
303 g_tx_cb_cfg.data = tx_data[i];
304 test_tx_rx_exec_one(suart, 4 * n_bits_frame, n_bits_frame);
305 }
306
307 g_tx_cb_cfg.data_len = 0;
308 g_tx_cb_cfg.data = NULL;
309 test_tx_rx_exec_one(suart, 4 * n_bits_frame, n_bits_frame);
310}
311
312static void test_tx_rx(void)
313{
314 struct osmo_soft_uart_cfg cfg;
315 struct osmo_soft_uart *suart;
Vadim Yanitskiy811638c2023-11-30 03:09:05 +0700316 int rc;
Vadim Yanitskiy9ef304d2023-11-14 20:46:01 +0700317
Vadim Yanitskiyd0b575c2023-12-09 04:26:51 +0700318 SUART_TEST_BEGIN;
319
Vadim Yanitskiy9ef304d2023-11-14 20:46:01 +0700320 suart = osmo_soft_uart_alloc(NULL, __func__, &suart_test_default_cfg);
321 OSMO_ASSERT(suart != NULL);
322
Vadim Yanitskiy811638c2023-11-30 03:09:05 +0700323 /* expect -EAGAIN when the transmitter is not enabled */
324 rc = osmo_soft_uart_tx_ubits(suart, NULL, 42);
325 OSMO_ASSERT(rc == -EAGAIN);
326 /* expect -EAGAIN when the receiver is not enabled */
327 rc = osmo_soft_uart_rx_ubits(suart, NULL, 42);
328 OSMO_ASSERT(rc == -EAGAIN);
329
Vadim Yanitskiy9ef304d2023-11-14 20:46:01 +0700330 osmo_soft_uart_set_tx(suart, true);
331 osmo_soft_uart_set_rx(suart, true);
332
Vadim Yanitskiyd0b575c2023-12-09 04:26:51 +0700333 printf("======== testing 8-N-1\n");
Vadim Yanitskiy9ef304d2023-11-14 20:46:01 +0700334 test_tx_rx_exec(suart, (1 + 8 + 1));
335
Vadim Yanitskiyd0b575c2023-12-09 04:26:51 +0700336 printf("======== testing 8-N-2\n");
Vadim Yanitskiy9ef304d2023-11-14 20:46:01 +0700337 cfg = suart_test_default_cfg;
338 cfg.num_stop_bits = 2;
339 osmo_soft_uart_configure(suart, &cfg);
340 test_tx_rx_exec(suart, (1 + 8 + 2));
341
Vadim Yanitskiyd0b575c2023-12-09 04:26:51 +0700342 printf("======== testing 8-E-1\n");
Vadim Yanitskiy9ef304d2023-11-14 20:46:01 +0700343 cfg = suart_test_default_cfg;
344 cfg.parity_mode = OSMO_SUART_PARITY_EVEN;
345 osmo_soft_uart_configure(suart, &cfg);
346 test_tx_rx_exec(suart, (1 + 8 + 1 + 1));
347
Vadim Yanitskiyd0b575c2023-12-09 04:26:51 +0700348 printf("======== testing 8-O-1\n");
Vadim Yanitskiy9ef304d2023-11-14 20:46:01 +0700349 cfg = suart_test_default_cfg;
350 cfg.parity_mode = OSMO_SUART_PARITY_ODD;
351 osmo_soft_uart_configure(suart, &cfg);
352 test_tx_rx_exec(suart, (1 + 8 + 1 + 1));
353
Vadim Yanitskiyd0b575c2023-12-09 04:26:51 +0700354 printf("======== testing 8-M-1\n");
Vadim Yanitskiy0d78a002023-11-19 16:15:38 +0700355 cfg = suart_test_default_cfg;
356 cfg.parity_mode = OSMO_SUART_PARITY_MARK;
357 osmo_soft_uart_configure(suart, &cfg);
358 test_tx_rx_exec(suart, (1 + 8 + 1 + 1));
359
Vadim Yanitskiyd0b575c2023-12-09 04:26:51 +0700360 printf("======== testing 8-S-1\n");
Vadim Yanitskiy0d78a002023-11-19 16:15:38 +0700361 cfg = suart_test_default_cfg;
362 cfg.parity_mode = OSMO_SUART_PARITY_SPACE;
363 osmo_soft_uart_configure(suart, &cfg);
364 test_tx_rx_exec(suart, (1 + 8 + 1 + 1));
365
Vadim Yanitskiyd0b575c2023-12-09 04:26:51 +0700366 printf("======== testing 6-N-1\n");
Vadim Yanitskiy9ef304d2023-11-14 20:46:01 +0700367 cfg = suart_test_default_cfg;
368 cfg.num_data_bits = 6;
369 osmo_soft_uart_configure(suart, &cfg);
370 test_tx_rx_exec(suart, (1 + 6 + 1));
371
372 osmo_soft_uart_free(suart);
373}
374
Vadim Yanitskiydab66292023-11-20 23:47:18 +0700375static void test_tx_rx_pull_n(unsigned int n)
376{
377 struct osmo_soft_uart *suart;
378 ubit_t tx_buf[32];
379 int rc;
380
Vadim Yanitskiyd0b575c2023-12-09 04:26:51 +0700381 SUART_TEST_BEGIN;
382
Vadim Yanitskiydab66292023-11-20 23:47:18 +0700383 suart = osmo_soft_uart_alloc(NULL, __func__, &suart_test_default_cfg);
384 OSMO_ASSERT(suart != NULL);
385
386 osmo_soft_uart_set_tx(suart, true);
387 osmo_soft_uart_set_rx(suart, true);
388
389 g_tx_cb_cfg.data = (void *)"\x55";
390 g_tx_cb_cfg.data_len = 1;
391
Vadim Yanitskiyd0b575c2023-12-09 04:26:51 +0700392 printf("======== pulling %lu bits (%u at a time)\n", sizeof(tx_buf), n);
Vadim Yanitskiydab66292023-11-20 23:47:18 +0700393 for (unsigned int i = 0; i < sizeof(tx_buf); i += n) {
394 rc = osmo_soft_uart_tx_ubits(suart, &tx_buf[i], n);
Vadim Yanitskiyffb8d5e2023-12-04 03:17:26 +0700395 OSMO_ASSERT(rc == n);
Vadim Yanitskiydab66292023-11-20 23:47:18 +0700396 }
397 printf("%s\n", osmo_ubit_dump(&tx_buf[0], sizeof(tx_buf)));
398
Vadim Yanitskiyd0b575c2023-12-09 04:26:51 +0700399 printf("======== feeding %lu bits into the receiver\n", sizeof(tx_buf));
Vadim Yanitskiydab66292023-11-20 23:47:18 +0700400 rc = osmo_soft_uart_rx_ubits(suart, &tx_buf[0], sizeof(tx_buf));
401 OSMO_ASSERT(rc == 0);
402 osmo_soft_uart_flush_rx(suart);
403
404 osmo_soft_uart_free(suart);
405}
406
Vadim Yanitskiy6587dd02023-11-30 03:04:32 +0700407static void test_modem_status(void)
408{
409 struct osmo_soft_uart *suart;
410 unsigned int status;
411
Vadim Yanitskiyd0b575c2023-12-09 04:26:51 +0700412 SUART_TEST_BEGIN;
413
Vadim Yanitskiy6587dd02023-11-30 03:04:32 +0700414 suart = osmo_soft_uart_alloc(NULL, __func__, &suart_test_default_cfg);
415 OSMO_ASSERT(suart != NULL);
416
Vadim Yanitskiyd0b575c2023-12-09 04:26:51 +0700417 printf("initial status=0x%08x\n", osmo_soft_uart_get_status(suart));
Vadim Yanitskiy6587dd02023-11-30 03:04:32 +0700418
419 printf("de-asserting DCD, which was not asserted\n");
420 osmo_soft_uart_set_status_line(suart, OSMO_SUART_STATUS_F_DCD, false);
421 OSMO_ASSERT(osmo_soft_uart_get_status(suart) == 0x00); /* no change */
422
423 printf("asserting both RI and DCD, expecting the callback to be called twice\n");
424 osmo_soft_uart_set_status_line(suart, OSMO_SUART_STATUS_F_RI, true);
425 osmo_soft_uart_set_status_line(suart, OSMO_SUART_STATUS_F_DCD, true);
426 status = osmo_soft_uart_get_status(suart);
427 OSMO_ASSERT(status == (OSMO_SUART_STATUS_F_RI | OSMO_SUART_STATUS_F_DCD));
428
429 printf("de-asserting RI, expecting the callback to be called\n");
430 osmo_soft_uart_set_status_line(suart, OSMO_SUART_STATUS_F_RI, false);
431 status = osmo_soft_uart_get_status(suart);
432 OSMO_ASSERT(status == (OSMO_SUART_STATUS_F_DCD));
433
434 printf("resetting to 0x00, expecting the callback to be called\n");
435 osmo_soft_uart_set_status(suart, 0x00);
436 OSMO_ASSERT(osmo_soft_uart_get_status(suart) == 0x00);
437
438 osmo_soft_uart_free(suart);
439}
440
441static void test_flow_control_dtr_dsr(void)
442{
443 struct osmo_soft_uart_cfg cfg;
444 struct osmo_soft_uart *suart;
445 ubit_t tx_buf[40];
446 int rc;
447
Vadim Yanitskiyd0b575c2023-12-09 04:26:51 +0700448 SUART_TEST_BEGIN;
449
Vadim Yanitskiy6587dd02023-11-30 03:04:32 +0700450 g_tx_cb_cfg.data = (void *)"\x42\x42\x42\x42";
451 g_tx_cb_cfg.data_len = 4;
452
453 cfg = suart_test_default_cfg;
454 cfg.flow_ctrl_mode = OSMO_SUART_FLOW_CTRL_DTR_DSR;
455
456 suart = osmo_soft_uart_alloc(NULL, __func__, &cfg);
457 OSMO_ASSERT(suart != NULL);
458
459 osmo_soft_uart_set_tx(suart, true);
460 osmo_soft_uart_set_rx(suart, true);
461
462 /* expect the initial status to be 0 (all lines de-asserted) */
Vadim Yanitskiyd0b575c2023-12-09 04:26:51 +0700463 printf("initial status=0x%08x\n", osmo_soft_uart_get_status(suart));
Vadim Yanitskiy6587dd02023-11-30 03:04:32 +0700464
465 memset(&tx_buf[0], 1, sizeof(tx_buf)); /* pre-initialize */
466
467 printf("expecting osmo_soft_uart_tx_ubits() to yield nothing\n");
468 rc = osmo_soft_uart_tx_ubits(suart, &tx_buf[0], sizeof(tx_buf));
469 OSMO_ASSERT(rc == 0);
470
471 printf("expecting osmo_soft_uart_rx_ubits() to yield nothing\n");
472 rc = osmo_soft_uart_rx_ubits(suart, &tx_buf[0], sizeof(tx_buf));
473 OSMO_ASSERT(rc == 0);
474 osmo_soft_uart_flush_rx(suart);
475
476 /* both DTR and DSR are asserted, expect both Rx and Tx to work */
Vadim Yanitskiyd0b575c2023-12-09 04:26:51 +0700477 printf("======== asserting both DTR and DSR\n");
Vadim Yanitskiy6587dd02023-11-30 03:04:32 +0700478 osmo_soft_uart_set_status_line(suart, OSMO_SUART_STATUS_F_DTR, true);
479 osmo_soft_uart_set_status_line(suart, OSMO_SUART_STATUS_F_DSR, true);
480
481 memset(&tx_buf[0], 1, sizeof(tx_buf)); /* pre-initialize */
482
483 printf("expecting osmo_soft_uart_tx_ubits() to "
484 "yield %zu bits (requesting %zu bits)\n",
485 sizeof(tx_buf), sizeof(tx_buf));
486 rc = osmo_soft_uart_tx_ubits(suart, &tx_buf[0], sizeof(tx_buf));
487 OSMO_ASSERT(rc == sizeof(tx_buf));
488 printf("%s\n", osmo_ubit_dump(&tx_buf[0], sizeof(tx_buf)));
489
490 printf("expecting osmo_soft_uart_rx_ubits() to "
491 "consume %zu bits and yield %zu chars\n",
492 sizeof(tx_buf), sizeof(tx_buf) / 10);
493 rc = osmo_soft_uart_rx_ubits(suart, &tx_buf[0], sizeof(tx_buf));
494 OSMO_ASSERT(rc == 0);
495 osmo_soft_uart_flush_rx(suart);
496
497 memset(&tx_buf[0], 1, sizeof(tx_buf)); /* pre-initialize */
498
499 /* make the transmitter consume one char, but pull only 2 bits */
500 printf("expecting osmo_soft_uart_tx_ubits() to "
501 "yield 2 bits (requesting 2 bits)\n");
502 rc = osmo_soft_uart_tx_ubits(suart, &tx_buf[0], 2);
503 OSMO_ASSERT(rc == 2);
504
505 /* CTS gets de-asserted, the transmitter is shutting down */
Vadim Yanitskiyd0b575c2023-12-09 04:26:51 +0700506 printf("======== de-asserting DSR\n");
Vadim Yanitskiy6587dd02023-11-30 03:04:32 +0700507 osmo_soft_uart_set_status_line(suart, OSMO_SUART_STATUS_F_DSR, false);
508
509 /* expect only the remaining 8 bits to be pulled out */
510 printf("expecting osmo_soft_uart_tx_ubits() to "
511 "yield 8 bits (requesting %zu bits)\n", sizeof(tx_buf));
512 rc = osmo_soft_uart_tx_ubits(suart, &tx_buf[2], sizeof(tx_buf) - 2);
513 OSMO_ASSERT(rc == 8);
514
515 printf("expecting osmo_soft_uart_rx_ubits() to "
516 "consume %zu bits and yield a pending char\n", sizeof(tx_buf));
517 rc = osmo_soft_uart_rx_ubits(suart, &tx_buf[0], sizeof(tx_buf));
518 OSMO_ASSERT(rc == 0);
519 osmo_soft_uart_flush_rx(suart);
520
521 osmo_soft_uart_free(suart);
522}
523
524static void test_flow_control_rts_cts(void)
525{
526 struct osmo_soft_uart_cfg cfg;
527 struct osmo_soft_uart *suart;
528 ubit_t tx_buf[40];
529 int rc;
530
Vadim Yanitskiyd0b575c2023-12-09 04:26:51 +0700531 SUART_TEST_BEGIN;
532
Vadim Yanitskiy6587dd02023-11-30 03:04:32 +0700533 g_tx_cb_cfg.data = (void *)"\x42\x42\x42\x42";
534 g_tx_cb_cfg.data_len = 4;
535
536 cfg = suart_test_default_cfg;
537 cfg.flow_ctrl_mode = OSMO_SUART_FLOW_CTRL_RTS_CTS;
538
539 suart = osmo_soft_uart_alloc(NULL, __func__, &cfg);
540 OSMO_ASSERT(suart != NULL);
541
542 osmo_soft_uart_set_tx(suart, true);
543 osmo_soft_uart_set_rx(suart, true);
544
545 /* expect the initial status to be 0 (all lines de-asserted) */
Vadim Yanitskiyd0b575c2023-12-09 04:26:51 +0700546 printf("initial status=0x%08x\n", osmo_soft_uart_get_status(suart));
Vadim Yanitskiy6587dd02023-11-30 03:04:32 +0700547
548 memset(&tx_buf[0], 1, sizeof(tx_buf)); /* pre-initialize */
549
550 printf("expecting osmo_soft_uart_tx_ubits() to yield nothing\n");
551 rc = osmo_soft_uart_tx_ubits(suart, &tx_buf[0], sizeof(tx_buf));
552 OSMO_ASSERT(rc == 0);
553
554 printf("expecting osmo_soft_uart_rx_ubits() to yield nothing\n");
555 rc = osmo_soft_uart_rx_ubits(suart, &tx_buf[0], sizeof(tx_buf));
556 OSMO_ASSERT(rc == 0);
557 osmo_soft_uart_flush_rx(suart);
558
559 /* both RTS/RTR and CTS are asserted, expect both Rx and Tx to work */
Vadim Yanitskiyd0b575c2023-12-09 04:26:51 +0700560 printf("======== asserting both CTS and RTS/RTR\n");
Vadim Yanitskiy6587dd02023-11-30 03:04:32 +0700561 osmo_soft_uart_set_status_line(suart, OSMO_SUART_STATUS_F_CTS, true);
562 osmo_soft_uart_set_status_line(suart, OSMO_SUART_STATUS_F_RTS_RTR, true);
563
564 memset(&tx_buf[0], 1, sizeof(tx_buf)); /* pre-initialize */
565
566 printf("expecting osmo_soft_uart_tx_ubits() to "
567 "yield %zu bits (requesting %zu bits)\n",
568 sizeof(tx_buf), sizeof(tx_buf));
569 rc = osmo_soft_uart_tx_ubits(suart, &tx_buf[0], sizeof(tx_buf));
570 OSMO_ASSERT(rc == sizeof(tx_buf));
571 printf("%s\n", osmo_ubit_dump(&tx_buf[0], sizeof(tx_buf)));
572
573 printf("expecting osmo_soft_uart_rx_ubits() to "
574 "consume %zu bits and yield %zu chars\n",
575 sizeof(tx_buf), sizeof(tx_buf) / 10);
576 rc = osmo_soft_uart_rx_ubits(suart, &tx_buf[0], sizeof(tx_buf));
577 OSMO_ASSERT(rc == 0);
578 osmo_soft_uart_flush_rx(suart);
579
580 memset(&tx_buf[0], 1, sizeof(tx_buf)); /* pre-initialize */
581
582 /* make the transmitter consume one char, but pull only 2 bits */
583 printf("expecting osmo_soft_uart_tx_ubits() to "
584 "yield 2 bits (requesting 2 bits)\n");
585 rc = osmo_soft_uart_tx_ubits(suart, &tx_buf[0], 2);
586 OSMO_ASSERT(rc == 2);
587
588 /* CTS gets de-asserted, the transmitter is shutting down */
Vadim Yanitskiyd0b575c2023-12-09 04:26:51 +0700589 printf("======== de-asserting CTS\n");
Vadim Yanitskiy6587dd02023-11-30 03:04:32 +0700590 osmo_soft_uart_set_status_line(suart, OSMO_SUART_STATUS_F_CTS, false);
591
592 /* expect only the remaining 8 bits to be pulled out */
593 printf("expecting osmo_soft_uart_tx_ubits() to "
594 "yield 8 bits (requesting %zu bits)\n", sizeof(tx_buf));
595 rc = osmo_soft_uart_tx_ubits(suart, &tx_buf[2], sizeof(tx_buf) - 2);
596 OSMO_ASSERT(rc == 8);
597
598 printf("expecting osmo_soft_uart_rx_ubits() to "
599 "consume %zu bits and yield a pending char\n", sizeof(tx_buf));
600 rc = osmo_soft_uart_rx_ubits(suart, &tx_buf[0], sizeof(tx_buf));
601 OSMO_ASSERT(rc == 0);
602 osmo_soft_uart_flush_rx(suart);
603
604 osmo_soft_uart_free(suart);
605}
606
Vadim Yanitskiyd8070f52023-12-11 22:51:29 +0700607static void test_tx_pull(void)
608{
609 struct osmo_soft_uart *suart;
610 ubit_t tx_buf[25 * 2];
611 int rc;
612
613 SUART_TEST_BEGIN;
614
615 g_tx_cb_cfg.data = (void *)"\x42\x42\x42\x42\x42";
616 g_tx_cb_cfg.data_len = 5;
617
618 suart = osmo_soft_uart_alloc(NULL, __func__, &suart_test_default_cfg);
619 OSMO_ASSERT(suart != NULL);
620
621 osmo_soft_uart_set_tx(suart, true);
622
623 printf("pulling 25 bits (first time) out of the transmitter\n");
624 rc = osmo_soft_uart_tx_ubits(suart, &tx_buf[0], sizeof(tx_buf) / 2);
625 OSMO_ASSERT(rc == 25);
626
627 printf("pulling 25 bits (second time) out of the transmitter\n");
628 rc = osmo_soft_uart_tx_ubits(suart, &tx_buf[25], sizeof(tx_buf) / 2);
629 OSMO_ASSERT(rc == 25);
630
631 /* FIXME: we pull total 25 + 25 == 50 bits out of the transmitter, which is enough
632 * to fit 5 characters (assuming 8-N-1). However, the current impelementation would
633 * pull only 2 + 2 == characters total, wasting 5 + 5 == 10 bits for padding. */
634
635 osmo_soft_uart_free(suart);
636}
637
Vadim Yanitskiy9ef304d2023-11-14 20:46:01 +0700638int main(int argc, char **argv)
639{
640 test_rx();
Vadim Yanitskiyd76cc372023-12-09 04:38:14 +0700641 test_rx_flush();
Vadim Yanitskiy9ef304d2023-11-14 20:46:01 +0700642 test_tx_rx();
643
Vadim Yanitskiydab66292023-11-20 23:47:18 +0700644 /* test pulling small number of bits at a time */
645 test_tx_rx_pull_n(1);
646 test_tx_rx_pull_n(2);
647 test_tx_rx_pull_n(4);
648 test_tx_rx_pull_n(8);
649
Vadim Yanitskiyd8070f52023-12-11 22:51:29 +0700650 test_tx_pull();
651
Vadim Yanitskiy6587dd02023-11-30 03:04:32 +0700652 /* test flow control */
653 test_modem_status();
654 test_flow_control_dtr_dsr();
655 test_flow_control_rts_cts();
656
Vadim Yanitskiy9ef304d2023-11-14 20:46:01 +0700657 return 0;
658}