1
0
mirror of https://github.com/rricharz/Tek4010.git synced 2026-04-13 15:34:44 +00:00

full implementation of Tektronix 4014 decoder

This commit is contained in:
¨Rene Richarz
2019-04-13 12:19:45 +02:00
parent bda22ae3a8
commit 2d3982b994
8 changed files with 167 additions and 119 deletions

View File

@@ -263,7 +263,7 @@ module.
If called with the -full option, the tek4010 emulator creates creates a full screen window,
and uses the full 4K resolution of the 4014 with enhanced graphics
module installed, scaled down to the actual window size.
Use control-q close the tek4010 window. This option is experimental.
Use control-q to close the tek4010 window. This option is experimental.
**Compiling the tek4010 project**
@@ -274,6 +274,7 @@ If you want to compile the project, you need to install "libgtk-3-dev":
There is a make file in the repo.
**Version**
See [versions.txt](versions.txt)

2
ards.c
View File

@@ -80,7 +80,7 @@ void ards_draw(cairo_t *cr, cairo_t *cr2, int first)
tube_clearSecond(cr2);
// clear persistent surface, if necessary
if (globaltube_clearPersistent) {
if (tube_doClearPersistent) {
tube_clearPersistent(cr,cr2);
}

6
main.c
View File

@@ -58,7 +58,7 @@ extern int argARDS;
int windowWidth;
int windowHeight;
int globaltube_clearPersistent;
extern int tube_doClearPersistent;
static void do_drawing(cairo_t *, GtkWidget *);
@@ -131,7 +131,7 @@ static void on_key_press(GtkWidget *widget, GdkEventKey *event, gpointer user_da
(event->keyval == 0xFF55) || // "page up" key
(event->keyval == 0xFF56)) // "page down" key
{
globaltube_clearPersistent = 1;
tube_doClearPersistent = 1;
gtk_widget_queue_draw(widget);
return;
}
@@ -142,7 +142,7 @@ static void on_key_press(GtkWidget *widget, GdkEventKey *event, gpointer user_da
else if (event->state & GDK_CONTROL_MASK) {
if ((event->keyval == 0xFF51) || // "<ctrl>left arrow" key
(event->keyval == 0xFF52)) { // "<ctrl>up arrow" key
globaltube_clearPersistent = 1;
tube_doClearPersistent = 1;
gtk_widget_queue_draw(widget);
return;
}

BIN
tek4010

Binary file not shown.

243
tek4010.c
View File

@@ -91,67 +91,95 @@ void tek4010_checkLimits()
if (tube_y0 > (windowHeight - vDotsPerChar)) tube_y0 = windowHeight - vDotsPerChar;
}
void tek4010_escapeCodeHandler(cairo_t *cr, cairo_t *cr2, int ch)
// handle escape sequencies
void tek4010_bell()
{
// bell function, delay 0.1 sec
tube_u100ResetSeconds(1);
usleep(50000);
showCursor=0;
todo = 0;
}
void tek4010_escapeCodeHandler(cairo_t *cr, cairo_t *cr2, int ch)
// handle escape sequencies, see 4014 user manual, table page G-1
// codes identical for all modes are handled elsewhere
{
if (DEBUG) printf("Escape mode, ch=%02X\n",ch);
switch (ch) {
case 0: break;
case 0: break; // ignore filler 0
case 5: // ENQ: ask for status and position
// not yet implemented, needs to send 7 bytes
printf("ENQ not implemented\n");
break;
case 12:
if (DEBUG) printf("Form feed, clear screen\n");
printf("ENQ not supported, ignored\n");
mode = 0; break;
case 6: break;
case 8: // backspace during ESC
tube_x0 -= hDotsPerChar;
tek4010_checkLimits();
mode = 0; break;
case 9: // tab during ESC
if (argTab1)
tube_x0 += hDotsPerChar;
else
tube_x0 = tube_x0 - (tube_x0 % (8 * hDotsPerChar)) + 8 * hDotsPerChar;
tek4010_checkLimits();
mode = 0; break;
case 11:// VT during ESC, move one line up
tube_y0 += vDotsPerChar;
tek4010_checkLimits();
mode = 0; break;
case 12:// FF during ESC
tube_changeCharacterSize(cr, cr2, 74, 35, (int) (18.0 * efactor));
tube_clearPersistent(cr,cr2);
mode = 0;
break;
case '[':
// a second escape code follows, do not reset mode
break;
mode = 0; break;
case 13:mode = 0; break;
case 14: // SO activate alternative char set, not implemented
case 15: // SI deactivate alternative char set
mode = 0;
case 15: // SI deactivate alternative char set, not implemented
break;
case 23: system("scrot --focussed"); mode= 0; break;
case 28: // file separator >> point plot mode
mode = 5;
plotPointMode= 1;
case 26: // sub
printf("GIN mode not supported, ignored\n");
mode = 50;
break;
case 29: // group separator >> graphics mode
mode = 1;
plotPointMode = 0;
// modes 27 and 29 - 31 are identical in all modes
case 28: // record sepatator
printf("Special point plot mode not supported, ignored\n");
mode = 50;
break;
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7': printf("esc %c\n", ch); mode = 31; break;
case '8': tube_changeCharacterSize(cr, cr2, 74, 35, (int)(efactor * 18)); break;
case '9': tube_changeCharacterSize(cr, cr2, 81, 38, (int)(efactor * 16)); break;
case ':': tube_changeCharacterSize(cr, cr2, 121, 58, (int)(efactor * 11)); break;
case ';': tube_changeCharacterSize(cr, cr2, 133, 64, (int)(efactor * 10)); break;
case ']': printf("esc %c\n", ch); break;
case 'm': mode = 0; break;
case '[': // a second escape code follows, do not reset mode
break;
// normal mode
case '`': ltype = SOLID; writeThroughMode = 0; mode = 0; break;
case 'a': ltype = DOTTED; writeThroughMode = 0; mode = 0; break;
case 'b': ltype = DOTDASH; writeThroughMode = 0; mode = 0; break;
case 'c': ltype = SHORTDASH;writeThroughMode = 0; mode = 0; break;
case 'd': ltype = LONGDASH; writeThroughMode = 0; mode = 0; break;
case 'e': ltype = SOLID; writeThroughMode = 0; mode = 0; break;
case 'f': ltype = SOLID; writeThroughMode = 0; mode = 0; break;
case 'h': ltype = SOLID; writeThroughMode = 0; mode = 0; break;
case 'f': ltype = SOLID; writeThroughMode = 0; mode = 0; break;
case 'g': ltype = SOLID; writeThroughMode = 0; mode = 0; break;
// defocussed mode
case 'h':
case 'i':
case 'j':
case 'k':
case 'l':
case 'm':
case 'n':
case 'o': printf("Defocussed mode ESC %c not supported, ignored\n", ch); mode = 101; break;
// write-trough mode
case 'p': ltype = SOLID; writeThroughMode = 1; mode = 101; showCursor = 0; break;
case 'q': ltype = DOTTED; writeThroughMode = 1; mode = 101; showCursor = 0; break;
case 'r': ltype = DOTDASH; writeThroughMode = 1; mode = 101; showCursor = 0; break;
@@ -162,21 +190,28 @@ void tek4010_escapeCodeHandler(cairo_t *cr, cairo_t *cr2, int ch)
case 'w': ltype = SOLID; writeThroughMode = 1; mode = 101; showCursor = 0; break;
default:
printf("Escape code %02X not implemented, mode = %d\n",ch, savemode);
printf("ESC %d not supported, ignored\n",ch);
mode = 0;
break;
}
}
int tek4010_checkExitFromGraphics(int ch)
// test for exit from graphics character
int tek4010_checkReturnToAlpha(int ch)
// test for return to alpha character set
// see 4014 manual, page F-10, note 1
{
if ((ch==31) || (ch==13) || (ch==27) || (ch==12)) {
if (DEBUG && mode) printf("Going to alpha mode\n");
mode = 0;
if (DEBUG) printf("Leaving graphics mode\n");
showCursor = 0;
if (ch == 12) globaltube_clearPersistent = 1;
if (ch == 12) {
tube_doClearPersistent = 1;
todo = 0;
}
if (ch == 27) {
mode = 30;
todo = 0;
}
plotPointMode = 0;
return 1;
}
@@ -223,7 +258,7 @@ void tek4010_draw(cairo_t *cr, cairo_t *cr2, int first)
tube_clearSecond(cr2);
// clear persistent surface, if necessary
if (globaltube_clearPersistent) {
if (tube_doClearPersistent) {
tube_clearPersistent(cr,cr2);
tube_changeCharacterSize(cr, cr2, 74, 35, (int) (18.0 * efactor));
}
@@ -256,35 +291,62 @@ void tek4010_draw(cairo_t *cr, cairo_t *cr2, int first)
if ((ch>0x20)&&(ch<=0x7E)) printf(" (%c)",ch);
printf("\n");
}
if (tek4010_checkReturnToAlpha(ch)) {
todo = todo - 4;
goto endDo;
}
// the following chars are identical in all modes (with exception: 13,28)
// see 4014 user manual, table on page G1 ff
if (mode == 31) {
printf("ANSI escape mode 31, ch=%02x\n",ch);
if ((ch>='0') && (ch<='9')) { savemode = mode; mode = 30; }
switch (ch) {
case 7: tek4010_bell();
goto endDo;
case 10: // new line
tube_y0 -= vDotsPerChar;
if (!argRaw) tube_x0 = leftmargin;
tek4010_checkLimits();
goto endDo;
case 13: // return
if (mode != 30) { // special handling in ESC mode
mode = 0; tube_x0 = leftmargin;
goto endDo;
}
break;
case 27: // escape code, all modes
savemode = mode;
mode = 30;
goto endDo;
case 28: // file separator >> point plot mode
if (mode != 30) { // special handling in ESC mode
mode = 5;
plotPointMode= 1;
goto endDo;
}
break;
case 29: // group separator >> graphics mode
mode = 1;
plotPointMode = 0;
goto endDo;
case 30: // record separator >> incremental mode
printf("Special point plot mode not supported, ignored\n");
mode = 40;
goto endDo;
case 31: // US, normal mode
mode = 0;
goto endDo;
}
if (ch == 27) { // escape code
savemode = mode;
mode = 30; return;
}
if (ch == 30) {
printf("Incremental plot mode not implemented\n");
mode = 40; return;
}
// handle skipping coordinate bytes
// this cannot be done in switch(mode) below, because multiple bytes
// can be skipped and the current byte must be executed after a mode change
int tag = (ch >> 5) & 3;
if ((mode >= 1) && (mode <= 8)) {
if (tek4010_checkExitFromGraphics(ch)) {
todo = todo - 4;
goto endDo;
}
// handle skipped coordinate bytes
// this cannot be done in switch(mode) below, because multiple bytes
// can be switched and the current byte must be executed after a mode change
if ((mode == 5) && (ch == 29)) {
if (DEBUG) printf("group separator, go from mode 5 to mode 1\n");
mode = 1;
@@ -293,10 +355,10 @@ void tek4010_draw(cairo_t *cr, cairo_t *cr2, int first)
if (DEBUG) {
if (mode & 1)
printf("mode=%d,tag=%d-H-val=%d,",
printf(" mode=%d,tag=%d-H-val=%d,",
mode,tag, 32 * (ch & 31));
else
printf("mode=%d,tag=%d-L-val=%d,",
printf(" mode=%d,tag=%d-L-val=%d,",
mode,tag, ch & 31);
printf("xh=%d,xl=%d,yh=%d,yl=%d\n",xh,xl,yh,yl);
}
@@ -340,6 +402,9 @@ void tek4010_draw(cairo_t *cr, cairo_t *cr2, int first)
}
}
// handling anything specific to a mode
switch (mode) {
case 1: plotPointMode = 0; // normal graphics mode, starting coordinates
@@ -425,22 +490,19 @@ void tek4010_draw(cairo_t *cr, cairo_t *cr2, int first)
tek4010_escapeCodeHandler(cr, cr2, ch);
break;
case 40: // incremental plot mode, not implemented
if (ch == 31) mode = 0; // leave this mode
tek4010_checkReturnToAlpha(ch); // check for exit
break;
case 50: // incremental plot mode, not implemented
tek4010_checkReturnToAlpha(ch); // check for exit
break;
case 101:
if (DEBUG) printf("Ignore until group separator, ch = %02x\n", ch);
if (ch == 29) mode = 1;
break;
default:
case 0: // handle ALPHA mode; 4014 user manual, table page G-1
// some characters are indentical for all modes and handled elsewhere
switch (ch) {
case 0: break;
case 7: // bell function, delay 0.1 sec
// cannot delay if bright spot is on, needs to be turned off first
tube_u100ResetSeconds(1);
usleep(50000);
showCursor=0;
todo = 0;
break;
case 8: // backspace
tube_x0 -= hDotsPerChar;
tek4010_checkLimits();
@@ -452,43 +514,24 @@ void tek4010_draw(cairo_t *cr, cairo_t *cr2, int first)
tube_x0 = tube_x0 - (tube_x0 % (8 * hDotsPerChar)) + 8 * hDotsPerChar;
tek4010_checkLimits();
break;
case 10: // new line
tube_y0 -= vDotsPerChar;
if (!argRaw) tube_x0 = leftmargin;
tek4010_checkLimits();
break;
case 11: // VT, move one line up
tube_y0 += vDotsPerChar;
tek4010_checkLimits();
break;
case 13: // return
mode = 0; tube_x0 = leftmargin;
break;
case 23: // ctrl-w screen dump
system("scrot --focussed");
break;
case 28: // file separator >> point plot mode
mode = 5;
plotPointMode= 1;
break;
case 29: // group separator
mode = 1;
break;
case 30: // record separator
mode = 40;
break;
case 31: // US, leave graphics mode
mode = 0;
break;
default: if ((ch >= 32) && (ch <127)) { // printable character
tek4010_checkLimits();
tube_drawCharacter(cr,cr2, ch);
tube_drawCharacter(cr,cr2, ch);
todo-= 2;
}
break;
}
break;
break;
default: printf("Illegal mode - this is a tek4010decoder error and should not happen\n");
break;
}
endDo:;
}

20
tube.c
View File

@@ -51,7 +51,6 @@
#include "tube.h"
extern void gtk_main_quit();
extern int globaltube_clearPersistent;
extern int windowWidth;
extern int windowHeight;
extern char *windowName;
@@ -75,6 +74,7 @@ double dashset[] = {2,6,2,2,6,3,3,3,6,6};
int plotPointMode = 0; // plot point mode
int writeThroughMode = 0; // write through mode
int tube_doClearPersistent;
int tube_x0, tube_x2,tube_y0, tube_y2;
@@ -162,7 +162,6 @@ int tube_getInputChar()
if (t < charResetCount * characterInterval)
return -1; // there is time to refresh the screen
int c = getc(getData) & 0x7F;
if (DEBUG) printf(">>%02X<<",c);
charCount++;
charResetCount++;
lastTime = t;
@@ -259,7 +258,7 @@ void tube_init(int argc, char* argv[])
if (DEBUG) printf("character_interval = %0.1f msec\n",(double)characterInterval/10.0);
globaltube_clearPersistent = 1;
tube_doClearPersistent = 1;
// create pipes for communication between parent and child
if (pipe(getDataPipe) == -1) {
@@ -403,7 +402,7 @@ void tube_clearPersistent(cairo_t *cr, cairo_t *cr2)
{
cairo_set_source_rgb(cr, BLACK_COLOR);
cairo_paint(cr);
globaltube_clearPersistent = 0;
tube_doClearPersistent = 0;
tube_x0 = 0;
tube_y0 = windowHeight - vDotsPerChar;
tube_x2 = tube_x0;
@@ -470,19 +469,19 @@ void tube_drawCharacter(cairo_t *cr, cairo_t *cr2, char ch)
if (writeThroughMode) { // draw the write-through character
cairo_set_source_rgb(cr2, 0, WRITE_TROUGH_INTENSITY, 0);
cairo_move_to(cr2, tube_x0 + eoffx, windowHeight - tube_y0 + 4);
cairo_move_to(cr2, tube_x0 + eoffx, windowHeight - tube_y0);
cairo_show_text(cr2, s);
}
else {
// draw the character
cairo_set_source_rgb(cr, 0, NORMAL_INTENSITY, 0);
cairo_move_to(cr, tube_x0 + eoffx, windowHeight - tube_y0 + 4);
cairo_move_to(cr, tube_x0 + eoffx, windowHeight - tube_y0);
cairo_show_text(cr, s);
// draw the bright spot
cairo_set_source_rgb(cr2, BRIGHT_SPOT_COLOR);
cairo_move_to(cr2, tube_x0 + eoffx, windowHeight - tube_y0 + 4);
cairo_move_to(cr2, tube_x0 + eoffx, windowHeight - tube_y0);
cairo_show_text(cr2, s);
}
@@ -531,8 +530,11 @@ void tube_drawPoint(cairo_t *cr, cairo_t *cr2)
void tube_drawVector(cairo_t *cr, cairo_t *cr2)
{
if (DEBUG) printf("******************************************** Drawing to (%d,%d)\n",tube_x2,tube_y2);
if (DEBUG) {
printf("********************************************");
printf("Drawing from (%d,%d) to (%d,%d), writethrough = %d\n",
tube_x0, tube_y0, tube_x2, tube_y2, writeThroughMode);
}
tube_emulateDeflectionTime();
if ((tube_x2 == tube_x0) && (tube_y2 == tube_y0)) tube_x0++; // cairo cannot draw a dot

5
tube.h
View File

@@ -3,7 +3,7 @@
enum LineType {SOLID,DOTTED,DOTDASH,SHORTDASH,LONGDASH};
extern enum LineType ltype;
extern int globaltube_clearPersistent;
extern int tube_doClearPersistent;
extern int windowWidth;
extern int windowHeight;
@@ -21,7 +21,7 @@ extern int showCursor; // set of cursor is shown (not set in gra
extern int isBrightSpot; // set if there is currently a bright spot on the screen
extern int plotPointMode;
int writeThroughMode;
extern int writeThroughMode;
extern double efactor;
extern int eoffx;
@@ -33,7 +33,6 @@ extern long tube_u100ResetSeconds(int reset);
extern void tube_doCursor(cairo_t *cr2);
extern void tube_clearPersistent(cairo_t *cr, cairo_t *cr2);
extern void tube_clearSecond(cairo_t *cr2);
extern void tube_clearPersistent(cairo_t *cr, cairo_t *cr2);
extern int tube_isInput();
extern int tube_getInputChar();
extern void tube_emulateDeflectionTime();

View File

@@ -2,11 +2,14 @@ Next version t.b.b
==================
New features
- variable character size, set with ESC sequencies, reset if screen is cleared
Bug fixes
- vertical position of characters corrected
- full implementation of Tektronix 4014 decoder
Appearance:
Version 1.1 April 12, 2019
==========================
Phase: Fist offical release
Phase: First offical release
Version 1.0.3 April 11, 2019
============================