forked from Imagelibrary/rtems
328 lines
6.7 KiB
C
328 lines
6.7 KiB
C
/*
|
|
* Copyright (c) 2017 embedded brains GmbH & Co. KG
|
|
*
|
|
* The license and distribution terms for this file may be
|
|
* found in the file LICENSE in this distribution or at
|
|
* http://www.rtems.com/license/LICENSE.
|
|
*/
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
#include "config.h"
|
|
#endif
|
|
|
|
#include <sys/param.h>
|
|
#include <sys/stat.h>
|
|
#include <fcntl.h>
|
|
#include <math.h>
|
|
#include <string.h>
|
|
#include <termios.h>
|
|
#include <unistd.h>
|
|
|
|
#include <rtems.h>
|
|
#include <rtems/console.h>
|
|
|
|
#include "tmacros.h"
|
|
|
|
const char rtems_test_name[] = "SPCONSOLE 1";
|
|
|
|
#define LINE_LEN 79
|
|
|
|
static const char n_line[LINE_LEN + 1] =
|
|
"nNnNnNnNnNnNnNnNnNnNnNnNnNnNnNnNnNnNnNnNnNnNnNnNnNnNnNnNnNnNnNnNnNnNnNnNnNnNnNn";
|
|
|
|
static const char b_line[LINE_LEN + 1] =
|
|
"bBbBbBbBbBbBbBbBbBbBbBbBbBbBbBbBbBbBbBbBbBbBbBbBbBbBbBbBbBbBbBbBbBbBbBbBbBbBbBb";
|
|
|
|
static const char e_line[LINE_LEN + 1] =
|
|
"eEeEeEeEeEeEeEeEeEeEeEeEeEeEeEeEeEeEeEeEeEeEeEeEeEeEeEeEeEeEeEeEeEeEeEeEeEeEeEe";
|
|
|
|
typedef struct {
|
|
speed_t speed;
|
|
uint32_t value;
|
|
const char *msg;
|
|
} speed_desc;
|
|
|
|
static const speed_desc speeds[] = {
|
|
{ .speed = B9600, .value = 9600, .msg = "9600 8N1" },
|
|
{ .speed = B19200, .value = 19200, .msg = "19200 8N1" },
|
|
{ .speed = B38400, .value = 38400, .msg = "38400 8N1" },
|
|
{ .speed = B57600, .value = 57600, .msg = "57600 8N1" },
|
|
{ .speed = B115200, .value = 115200, .msg = "115200 8N1" }
|
|
};
|
|
|
|
#define BITS_PER_CHAR 10
|
|
|
|
typedef struct {
|
|
int fd;
|
|
struct termios saved_term;
|
|
struct termios term;
|
|
char buf[9600 / BITS_PER_CHAR];
|
|
rtems_id done;
|
|
} test_context;
|
|
|
|
static test_context test_instance;
|
|
|
|
static void drain(test_context *ctx)
|
|
{
|
|
int rv;
|
|
|
|
rv = tcdrain(ctx->fd);
|
|
rtems_test_assert(rv == 0);
|
|
|
|
/* Ensure that a hardware transmit FIFO of reasonable size is empty */
|
|
rv = usleep(200000);
|
|
rtems_test_assert(rv == 0);
|
|
}
|
|
|
|
static void do_begin(test_context *ctx, const char *msg)
|
|
{
|
|
puts(n_line);
|
|
puts(msg);
|
|
puts(b_line);
|
|
drain(ctx);
|
|
}
|
|
|
|
static void do_end(test_context *ctx)
|
|
{
|
|
int rv;
|
|
|
|
drain(ctx);
|
|
|
|
rv = cfsetspeed(&ctx->term, cfgetospeed(&ctx->saved_term));
|
|
rtems_test_assert(rv == 0);
|
|
|
|
rv = tcsetattr(ctx->fd, TCSANOW, &ctx->term);
|
|
rtems_test_assert(rv == 0);
|
|
|
|
puts("");
|
|
puts(e_line);
|
|
}
|
|
|
|
static void test_steps_one_task(test_context *ctx, char c)
|
|
{
|
|
char buf[128];
|
|
size_t i;
|
|
|
|
for (i = 0; i < RTEMS_ARRAY_SIZE(buf); ++i) {
|
|
size_t r;
|
|
char *p;
|
|
|
|
buf[i] = '\n';
|
|
|
|
r = i;
|
|
p = buf;
|
|
while (r > 0) {
|
|
ssize_t m;
|
|
|
|
m = write(ctx->fd, p, r);
|
|
rtems_test_assert(m > 0);
|
|
|
|
r -= (size_t) m;
|
|
p += (size_t) m;
|
|
}
|
|
|
|
if (i > 1) {
|
|
buf[i - 2] = c;
|
|
}
|
|
|
|
if (i > 0) {
|
|
buf[i - 1] = '\r';
|
|
}
|
|
}
|
|
}
|
|
|
|
static void test_speeds(test_context *ctx)
|
|
{
|
|
size_t i;
|
|
|
|
for (i = 0; i < RTEMS_ARRAY_SIZE(speeds); ++i) {
|
|
uint64_t t0;
|
|
uint64_t t1;
|
|
size_t n;
|
|
size_t r;
|
|
int rv;
|
|
|
|
do_begin(ctx, speeds[i].msg);
|
|
|
|
rv = cfsetspeed(&ctx->term, speeds[i].speed);
|
|
rtems_test_assert(rv == 0);
|
|
|
|
rv = tcsetattr(ctx->fd, TCSANOW, &ctx->term);
|
|
rtems_test_assert(rv == 0);
|
|
|
|
n = speeds[i].value / BITS_PER_CHAR;
|
|
r = n;
|
|
t0 = rtems_clock_get_uptime_nanoseconds();
|
|
|
|
while (r > 0) {
|
|
ssize_t m;
|
|
|
|
m = write(ctx->fd, ctx->buf, MIN(sizeof(ctx->buf), r));
|
|
rtems_test_assert(m > 0);
|
|
|
|
r -= (size_t) m;
|
|
}
|
|
|
|
rv = tcdrain(ctx->fd);
|
|
rtems_test_assert(rv == 0);
|
|
|
|
t1 = rtems_clock_get_uptime_nanoseconds();
|
|
|
|
do_end(ctx);
|
|
|
|
printf("transmitted chars: %zu\n", n);
|
|
printf(
|
|
"transmitted bits (1 start, 8 data, 1 stop): %zu\n",
|
|
n * BITS_PER_CHAR
|
|
);
|
|
|
|
printf("actual transmit time: %10" PRIu64 "ns\n", t1 - t0);
|
|
printf("expected transmit time: 1000000000ns\n");
|
|
}
|
|
}
|
|
|
|
static void task(test_context *ctx, char c)
|
|
{
|
|
rtems_status_code sc;
|
|
|
|
test_steps_one_task(ctx, c);
|
|
|
|
sc = rtems_semaphore_release(ctx->done);
|
|
rtems_test_assert(sc == RTEMS_SUCCESSFUL);
|
|
|
|
rtems_task_suspend(RTEMS_SELF);
|
|
}
|
|
|
|
static void task_y(rtems_task_argument arg)
|
|
{
|
|
test_context *ctx;
|
|
|
|
ctx = (test_context *) arg;
|
|
task(ctx, 'Y');
|
|
}
|
|
|
|
static void task_z(rtems_task_argument arg)
|
|
{
|
|
test_context *ctx;
|
|
|
|
ctx = (test_context *) arg;
|
|
task(ctx, 'z');
|
|
}
|
|
|
|
static void test(test_context *ctx)
|
|
{
|
|
int rv;
|
|
rtems_status_code sc;
|
|
rtems_id y;
|
|
rtems_id z;
|
|
|
|
sc = rtems_semaphore_create(
|
|
rtems_build_name('D', 'O', 'N', 'E'),
|
|
0,
|
|
RTEMS_COUNTING_SEMAPHORE,
|
|
0,
|
|
&ctx->done
|
|
);
|
|
rtems_test_assert(sc == RTEMS_SUCCESSFUL);
|
|
|
|
ctx->fd = open(CONSOLE_DEVICE_NAME, O_RDWR);
|
|
rtems_test_assert(ctx->fd >= 0);
|
|
|
|
rv = tcgetattr(ctx->fd, &ctx->saved_term);
|
|
rtems_test_assert(rv == 0);
|
|
|
|
ctx->term = ctx->saved_term;
|
|
cfmakeraw(&ctx->term);
|
|
|
|
rv = tcsetattr(ctx->fd, TCSANOW, &ctx->term);
|
|
rtems_test_assert(rv == 0);
|
|
|
|
memset(&ctx->buf, 'd', sizeof(ctx->buf));
|
|
|
|
do_begin(ctx, "steps one task");
|
|
test_steps_one_task(ctx, 'x');
|
|
do_end(ctx);
|
|
|
|
do_begin(ctx, "steps three tasks");
|
|
|
|
sc = rtems_task_create(
|
|
rtems_build_name(' ', ' ', ' ', 'Y'),
|
|
1,
|
|
RTEMS_MINIMUM_STACK_SIZE,
|
|
RTEMS_DEFAULT_MODES,
|
|
RTEMS_DEFAULT_ATTRIBUTES,
|
|
&y
|
|
);
|
|
rtems_test_assert(sc == RTEMS_SUCCESSFUL);
|
|
|
|
sc = rtems_task_start(y, task_y, (rtems_task_argument) ctx);
|
|
rtems_test_assert(sc == RTEMS_SUCCESSFUL);
|
|
|
|
sc = rtems_task_create(
|
|
rtems_build_name(' ', ' ', ' ', 'Z'),
|
|
1,
|
|
RTEMS_MINIMUM_STACK_SIZE,
|
|
RTEMS_DEFAULT_MODES,
|
|
RTEMS_DEFAULT_ATTRIBUTES,
|
|
&z
|
|
);
|
|
rtems_test_assert(sc == RTEMS_SUCCESSFUL);
|
|
|
|
sc = rtems_task_start(z, task_z, (rtems_task_argument) ctx);
|
|
rtems_test_assert(sc == RTEMS_SUCCESSFUL);
|
|
|
|
test_steps_one_task(ctx, 'x');
|
|
|
|
sc = rtems_semaphore_obtain(ctx->done, RTEMS_WAIT, RTEMS_NO_TIMEOUT);
|
|
rtems_test_assert(sc == RTEMS_SUCCESSFUL);
|
|
|
|
sc = rtems_semaphore_obtain(ctx->done, RTEMS_WAIT, RTEMS_NO_TIMEOUT);
|
|
rtems_test_assert(sc == RTEMS_SUCCESSFUL);
|
|
|
|
do_end(ctx);
|
|
|
|
test_speeds(ctx);
|
|
|
|
rv = close(ctx->fd);
|
|
rtems_test_assert(rv == 0);
|
|
|
|
sc = rtems_task_delete(y);
|
|
rtems_test_assert(sc == RTEMS_SUCCESSFUL);
|
|
|
|
sc = rtems_task_delete(z);
|
|
rtems_test_assert(sc == RTEMS_SUCCESSFUL);
|
|
|
|
sc = rtems_semaphore_delete(ctx->done);
|
|
rtems_test_assert(sc == RTEMS_SUCCESSFUL);
|
|
}
|
|
|
|
static void Init(rtems_task_argument arg)
|
|
{
|
|
TEST_BEGIN();
|
|
|
|
rtems_print_printer_fprintf_putc(&rtems_test_printer);
|
|
test(&test_instance);
|
|
|
|
TEST_END();
|
|
rtems_test_exit(0);
|
|
}
|
|
|
|
#define CONFIGURE_APPLICATION_NEEDS_CLOCK_DRIVER
|
|
#define CONFIGURE_APPLICATION_NEEDS_CONSOLE_DRIVER
|
|
|
|
#define CONFIGURE_MAXIMUM_FILE_DESCRIPTORS 4
|
|
|
|
#define CONFIGURE_MAXIMUM_TASKS 3
|
|
#define CONFIGURE_MAXIMUM_SEMAPHORES 1
|
|
|
|
#define CONFIGURE_INITIAL_EXTENSIONS RTEMS_TEST_INITIAL_EXTENSION
|
|
|
|
#define CONFIGURE_INIT_TASK_INITIAL_MODES RTEMS_DEFAULT_MODES
|
|
#define CONFIGURE_INIT_TASK_ATTRIBUTES RTEMS_FLOATING_POINT
|
|
|
|
#define CONFIGURE_RTEMS_INIT_TASKS_TABLE
|
|
|
|
#define CONFIGURE_INIT
|
|
|
|
#include <rtems/confdefs.h>
|