1136 lines
36 KiB
C
1136 lines
36 KiB
C
|
/* unix.c V1.1.1
|
|||
|
*
|
|||
|
* Unix (med X11) systemspesifikk kode for TIKI-100_emul
|
|||
|
* Copyright (C) Asbj<EFBFBD>rn Djupdal 2001
|
|||
|
*/
|
|||
|
|
|||
|
#include "TIKI-100_emul.h"
|
|||
|
|
|||
|
#include <stdio.h>
|
|||
|
#include <stdlib.h>
|
|||
|
#include <string.h>
|
|||
|
#include <ctype.h>
|
|||
|
|
|||
|
#include <sys/time.h>
|
|||
|
#include <sys/types.h>
|
|||
|
#include <sys/stat.h>
|
|||
|
#include <sys/uio.h>
|
|||
|
#include <sys/ioctl.h>
|
|||
|
#include <fcntl.h>
|
|||
|
#include <unistd.h>
|
|||
|
#include <termios.h>
|
|||
|
#ifndef FIONREAD
|
|||
|
#include <sys/filio.h> /* antar at FIONREAD er definert i sys/filio.h */
|
|||
|
#endif
|
|||
|
|
|||
|
#include <X11/Xlib.h>
|
|||
|
#include <X11/Xutil.h>
|
|||
|
#include <X11/Xresource.h>
|
|||
|
#include <X11/keysym.h>
|
|||
|
|
|||
|
#define STATUSBAR_HEIGHT 19
|
|||
|
|
|||
|
/* protos */
|
|||
|
int main (int argc, char *argv[]);
|
|||
|
static void update (int x, int y, int w, int h);
|
|||
|
static void createStatusBar (void);
|
|||
|
static byte keysymToTikikey (KeySym keysym);
|
|||
|
static void commandline (void);
|
|||
|
static void readDiskImage (int drive, char *filename);
|
|||
|
static void setParam (int portfd, struct serParams *params);
|
|||
|
static void setPrintCmd (char *p);
|
|||
|
static void setPrintFile (char *p);
|
|||
|
|
|||
|
/* variabler */
|
|||
|
|
|||
|
static byte *dsk[2] = {NULL, NULL};
|
|||
|
static int dsksize[2] = {0, 0};
|
|||
|
static int resolution = MEDRES;
|
|||
|
static byte pressedKeys[256];
|
|||
|
static boolean updateWindow = FALSE;
|
|||
|
static unsigned int xmin = (unsigned)~0;
|
|||
|
static unsigned int ymin = (unsigned)~0;
|
|||
|
static unsigned int xmax = 0;
|
|||
|
static unsigned int ymax = 0;
|
|||
|
static boolean scanlines;
|
|||
|
static boolean slowDown;
|
|||
|
static int width[3];
|
|||
|
static int height[3];
|
|||
|
static int times40;
|
|||
|
static int times80;
|
|||
|
static byte *screen;
|
|||
|
static FILE *printCmd = 0;
|
|||
|
static FILE *printFile = 0;
|
|||
|
static int port1 = 0;
|
|||
|
static int port2 = 0;
|
|||
|
static boolean lock = FALSE;
|
|||
|
static boolean grafikk = FALSE;
|
|||
|
static boolean disk[2] = {FALSE, FALSE};
|
|||
|
static boolean dyn_cmap;
|
|||
|
static Colormap default_cmap;
|
|||
|
static unsigned long pixels[16];
|
|||
|
static unsigned long blackpix, whitepix, backpix, diodepix;
|
|||
|
static Display *display;
|
|||
|
static Window mainwindow;
|
|||
|
static Pixmap mainpixmap;
|
|||
|
static GC colorGC[16];
|
|||
|
static GC blackGC, backGC, diodeGC;
|
|||
|
static XrmDatabase options_db = NULL;
|
|||
|
static XSizeHints xsh;
|
|||
|
|
|||
|
static XrmOptionDescRec options[] = {
|
|||
|
{"-display", "*display", XrmoptionSepArg, NULL},
|
|||
|
{"-d", "*display", XrmoptionSepArg, NULL},
|
|||
|
{"-geometry", "*geometry", XrmoptionSepArg, NULL},
|
|||
|
{"-g", "*geometry", XrmoptionSepArg, NULL},
|
|||
|
{"-diska", "*diska", XrmoptionSepArg, NULL},
|
|||
|
{"-diskb", "*diskb", XrmoptionSepArg, NULL},
|
|||
|
{"-bevarforhold", "*bevarforhold", XrmoptionNoArg, "on"},
|
|||
|
{"-ikkebevarforhold", "*bevarforhold", XrmoptionNoArg, "off"},
|
|||
|
{"-40x", "*40x", XrmoptionSepArg, NULL},
|
|||
|
{"-80x", "*80x", XrmoptionSepArg, NULL},
|
|||
|
{"-begrens", "*begrens", XrmoptionNoArg, "on"},
|
|||
|
{"-ikkebegrens", "*begrens", XrmoptionNoArg, "off"},
|
|||
|
{"-port1", "*port1", XrmoptionSepArg, NULL},
|
|||
|
{"-port2", "*port2", XrmoptionSepArg, NULL},
|
|||
|
{"-pk", "*pk", XrmoptionSepArg, NULL},
|
|||
|
{"-pf", "*pf", XrmoptionSepArg, NULL},
|
|||
|
{"-st28b", "*st28b", XrmoptionNoArg, "on"},
|
|||
|
{"-ikkest28b", "*st28b", XrmoptionNoArg, "off"}
|
|||
|
};
|
|||
|
|
|||
|
static int num_opts = (sizeof options / sizeof options[0]);
|
|||
|
|
|||
|
typedef struct KeyConv {
|
|||
|
byte tikikey;
|
|||
|
KeySym keysym;
|
|||
|
} KeyConv;
|
|||
|
|
|||
|
/* Tabell som konverterer X11-keysym til TIKI-100 tasteverdier */
|
|||
|
static const KeyConv keyConvTable[] = {
|
|||
|
{KEY_CTRL, XK_Control_L}, {KEY_CTRL, XK_Control_R}, {KEY_SHIFT, XK_Shift_L},
|
|||
|
{KEY_SHIFT, XK_Shift_R}, {KEY_BRYT, XK_Break}, {KEY_BRYT, XK_F10},
|
|||
|
{KEY_CR, XK_Return}, {KEY_SPACE, XK_space}, {KEY_SLETT, XK_BackSpace},
|
|||
|
{KEY_SLETT, XK_Delete}, {KEY_GRAFIKK, XK_F8}, {KEY_ANGRE, XK_Redo},
|
|||
|
{KEY_ANGRE, XK_F9}, {KEY_LOCK, XK_Caps_Lock}, {KEY_LOCK, XK_Shift_Lock},
|
|||
|
{KEY_LOCK, XK_F7}, {KEY_HJELP, XK_Help}, {KEY_HJELP, XK_F11},
|
|||
|
{KEY_LEFT, XK_Left}, {KEY_UTVID, XK_Insert}, {KEY_UTVID, XK_F12},
|
|||
|
{KEY_F1, XK_F1}, {KEY_F4, XK_F4}, {KEY_RIGHT, XK_Right},
|
|||
|
{KEY_F2, XK_F2}, {KEY_F3, XK_F3}, {KEY_F5, XK_F5},
|
|||
|
{KEY_F6, XK_F6}, {KEY_DOWN, XK_Down}, {KEY_PGUP, XK_Page_Up},
|
|||
|
{KEY_PGDOWN, XK_Page_Down}, {KEY_UP, XK_Up}, {KEY_HOME, XK_Home},
|
|||
|
{KEY_TABLEFT, XK_Prior}, {KEY_TABRIGHT, XK_Tab}, {KEY_TABRIGHT, XK_Next},
|
|||
|
{KEY_NUMDIV, XK_KP_Divide}, {KEY_NUMPLUS, XK_KP_Add}, {KEY_NUMMINUS, XK_KP_Subtract},
|
|||
|
{KEY_NUMMULT, XK_KP_Multiply}, {KEY_NUMPERCENT, XK_percent}, {KEY_NUMEQU, XK_KP_Equal},
|
|||
|
{KEY_ENTER, XK_KP_Enter}, {KEY_NUM0, XK_KP_0}, {KEY_NUM1, XK_KP_1},
|
|||
|
{KEY_NUM2, XK_KP_2}, {KEY_NUM3, XK_KP_3}, {KEY_NUM4, XK_KP_4},
|
|||
|
{KEY_NUM5, XK_KP_5}, {KEY_NUM6, XK_KP_6}, {KEY_NUM7, XK_KP_7},
|
|||
|
{KEY_NUM8, XK_KP_8}, {KEY_NUM9, XK_KP_9}, {KEY_NUMDOT, XK_KP_Separator},
|
|||
|
{KEY_NUMDOT, XK_KP_Decimal}, {(byte)'a', XK_a}, {(byte)'b', XK_b},
|
|||
|
{(byte)'c', XK_c}, {(byte)'d', XK_d}, {(byte)'e', XK_e},
|
|||
|
{(byte)'f', XK_f}, {(byte)'g', XK_g}, {(byte)'h', XK_h},
|
|||
|
{(byte)'i', XK_i}, {(byte)'j', XK_j}, {(byte)'k', XK_k},
|
|||
|
{(byte)'l', XK_l}, {(byte)'m', XK_m}, {(byte)'n', XK_n},
|
|||
|
{(byte)'o', XK_o}, {(byte)'p', XK_p}, {(byte)'q', XK_q},
|
|||
|
{(byte)'r', XK_r}, {(byte)'s', XK_s}, {(byte)'t', XK_t},
|
|||
|
{(byte)'u', XK_u}, {(byte)'v', XK_v}, {(byte)'w', XK_w},
|
|||
|
{(byte)'x', XK_x}, {(byte)'y', XK_y}, {(byte)'z', XK_z},
|
|||
|
{(byte)'1', XK_1}, {(byte)'2', XK_2}, {(byte)'3', XK_3},
|
|||
|
{(byte)'4', XK_4}, {(byte)'5', XK_5}, {(byte)'6', XK_6},
|
|||
|
{(byte)'7', XK_7}, {(byte)'8', XK_8}, {(byte)'9', XK_9},
|
|||
|
{(byte)'0', XK_0}, {(byte)'<', XK_less}, {(byte)',', XK_comma},
|
|||
|
{(byte)'.', XK_period}, {(byte)'-', XK_minus}, {(byte)'<EFBFBD>', XK_ae},
|
|||
|
{(byte)'<EFBFBD>', XK_oslash}, {(byte)'<EFBFBD>', XK_aring}, {(byte)'\'', XK_apostrophe},
|
|||
|
{(byte)'^', XK_asciicircum}, {(byte)'+', XK_plus}, {(byte)'@', XK_at}
|
|||
|
};
|
|||
|
|
|||
|
/*****************************************************************************/
|
|||
|
|
|||
|
int main (int argc, char *argv[]) {
|
|||
|
char *resType; /* for resourcekall */
|
|||
|
XrmValue resValue; /* -- " -- */
|
|||
|
XrmDatabase cline_db = NULL;
|
|||
|
|
|||
|
XrmInitialize();
|
|||
|
|
|||
|
/* parse kommandolinjeopsoner */
|
|||
|
XrmParseCommand (&cline_db, options, num_opts, "tikiemul", &argc, argv);
|
|||
|
|
|||
|
/* feil i argumenter */
|
|||
|
if (argc > 1) {
|
|||
|
printf ("TIKI-100_emul V1.1.1 brukes:\n"
|
|||
|
" tikiemul [-opsjoner...]\n"
|
|||
|
"\n"
|
|||
|
"Opsjoner:\n"
|
|||
|
" -display displaynavn X-server som skal benyttes\n"
|
|||
|
" -d displaynavn Forkortelse for den over\n"
|
|||
|
" -geometry geom Vindusposisjon\n"
|
|||
|
" -g geom Forkortelse for den over\n"
|
|||
|
" -diska diskettfilnavn Diskettfil i stasjon a\n"
|
|||
|
" -diskb diskettfilnavn Diskettfil i stasjon b\n"
|
|||
|
" -bevarforhold Emulatorvindu formlik TIKI-100 skjerm\n"
|
|||
|
" -ikkebevarforhold Negasjonen av den over\n"
|
|||
|
" -40x forst<73>rrelsesfaktor Forst<73>rring av 40-modus vindu\n"
|
|||
|
" -80x forst<73>rrelsesfaktor Forst<73>rring av 80-modus vindu\n"
|
|||
|
" -begrens Begrens hastighet til vanlig TIKI-hastighet\n"
|
|||
|
" -ikkebegrens Negasjonen av den over\n"
|
|||
|
" -port1 devicenavn Skru p<> serieport P1\n"
|
|||
|
" -port2 devicenavn Skru p<> serieport P2\n"
|
|||
|
" -pk utskriftskommando Send utskrift til kommando\n"
|
|||
|
" -pf utskriftsfil Send utskrift til fil\n"
|
|||
|
" -st28b Sett b<>yle ST 28 b\n"
|
|||
|
" -ikkest28b Negasjonen av den over\n"
|
|||
|
"\n"
|
|||
|
"Underveis i emulering kan du trykke p<> Escapetasten for <20> g<> inn i\n"
|
|||
|
"kommandomodus. Kommandoen 'hjelp' gir en liste over gyldige kommandoer.\n"
|
|||
|
"\n");
|
|||
|
exit (1);
|
|||
|
}
|
|||
|
|
|||
|
/* <20>pne display */
|
|||
|
XrmGetResource (cline_db, "tikiemul.display", "Tikiemul.display", &resType, &resValue);
|
|||
|
if ((display = XOpenDisplay (resValue.addr)) == NULL) {
|
|||
|
fprintf (stderr, "Kan ikke <20>pne display %s\n", XDisplayName (resValue.addr));
|
|||
|
exit (1);
|
|||
|
}
|
|||
|
|
|||
|
{ /* hent defaults fra server */
|
|||
|
char *xrms;
|
|||
|
|
|||
|
xrms = XResourceManagerString (display);
|
|||
|
if (xrms != NULL) {
|
|||
|
options_db = XrmGetStringDatabase (xrms);
|
|||
|
XrmMergeDatabases (cline_db, &options_db);
|
|||
|
} else {
|
|||
|
options_db = cline_db;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
/* finn geometry */
|
|||
|
XrmGetResource (options_db, "tikiemul.geometry", "Tikiemul.geometry", &resType, &resValue);
|
|||
|
XGeometry (display, DefaultScreen (display), resValue.addr, "+0+0", 1,
|
|||
|
1, 1, 0, 0, &(xsh.x), &(xsh.y), &(xsh.width), &(xsh.height));
|
|||
|
|
|||
|
/* skal forhold bevares? */
|
|||
|
XrmGetResource (options_db, "tikiemul.bevarforhold", "Tikiemul.bevarforhold",
|
|||
|
&resType, &resValue);
|
|||
|
scanlines = FALSE;
|
|||
|
if (resValue.addr) {
|
|||
|
if (!strcmp (resValue.addr, "on")) {
|
|||
|
scanlines = TRUE;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
/* finn forst<73>rring og vindusst<73>rrelse */
|
|||
|
XrmGetResource (options_db, "tikiemul.40x", "Tikiemul.40x", &resType, &resValue);
|
|||
|
if (resValue.addr) times40 = atoi (resValue.addr);
|
|||
|
if (times40 > 4) times40 = 4;
|
|||
|
if (times40 < 1) times40 = 1;
|
|||
|
width[0] = 256 * times40;
|
|||
|
height[0] = 256 * times40;
|
|||
|
XrmGetResource (options_db, "tikiemul.80x", "Tikiemul.80x", &resType, &resValue);
|
|||
|
if (resValue.addr) times80 = atoi (resValue.addr);
|
|||
|
if (times80 > 2) times80 = 2;
|
|||
|
if (times80 < 1) times80 = 1;
|
|||
|
width[1] = 512 * times80;
|
|||
|
height[1] = 256 * times80 * (scanlines ? 2 : 1);
|
|||
|
width[2] = 1024;
|
|||
|
height[2] = 256 * (scanlines ? 4 : 1);
|
|||
|
|
|||
|
/* skal hastighet begrenses? */
|
|||
|
XrmGetResource (options_db, "tikiemul.begrens", "Tikiemul.begrens", &resType, &resValue);
|
|||
|
slowDown = TRUE;
|
|||
|
if (resValue.addr) {
|
|||
|
if (!strcmp (resValue.addr, "off")) {
|
|||
|
slowDown = FALSE;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
/* hent inn eventuelle diskfiler */
|
|||
|
XrmGetResource (options_db, "tikiemul.diska", "Tikiemul.diska", &resType, &resValue);
|
|||
|
if (resValue.addr) readDiskImage (0, resValue.addr);
|
|||
|
XrmGetResource (options_db, "tikiemul.diskb", "Tikiemul.diskb", &resType, &resValue);
|
|||
|
if (resValue.addr) readDiskImage (1, resValue.addr);
|
|||
|
|
|||
|
/* sett opp farger */
|
|||
|
default_cmap = DefaultColormap (display, DefaultScreen (display));
|
|||
|
{
|
|||
|
int visclass = DefaultVisual (display, DefaultScreen (display))->class;
|
|||
|
|
|||
|
whitepix = WhitePixel (display, DefaultScreen (display));
|
|||
|
blackpix = BlackPixel (display, DefaultScreen (display));
|
|||
|
{ /* farger for statusbar */
|
|||
|
XColor color;
|
|||
|
XColor exact;
|
|||
|
|
|||
|
if (!XAllocNamedColor (display, default_cmap, "grey80", &exact, &color)) {
|
|||
|
backpix = blackpix;
|
|||
|
} else {
|
|||
|
backpix = color.pixel;
|
|||
|
}
|
|||
|
if (!XAllocNamedColor (display, default_cmap, "green", &exact, &color)) {
|
|||
|
diodepix = whitepix;
|
|||
|
} else {
|
|||
|
diodepix = color.pixel;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if (visclass == PseudoColor || visclass == DirectColor) {
|
|||
|
/* dynamisk colormap - skaff r/w-fargeceller */
|
|||
|
if (!XAllocColorCells (display, default_cmap, False, NULL, 0, pixels, 16)) {
|
|||
|
printf ("For f<> ledige fargeceller\n");
|
|||
|
free (dsk[0]);
|
|||
|
free (dsk[1]);
|
|||
|
XCloseDisplay (display);
|
|||
|
exit (1);
|
|||
|
}
|
|||
|
dyn_cmap = TRUE;
|
|||
|
} else if (visclass == TrueColor || visclass == StaticColor) {
|
|||
|
/* statisk colormap - skaff ny pixel hver gang farge forandres */
|
|||
|
int i;
|
|||
|
|
|||
|
if (!(screen = malloc (1024 * 256))) {
|
|||
|
fprintf (stderr, "Ikke nok minne\n");
|
|||
|
free (dsk[0]);
|
|||
|
free (dsk[1]);
|
|||
|
XCloseDisplay (display);
|
|||
|
exit (1);
|
|||
|
}
|
|||
|
memset (screen, 0, 1024 * 256);
|
|||
|
|
|||
|
for (i = 0; i < 16; i++) {
|
|||
|
pixels[i] = blackpix;
|
|||
|
}
|
|||
|
dyn_cmap = FALSE;
|
|||
|
} else {
|
|||
|
/* svart/hvitt display, kan ikke brukes */
|
|||
|
fprintf (stderr, "Display ikke tilstrekkelig!\n");
|
|||
|
free (dsk[0]);
|
|||
|
free (dsk[1]);
|
|||
|
XCloseDisplay (display);
|
|||
|
exit (1);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
{ /* graphics context, en for hver farge */
|
|||
|
int i;
|
|||
|
XGCValues gcv;
|
|||
|
|
|||
|
gcv.foreground = blackpix;
|
|||
|
blackGC = XCreateGC (display, DefaultRootWindow (display),
|
|||
|
GCForeground | GCBackground, &gcv);
|
|||
|
gcv.foreground = backpix;
|
|||
|
backGC = XCreateGC (display, DefaultRootWindow (display),
|
|||
|
GCForeground | GCBackground, &gcv);
|
|||
|
gcv.foreground = diodepix;
|
|||
|
diodeGC = XCreateGC (display, DefaultRootWindow (display),
|
|||
|
GCForeground | GCBackground, &gcv);
|
|||
|
|
|||
|
for (i = 0; i < 16; i++) {
|
|||
|
gcv.foreground = pixels[i];
|
|||
|
colorGC[i] = XCreateGC (display, DefaultRootWindow (display),
|
|||
|
GCForeground | GCBackground, &gcv);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
/* lag vindu */
|
|||
|
mainwindow =
|
|||
|
XCreateSimpleWindow (display, DefaultRootWindow (display),
|
|||
|
xsh.x, xsh.y, width[1], height[1] + STATUSBAR_HEIGHT,
|
|||
|
1, pixels[0], pixels[0]);
|
|||
|
|
|||
|
{ /* gi hint til window manager */
|
|||
|
XWMHints xwmh;
|
|||
|
|
|||
|
xsh.flags = (PPosition | PSize | PMinSize | PMaxSize);
|
|||
|
xsh.width = width[1];
|
|||
|
xsh.height = height[1] + STATUSBAR_HEIGHT;
|
|||
|
xsh.min_width = xsh.width;
|
|||
|
xsh.min_height = xsh.height;
|
|||
|
xsh.max_width = xsh.width;
|
|||
|
xsh.max_height = xsh.height;
|
|||
|
XSetStandardProperties (display, mainwindow, "tikiemul", "tikiemul", None,
|
|||
|
argv, argc, &xsh);
|
|||
|
xwmh.flags = (InputHint | StateHint);
|
|||
|
xwmh.input = True;
|
|||
|
xwmh.initial_state = NormalState;
|
|||
|
XSetWMHints (display, mainwindow, &xwmh);
|
|||
|
}
|
|||
|
|
|||
|
{ /* lag pixmap. Alt tegnes til pixmap, kopieres til vindu hver loopEmul() */
|
|||
|
int maxheight = height[0];
|
|||
|
|
|||
|
if (height[1] > maxheight) maxheight = height[1];
|
|||
|
if (height[2] > maxheight) maxheight = height[2];
|
|||
|
|
|||
|
mainpixmap = XCreatePixmap (display, mainwindow, 1024, maxheight + STATUSBAR_HEIGHT,
|
|||
|
DefaultDepth (display, DefaultScreen (display)));
|
|||
|
XFillRectangle (display, mainpixmap, colorGC[0], 0, 0, xsh.width, xsh.height);
|
|||
|
update (0, 0, xsh.width, xsh.height);
|
|||
|
}
|
|||
|
|
|||
|
/* lag statusbar */
|
|||
|
createStatusBar();
|
|||
|
|
|||
|
/* gi beskjed om hvilke events som trengs */
|
|||
|
XSelectInput (display, mainwindow,
|
|||
|
ExposureMask | KeyPressMask | KeyReleaseMask);
|
|||
|
|
|||
|
/* gj<67>r vindu synlig */
|
|||
|
XMapWindow (display, mainwindow);
|
|||
|
|
|||
|
/* init pressedKeys tabell */
|
|||
|
memset (pressedKeys, 1, 256);
|
|||
|
|
|||
|
/* b<>yle st28b? */
|
|||
|
XrmGetResource (options_db, "tikiemul.st28b", "Tikiemul.st28b", &resType, &resValue);
|
|||
|
if (resValue.addr) {
|
|||
|
if (!strcmp (resValue.addr, "on")) {
|
|||
|
setST28b (TRUE);
|
|||
|
} else {
|
|||
|
setST28b (FALSE);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
/* sett opp printfil/kommando */
|
|||
|
XrmGetResource (options_db, "tikiemul.pk", "Tikiemul.pk", &resType, &resValue);
|
|||
|
if (resValue.addr) {
|
|||
|
setPrintCmd (resValue.addr);
|
|||
|
}
|
|||
|
XrmGetResource (options_db, "tikiemul.pf", "Tikiemul.pf", &resType, &resValue);
|
|||
|
if (resValue.addr) {
|
|||
|
setPrintFile (resValue.addr);
|
|||
|
}
|
|||
|
|
|||
|
/* sett opp serieporter */
|
|||
|
XrmGetResource (options_db, "tikiemul.port1", "Tikiemul.port1", &resType, &resValue);
|
|||
|
if (resValue.addr) {
|
|||
|
if ((port1 = open (resValue.addr, O_RDWR | O_NOCTTY | O_NDELAY)) == -1) {
|
|||
|
fprintf (stderr, "Kan ikke <20>pne port %s\n", resValue.addr);
|
|||
|
port1 = 0;
|
|||
|
} else {
|
|||
|
fcntl (port1, F_SETFL, 0);
|
|||
|
}
|
|||
|
}
|
|||
|
XrmGetResource (options_db, "tikiemul.port2", "Tikiemul.port2", &resType, &resValue);
|
|||
|
if (resValue.addr) {
|
|||
|
if ((port2 = open (resValue.addr, O_RDWR | O_NOCTTY | O_NDELAY)) == -1) {
|
|||
|
fprintf (stderr, "Kan ikke <20>pne port %s\n", resValue.addr);
|
|||
|
port2 = 0;
|
|||
|
} else {
|
|||
|
fcntl (port2, F_SETFL, 0);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
/* kj<6B>r emulator */
|
|||
|
if (!runEmul()) {
|
|||
|
fprintf (stderr, "Finner ikke ROM-fil\n");
|
|||
|
}
|
|||
|
|
|||
|
/* avslutt */
|
|||
|
if (port2) close (port2);
|
|||
|
if (port1) close (port1);
|
|||
|
if (printFile) fclose (printFile);
|
|||
|
if (printCmd) fclose (printCmd);
|
|||
|
XFreePixmap (display, mainpixmap);
|
|||
|
{
|
|||
|
int i;
|
|||
|
|
|||
|
XFreeGC (display, blackGC);
|
|||
|
XFreeGC (display, backGC);
|
|||
|
XFreeGC (display, diodeGC);
|
|||
|
|
|||
|
for (i = 0; i < 16; i++) {
|
|||
|
XFreeGC (display, colorGC[i]);
|
|||
|
}
|
|||
|
}
|
|||
|
XDestroyWindow (display, mainwindow);
|
|||
|
if (dyn_cmap) {
|
|||
|
XFreeColors (display, default_cmap, pixels, 16, 0);
|
|||
|
} else {
|
|||
|
free (screen);
|
|||
|
}
|
|||
|
free (dsk[0]);
|
|||
|
free (dsk[1]);
|
|||
|
XCloseDisplay (display);
|
|||
|
|
|||
|
exit (0);
|
|||
|
}
|
|||
|
/* oppdater gitt rektangel ved neste loopEmul() */
|
|||
|
static void update (int x, int y, int w, int h) {
|
|||
|
if (xmin > x) xmin = x;
|
|||
|
if (ymin > y) ymin = y;
|
|||
|
if (xmax < (x + w)) xmax = x + w;
|
|||
|
if (ymax < (y + h)) ymax = y + h;
|
|||
|
updateWindow = TRUE;
|
|||
|
}
|
|||
|
/* tegner statusbar */
|
|||
|
static void createStatusBar (void) {
|
|||
|
/* statuslinje */
|
|||
|
XFillRectangle (display, mainpixmap, backGC,
|
|||
|
0, xsh.height - STATUSBAR_HEIGHT, xsh.width, STATUSBAR_HEIGHT);
|
|||
|
|
|||
|
/* "hull" til dioder */
|
|||
|
XFillRectangle (display, mainpixmap, blackGC,
|
|||
|
20, xsh.height - STATUSBAR_HEIGHT + 3, 10, 10);
|
|||
|
XFillRectangle (display, mainpixmap, blackGC,
|
|||
|
40, xsh.height - STATUSBAR_HEIGHT + 3, 10, 10);
|
|||
|
XFillRectangle (display, mainpixmap, blackGC,
|
|||
|
60, xsh.height - STATUSBAR_HEIGHT + 3, 10, 10);
|
|||
|
XFillRectangle (display, mainpixmap, blackGC,
|
|||
|
80, xsh.height - STATUSBAR_HEIGHT + 3, 10, 10);
|
|||
|
|
|||
|
/* oppdater diodelys */
|
|||
|
lockLight (lock);
|
|||
|
grafikkLight (grafikk);
|
|||
|
diskLight (0, disk[0]);
|
|||
|
diskLight (1, disk[1]);
|
|||
|
|
|||
|
update (0, xsh.height - STATUSBAR_HEIGHT, xsh.width, STATUSBAR_HEIGHT);
|
|||
|
}
|
|||
|
/* Forandre oppl<70>sning */
|
|||
|
void changeRes (int newRes) {
|
|||
|
resolution = newRes;
|
|||
|
|
|||
|
switch (resolution) {
|
|||
|
case LOWRES:
|
|||
|
xsh.width = width[0];
|
|||
|
xsh.height = height[0];
|
|||
|
break;
|
|||
|
case MEDRES:
|
|||
|
xsh.width = width[1];
|
|||
|
xsh.height = height[1];
|
|||
|
break;
|
|||
|
case HIGHRES:
|
|||
|
xsh.width = width[2];
|
|||
|
xsh.height = height[2];
|
|||
|
break;
|
|||
|
}
|
|||
|
xsh.height += STATUSBAR_HEIGHT;
|
|||
|
|
|||
|
/* slett gammelt innhold */
|
|||
|
XFillRectangle (display, mainpixmap, colorGC[0], 0, 0, xsh.width, xsh.height - STATUSBAR_HEIGHT);
|
|||
|
update (0, 0, xsh.width, xsh.height - STATUSBAR_HEIGHT);
|
|||
|
|
|||
|
/* nye hints til window manager */
|
|||
|
xsh.flags = (PSize | PMinSize | PMaxSize);
|
|||
|
xsh.min_width = xsh.width;
|
|||
|
xsh.min_height = xsh.height;
|
|||
|
xsh.max_width = xsh.width;
|
|||
|
xsh.max_height = xsh.height;
|
|||
|
XSetNormalHints (display, mainwindow, &xsh);
|
|||
|
|
|||
|
/* forandre vindusst<73>rrelse */
|
|||
|
XResizeWindow (display, mainwindow, xsh.width, xsh.height);
|
|||
|
|
|||
|
if (!dyn_cmap) {
|
|||
|
/* slett gammelt innhold i screen */
|
|||
|
memset (screen, 0, 1024 * 256);
|
|||
|
}
|
|||
|
|
|||
|
/* lag statusbar */
|
|||
|
createStatusBar();
|
|||
|
}
|
|||
|
/* Plotter en pixel med farge tatt fra pallett */
|
|||
|
void plotPixel (int x, int y, int color) {
|
|||
|
if (!dyn_cmap) {
|
|||
|
screen[x + y * 1024] = color;
|
|||
|
}
|
|||
|
|
|||
|
switch (resolution) {
|
|||
|
case LOWRES:
|
|||
|
x = x * times40;
|
|||
|
y = y * times40;
|
|||
|
break;
|
|||
|
case MEDRES:
|
|||
|
x = x * times80;
|
|||
|
y = y * times80 * (scanlines ? 2 : 1);
|
|||
|
break;
|
|||
|
case HIGHRES:
|
|||
|
y = y * (scanlines ? 4 : 1);
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
XDrawPoint (display, mainpixmap, colorGC[color], x, y);
|
|||
|
|
|||
|
update (x, y, 1, 1);
|
|||
|
}
|
|||
|
/* Scroller skjerm 'distance' linjer oppover */
|
|||
|
void scrollScreen (int distance) {
|
|||
|
if (!dyn_cmap) {
|
|||
|
/* scroll screen */
|
|||
|
if (distance > 0) {
|
|||
|
memmove (screen, screen + distance * 1024, (256 - distance) * 1024);
|
|||
|
memset (screen + (256 - distance) * 1024, 0, distance * 1024);
|
|||
|
} else {
|
|||
|
memmove (screen + (-distance * 1024), screen, (byte)distance * 1024);
|
|||
|
memset (screen, 0, -distance * 1024);
|
|||
|
}
|
|||
|
}
|
|||
|
switch (resolution) {
|
|||
|
case LOWRES:
|
|||
|
distance *= times40;
|
|||
|
break;
|
|||
|
case MEDRES:
|
|||
|
distance *= times80 * (scanlines ? 2 : 1);
|
|||
|
break;
|
|||
|
case HIGHRES:
|
|||
|
distance *= (scanlines ? 4 : 1);
|
|||
|
break;
|
|||
|
}
|
|||
|
/* scroll pixmap */
|
|||
|
if (distance > 0) {
|
|||
|
XCopyArea (display, mainpixmap, mainpixmap, colorGC[1],
|
|||
|
0, distance, xsh.width, xsh.height - STATUSBAR_HEIGHT - distance, 0, 0);
|
|||
|
XFillRectangle (display, mainpixmap, colorGC[0], 0, xsh.height - STATUSBAR_HEIGHT - distance,
|
|||
|
xsh.width, distance);
|
|||
|
} else {
|
|||
|
XCopyArea (display, mainpixmap, mainpixmap, colorGC[1],
|
|||
|
0, 0, xsh.width, xsh.height - STATUSBAR_HEIGHT - (-distance), 0, -distance);
|
|||
|
XFillRectangle (display, mainpixmap, colorGC[0], 0, 0,
|
|||
|
xsh.width, -distance);
|
|||
|
}
|
|||
|
/* oppdater hele vinduet */
|
|||
|
update (0, 0, xsh.width, xsh.height - STATUSBAR_HEIGHT);
|
|||
|
}
|
|||
|
/* Ny farge, gitt pallett nummer og intensitet 0-255 */
|
|||
|
void changePalette (int colornumber, byte red, byte green, byte blue) {
|
|||
|
XColor color;
|
|||
|
|
|||
|
color.red = red << 8;
|
|||
|
color.green = green << 8;
|
|||
|
color.blue = blue << 8;
|
|||
|
if (dyn_cmap) {
|
|||
|
color.flags = DoRed | DoGreen | DoBlue;
|
|||
|
color.pixel = pixels[colornumber];
|
|||
|
XStoreColor (display, default_cmap, &color);
|
|||
|
} else {
|
|||
|
XGCValues gcv;
|
|||
|
|
|||
|
/* skaff pixel */
|
|||
|
if (!XAllocColor (display, default_cmap, &color)) {
|
|||
|
fprintf (stderr, "Farge %x %x %x ikke tilgjengelig, bruker hvit!\n", red, green, blue);
|
|||
|
color.pixel = whitepix;
|
|||
|
}
|
|||
|
pixels[colornumber] = color.pixel;
|
|||
|
/* forandre GC */
|
|||
|
gcv.foreground = pixels[colornumber];
|
|||
|
XChangeGC (display, colorGC[colornumber], GCForeground, &gcv);
|
|||
|
{ /* oppdater skjerm */
|
|||
|
int x, y;
|
|||
|
|
|||
|
for (y = 0; y < 256; y++) {
|
|||
|
for (x = 0; x < 1024; x++) {
|
|||
|
if (screen[x + y * 1024] == colornumber) {
|
|||
|
plotPixel (x, y, colornumber);
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
/* Kalles periodisk. Lar system kode m<>le / senke emuleringshastighet
|
|||
|
* Kan ogs<EFBFBD> brukes til sjekk av brukeraktivitet
|
|||
|
* ms er antall "emulerte" millisekunder siden forrige gang loopEmul ble kalt
|
|||
|
*/
|
|||
|
void loopEmul (int ms) {
|
|||
|
int events;
|
|||
|
XEvent event;
|
|||
|
|
|||
|
/* senk hastighet */
|
|||
|
if (slowDown) {
|
|||
|
static boolean firsttime = TRUE; /* brukes for <20> initialisere lastTOD */
|
|||
|
static struct timeval lastTOD;
|
|||
|
struct timeval currentTOD;
|
|||
|
|
|||
|
if (firsttime) { /* initialiser lastTOD */
|
|||
|
gettimeofday (&lastTOD, NULL);
|
|||
|
firsttime = FALSE;
|
|||
|
} else {
|
|||
|
long sleepPeriod;
|
|||
|
|
|||
|
gettimeofday (¤tTOD, NULL);
|
|||
|
|
|||
|
/* finner soveintervall */
|
|||
|
if ((currentTOD.tv_sec - lastTOD.tv_sec) != 0) { /* har krysset sekundgrense */
|
|||
|
sleepPeriod = (ms * 1000) - (currentTOD.tv_usec + (1000000 - lastTOD.tv_usec));
|
|||
|
} else {
|
|||
|
sleepPeriod = (ms * 1000) - (currentTOD.tv_usec - lastTOD.tv_usec);
|
|||
|
}
|
|||
|
|
|||
|
lastTOD = currentTOD;
|
|||
|
|
|||
|
/* ta en liten lur */
|
|||
|
if (sleepPeriod > 0) {
|
|||
|
usleep (sleepPeriod);
|
|||
|
|
|||
|
/* lastTOD += sleepPeriod */
|
|||
|
lastTOD.tv_usec = lastTOD.tv_usec + sleepPeriod;
|
|||
|
if (lastTOD.tv_usec > 999999) {
|
|||
|
lastTOD.tv_sec++;
|
|||
|
lastTOD.tv_usec -= 1000000;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
/* oppdater skjerm */
|
|||
|
if (updateWindow) {
|
|||
|
XCopyArea (display, mainpixmap, mainwindow, colorGC[1],
|
|||
|
xmin, ymin, xmax - xmin, ymax - ymin, xmin, ymin);
|
|||
|
xmin = (unsigned)~0; ymin = (unsigned)~0; xmax = 0; ymax = 0;
|
|||
|
updateWindow = FALSE;
|
|||
|
}
|
|||
|
|
|||
|
XFlush (display);
|
|||
|
|
|||
|
/* sjekk events */
|
|||
|
if ((events = XEventsQueued (display, QueuedAfterReading))) {
|
|||
|
while (events--) {
|
|||
|
XNextEvent (display, &event);
|
|||
|
switch (event.type) {
|
|||
|
case MappingNotify:
|
|||
|
XRefreshKeyboardMapping ((XMappingEvent *)&event);
|
|||
|
break;
|
|||
|
case Expose:
|
|||
|
XCopyArea (display, mainpixmap, mainwindow, colorGC[1],
|
|||
|
event.xexpose.x, event.xexpose.y,
|
|||
|
event.xexpose.width, event.xexpose.height,
|
|||
|
event.xexpose.x, event.xexpose.y);
|
|||
|
break;
|
|||
|
case KeyPress: {
|
|||
|
if (XKeycodeToKeysym (display, event.xkey.keycode, 0) == XK_Escape) {
|
|||
|
commandline();
|
|||
|
} else {
|
|||
|
pressedKeys[keysymToTikikey (XKeycodeToKeysym (display, event.xkey.keycode, 0))]
|
|||
|
= 0;
|
|||
|
}
|
|||
|
break;
|
|||
|
}
|
|||
|
case KeyRelease: {
|
|||
|
pressedKeys[keysymToTikikey (XKeycodeToKeysym (display, event.xkey.keycode, 0))]
|
|||
|
= 1;
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
/* sjekk serieporter */
|
|||
|
if (port1) {
|
|||
|
int bytes;
|
|||
|
|
|||
|
ioctl (port1, FIONREAD, &bytes);
|
|||
|
if (bytes) {
|
|||
|
charAvailable (0);
|
|||
|
}
|
|||
|
}
|
|||
|
if (port2) {
|
|||
|
int bytes;
|
|||
|
|
|||
|
ioctl (port2, FIONREAD, &bytes);
|
|||
|
if (bytes) {
|
|||
|
charAvailable (1);
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
/* oversetter fra keysym til tikitaster */
|
|||
|
static byte keysymToTikikey (KeySym keysym) {
|
|||
|
int i;
|
|||
|
|
|||
|
/* line<6E>rs<72>k gjennom tabell */
|
|||
|
for (i = 0; i < (sizeof keyConvTable / sizeof (struct KeyConv)); i++) {
|
|||
|
if (keyConvTable[i].keysym == keysym)
|
|||
|
return keyConvTable[i].tikikey;
|
|||
|
}
|
|||
|
return KEY_NONE;
|
|||
|
}
|
|||
|
/* tar imot kommandoer via konsoll */
|
|||
|
static void commandline (void) {
|
|||
|
while (TRUE) {
|
|||
|
char cmdline[256];
|
|||
|
char *cmd;
|
|||
|
|
|||
|
printf ("Kommando [h for hjelp]> ");
|
|||
|
fflush (stdout);
|
|||
|
|
|||
|
fgets (cmdline, 256, stdin);
|
|||
|
|
|||
|
if ((cmd = strtok (cmdline, " \t\n"))) {
|
|||
|
if (!strcmp (cmd, "h") || !strcmp (cmd, "hjelp")) {
|
|||
|
/* vis hjelpetekst */
|
|||
|
puts ("\n***** Kommandoer *****");
|
|||
|
puts ("hjelp : Vis denne hjelpeteksten");
|
|||
|
puts ("h : ");
|
|||
|
puts ("disk <stasjon> <filnavn> : Hent inn diskettfil");
|
|||
|
puts ("d <stasjon> <filnavn> : ");
|
|||
|
puts ("lagre <stasjon> <filnavn> : Lagre diskettfil");
|
|||
|
puts ("l <stasjon> <filnavn> : ");
|
|||
|
puts ("fjern <stasjon> : Fjern diskettfil");
|
|||
|
puts ("f <stasjon> : ");
|
|||
|
puts ("pk [kommandonavn] : Send utskrift til print-kommando");
|
|||
|
puts ("pf [filnavn] : Send utskrift til fil");
|
|||
|
puts ("reset : Reset emulator");
|
|||
|
puts ("fortsett : Fortsett emulering");
|
|||
|
puts ("c : ");
|
|||
|
puts ("om : Om emulator");
|
|||
|
puts ("avslutt : Avslutt emulator");
|
|||
|
puts ("q : ");
|
|||
|
#ifdef DEBUG
|
|||
|
puts ("monitor : Z80-monitor");
|
|||
|
puts ("m : ");
|
|||
|
#endif
|
|||
|
puts ("");
|
|||
|
} else if (!strcmp (cmd, "d") || !strcmp (cmd, "disk")) {
|
|||
|
/* hent diskfil */
|
|||
|
char *driveString = strtok (NULL, " \t\n");
|
|||
|
char *filename = strtok (NULL, " \t\n");
|
|||
|
|
|||
|
if (!filename) {
|
|||
|
fprintf (stderr, "For f<> argumenter\n");
|
|||
|
continue;
|
|||
|
}
|
|||
|
|
|||
|
if (!strcmp (driveString, "a") || !strcmp (driveString, "a:")) {
|
|||
|
readDiskImage (0, filename);
|
|||
|
} else if (!strcmp (driveString, "b") || !strcmp (driveString, "b:")) {
|
|||
|
readDiskImage (1, filename);
|
|||
|
} else fprintf (stderr, "Ugyldig stasjon\n");
|
|||
|
} else if (!strcmp (cmd, "l") || !strcmp (cmd, "lagre")) {
|
|||
|
/* lagre diskfil */
|
|||
|
int drive;
|
|||
|
char *driveString = strtok (NULL, " \t\n");
|
|||
|
char *filename = strtok (NULL, " \t\n");
|
|||
|
|
|||
|
if (!filename) {
|
|||
|
fprintf (stderr, "For f<> argumenter\n");
|
|||
|
continue;
|
|||
|
}
|
|||
|
|
|||
|
if (!strcmp (driveString, "a") || !strcmp (driveString, "a:")) {
|
|||
|
drive = 0;
|
|||
|
} else if (!strcmp (driveString, "b") || !strcmp (driveString, "b:")) {
|
|||
|
drive = 1;
|
|||
|
} else {
|
|||
|
fprintf (stderr, "Ugyldig stasjon\n");
|
|||
|
continue;
|
|||
|
}
|
|||
|
if (dsksize[drive] != 0) {
|
|||
|
int fd;
|
|||
|
|
|||
|
if ((fd = creat (filename, 0640)) != -1) {
|
|||
|
if (write (fd, dsk[drive], dsksize[drive]) == -1) {
|
|||
|
fprintf (stderr, "Kan ikke skrive til fil %s\n", filename);
|
|||
|
}
|
|||
|
close (fd);
|
|||
|
} else fprintf (stderr, "Kan ikke skrive til fil %s\n", filename);
|
|||
|
}
|
|||
|
} else if (!strcmp (cmd, "f") || !strcmp (cmd, "fjern")) {
|
|||
|
/* fjern diskfil */
|
|||
|
int drive;
|
|||
|
char *driveString = strtok (NULL, " \t\n");
|
|||
|
|
|||
|
if (!driveString) {
|
|||
|
fprintf (stderr, "For f<> argumenter\n");
|
|||
|
continue;
|
|||
|
}
|
|||
|
|
|||
|
if (!strcmp (driveString, "a") || !strcmp (driveString, "a:")) {
|
|||
|
drive = 0;
|
|||
|
} else if (!strcmp (driveString, "b") || !strcmp (driveString, "b:")) {
|
|||
|
drive = 1;
|
|||
|
} else {
|
|||
|
fprintf (stderr, "Ugyldig stasjon\n");
|
|||
|
continue;
|
|||
|
}
|
|||
|
removeDisk (drive);
|
|||
|
free (dsk[drive]);
|
|||
|
dsk[drive] = NULL;
|
|||
|
dsksize[drive] = 0;
|
|||
|
} else if (!strcmp (cmd, "pk")) {
|
|||
|
char *pc = strtok (NULL, " \t\n");
|
|||
|
|
|||
|
if (!pc) {
|
|||
|
if (printCmd) {
|
|||
|
pclose (printCmd);
|
|||
|
printCmd = 0;
|
|||
|
}
|
|||
|
} else {
|
|||
|
setPrintCmd (pc);
|
|||
|
}
|
|||
|
} else if (!strcmp (cmd, "pf")) {
|
|||
|
char *pf = strtok (NULL, " \t\n");
|
|||
|
|
|||
|
if (!pf) {
|
|||
|
if (printFile) {
|
|||
|
fclose (printFile);
|
|||
|
printFile = 0;
|
|||
|
}
|
|||
|
} else {
|
|||
|
setPrintFile (pf);
|
|||
|
}
|
|||
|
} else if (!strcmp (cmd, "reset")) {
|
|||
|
/* reset */
|
|||
|
resetEmul();
|
|||
|
} else if (!strcmp (cmd, "c") || !strcmp (cmd, "fortsett")) {
|
|||
|
/* fortsett emulering */
|
|||
|
return;
|
|||
|
} else if (!strcmp (cmd, "om")) {
|
|||
|
/* vis "om"-tekst */
|
|||
|
puts ("\nTIKI-100_emul V1.1.1 - en freeware TIKI 100 Rev. C emulator.");
|
|||
|
puts ("Z80 emulering copyright (C) Marat Fayzullin 1994,1995,1996,1997.");
|
|||
|
puts ("Resten copyright (C) Asbj<62>rn Djupdal 2000-2001.\n");
|
|||
|
} else if (!strcmp (cmd, "q") || !strcmp (cmd, "avslutt")) {
|
|||
|
/* avslutt */
|
|||
|
quitEmul();
|
|||
|
return;
|
|||
|
#ifdef DEBUG
|
|||
|
} else if (!strcmp (cmd, "m") || !strcmp (cmd, "monitor")) {
|
|||
|
/* z80-debugger */
|
|||
|
trace();
|
|||
|
return;
|
|||
|
#endif
|
|||
|
} else {
|
|||
|
fprintf (stderr, "Ugyldig kommando\n");
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
/* setter opp printkommando/fil */
|
|||
|
static void setPrintCmd (char *p) {
|
|||
|
if (printCmd) pclose (printCmd);
|
|||
|
if (!(printCmd = popen (p, "w"))) {
|
|||
|
fprintf (stderr, "Kan ikke starte printkommando\n");
|
|||
|
}
|
|||
|
}
|
|||
|
static void setPrintFile (char *p) {
|
|||
|
if (printFile) fclose (printFile);
|
|||
|
if (!(printFile = fopen (p, "wb"))) {
|
|||
|
fprintf (stderr, "Kan ikke lage printerfil %s\n", p);
|
|||
|
}
|
|||
|
}
|
|||
|
/* henter inn diskbilde fra fil */
|
|||
|
static void readDiskImage (int drive, char *filename) {
|
|||
|
int fd;
|
|||
|
|
|||
|
if ((fd = open (filename, O_RDONLY)) != -1) {
|
|||
|
struct stat fileInfo;
|
|||
|
|
|||
|
removeDisk (drive);
|
|||
|
free (dsk[drive]);
|
|||
|
fstat (fd, &fileInfo);
|
|||
|
if ((dsk[drive] = malloc (fileInfo.st_size))) {
|
|||
|
dsksize[drive] = read (fd, dsk[drive], fileInfo.st_size);
|
|||
|
|
|||
|
switch (dsksize[drive]) {
|
|||
|
case 40*1*18*128:
|
|||
|
insertDisk (drive, dsk[drive], 40, 1, 18, 128);
|
|||
|
break;
|
|||
|
case 40*1*10*512:
|
|||
|
insertDisk (drive, dsk[drive], 40, 1, 10, 512);
|
|||
|
break;
|
|||
|
case 40*2*10*512:
|
|||
|
insertDisk (drive, dsk[drive], 40, 2, 10, 512);
|
|||
|
break;
|
|||
|
case 80*2*10*512:
|
|||
|
insertDisk (drive, dsk[drive], 80, 2, 10, 512);
|
|||
|
break;
|
|||
|
case -1:
|
|||
|
fprintf (stderr, "Klarer ikke lese fra fil %s\n", filename);
|
|||
|
break;
|
|||
|
default:
|
|||
|
fprintf (stderr, "Kjenner ikke diskformatet\n");
|
|||
|
dsksize[drive] = 0;
|
|||
|
free (dsk[drive]);
|
|||
|
dsk[drive] = NULL;
|
|||
|
break;
|
|||
|
}
|
|||
|
} else {
|
|||
|
fprintf (stderr, "Ikke nok minne til diskettfil\n");
|
|||
|
dsksize[drive] = 0;
|
|||
|
}
|
|||
|
close (fd);
|
|||
|
} else {
|
|||
|
fprintf (stderr, "Klarer ikke lese fra fil %s\n", filename);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
/* Tenn/slukk lock lys */
|
|||
|
void lockLight (boolean status) {
|
|||
|
GC gc = (status ? diodeGC : blackGC);
|
|||
|
|
|||
|
XFillRectangle (display, mainpixmap, gc,
|
|||
|
21, xsh.height - STATUSBAR_HEIGHT + 4, 8, 8);
|
|||
|
|
|||
|
update (21, xsh.height - STATUSBAR_HEIGHT + 4, 9, 9);
|
|||
|
lock = status;
|
|||
|
}
|
|||
|
/* Tenn/slukk grafikk lys */
|
|||
|
void grafikkLight (boolean status) {
|
|||
|
GC gc = (status ? diodeGC : blackGC);
|
|||
|
|
|||
|
XFillRectangle (display, mainpixmap, gc,
|
|||
|
41, xsh.height - STATUSBAR_HEIGHT + 4, 8, 8);
|
|||
|
|
|||
|
update (41, xsh.height - STATUSBAR_HEIGHT + 4, 9, 9);
|
|||
|
grafikk = status;
|
|||
|
}
|
|||
|
/* Tenn/slukk disk lys for gitt stasjon */
|
|||
|
void diskLight (int drive, boolean status) {
|
|||
|
GC gc = (status ? diodeGC : blackGC);
|
|||
|
int x = (drive ? 81 : 61);
|
|||
|
|
|||
|
XFillRectangle (display, mainpixmap, gc,
|
|||
|
x, xsh.height - STATUSBAR_HEIGHT + 4, 8, 8);
|
|||
|
|
|||
|
update (x, xsh.height - STATUSBAR_HEIGHT + 4, 9, 9);
|
|||
|
disk[drive] = status;
|
|||
|
}
|
|||
|
/* Sjekk status til hver av de gitte tastene
|
|||
|
* Sett bit n i returkode hvis tast n IKKE er nedtrykt
|
|||
|
*/
|
|||
|
byte testKey (byte keys[8]) {
|
|||
|
return pressedKeys[keys[0]] | (pressedKeys[keys[1]] << 1) | (pressedKeys[keys[2]] << 2) |
|
|||
|
(pressedKeys[keys[3]] << 3) | (pressedKeys[keys[4]] << 4) | (pressedKeys[keys[5]] << 5) |
|
|||
|
(pressedKeys[keys[6]] << 6) | (pressedKeys[keys[7]] << 7);
|
|||
|
}
|
|||
|
/* setter seriekanalparametre */
|
|||
|
void setParams (struct serParams *p1Params, struct serParams *p2Params) {
|
|||
|
if (port1) setParam (port1, p1Params);
|
|||
|
if (port2) setParam (port2, p2Params);
|
|||
|
}
|
|||
|
static void setParam (int portfd, struct serParams *params) {
|
|||
|
struct termios options;
|
|||
|
|
|||
|
tcgetattr (portfd, &options);
|
|||
|
|
|||
|
options.c_iflag = 0;
|
|||
|
options.c_oflag = 0;
|
|||
|
options.c_lflag = 0;
|
|||
|
memset (options.c_cc, 0, sizeof (options.c_cc));
|
|||
|
|
|||
|
options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);
|
|||
|
options.c_cflag |= (CLOCAL | CREAD);
|
|||
|
|
|||
|
/* rec/send bits */
|
|||
|
options.c_cflag &= ~CSIZE;
|
|||
|
switch (params->sendBits) {
|
|||
|
case 5:
|
|||
|
options.c_cflag |= CS5;
|
|||
|
break;
|
|||
|
case 6:
|
|||
|
options.c_cflag |= CS6;
|
|||
|
break;
|
|||
|
case 7:
|
|||
|
options.c_cflag |= CS7;
|
|||
|
break;
|
|||
|
default:
|
|||
|
case 8:
|
|||
|
options.c_cflag |= CS8;
|
|||
|
break;
|
|||
|
}
|
|||
|
/* parity */
|
|||
|
switch (params->parity) {
|
|||
|
case PAR_NONE:
|
|||
|
options.c_cflag &= ~PARENB;
|
|||
|
options.c_iflag &= ~(INPCK | ISTRIP);
|
|||
|
break;
|
|||
|
case PAR_EVEN:
|
|||
|
options.c_cflag |= PARENB;
|
|||
|
options.c_cflag &= ~PARODD;
|
|||
|
options.c_iflag |= (INPCK | ISTRIP);
|
|||
|
break;
|
|||
|
case PAR_ODD:
|
|||
|
options.c_cflag |= PARENB;
|
|||
|
options.c_cflag |= PARODD;
|
|||
|
options.c_iflag |= (INPCK | ISTRIP);
|
|||
|
break;
|
|||
|
}
|
|||
|
/* stopbits */
|
|||
|
switch (params->stopBits) {
|
|||
|
case ONE_SB:
|
|||
|
options.c_cflag &= ~CSTOPB;
|
|||
|
break;
|
|||
|
case ONE_PT_FIVE_SB:
|
|||
|
case TWO_SB:
|
|||
|
options.c_cflag |= CSTOPB;
|
|||
|
break;
|
|||
|
}
|
|||
|
/* baud */
|
|||
|
if (params->baud < 62) {
|
|||
|
params->baud = B50;
|
|||
|
} else if (params->baud < 92) {
|
|||
|
params->baud = B75;
|
|||
|
} else if (params->baud < 122) {
|
|||
|
params->baud = B110;
|
|||
|
} else if (params->baud < 142) {
|
|||
|
params->baud = B134;
|
|||
|
} else if (params->baud < 175) {
|
|||
|
params->baud = B150;
|
|||
|
} else if (params->baud < 250) {
|
|||
|
params->baud = B200;
|
|||
|
} else if (params->baud < 450) {
|
|||
|
params->baud = B300;
|
|||
|
} else if (params->baud < 900) {
|
|||
|
params->baud = B600;
|
|||
|
} else if (params->baud < 1500) {
|
|||
|
params->baud = B1200;
|
|||
|
} else if (params->baud < 2100) {
|
|||
|
params->baud = B1800;
|
|||
|
} else if (params->baud < 3600) {
|
|||
|
params->baud = B2400;
|
|||
|
} else if (params->baud < 7200) {
|
|||
|
params->baud = B4800;
|
|||
|
} else if (params->baud < 14400) {
|
|||
|
params->baud = B9600;
|
|||
|
} else {
|
|||
|
params->baud = B19200;
|
|||
|
}
|
|||
|
cfsetispeed (&options, params->baud);
|
|||
|
cfsetospeed (&options, params->baud);
|
|||
|
|
|||
|
tcsetattr (portfd, TCSADRAIN, &options);
|
|||
|
}
|
|||
|
/* send tegn til seriekanal */
|
|||
|
void sendChar (int port, byte value) {
|
|||
|
int portfd = port ? port2 : port1;
|
|||
|
|
|||
|
if (portfd) {
|
|||
|
if (write (portfd, &value, 1) == -1) {
|
|||
|
/* klarer ikke sende tegn */
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
/* hent tegn fra seriekanal */
|
|||
|
byte getChar (int port) {
|
|||
|
int portfd = port ? port2 : port1;
|
|||
|
byte value;
|
|||
|
|
|||
|
if (portfd) {
|
|||
|
read (portfd, &value, 1);
|
|||
|
|
|||
|
{ /* flere tegn? */
|
|||
|
int bytes;
|
|||
|
|
|||
|
ioctl (portfd, FIONREAD, &bytes);
|
|||
|
if (bytes) {
|
|||
|
charAvailable (port);
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
return value;
|
|||
|
}
|
|||
|
/* send tegn til skriver */
|
|||
|
void printChar (byte value) {
|
|||
|
if (printCmd) {
|
|||
|
if (fputc (value, printCmd) == EOF) {
|
|||
|
/* klarer ikke skrive til printkommando */
|
|||
|
}
|
|||
|
}
|
|||
|
if (printFile) {
|
|||
|
if (fputc (value, printFile) == EOF) {
|
|||
|
/* klarer ikke skrive til printfil */
|
|||
|
}
|
|||
|
}
|
|||
|
}
|