]> ncurses.scripts.mit.edu Git - ncurses.git/blobdiff - tack/sync.c
ncurses 5.0
[ncurses.git] / tack / sync.c
diff --git a/tack/sync.c b/tack/sync.c
new file mode 100644 (file)
index 0000000..d8866a0
--- /dev/null
@@ -0,0 +1,424 @@
+/*
+** Copyright (C) 1991, 1997 Free Software Foundation, Inc.
+** 
+** This file is part of TACK.
+** 
+** TACK is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2, or (at your option)
+** any later version.
+** 
+** TACK is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+** GNU General Public License for more details.
+** 
+** You should have received a copy of the GNU General Public License
+** along with TACK; see the file COPYING.  If not, write to
+** the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+** Boston, MA 02111-1307, USA.
+*/
+
+#include <tack.h>
+#include <time.h>
+
+MODULE_ID("$Id: sync.c,v 1.1 1998/01/10 00:31:07 tom Exp $")
+
+/* terminal-synchronization and performance tests */
+
+static void sync_home(struct test_list *, int *, int *);
+static void sync_lines(struct test_list *, int *, int *);
+static void sync_clear(struct test_list *, int *, int *);
+static void sync_summary(struct test_list *, int *, int *);
+
+struct test_list sync_test_list[] = {
+       {MENU_NEXT, 0, 0, 0, "b) baud rate test", sync_home, 0},
+       {MENU_NEXT, 0, 0, 0, "l) scroll performance", sync_lines, 0},
+       {MENU_NEXT, 0, 0, 0, "c) clear screen performance", sync_clear, 0},
+       {MENU_NEXT, 0, 0, 0, "p) summary of results", sync_summary, 0},
+       {0, 0, 0, 0, txt_longer_test_time, longer_test_time, 0},
+       {0, 0, 0, 0, txt_shorter_test_time, shorter_test_time, 0},
+       {MENU_LAST, 0, 0, 0, 0, 0, 0}
+};
+
+struct test_menu sync_menu = {
+       0, 'n', 0,
+       "Performance tests", "perf", "n) run standard tests",
+       sync_test, sync_test_list, 0, 0, 0
+};
+
+int tty_can_sync;              /* TRUE if tty_sync_error() returned FALSE */
+int tty_newline_rate;          /* The number of newlines per second */
+int tty_clear_rate;            /* The number of clear-screens per second */
+int tty_cps;                   /* The number of characters per second */
+
+#define TTY_ACK_SIZE 64
+
+int ACK_terminator;            /* terminating ACK character */
+int ACK_length;                        /* length of ACK string */
+const char *tty_ENQ;           /* enquire string */
+char tty_ACK[TTY_ACK_SIZE];    /* ACK response, set by tty_sync_error() */
+
+/*****************************************************************************
+ *
+ * Terminal synchronization.
+ *
+ *     These functions handle the messy business of enq-ack handshaking
+ *     for timing purposes.
+ *
+ *****************************************************************************/
+
+int
+tty_sync_error(void)
+{
+       int ch, trouble, ack;
+
+       trouble = FALSE;
+       for (;;) {
+               tt_putp(tty_ENQ);       /* send ENQ */
+               ch = getnext(STRIP_PARITY);
+               event_start(TIME_SYNC); /* start the timer */
+
+               /*
+                  The timer doesn't start until we get the first character.
+                  After that I expect to get the remaining characters of
+                  the acknowledge string in a short period of time.  If
+                  that is not true then these characters are coming from
+                  the user and we need to send the ENQ sequence out again.
+               */
+               for (ack = 0; ; ) {
+                       if (ack < TTY_ACK_SIZE - 2) {
+                               tty_ACK[ack] = ch;
+                               tty_ACK[ack + 1] = '\0';
+                       }
+                       if (ch == ACK_terminator) {
+                               return trouble;
+                       }
+                       if (++ack >= ACK_length) {
+                               return trouble;
+                       }
+                       ch = getnext(STRIP_PARITY);
+                       if (event_time(TIME_SYNC) > 400000) {
+                               break;
+                       }
+               }
+
+               set_attr(0);    /* just in case */
+               put_crlf();
+               if (trouble) {
+                       /* The terminal won't sync.  Life is not good. */
+                       return TRUE;
+               }
+               put_str(" -- sync -- ");
+               trouble = TRUE;
+       }
+}
+
+/*
+**     flush_input()
+**
+**     Throw away any output.
+*/
+void 
+flush_input(void)
+{
+       if (tty_can_sync == SYNC_TESTED && ACK_terminator >= 0) {
+               (void) tty_sync_error();
+       } else {
+               spin_flush();
+       }
+}
+
+/*
+**     probe_enq_ok()
+**
+**     does the terminal do enq/ack handshaking?
+*/
+static void 
+probe_enq_ok(void)
+{
+       int tc, len, ulen;
+
+       put_str("Testing ENQ/ACK, standby...");
+       fflush(stdout);
+       can_test("u8 u9", FLAG_TESTED);
+
+       tty_ENQ = user9 ? user9 : "\005";
+       tc_putp(tty_ENQ);
+       event_start(TIME_SYNC); /* start the timer */
+       read_key(tty_ACK, TTY_ACK_SIZE - 1);
+
+       if (event_time(TIME_SYNC) > 400000 || tty_ACK[0] == '\0') {
+               /* These characters came from the user.  Sigh. */
+               tty_can_sync = SYNC_FAILED;
+               ptext("\nThis program expects the ENQ sequence to be");
+               ptext(" answered with the ACK character.  This will help");
+               ptext(" the program reestablish synchronization when");
+               ptextln(" the terminal is overrun with data.");
+               ptext("\nENQ sequence from (u9): ");
+               putln(expand(tty_ENQ));
+               ptext("ACK recieved: ");
+               putln(expand(tty_ACK));
+               len = user8 ? strlen(user8) : 0;
+               sprintf(temp, "Length of ACK %d.  Expected length of ACK %d.",
+                       (int) strlen(tty_ACK), len);
+               ptextln(temp);
+               if (len) {
+                       temp[0] = user8[len - 1];
+                       temp[1] = '\0';
+                       ptext("Terminating character found in (u8): ");
+                       putln(expand(temp));
+               }
+               return;
+       }
+
+       tty_can_sync = SYNC_TESTED;
+       if ((len = strlen(tty_ACK)) == 1) {
+               /* single character acknowledge string */
+               ACK_terminator = tty_ACK[0];
+               ACK_length = 4096;
+               return;
+       }
+       tc = tty_ACK[len - 1];
+       if (user8) {
+               ulen = strlen(user8);
+               if (tc == user8[ulen - 1]) {
+                       /* ANSI style acknowledge string */
+                       ACK_terminator = tc;
+                       ACK_length = 4096;
+                       return;
+               }
+       }
+       /* fixed length acknowledge string */
+       ACK_length = len;
+       ACK_terminator = -2;
+}
+
+/*
+**     verify_time()
+**
+**     verify that the time tests are ready to run.
+**     If the baud rate is not set then compute it.
+*/
+void
+verify_time(void)
+{
+       int status, ch;
+
+       if (tty_can_sync == SYNC_FAILED) {
+               return;
+       }
+       probe_enq_ok();
+       put_crlf();
+       if (tty_can_sync == SYNC_TESTED) {
+               put_crlf();
+               if (ACK_terminator >= 0) {
+                       ptext("ACK terminating character: ");
+                       temp[0] = ACK_terminator;
+                       temp[1] = '\0';
+                       ptextln(expand(temp));
+               } else {
+                       sprintf(temp, "Fixed length ACK, %d characters",
+                               ACK_length);
+                       ptextln(temp);
+               }
+       }
+       if (tty_baud_rate == 0) {
+               sync_home(&sync_test_list[0], &status, &ch);
+       }
+}
+
+/*****************************************************************************
+ *
+ * Terminal performance tests
+ *
+ *     Find out how fast the terminal can:
+ *       1) accept characters
+ *       2) scroll the screen
+ *       3) clear the screen
+ *
+ *****************************************************************************/
+
+/*
+**     sync_home(test_list, status, ch)
+**
+**     Baudrate test
+*/
+void
+sync_home(
+       struct test_list *t,
+       int *state,
+       int *ch)
+{
+       int j, k;
+       unsigned long rate;
+
+       if (!cursor_home && !cursor_address && !row_address) {
+               ptext("Terminal can not home cursor.  ");
+               generic_done_message(t, state, ch);
+               return;
+       }
+       if (skip_pad_test(t, state, ch,
+               "(home) Start baudrate search")) {
+               return;
+       }
+       pad_test_startup(1);
+       do {
+               go_home();
+               for (j = 1; j < lines; j++) {
+                       for (k = 0; k < columns; k++) {
+                               if (k & 0xF) {
+                                       put_this(letter);
+                               } else {
+                                       put_this('.');
+                               }
+                       }
+                       SLOW_TERMINAL_EXIT;
+               }
+               NEXT_LETTER;
+       } while(still_testing());
+       pad_test_shutdown(t, auto_right_margin == 0);
+       /* note:  tty_frame_size is the real framesize times two.
+          This takes care of half bits. */
+       rate = (tx_cps * tty_frame_size) >> 1;
+       if (rate > tty_baud_rate) {
+               tty_baud_rate = rate;
+       }
+       if (tx_cps > tty_cps) {
+               tty_cps = tx_cps;
+       }
+       sprintf(temp, "%d characters per second.  Baudrate %d  ", tx_cps, j);
+       ptext(temp);
+       generic_done_message(t, state, ch);
+}
+
+/*
+**     sync_lines(test_list, status, ch)
+**
+**     How many newlines/second?
+*/
+static void
+sync_lines(
+       struct test_list *t,
+       int *state,
+       int *ch)
+{
+       int j;
+
+       if (skip_pad_test(t, state, ch,
+               "(nel) Start scroll performance test")) {
+               return;
+       }
+       pad_test_startup(0);
+       repeats = 100;
+       do {
+               sprintf(temp, "%d", test_complete);
+               put_str(temp);
+               put_newlines(repeats);
+       } while(still_testing());
+       pad_test_shutdown(t, 0);
+       j = sliding_scale(tx_count[0], 1000000, usec_run_time);
+       if (j > tty_newline_rate) {
+               tty_newline_rate = j;
+       }
+       sprintf(temp, "%d linefeeds per second.  ", j);
+       ptext(temp);
+       generic_done_message(t, state, ch);
+}
+
+/*
+**     sync_clear(test_list, status, ch)
+**
+**     How many clear-screens/second?
+*/
+static void
+sync_clear(
+       struct test_list *t,
+       int *state,
+       int *ch)
+{
+       int j;
+
+       if (!clear_screen) {
+               ptext("Terminal can not clear-screen.  ");
+               generic_done_message(t, state, ch);
+               return;
+       }
+       if (skip_pad_test(t, state, ch,
+               "(clear) Start clear-screen performance test")) {
+               return;
+       }
+       pad_test_startup(0);
+       repeats = 20;
+       do {
+               sprintf(temp, "%d", test_complete);
+               put_str(temp);
+               for (j = 0; j < repeats; j++) {
+                       put_clear();
+               }
+       } while(still_testing());
+       pad_test_shutdown(t, 0);
+       j = sliding_scale(tx_count[0], 1000000, usec_run_time);
+       if (j > tty_clear_rate) {
+               tty_clear_rate = j;
+       }
+       sprintf(temp, "%d clear-screens per second.  ", j);
+       ptext(temp);
+       generic_done_message(t, state, ch);
+}
+
+/*
+**     sync_symmary(test_list, status, ch)
+**
+**     Print out the test results.
+*/
+static void
+sync_summary(
+       struct test_list *t,
+       int *state,
+       int *ch)
+{
+       char size[32];
+
+       put_crlf();
+       ptextln("Terminal  size    characters/sec linefeeds/sec  clears/sec");
+       sprintf(size, "%dx%d", columns, lines);
+       sprintf(temp, "%-10s%-11s%11d   %11d %11d", tty_basename, size,
+               tty_cps, tty_newline_rate, tty_clear_rate);
+       ptextln(temp);
+       generic_done_message(t, state, ch);
+}
+
+/*
+**     sync_test(menu)
+**
+**     Run at the beginning of the pad tests and function key tests
+*/
+void
+sync_test(
+       struct test_menu *menu)
+{
+       control_init();
+       if (tty_can_sync == SYNC_NOT_TESTED) {
+               verify_time();
+       }
+       if (menu->menu_title) {
+               put_crlf();
+               ptextln(menu->menu_title);
+       }
+}
+
+/*
+**     sync_handshake(test_list, status, ch)
+**
+**     Test or retest the ENQ/ACK handshake
+*/
+void
+sync_handshake(
+       struct test_list *t GCC_UNUSED,
+       int *state GCC_UNUSED,
+       int *ch GCC_UNUSED)
+{
+       tty_can_sync = SYNC_NOT_TESTED;
+       verify_time();
+}