Back to home page

LXR

 
 

    


File indexing completed on 2025-05-11 08:24:46

0001 /*
0002  * Copyright (c) 2017 embedded brains GmbH & Co. KG
0003  *
0004  * The license and distribution terms for this file may be
0005  * found in the file LICENSE in this distribution or at
0006  * http://www.rtems.com/license/LICENSE.
0007  */
0008 
0009 #ifdef HAVE_CONFIG_H
0010 #include "config.h"
0011 #endif
0012 
0013 #include <sys/param.h>
0014 #include <sys/stat.h>
0015 #include <fcntl.h>
0016 #include <math.h>
0017 #include <string.h>
0018 #include <termios.h>
0019 #include <unistd.h>
0020 
0021 #include <rtems.h>
0022 #include <rtems/console.h>
0023 
0024 #include "tmacros.h"
0025 
0026 const char rtems_test_name[] = "SPCONSOLE 1";
0027 
0028 #define LINE_LEN 79
0029 
0030 static const char n_line[LINE_LEN + 1] =
0031 "nNnNnNnNnNnNnNnNnNnNnNnNnNnNnNnNnNnNnNnNnNnNnNnNnNnNnNnNnNnNnNnNnNnNnNnNnNnNnNn";
0032 
0033 static const char b_line[LINE_LEN + 1] =
0034 "bBbBbBbBbBbBbBbBbBbBbBbBbBbBbBbBbBbBbBbBbBbBbBbBbBbBbBbBbBbBbBbBbBbBbBbBbBbBbBb";
0035 
0036 static const char e_line[LINE_LEN + 1] =
0037 "eEeEeEeEeEeEeEeEeEeEeEeEeEeEeEeEeEeEeEeEeEeEeEeEeEeEeEeEeEeEeEeEeEeEeEeEeEeEeEe";
0038 
0039 typedef struct {
0040   speed_t speed;
0041   uint32_t value;
0042   const char *msg;
0043 } speed_desc;
0044 
0045 static const speed_desc speeds[] = {
0046   { .speed = B9600, .value = 9600, .msg = "9600 8N1" },
0047   { .speed = B19200, .value = 19200, .msg = "19200 8N1" },
0048   { .speed = B38400, .value = 38400, .msg = "38400 8N1" },
0049   { .speed = B57600, .value = 57600, .msg = "57600 8N1" },
0050   { .speed = B115200, .value = 115200, .msg = "115200 8N1" }
0051 };
0052 
0053 #define BITS_PER_CHAR 10
0054 
0055 typedef struct {
0056   int fd;
0057   struct termios saved_term;
0058   struct termios term;
0059   char buf[9600 / BITS_PER_CHAR];
0060   rtems_id done;
0061 } test_context;
0062 
0063 static test_context test_instance;
0064 
0065 static void drain(test_context *ctx)
0066 {
0067   int rv;
0068 
0069   rv = tcdrain(ctx->fd);
0070   rtems_test_assert(rv == 0);
0071 
0072   /* Ensure that a hardware transmit FIFO of reasonable size is empty */
0073   rv = usleep(200000);
0074   rtems_test_assert(rv == 0);
0075 }
0076 
0077 static void do_begin(test_context *ctx, const char *msg)
0078 {
0079   puts(n_line);
0080   puts(msg);
0081   puts(b_line);
0082   drain(ctx);
0083 }
0084 
0085 static void do_end(test_context *ctx)
0086 {
0087   int rv;
0088 
0089   drain(ctx);
0090 
0091   rv = cfsetspeed(&ctx->term, cfgetospeed(&ctx->saved_term));
0092   rtems_test_assert(rv == 0);
0093 
0094   rv = tcsetattr(ctx->fd, TCSANOW, &ctx->term);
0095   rtems_test_assert(rv == 0);
0096 
0097   puts("");
0098   puts(e_line);
0099 }
0100 
0101 static void test_steps_one_task(test_context *ctx, char c)
0102 {
0103   char buf[128];
0104   size_t i;
0105 
0106   for (i = 0; i < RTEMS_ARRAY_SIZE(buf); ++i) {
0107     size_t r;
0108     char *p;
0109 
0110     buf[i] = '\n';
0111 
0112     r = i;
0113     p = buf;
0114     while (r > 0) {
0115       ssize_t m;
0116 
0117       m = write(ctx->fd, p, r);
0118       rtems_test_assert(m > 0);
0119 
0120       r -= (size_t) m;
0121       p += (size_t) m;
0122     }
0123 
0124     if (i > 1) {
0125       buf[i - 2] = c;
0126     }
0127 
0128     if (i > 0) {
0129       buf[i - 1] = '\r';
0130     }
0131   }
0132 }
0133 
0134 static void test_speeds(test_context *ctx)
0135 {
0136   size_t i;
0137 
0138   for (i = 0; i < RTEMS_ARRAY_SIZE(speeds); ++i) {
0139     uint64_t t0;
0140     uint64_t t1;
0141     size_t n;
0142     size_t r;
0143     int rv;
0144 
0145     do_begin(ctx, speeds[i].msg);
0146 
0147     rv = cfsetspeed(&ctx->term, speeds[i].speed);
0148     rtems_test_assert(rv == 0);
0149 
0150     rv = tcsetattr(ctx->fd, TCSANOW, &ctx->term);
0151     rtems_test_assert(rv == 0);
0152 
0153     n = speeds[i].value / BITS_PER_CHAR;
0154     r = n;
0155     t0 = rtems_clock_get_uptime_nanoseconds();
0156 
0157     while (r > 0) {
0158       ssize_t m;
0159 
0160       m = write(ctx->fd, ctx->buf, MIN(sizeof(ctx->buf), r));
0161       rtems_test_assert(m > 0);
0162 
0163       r -= (size_t) m;
0164     }
0165 
0166     rv = tcdrain(ctx->fd);
0167     rtems_test_assert(rv == 0);
0168 
0169     t1 = rtems_clock_get_uptime_nanoseconds();
0170 
0171     do_end(ctx);
0172 
0173     printf("transmitted chars: %zu\n", n);
0174     printf(
0175       "transmitted bits (1 start, 8 data, 1 stop): %zu\n",
0176       n * BITS_PER_CHAR
0177     );
0178 
0179     printf("actual transmit time:   %10" PRIu64 "ns\n", t1 - t0);
0180     printf("expected transmit time: 1000000000ns\n");
0181   }
0182 }
0183 
0184 static void task(test_context *ctx, char c)
0185 {
0186   rtems_status_code sc;
0187 
0188   test_steps_one_task(ctx, c);
0189 
0190   sc = rtems_semaphore_release(ctx->done);
0191   rtems_test_assert(sc == RTEMS_SUCCESSFUL);
0192 
0193   rtems_task_suspend(RTEMS_SELF);
0194 }
0195 
0196 static void task_y(rtems_task_argument arg)
0197 {
0198   test_context *ctx;
0199 
0200   ctx = (test_context *) arg;
0201   task(ctx, 'Y');
0202 }
0203 
0204 static void task_z(rtems_task_argument arg)
0205 {
0206   test_context *ctx;
0207 
0208   ctx = (test_context *) arg;
0209   task(ctx, 'z');
0210 }
0211 
0212 static void test(test_context *ctx)
0213 {
0214   int rv;
0215   rtems_status_code sc;
0216   rtems_id y;
0217   rtems_id z;
0218 
0219   sc = rtems_semaphore_create(
0220     rtems_build_name('D', 'O', 'N', 'E'),
0221     0,
0222     RTEMS_COUNTING_SEMAPHORE,
0223     0,
0224     &ctx->done
0225   );
0226   rtems_test_assert(sc == RTEMS_SUCCESSFUL);
0227 
0228   ctx->fd = open(CONSOLE_DEVICE_NAME, O_RDWR);
0229   rtems_test_assert(ctx->fd >= 0);
0230 
0231   rv = tcgetattr(ctx->fd, &ctx->saved_term);
0232   rtems_test_assert(rv == 0);
0233 
0234   ctx->term = ctx->saved_term;
0235   cfmakeraw(&ctx->term);
0236 
0237   rv = tcsetattr(ctx->fd, TCSANOW, &ctx->term);
0238   rtems_test_assert(rv == 0);
0239 
0240   memset(&ctx->buf, 'd', sizeof(ctx->buf));
0241 
0242   do_begin(ctx, "steps one task");
0243   test_steps_one_task(ctx, 'x');
0244   do_end(ctx);
0245 
0246   do_begin(ctx, "steps three tasks");
0247 
0248   sc = rtems_task_create(
0249     rtems_build_name(' ', ' ', ' ', 'Y'),
0250     1,
0251     RTEMS_MINIMUM_STACK_SIZE,
0252     RTEMS_DEFAULT_MODES,
0253     RTEMS_DEFAULT_ATTRIBUTES,
0254     &y
0255   );
0256   rtems_test_assert(sc == RTEMS_SUCCESSFUL);
0257 
0258   sc = rtems_task_start(y, task_y, (rtems_task_argument) ctx);
0259   rtems_test_assert(sc == RTEMS_SUCCESSFUL);
0260 
0261   sc = rtems_task_create(
0262     rtems_build_name(' ', ' ', ' ', 'Z'),
0263     1,
0264     RTEMS_MINIMUM_STACK_SIZE,
0265     RTEMS_DEFAULT_MODES,
0266     RTEMS_DEFAULT_ATTRIBUTES,
0267     &z
0268   );
0269   rtems_test_assert(sc == RTEMS_SUCCESSFUL);
0270 
0271   sc = rtems_task_start(z, task_z, (rtems_task_argument) ctx);
0272   rtems_test_assert(sc == RTEMS_SUCCESSFUL);
0273 
0274   test_steps_one_task(ctx, 'x');
0275 
0276   sc = rtems_semaphore_obtain(ctx->done, RTEMS_WAIT, RTEMS_NO_TIMEOUT);
0277   rtems_test_assert(sc == RTEMS_SUCCESSFUL);
0278 
0279   sc = rtems_semaphore_obtain(ctx->done, RTEMS_WAIT, RTEMS_NO_TIMEOUT);
0280   rtems_test_assert(sc == RTEMS_SUCCESSFUL);
0281 
0282   do_end(ctx);
0283 
0284   test_speeds(ctx);
0285 
0286   rv = close(ctx->fd);
0287   rtems_test_assert(rv == 0);
0288 
0289   sc = rtems_task_delete(y);
0290   rtems_test_assert(sc == RTEMS_SUCCESSFUL);
0291 
0292   sc = rtems_task_delete(z);
0293   rtems_test_assert(sc == RTEMS_SUCCESSFUL);
0294 
0295   sc = rtems_semaphore_delete(ctx->done);
0296   rtems_test_assert(sc == RTEMS_SUCCESSFUL);
0297 }
0298 
0299 static void Init(rtems_task_argument arg)
0300 {
0301   TEST_BEGIN();
0302 
0303   rtems_print_printer_fprintf_putc(&rtems_test_printer);
0304   test(&test_instance);
0305 
0306   TEST_END();
0307   rtems_test_exit(0);
0308 }
0309 
0310 #define CONFIGURE_APPLICATION_NEEDS_CLOCK_DRIVER
0311 #define CONFIGURE_APPLICATION_NEEDS_CONSOLE_DRIVER
0312 
0313 #define CONFIGURE_MAXIMUM_FILE_DESCRIPTORS 4
0314 
0315 #define CONFIGURE_MAXIMUM_TASKS 3
0316 #define CONFIGURE_MAXIMUM_SEMAPHORES 1
0317 
0318 #define CONFIGURE_INITIAL_EXTENSIONS RTEMS_TEST_INITIAL_EXTENSION
0319 
0320 #define CONFIGURE_INIT_TASK_INITIAL_MODES RTEMS_DEFAULT_MODES
0321 #define CONFIGURE_INIT_TASK_ATTRIBUTES RTEMS_FLOATING_POINT
0322 
0323 #define CONFIGURE_RTEMS_INIT_TASKS_TABLE
0324 
0325 #define CONFIGURE_INIT
0326 
0327 #include <rtems/confdefs.h>