source: rtems/testsuites/libtests/termios09/init.c @ 902ffed

5
Last change on this file since 902ffed was 902ffed, checked in by Sebastian Huber <sebastian.huber@…>, on 02/24/17 at 13:56:51

termios09: Test send callback

  • Property mode set to 100644
File size: 25.9 KB
Line 
1/*
2 * Copyright (c) 2017 embedded brains GmbH.  All rights reserved.
3 *
4 *  embedded brains GmbH
5 *  Dornierstr. 4
6 *  82178 Puchheim
7 *  Germany
8 *  <rtems@embedded-brains.de>
9 *
10 * The license and distribution terms for this file may be
11 * found in the file LICENSE in this distribution or at
12 * http://www.rtems.org/license/LICENSE.
13 */
14
15#ifdef HAVE_CONFIG_H
16#include "config.h"
17#endif
18
19#include <sys/stat.h>
20#include <fcntl.h>
21#include <string.h>
22#include <termios.h>
23#include <unistd.h>
24
25#include <rtems/termiostypes.h>
26
27#include "tmacros.h"
28
29const char rtems_test_name[] = "TERMIOS 9";
30
31#define INTERRUPT 0
32
33#define POLLED 1
34
35#define DEVICE_COUNT 2
36
37#define OUTPUT_BUFFER_SIZE 64
38
39static const char * const paths[DEVICE_COUNT] = {
40  "/interrupt",
41  "/polled"
42};
43
44typedef struct {
45  rtems_termios_device_context base;
46  rtems_termios_tty *tty;
47  size_t output_pending;
48  size_t output_count;
49  char output_buf[OUTPUT_BUFFER_SIZE];
50  int input_char;
51  int callback_counter;
52} device_context;
53
54typedef struct {
55  device_context devices[DEVICE_COUNT];
56  int fds[DEVICE_COUNT];
57  struct termios term[DEVICE_COUNT];
58  int context_switch_counter;
59  rtems_id flush_task_id;
60} test_context;
61
62static test_context test_instance = {
63  .devices = {
64    {
65      .base = RTEMS_TERMIOS_DEVICE_CONTEXT_INITIALIZER("Interrupt")
66    }, {
67      .base = RTEMS_TERMIOS_DEVICE_CONTEXT_INITIALIZER("Polled"),
68      .input_char = -1
69    }
70  }
71};
72
73static bool first_open(
74  rtems_termios_tty *tty,
75  rtems_termios_device_context *base,
76  struct termios *term,
77  rtems_libio_open_close_args_t *args
78)
79{
80  device_context *dev = (device_context *) base;
81
82  dev->tty = tty;
83
84  return true;
85}
86
87static void write_polled(
88  rtems_termios_device_context *base,
89  const char *buf,
90  size_t len
91)
92{
93  device_context *dev = (device_context *) base;
94
95  rtems_test_assert(dev->output_count + len <= OUTPUT_BUFFER_SIZE);
96  memcpy(&dev->output_buf[dev->output_count], buf, len);
97  dev->output_count += len;
98}
99
100static void write_interrupt(
101  rtems_termios_device_context *base,
102  const char *buf,
103  size_t len
104)
105{
106  device_context *dev = (device_context *) base;
107
108  write_polled(base, buf, len);
109  dev->output_pending = len;
110}
111
112static int read_polled(rtems_termios_device_context *base)
113{
114  device_context *dev = (device_context *) base;
115  int c = dev->input_char;
116
117  dev->input_char = -1;
118
119  return c;
120}
121
122static const rtems_termios_device_handler handlers[DEVICE_COUNT] = {
123  {
124    .first_open = first_open,
125    .write = write_interrupt,
126    .mode = TERMIOS_IRQ_DRIVEN
127  }, {
128    .first_open = first_open,
129    .write = write_polled,
130    .poll_read = read_polled,
131    .mode = TERMIOS_POLLED
132  }
133};
134
135static void set_term(test_context *ctx, size_t i)
136{
137  int rv;
138
139  rv = tcsetattr(ctx->fds[i], TCSANOW, &ctx->term[i]);
140  rtems_test_assert(rv == 0);
141}
142
143static void init_term(test_context *ctx, size_t i)
144{
145  int rv;
146
147  rv = tcgetattr(ctx->fds[i], &ctx->term[i]);
148  rtems_test_assert(rv == 0);
149
150  ctx->term[i].c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP
151    | INLCR | IGNCR | ICRNL | IXON);
152  ctx->term[i].c_lflag &= ~(ECHO | ECHOE | ECHOK | ECHONL | ECHOPRT
153    | ECHOCTL | ECHOKE | ICANON | ISIG | IEXTEN);
154  ctx->term[i].c_cflag &= ~(CSIZE | PARENB);
155  ctx->term[i].c_cflag |= CS8;
156  ctx->term[i].c_oflag &= ~(OPOST | ONLRET | ONLCR | OCRNL | ONLRET
157    | TABDLY | OLCUC);
158
159  ctx->term[i].c_cc[VMIN] = 0;
160  ctx->term[i].c_cc[VTIME] = 0;
161
162  set_term(ctx, i);
163}
164
165static void setup(test_context *ctx)
166{
167  rtems_status_code sc;
168  size_t i;
169
170  rtems_termios_initialize();
171
172  for (i = 0; i < DEVICE_COUNT; ++i) {
173    sc = rtems_termios_device_install(
174      paths[i],
175      &handlers[i],
176      NULL,
177      &ctx->devices[i].base
178    );
179    rtems_test_assert(sc == RTEMS_SUCCESSFUL);
180
181    ctx->fds[i] = open(paths[i], O_RDWR);
182    rtems_test_assert(ctx->fds[i] >= 0);
183
184    init_term(ctx, i);
185  }
186}
187
188static void input(test_context *ctx, size_t i, char c)
189{
190  switch (i) {
191    case INTERRUPT:
192      rtems_termios_enqueue_raw_characters(ctx->devices[i].tty, &c, sizeof(c));
193      break;
194    case POLLED:
195      ctx->devices[i].input_char = (unsigned char) c;
196      break;
197    default:
198      rtems_test_assert(0);
199  }
200}
201
202static void enable_non_blocking(test_context *ctx, size_t i, bool enable)
203{
204  int flags;
205  int rv;
206
207  flags = fcntl(ctx->fds[i], F_GETFL, 0);
208  rtems_test_assert(flags >= 0);
209
210  if (enable) {
211    flags |= O_NONBLOCK;
212  } else {
213    flags &= ~O_NONBLOCK;
214  }
215
216  rv = fcntl(ctx->fds[i], F_SETFL, flags);
217  rtems_test_assert(rv == 0);
218}
219
220static void clear_set_iflag(
221  test_context *ctx,
222  size_t i,
223  tcflag_t clear,
224  tcflag_t set
225)
226{
227  ctx->term[i].c_iflag &= ~clear;
228  ctx->term[i].c_iflag |= set;
229  set_term(ctx, i);
230}
231
232static void clear_set_lflag(
233  test_context *ctx,
234  size_t i,
235  tcflag_t clear,
236  tcflag_t set
237)
238{
239  ctx->term[i].c_lflag &= ~clear;
240  ctx->term[i].c_lflag |= set;
241  set_term(ctx, i);
242}
243
244static void clear_set_oflag(
245  test_context *ctx,
246  size_t i,
247  tcflag_t clear,
248  tcflag_t set
249)
250{
251  ctx->term[i].c_oflag &= ~clear;
252  ctx->term[i].c_oflag |= set;
253  set_term(ctx, i);
254}
255
256static void set_vmin_vtime(
257  test_context *ctx,
258  size_t i,
259  cc_t vmin,
260  cc_t vtime
261)
262{
263  ctx->term[i].c_cc[VMIN] = vmin;
264  ctx->term[i].c_cc[VTIME] = vtime;
265  set_term(ctx, i);
266}
267
268static void set_veol_veol2(
269  test_context *ctx,
270  size_t i,
271  cc_t veol,
272  cc_t veol2
273)
274{
275  ctx->term[i].c_cc[VEOL] = veol;
276  ctx->term[i].c_cc[VEOL2] = veol2;
277  set_term(ctx, i);
278}
279
280static void test_igncr(test_context *ctx)
281{
282  size_t i;
283
284  for (i = 0; i < DEVICE_COUNT; ++i) {
285    ssize_t n;
286    char c;
287
288    c = 'x';
289
290    clear_set_iflag(ctx, i, 0, IGNCR);
291
292    n = read(ctx->fds[i], &c, sizeof(c));
293    rtems_test_assert(n == 0);
294    rtems_test_assert(c == 'x');
295
296    input(ctx, i, '\r');
297
298    n = read(ctx->fds[i], &c, sizeof(c));
299    rtems_test_assert(n == 0);
300    rtems_test_assert(c == 'x');
301
302    clear_set_iflag(ctx, i, IGNCR, 0);
303    input(ctx, i, '\r');
304
305    n = read(ctx->fds[i], &c, sizeof(c));
306    rtems_test_assert(n == 1);
307    rtems_test_assert(c == '\r');
308  }
309}
310
311static void test_istrip(test_context *ctx)
312{
313  size_t i;
314
315  for (i = 0; i < DEVICE_COUNT; ++i) {
316    ssize_t n;
317    char c;
318
319    c = 'x';
320
321    clear_set_iflag(ctx, i, 0, ISTRIP);
322
323    n = read(ctx->fds[i], &c, sizeof(c));
324    rtems_test_assert(n == 0);
325    rtems_test_assert(c == 'x');
326
327    input(ctx, i, '\376');
328
329    n = read(ctx->fds[i], &c, sizeof(c));
330    rtems_test_assert(n == 1);
331    rtems_test_assert(c == '~');
332
333    clear_set_iflag(ctx, i, ISTRIP, 0);
334    input(ctx, i, '\376');
335
336    n = read(ctx->fds[i], &c, sizeof(c));
337    rtems_test_assert(n == 1);
338    rtems_test_assert(c == '\376');
339  }
340}
341
342static void test_iuclc(test_context *ctx)
343{
344  size_t i;
345
346  for (i = 0; i < DEVICE_COUNT; ++i) {
347    ssize_t n;
348    char c;
349
350    c = 'x';
351
352    clear_set_iflag(ctx, i, 0, IUCLC);
353
354    n = read(ctx->fds[i], &c, sizeof(c));
355    rtems_test_assert(n == 0);
356    rtems_test_assert(c == 'x');
357
358    input(ctx, i, 'A');
359
360    n = read(ctx->fds[i], &c, sizeof(c));
361    rtems_test_assert(n == 1);
362    rtems_test_assert(c == 'a');
363
364    clear_set_iflag(ctx, i, IUCLC, 0);
365    input(ctx, i, 'A');
366
367    n = read(ctx->fds[i], &c, sizeof(c));
368    rtems_test_assert(n == 1);
369    rtems_test_assert(c == 'A');
370  }
371}
372
373static void test_icrnl(test_context *ctx)
374{
375  size_t i;
376
377  for (i = 0; i < DEVICE_COUNT; ++i) {
378    ssize_t n;
379    char c;
380
381    c = 'x';
382
383    clear_set_iflag(ctx, i, 0, ICRNL);
384
385    n = read(ctx->fds[i], &c, sizeof(c));
386    rtems_test_assert(n == 0);
387    rtems_test_assert(c == 'x');
388
389    input(ctx, i, '\r');
390
391    n = read(ctx->fds[i], &c, sizeof(c));
392    rtems_test_assert(n == 1);
393    rtems_test_assert(c == '\n');
394
395    clear_set_iflag(ctx, i, ICRNL, 0);
396    input(ctx, i, '\r');
397
398    n = read(ctx->fds[i], &c, sizeof(c));
399    rtems_test_assert(n == 1);
400    rtems_test_assert(c == '\r');
401  }
402}
403
404static void test_inlcr(test_context *ctx)
405{
406  size_t i;
407
408  for (i = 0; i < DEVICE_COUNT; ++i) {
409    ssize_t n;
410    char c;
411
412    c = 'x';
413
414    clear_set_iflag(ctx, i, 0, INLCR);
415
416    n = read(ctx->fds[i], &c, sizeof(c));
417    rtems_test_assert(n == 0);
418    rtems_test_assert(c == 'x');
419
420    input(ctx, i, '\n');
421
422    n = read(ctx->fds[i], &c, sizeof(c));
423    rtems_test_assert(n == 1);
424    rtems_test_assert(c == '\r');
425
426    clear_set_iflag(ctx, i, INLCR, 0);
427    input(ctx, i, '\n');
428
429    n = read(ctx->fds[i], &c, sizeof(c));
430    rtems_test_assert(n == 1);
431    rtems_test_assert(c == '\n');
432  }
433}
434
435static void callback(struct termios *tty, void *arg)
436{
437  device_context *ctx = arg;
438
439  ++ctx->callback_counter;
440}
441
442static void test_rx_callback(test_context *ctx)
443{
444  size_t i = INTERRUPT;
445  device_context *dev = &ctx->devices[i];
446  ssize_t n;
447  char buf[3];
448
449  buf[0] = 'x';
450
451  dev->callback_counter = 0;
452  dev->tty->tty_rcv.sw_pfn = callback;
453  dev->tty->tty_rcv.sw_arg = dev;
454  clear_set_lflag(ctx, i, ICANON, 0);
455
456  set_vmin_vtime(ctx, i, 0, 0);
457
458  n = read(ctx->fds[i], buf, 1);
459  rtems_test_assert(n == 0);
460  rtems_test_assert(buf[0] == 'x');
461
462  input(ctx, i, 'a');
463  rtems_test_assert(dev->callback_counter == 1);
464
465  input(ctx, i, 'b');
466  rtems_test_assert(dev->callback_counter == 1);
467
468  n = read(ctx->fds[i], buf, 2);
469  rtems_test_assert(n == 2);
470  rtems_test_assert(buf[0] == 'a');
471  rtems_test_assert(buf[1] == 'b');
472
473  set_vmin_vtime(ctx, i, 2, 0);
474
475  input(ctx, i, 'd');
476  rtems_test_assert(dev->callback_counter == 1);
477
478  input(ctx, i, 'e');
479  rtems_test_assert(dev->callback_counter == 2);
480
481  input(ctx, i, 'f');
482  rtems_test_assert(dev->callback_counter == 2);
483
484  n = read(ctx->fds[i], buf, 3);
485  rtems_test_assert(n == 3);
486  rtems_test_assert(buf[0] == 'd');
487  rtems_test_assert(buf[1] == 'e');
488  rtems_test_assert(buf[2] == 'f');
489
490  dev->tty->tty_rcv.sw_pfn = NULL;
491  dev->tty->tty_rcv.sw_arg = NULL;
492}
493
494static void test_rx_callback_icanon(test_context *ctx)
495{
496  size_t i = INTERRUPT;
497  device_context *dev = &ctx->devices[i];
498  ssize_t n;
499  char buf[255];
500  size_t j;
501
502  buf[0] = 'x';
503
504  dev->callback_counter = 0;
505  dev->tty->tty_rcv.sw_pfn = callback;
506  dev->tty->tty_rcv.sw_arg = dev;
507
508  set_vmin_vtime(ctx, i, 0, 0);
509
510  n = read(ctx->fds[i], buf, 1);
511  rtems_test_assert(n == 0);
512  rtems_test_assert(buf[0] == 'x');
513
514  clear_set_lflag(ctx, i, 0, ICANON);
515  set_veol_veol2(ctx, i, '1', '2');
516
517  input(ctx, i, '\n');
518  rtems_test_assert(dev->callback_counter == 1);
519
520  input(ctx, i, 'a');
521  rtems_test_assert(dev->callback_counter == 1);
522
523  input(ctx, i, '\n');
524  rtems_test_assert(dev->callback_counter == 1);
525
526  n = read(ctx->fds[i], buf, 3);
527  rtems_test_assert(n == 3);
528  rtems_test_assert(buf[0] == '\n');
529  rtems_test_assert(buf[1] == 'a');
530  rtems_test_assert(buf[2] == '\n');
531
532  input(ctx, i, '\4');
533  rtems_test_assert(dev->callback_counter == 2);
534
535  input(ctx, i, 'b');
536  rtems_test_assert(dev->callback_counter == 2);
537
538  input(ctx, i, '\n');
539  rtems_test_assert(dev->callback_counter == 2);
540
541  n = read(ctx->fds[i], buf, 2);
542  rtems_test_assert(n == 2);
543  rtems_test_assert(buf[0] == 'b');
544  rtems_test_assert(buf[1] == '\n');
545
546  input(ctx, i, '1');
547  rtems_test_assert(dev->callback_counter == 3);
548
549  input(ctx, i, 'c');
550  rtems_test_assert(dev->callback_counter == 3);
551
552  input(ctx, i, '\n');
553  rtems_test_assert(dev->callback_counter == 3);
554
555  n = read(ctx->fds[i], buf, 3);
556  rtems_test_assert(n == 3);
557  rtems_test_assert(buf[0] == '1');
558  rtems_test_assert(buf[1] == 'c');
559  rtems_test_assert(buf[2] == '\n');
560
561  input(ctx, i, '2');
562  rtems_test_assert(dev->callback_counter == 4);
563
564  input(ctx, i, 'd');
565  rtems_test_assert(dev->callback_counter == 4);
566
567  input(ctx, i, '\n');
568  rtems_test_assert(dev->callback_counter == 4);
569
570  n = read(ctx->fds[i], buf, 3);
571  rtems_test_assert(n == 3);
572  rtems_test_assert(buf[0] == '2');
573  rtems_test_assert(buf[1] == 'd');
574  rtems_test_assert(buf[2] == '\n');
575
576  for (j = 0; j < 255; ++j) {
577    input(ctx, i, 'e');
578    rtems_test_assert(dev->callback_counter == 4);
579  }
580
581  /* Raw input buffer overflow */
582  input(ctx, i, 'e');
583  rtems_test_assert(dev->callback_counter == 5);
584
585  n = read(ctx->fds[i], buf, 255);
586  rtems_test_assert(n == 255);
587
588  dev->tty->tty_rcv.sw_pfn = NULL;
589  dev->tty->tty_rcv.sw_arg = NULL;
590  set_veol_veol2(ctx, i, '\0', '\0');
591  clear_set_lflag(ctx, i, ICANON, 0);
592}
593
594static void flush_output(test_context *ctx, size_t i)
595{
596  if (i == INTERRUPT) {
597    device_context *dev = &ctx->devices[i];
598    int left;
599
600    do {
601      left = rtems_termios_dequeue_characters(dev->tty, dev->output_pending);
602    } while (left > 0);
603  }
604}
605
606static void clear_output(test_context *ctx, size_t i)
607{
608  device_context *dev = &ctx->devices[i];
609
610  flush_output(ctx, i);
611  dev->output_count = 0;
612  memset(&dev->output_buf, 0, OUTPUT_BUFFER_SIZE);
613}
614
615static void test_onlret(test_context *ctx)
616{
617  tcflag_t oflags = OPOST | ONLRET;
618  size_t i;
619
620  for (i = 0; i < DEVICE_COUNT; ++i) {
621    device_context *dev = &ctx->devices[i];
622    char c;
623    ssize_t n;
624
625    dev->tty->column = 0;
626    clear_output(ctx, i);
627
628    clear_set_oflag(ctx, i, 0, oflags);
629
630    c = 'a';
631    n = write(ctx->fds[i], &c, sizeof(c));
632    rtems_test_assert(n == 1);
633    rtems_test_assert(dev->tty->column == 1);
634    flush_output(ctx, i);
635    rtems_test_assert(dev->output_count == 1);
636    rtems_test_assert(dev->output_buf[0] == 'a');
637
638    c = '\n';
639    n = write(ctx->fds[i], &c, sizeof(c));
640    rtems_test_assert(n == 1);
641    rtems_test_assert(dev->tty->column == 0);
642    flush_output(ctx, i);
643    rtems_test_assert(dev->output_count == 2);
644    rtems_test_assert(dev->output_buf[1] == '\n');
645
646    clear_set_oflag(ctx, i, oflags, 0);
647  }
648}
649
650static void test_onlcr(test_context *ctx)
651{
652  tcflag_t oflags = OPOST | ONLCR;
653  size_t i;
654
655  for (i = 0; i < DEVICE_COUNT; ++i) {
656    device_context *dev = &ctx->devices[i];
657    char c;
658    ssize_t n;
659
660    dev->tty->column = 0;
661    clear_output(ctx, i);
662
663    clear_set_oflag(ctx, i, 0, oflags);
664
665    c = 'a';
666    n = write(ctx->fds[i], &c, sizeof(c));
667    rtems_test_assert(n == 1);
668    rtems_test_assert(dev->tty->column == 1);
669    flush_output(ctx, i);
670    rtems_test_assert(dev->output_count == 1);
671    rtems_test_assert(dev->output_buf[0] == 'a');
672
673    c = '\n';
674    n = write(ctx->fds[i], &c, sizeof(c));
675    rtems_test_assert(n == 1);
676    rtems_test_assert(dev->tty->column == 0);
677    flush_output(ctx, i);
678    rtems_test_assert(dev->output_count == 3);
679    rtems_test_assert(dev->output_buf[1] == '\r');
680    rtems_test_assert(dev->output_buf[2] == '\n');
681
682    clear_set_oflag(ctx, i, oflags, 0);
683  }
684}
685
686static void test_onocr(test_context *ctx)
687{
688  tcflag_t oflags = OPOST | ONOCR;
689  size_t i;
690
691  for (i = 0; i < DEVICE_COUNT; ++i) {
692    device_context *dev = &ctx->devices[i];
693    char c;
694    ssize_t n;
695
696    dev->tty->column = 0;
697    clear_output(ctx, i);
698
699    clear_set_oflag(ctx, i, 0, oflags);
700
701    c = '\r';
702    n = write(ctx->fds[i], &c, sizeof(c));
703    rtems_test_assert(n == 1);
704    rtems_test_assert(dev->tty->column == 0);
705    flush_output(ctx, i);
706    rtems_test_assert(dev->output_count == 0);
707
708    c = 'a';
709    n = write(ctx->fds[i], &c, sizeof(c));
710    rtems_test_assert(n == 1);
711    rtems_test_assert(dev->tty->column == 1);
712    flush_output(ctx, i);
713    rtems_test_assert(dev->output_count == 1);
714    rtems_test_assert(dev->output_buf[0] == 'a');
715
716    c = '\r';
717    n = write(ctx->fds[i], &c, sizeof(c));
718    rtems_test_assert(n == 1);
719    rtems_test_assert(dev->tty->column == 0);
720    flush_output(ctx, i);
721    rtems_test_assert(dev->output_count == 2);
722    rtems_test_assert(dev->output_buf[1] == '\r');
723
724    clear_set_oflag(ctx, i, oflags, 0);
725  }
726}
727
728static void test_ocrnl(test_context *ctx)
729{
730  tcflag_t oflags = OPOST | OCRNL;
731  size_t i;
732
733  for (i = 0; i < DEVICE_COUNT; ++i) {
734    device_context *dev = &ctx->devices[i];
735    char c;
736    ssize_t n;
737
738    dev->tty->column = 0;
739    clear_output(ctx, i);
740
741    clear_set_oflag(ctx, i, 0, oflags);
742
743    c = '\r';
744    n = write(ctx->fds[i], &c, sizeof(c));
745    rtems_test_assert(n == 1);
746    rtems_test_assert(dev->tty->column == 0);
747    flush_output(ctx, i);
748    rtems_test_assert(dev->output_count == 1);
749    rtems_test_assert(dev->output_buf[0] == '\n');
750
751    clear_set_oflag(ctx, i, oflags, 0);
752  }
753}
754
755static void test_ocrnl_onlret(test_context *ctx)
756{
757  tcflag_t oflags = OPOST | OCRNL | ONLRET;
758  size_t i;
759
760  for (i = 0; i < DEVICE_COUNT; ++i) {
761    device_context *dev = &ctx->devices[i];
762    char c;
763    ssize_t n;
764
765    dev->tty->column = 0;
766    clear_output(ctx, i);
767
768    clear_set_oflag(ctx, i, 0, oflags);
769
770    c = 'a';
771    n = write(ctx->fds[i], &c, sizeof(c));
772    rtems_test_assert(n == 1);
773    rtems_test_assert(dev->tty->column == 1);
774    flush_output(ctx, i);
775    rtems_test_assert(dev->output_count == 1);
776    rtems_test_assert(dev->output_buf[0] == 'a');
777
778    c = '\r';
779    n = write(ctx->fds[i], &c, sizeof(c));
780    rtems_test_assert(n == 1);
781    rtems_test_assert(dev->tty->column == 0);
782    flush_output(ctx, i);
783    rtems_test_assert(dev->output_count == 2);
784    rtems_test_assert(dev->output_buf[1] == '\n');
785
786    clear_set_oflag(ctx, i, oflags, 0);
787  }
788}
789
790static void test_opost(test_context *ctx)
791{
792  tcflag_t oflags = OPOST;
793  size_t i;
794
795  for (i = 0; i < DEVICE_COUNT; ++i) {
796    device_context *dev = &ctx->devices[i];
797    char c;
798    ssize_t n;
799
800    dev->tty->column = 0;
801    clear_output(ctx, i);
802
803    clear_set_oflag(ctx, i, 0, oflags);
804
805    c = 'a';
806    n = write(ctx->fds[i], &c, sizeof(c));
807    rtems_test_assert(n == 1);
808    rtems_test_assert(dev->tty->column == 1);
809    flush_output(ctx, i);
810    rtems_test_assert(dev->output_count == 1);
811    rtems_test_assert(dev->output_buf[0] == 'a');
812
813    c = '\33';
814    n = write(ctx->fds[i], &c, sizeof(c));
815    rtems_test_assert(n == 1);
816    rtems_test_assert(dev->tty->column == 1);
817    flush_output(ctx, i);
818    rtems_test_assert(dev->output_count == 2);
819    rtems_test_assert(dev->output_buf[1] == '\33');
820
821    c = '\t';
822    n = write(ctx->fds[i], &c, sizeof(c));
823    rtems_test_assert(n == 1);
824    rtems_test_assert(dev->tty->column == 8);
825    flush_output(ctx, i);
826    rtems_test_assert(dev->output_count == 3);
827    rtems_test_assert(dev->output_buf[2] == '\t');
828
829    c = '\b';
830    n = write(ctx->fds[i], &c, sizeof(c));
831    rtems_test_assert(n == 1);
832    rtems_test_assert(dev->tty->column == 7);
833    flush_output(ctx, i);
834    rtems_test_assert(dev->output_count == 4);
835    rtems_test_assert(dev->output_buf[3] == '\b');
836
837    c = '\r';
838    n = write(ctx->fds[i], &c, sizeof(c));
839    rtems_test_assert(n == 1);
840    rtems_test_assert(dev->tty->column == 0);
841    flush_output(ctx, i);
842    rtems_test_assert(dev->output_count == 5);
843    rtems_test_assert(dev->output_buf[4] == '\r');
844
845    clear_set_oflag(ctx, i, oflags, 0);
846  }
847}
848
849static void test_xtabs(test_context *ctx)
850{
851  tcflag_t oflags = OPOST | XTABS;
852  size_t i;
853
854  for (i = 0; i < DEVICE_COUNT; ++i) {
855    device_context *dev = &ctx->devices[i];
856    char c;
857    ssize_t n;
858
859    dev->tty->column = 0;
860    clear_output(ctx, i);
861
862    clear_set_oflag(ctx, i, 0, oflags);
863
864    c = 'a';
865    n = write(ctx->fds[i], &c, sizeof(c));
866    rtems_test_assert(n == 1);
867    rtems_test_assert(dev->tty->column == 1);
868    flush_output(ctx, i);
869    rtems_test_assert(dev->output_count == 1);
870    rtems_test_assert(dev->output_buf[0] == 'a');
871
872    c = '\t';
873    n = write(ctx->fds[i], &c, sizeof(c));
874    rtems_test_assert(n == 1);
875    rtems_test_assert(dev->tty->column == 8);
876    flush_output(ctx, i);
877    rtems_test_assert(dev->output_count == 8);
878    rtems_test_assert(dev->output_buf[1] == ' ');
879    rtems_test_assert(dev->output_buf[2] == ' ');
880    rtems_test_assert(dev->output_buf[3] == ' ');
881    rtems_test_assert(dev->output_buf[4] == ' ');
882    rtems_test_assert(dev->output_buf[5] == ' ');
883    rtems_test_assert(dev->output_buf[6] == ' ');
884    rtems_test_assert(dev->output_buf[7] == ' ');
885
886    clear_set_oflag(ctx, i, oflags, 0);
887  }
888}
889
890static void test_olcuc(test_context *ctx)
891{
892  tcflag_t oflags = OPOST | OLCUC;
893  size_t i;
894
895  for (i = 0; i < DEVICE_COUNT; ++i) {
896    device_context *dev = &ctx->devices[i];
897    char c;
898    ssize_t n;
899
900    dev->tty->column = 0;
901    clear_output(ctx, i);
902
903    clear_set_oflag(ctx, i, 0, oflags);
904
905    c = 'a';
906    n = write(ctx->fds[i], &c, sizeof(c));
907    rtems_test_assert(n == 1);
908    rtems_test_assert(dev->tty->column == 1);
909    flush_output(ctx, i);
910    rtems_test_assert(dev->output_count == 1);
911    rtems_test_assert(dev->output_buf[0] == 'A');
912
913    c = 'B';
914    n = write(ctx->fds[i], &c, sizeof(c));
915    rtems_test_assert(n == 1);
916    rtems_test_assert(dev->tty->column == 2);
917    flush_output(ctx, i);
918    rtems_test_assert(dev->output_count == 2);
919    rtems_test_assert(dev->output_buf[1] == 'B');
920
921    c = '9';
922    n = write(ctx->fds[i], &c, sizeof(c));
923    rtems_test_assert(n == 1);
924    rtems_test_assert(dev->tty->column == 3);
925    flush_output(ctx, i);
926    rtems_test_assert(dev->output_count == 3);
927    rtems_test_assert(dev->output_buf[2] == '9');
928
929    clear_set_oflag(ctx, i, oflags, 0);
930  }
931}
932
933static void
934set_self_prio(rtems_task_priority prio)
935{
936  rtems_status_code sc;
937
938  sc = rtems_task_set_priority(RTEMS_SELF, prio, &prio);
939  rtems_test_assert(sc == RTEMS_SUCCESSFUL);
940}
941
942static void flush_task(rtems_task_argument arg)
943{
944  test_context *ctx = (test_context *) arg;
945
946  while (true) {
947    set_self_prio(1);
948    flush_output(ctx, INTERRUPT);
949    set_self_prio(2);
950  }
951}
952
953static void test_write(test_context *ctx)
954{
955  tcflag_t oflags = OPOST | ONLCR | XTABS;
956  rtems_status_code sc;
957  size_t i = INTERRUPT;
958  device_context *dev = &ctx->devices[i];
959  char buf[OUTPUT_BUFFER_SIZE];
960  ssize_t n;
961
962  ctx->context_switch_counter = 0;
963
964  sc = rtems_task_create(
965    rtems_build_name('F', 'L', 'S', 'H'),
966    2,
967    RTEMS_MINIMUM_STACK_SIZE,
968    RTEMS_DEFAULT_MODES,
969    RTEMS_DEFAULT_ATTRIBUTES,
970    &ctx->flush_task_id
971  );
972  rtems_test_assert(sc == RTEMS_SUCCESSFUL);
973
974  sc = rtems_task_start(
975    ctx->flush_task_id,
976    flush_task,
977    (rtems_task_argument) ctx
978  );
979  rtems_test_assert(sc == RTEMS_SUCCESSFUL);
980
981  clear_output(ctx, i);
982  memset(buf, 'a', OUTPUT_BUFFER_SIZE);
983
984  n = write(ctx->fds[i], &buf[0], OUTPUT_BUFFER_SIZE);
985  rtems_test_assert(n == OUTPUT_BUFFER_SIZE - 1);
986
987  rtems_test_assert(ctx->context_switch_counter == 0);
988
989  enable_non_blocking(ctx, i, true);
990  n = write(ctx->fds[i], &buf[OUTPUT_BUFFER_SIZE - 1], 1);
991  rtems_test_assert(n == 0);
992
993  enable_non_blocking(ctx, i, false);
994  n = write(ctx->fds[i], &buf[OUTPUT_BUFFER_SIZE - 1], 1);
995  rtems_test_assert(n == 1);
996
997  rtems_test_assert(ctx->context_switch_counter == 2);
998  rtems_test_assert(dev->output_count == OUTPUT_BUFFER_SIZE);
999  rtems_test_assert(memcmp(dev->output_buf, buf, OUTPUT_BUFFER_SIZE) == 0);
1000
1001  clear_set_oflag(ctx, i, 0, oflags);
1002
1003  /* Ensure that ONLCR output expansion is taken into account */
1004
1005  dev->tty->column = 0;
1006  clear_output(ctx, i);
1007  memset(buf, 'b', OUTPUT_BUFFER_SIZE - 1);
1008  buf[OUTPUT_BUFFER_SIZE - 2] = '\n';
1009
1010  n = write(ctx->fds[i], &buf[0], OUTPUT_BUFFER_SIZE - 3);
1011  rtems_test_assert(n == OUTPUT_BUFFER_SIZE - 3);
1012
1013  rtems_test_assert(ctx->context_switch_counter == 2);
1014
1015  n = write(ctx->fds[i], &buf[OUTPUT_BUFFER_SIZE - 3], 2);
1016  rtems_test_assert(n == 1);
1017
1018  rtems_test_assert(ctx->context_switch_counter == 2);
1019
1020  enable_non_blocking(ctx, i, true);
1021  n = write(ctx->fds[i], &buf[OUTPUT_BUFFER_SIZE - 2], 1);
1022  rtems_test_assert(n == 0);
1023
1024  enable_non_blocking(ctx, i, false);
1025  n = write(ctx->fds[i], &buf[OUTPUT_BUFFER_SIZE - 2], 1);
1026  rtems_test_assert(n == 1);
1027
1028  rtems_test_assert(ctx->context_switch_counter == 4);
1029  rtems_test_assert(dev->output_count == OUTPUT_BUFFER_SIZE);
1030  buf[OUTPUT_BUFFER_SIZE - 2] = '\r';
1031  buf[OUTPUT_BUFFER_SIZE - 1] = '\n';
1032  rtems_test_assert(memcmp(dev->output_buf, buf, OUTPUT_BUFFER_SIZE) == 0);
1033
1034  /* Ensure that XTABS output expansion is taken into account */
1035
1036  dev->tty->column = 0;
1037  clear_output(ctx, i);
1038  memset(buf, 'c', OUTPUT_BUFFER_SIZE - 8);
1039  buf[OUTPUT_BUFFER_SIZE - 8] = '\t';
1040
1041  n = write(ctx->fds[i], &buf[0], OUTPUT_BUFFER_SIZE - 9);
1042  rtems_test_assert(n == OUTPUT_BUFFER_SIZE - 9);
1043
1044  rtems_test_assert(ctx->context_switch_counter == 4);
1045
1046  n = write(ctx->fds[i], &buf[OUTPUT_BUFFER_SIZE - 9], 2);
1047  rtems_test_assert(n == 1);
1048
1049  rtems_test_assert(ctx->context_switch_counter == 4);
1050
1051  enable_non_blocking(ctx, i, true);
1052  n = write(ctx->fds[i], &buf[OUTPUT_BUFFER_SIZE - 8], 1);
1053  rtems_test_assert(n == 0);
1054
1055  enable_non_blocking(ctx, i, false);
1056  n = write(ctx->fds[i], &buf[OUTPUT_BUFFER_SIZE - 8], 1);
1057  rtems_test_assert(n == 1);
1058
1059  rtems_test_assert(ctx->context_switch_counter == 6);
1060  rtems_test_assert(dev->output_count == OUTPUT_BUFFER_SIZE);
1061  memset(&buf[OUTPUT_BUFFER_SIZE - 8], ' ', 8);
1062  rtems_test_assert(memcmp(dev->output_buf, buf, OUTPUT_BUFFER_SIZE) == 0);
1063
1064  clear_set_oflag(ctx, i, oflags, 0);
1065
1066  sc = rtems_task_delete(ctx->flush_task_id);
1067  rtems_test_assert(sc == RTEMS_SUCCESSFUL);
1068}
1069
1070static void test_tx_callback(test_context *ctx)
1071{
1072  size_t i = INTERRUPT;
1073  device_context *dev = &ctx->devices[i];
1074  char c;
1075  ssize_t n;
1076
1077  clear_output(ctx, i);
1078  dev->callback_counter = 0;
1079  dev->tty->tty_snd.sw_pfn = callback;
1080  dev->tty->tty_snd.sw_arg = dev;
1081
1082  c = 'a';
1083  n = write(ctx->fds[i], &c, sizeof(c));
1084  rtems_test_assert(n == 1);
1085  rtems_test_assert(dev->callback_counter == 0);
1086  flush_output(ctx, i);
1087  rtems_test_assert(dev->callback_counter == 1);
1088  rtems_test_assert(dev->output_count == 1);
1089  rtems_test_assert(dev->output_buf[0] == 'a');
1090
1091  dev->tty->tty_snd.sw_pfn = NULL;
1092  dev->tty->tty_snd.sw_arg = NULL;
1093}
1094
1095static void Init(rtems_task_argument arg)
1096{
1097  test_context *ctx = &test_instance;
1098
1099  TEST_BEGIN();
1100
1101  setup(ctx);
1102  test_igncr(ctx);
1103  test_istrip(ctx);
1104  test_iuclc(ctx);
1105  test_icrnl(ctx);
1106  test_inlcr(ctx);
1107  test_rx_callback(ctx);
1108  test_rx_callback_icanon(ctx);
1109  test_onlret(ctx);
1110  test_onlcr(ctx);
1111  test_onocr(ctx);
1112  test_ocrnl(ctx);
1113  test_ocrnl_onlret(ctx);
1114  test_opost(ctx);
1115  test_xtabs(ctx);
1116  test_olcuc(ctx);
1117  test_write(ctx);
1118  test_tx_callback(ctx);
1119
1120  TEST_END();
1121  rtems_test_exit(0);
1122}
1123
1124static void switch_extension(Thread_Control *executing, Thread_Control *heir)
1125{
1126  test_context *ctx = &test_instance;
1127
1128  ++ctx->context_switch_counter;
1129}
1130
1131#define CONFIGURE_APPLICATION_NEEDS_CLOCK_DRIVER
1132#define CONFIGURE_APPLICATION_NEEDS_CONSOLE_DRIVER
1133
1134#define CONFIGURE_LIBIO_MAXIMUM_FILE_DESCRIPTORS 5
1135
1136#define CONFIGURE_MAXIMUM_TASKS 2
1137
1138#define CONFIGURE_MAXIMUM_SEMAPHORES 7
1139
1140#define CONFIGURE_INITIAL_EXTENSIONS \
1141  { .thread_switch = switch_extension }, \
1142  RTEMS_TEST_INITIAL_EXTENSION
1143
1144#define CONFIGURE_RTEMS_INIT_TASKS_TABLE
1145
1146#define CONFIGURE_INIT
1147
1148#include <rtems/confdefs.h>
Note: See TracBrowser for help on using the repository browser.