1
0
mirror of https://github.com/rricharz/Tek4010.git synced 2026-02-27 01:09:54 +00:00

improved robustness against 4014 codes

This commit is contained in:
¨Rene Richarz
2019-03-29 11:33:25 +01:00
parent 14085fae64
commit bd25d537c3
5 changed files with 128 additions and 95 deletions

33
main.c
View File

@@ -44,7 +44,6 @@
extern FILE *putKeys;
static cairo_surface_t *global_surface, *global_surface2;
static int global_firstcall;
int globalClearPersistent;
@@ -61,14 +60,14 @@ static gboolean on_draw_event(GtkWidget *widget, cairo_t *cr,
static gboolean on_timer_event(GtkWidget *widget)
{
if (tek4010_on_timer_event())
gtk_widget_queue_draw(widget);
gtk_widget_queue_draw(widget);
return TRUE;
}
static gboolean clicked(GtkWidget *widget, GdkEventButton *event, gpointer user_data)
{
if (tek4010_clicked(event->button, event->x, event->y))
gtk_widget_queue_draw(widget);
gtk_widget_queue_draw(widget);
return TRUE;
}
@@ -81,28 +80,30 @@ static void on_quit_event()
static void do_drawing(cairo_t *cr, GtkWidget *widget)
{
int width = WINDOW_WIDTH; // we do not use actual window size here
int height = WINDOW_HEIGHT; // because global_surface does not change size
int width = WINDOW_WIDTH; // we do not use actual window size here
int height = WINDOW_HEIGHT; // because surfaces does not change size
static cairo_surface_t *permanent_surface, *temporary_surface;
if (global_firstcall) {
global_surface = cairo_surface_create_similar(cairo_get_target(cr),
permanent_surface = cairo_surface_create_similar(cairo_get_target(cr),
CAIRO_CONTENT_COLOR_ALPHA, width, height);
global_surface2 = cairo_surface_create_similar(cairo_get_target(cr),
temporary_surface = cairo_surface_create_similar(cairo_get_target(cr),
CAIRO_CONTENT_COLOR_ALPHA, width, height);
}
cairo_t *surface_cr = cairo_create(global_surface);
cairo_t *surface2_cr = cairo_create(global_surface2);
tek4010_draw(surface_cr, surface2_cr, width, height, global_firstcall);
cairo_t *permanent_cr = cairo_create(permanent_surface);
cairo_t *temporary_cr = cairo_create(temporary_surface);
tek4010_draw(permanent_cr, temporary_cr, width, height, global_firstcall);
global_firstcall = FALSE;
cairo_set_source_surface(cr, global_surface, 0, 0);
cairo_set_source_surface(cr, permanent_surface, 0, 0);
cairo_paint(cr);
cairo_set_source_surface(cr, global_surface2, 0, 0);
cairo_set_source_surface(cr, temporary_surface, 0, 0);
cairo_paint(cr);
cairo_destroy(surface_cr);
cairo_destroy(surface2_cr);
cairo_destroy(permanent_cr);
cairo_destroy(temporary_cr);
}
static void on_key_press(GtkWidget *widget, GdkEventKey *event, gpointer user_data)
@@ -115,6 +116,7 @@ static void on_key_press(GtkWidget *widget, GdkEventKey *event, gpointer user_da
(event->keyval == 0xFF56)) // "page down" key
{
globalClearPersistent = 1;
gtk_widget_queue_draw(widget);
return;
}
@@ -125,6 +127,7 @@ static void on_key_press(GtkWidget *widget, GdkEventKey *event, gpointer user_da
if ((event->keyval == 0xFF51) || // "<ctrl>left arrow" key
(event->keyval == 0xFF52)) { // "<ctrl>up arrow" key
globalClearPersistent = 1;
gtk_widget_queue_draw(widget);
return;
}
else
@@ -157,7 +160,7 @@ int main (int argc, char *argv[])
gtk_widget_add_events(window, GDK_BUTTON_PRESS_MASK);
gtk_widget_add_events(window, GDK_KEY_PRESS_MASK);
g_signal_connect(G_OBJECT(darea), "draw", G_CALLBACK(on_draw_event), NULL);
g_signal_connect(G_OBJECT(darea), "draw", G_CALLBACK(on_draw_event), NULL);
g_signal_connect(G_OBJECT(window), "destroy", G_CALLBACK(on_quit_event), NULL);
g_signal_connect(G_OBJECT(window), "button-press-event", G_CALLBACK(clicked), NULL);
g_signal_connect(G_OBJECT(window), "key_press_event", G_CALLBACK(on_key_press), NULL);

View File

@@ -6,3 +6,6 @@ all: tek4010
tek4010: main.c tek4010.c tek4010.h main.h
gcc -o tek4010 main.c tek4010.c tek4010.h main.h $(LIBS) $(CFLAGS)
install:
cp tek4010 ~/bin

BIN
tek4010

Binary file not shown.

185
tek4010.c
View File

@@ -7,11 +7,9 @@
*
*/
#define MEM 128
#define DEBUG 0 // print debug info
#define TODO 6 // for speed reasons, draw multiple objects until screen updates
#define TODO 8 // for speed reasons, draw multiple objects until screen updates
#include <stdio.h>
#include <stdlib.h>
@@ -28,15 +26,13 @@
extern void gtk_main_quit();
extern int globalClearPersistent;
int noexit;
/* not yet used, for dsrk mode
int memx1[MEM], memy1[MEM], memx2[MEM], memy2[MEM];
float memv[MEM];
*/
int noexit = 0;
int showCursor;
int isBrightSpot = 0;
int count = 0;
static int x0,y0,x2,y2,xh,xl,yh,yl,xy2014;
static int x0,y0,x2,y2,xh,xl,yh,yl,xy4014;
// mode handles the current state of the emulator:
//
@@ -69,14 +65,18 @@ int getDataPipe[2];
FILE *putKeys;
int putKeysPipe[2];
int getk()
// get a char, if available, otherwise return -1
// When called for the first time, a child process for rsh is forked
// and communication between parent and child are established
int isInput()
// is char available on getDataPipe?
{
int bytesWaiting;
ioctl(getDataPipe[0], FIONREAD, &bytesWaiting);
if (bytesWaiting > 0)
return bytesWaiting;
}
int getInputChar()
// get a char from getDataPipe, if available, otherwise return -1
{
if (isInput())
return getc(getData);
else
return -1;
@@ -96,8 +96,9 @@ void tek4010_init(int argc, char* argv[])
noexit = 1;
argc--;
}
else
noexit = 0;
// A child process for rsh is forked ans communication
// between parent and child are established
// expand argv[1] to full path and check, whether it exists
char *str = (char *) malloc(bufsize * sizeof(char));
@@ -202,7 +203,11 @@ int tek4010_on_timer_event()
// is called every TIMER-INTERVAL milliseconds
// if the function returns 1, the window is redrawn by calling applicatin_draw
{
return 1;
// if there is a char available on the imput stream
// or there is still a bright spot, return 1 to ask for
// one more redraw
return (isBrightSpot || isInput);
}
int tek4010_clicked(int button, int x, int y)
@@ -221,34 +226,40 @@ void tek4010_quit()
pclose(getData);
}
int checkExitFromGraphics(int ch)
// test for exit from graphics character
{
if ((ch==31) || (ch==13) || (ch==27) || (ch==12)) {
mode = 0;
if (DEBUG) printf("Leaving graphics mode\n");
showCursor = 0;
if (ch == 12) globalClearPersistent = 1;
return 1;
}
else return 0;
}
void tek4010_draw(cairo_t *cr, cairo_t *cr2, int width, int height, int first)
// draw onto the main window using cairo
// width is the actual width of the main window
// height is the actual height of the main window
// surface1 is used for persistent drawing, surface2 for faiding drawing
// cr is used for persistent drawing, cr2 for temporary drawing
{
int ch;
int todo;
char s[2];
int showCursor = 1;
showCursor = 1;
isBrightSpot = 0;
/* if (first) {
for (int i=0; i<MEM; i++) {
memx1[i]=2;
memy1[i]=i * (WINDOW_HEIGHT/MEM);
memx2[i]=100;
memy2[i]=i * (WINDOW_HEIGHT/MEM);
memv[i]=0;
}
} */
// clear persistent surface, if necessary
if (globalClearPersistent) {
cairo_set_source_rgb(cr, 0, 0, 0);
cairo_paint(cr);
globalClearPersistent = 0;
x0 = 0;
x0 = 0;
y0 = WINDOW_HEIGHT - vDotsPerChar;
leftmargin = 0;
}
@@ -271,11 +282,8 @@ void tek4010_draw(cairo_t *cr, cairo_t *cr2, int width, int height, int first)
todo = TODO;
do {
ch = getk();
if (ch == 31) { // exit from graphics mode
mode = 0;
ch = getk();
}
ch = getInputChar();
if (ch == -1) todo--; // no char available, need to allow for updates
if (DEBUG && (ch != -1)) {
@@ -284,38 +292,35 @@ void tek4010_draw(cairo_t *cr, cairo_t *cr2, int width, int height, int first)
printf("\n");
}
if ((mode>=1) && (mode <=9))
if ((ch==31) || (ch==13) || (ch==27) || (ch==12)) {
mode = 0; // exit from graphics mode
if (DEBUG) printf("Leaving graphics mode\n");
showCursor = 0;
ch = -1;
}
if (mode == 31) {
// printf("ANSI escape mode 31, ch=%02x\n",ch);
if ((ch>='0') && (ch<='9')) mode = 30;
}
int tag = ch >> 5;
// this overwrites the extra data byte of the 4014 for the
// first dark mode coordinates and stores it for further use
if ((mode == 3) && (tag == 3)) {
mode = 2;
xy2014 = yl;
if (DEBUG) printf("4014 coordinates, overwrite last value\n");
}
if ((mode>=1)&&(mode<=8)) {
if ((mode >= 1) && (mode <= 8)) {
checkExitFromGraphics(ch);
// 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 == 3) && (tag == 3)) {
// this overwrites the extra data byte of the 4014 for the
// first dark mode coordinates and stores it for further use
mode = 2;
xy4014 = yl;
if (DEBUG) printf("4014 coordinates, overwrite last value\n");
}
if ((mode == 5) && (ch == 29)) {
mode = 1; return;
}
if (ch == 30) {
if (DEBUG) printf("Leaving graphics mode\n");
mode = 0; return;
}
if (tag == 0) {
return;
if (DEBUG) printf("Starting incremental plot mode (4014)\n");
mode = 40; return;
}
if (DEBUG) {
@@ -326,39 +331,53 @@ void tek4010_draw(cairo_t *cr, cairo_t *cr2, int width, int height, int first)
printf("mode=%d,tag=%d-L-val=%d\n",
mode,tag, ch & 31);
}
if (tag > 0) { // bytes identified by tag, some can be skipped
if ((mode == 5) && (tag != 1)) mode = 6;
if (tag == 0) {
return; // each coordinate byte must have a tag. If not, ignore
}
if ((mode == 5) && (tag != 1)) mode = 6;
if ((mode == 7) && (tag == 3)) {
// this overwrites the extra data byte of the 4014 for the
// persistent mode ccordinates and stores it for further use
if ((mode == 7) && (tag == 3)) {
mode = 6;
xy2014 = yl;
if (DEBUG)
printf("4014 coordinates, overwrite last value\n");
}
if ((mode == 6) && (tag != 3)) mode = 7;
if ((mode == 7) && (tag != 1)) mode = 8;
mode = 6;
xy4014 = yl;
if (DEBUG)
printf("4014 coordinates, overwrite last value\n");
}
if ((mode == 6) && (tag != 3)) mode = 7;
if ((mode == 7) && (tag != 1)) mode = 8;
}
switch (mode) {
case 1: yh = 32 * (ch & 31); mode++; break;
case 2: yl = (ch & 31); y0 = yh + yl; mode++; break;
case 3: xh = 32 * (ch & 31); mode++; break;
case 4: xl = (ch & 31); x0= xh + xl; mode++;
if (DEBUG) printf("***** Moving to (%d,%d)\n",x0,y0);
switch (mode) {
case 1: yh = 32 * (ch & 31); mode++;
break;
case 2: yl = (ch & 31); y0 = yh + yl; mode++;
break;
case 3: xh = 32 * (ch & 31); mode++;
break;
case 4: xl = (ch & 31); x0= xh + xl; mode++;
if (DEBUG) printf("***** Moving to (%d,%d)\n",x0,y0);
break;
case 5: if (ch == 29) mode = 1;
else {
yh = 32 * (ch & 31); mode++;
}
break;
case 6: yl = (ch & 31); mode++;
break;
case 7: xh = 32 * (ch & 31); mode++;
break;
case 5: yh = 32 * (ch & 31); mode++; break;
case 6: yl = (ch & 31); mode++; break;
case 7: xh = 32 * (ch & 31); mode++; break;
case 8: xl = (ch & 31);
x2 = xh + xl;
y2 = yh + yl;
if (DEBUG) printf("tag=%d,***** Drawing vector to (%d,%d)\n",tag,x2,y2);
if (DEBUG) printf("tag=%d,***** Drawing vector to (%d,%d)\n",
tag, x2, y2);
cairo_move_to(cr, x0, WINDOW_HEIGHT - y0);
cairo_line_to(cr, x2, WINDOW_HEIGHT - y2);
cairo_stroke (cr);
@@ -366,6 +385,7 @@ void tek4010_draw(cairo_t *cr, cairo_t *cr2, int width, int height, int first)
cairo_line_to(cr2, x2, WINDOW_HEIGHT - y2);
cairo_stroke (cr2);
showCursor = 0;
isBrightSpot = 1;
// for speed reasons, do not update screen right away
// if many very small verctors are drawn
@@ -379,7 +399,7 @@ void tek4010_draw(cairo_t *cr, cairo_t *cr2, int width, int height, int first)
y0 = y2;
mode = 5;
break;
case 30: // handle escape sequencies
case 30: // handle escape sequencies
if (DEBUG) printf("Escape mode, ch=%02X\n",ch);
switch (ch) {
case 12:
@@ -414,6 +434,9 @@ void tek4010_draw(cairo_t *cr, cairo_t *cr2, int width, int height, int first)
break;
}
break;
case 40: // used to ignore certain 4014 sequencies
if (ch == 31) mode = 0; // leave this mode
break;
default: switch (ch) {
case 0: break;
case EOF: break;
@@ -446,6 +469,9 @@ void tek4010_draw(cairo_t *cr, cairo_t *cr2, int width, int height, int first)
case 29: // group separator
mode = 1;
break;
case 30: // record separator
mode = 40;
break;
case 31: // US, leave graphics mode
mode = 0;
break;
@@ -459,6 +485,7 @@ void tek4010_draw(cairo_t *cr, cairo_t *cr2, int width, int height, int first)
cairo_move_to(cr2, x0, WINDOW_HEIGHT - y0 + 4);
cairo_show_text(cr2, s);
x0 += hDotsPerChar;
isBrightSpot = 1;
todo--;
}
break;

View File

@@ -4,5 +4,5 @@
#define WINDOW_NAME "Tektronix 4010" // name of main window
#define ICON_NAME "" // path to icon for window
#define TIME_INTERVAL 50 // time interval for timer function in msec
#define TIME_INTERVAL 25 // time interval for timer function in msec
// 0 means no timer function