Start of Terminal widget.
This commit is contained in:
parent
71c13fdc71
commit
fb0d5ad0ac
15 changed files with 2819 additions and 19 deletions
18
LICENSE
18
LICENSE
|
@ -22,14 +22,32 @@ Licenses Used By:
|
|||
Client
|
||||
======
|
||||
|
||||
DOS Serial Library
|
||||
------------------
|
||||
https://github.com/kstenerud/DOS-Serial-Library
|
||||
Attribution
|
||||
|
||||
MemWatch
|
||||
--------
|
||||
http://www.linkdata.se/sourcecode/memwatch/
|
||||
GPL2
|
||||
|
||||
SDL2
|
||||
----
|
||||
https://www.libsdl.org/
|
||||
BSD 3-Clause
|
||||
|
||||
SDL2_Net
|
||||
--------
|
||||
https://www.libsdl.org/
|
||||
BSD 3-Clause
|
||||
|
||||
stb_ds.h
|
||||
--------
|
||||
https://github.com/nothings/stb
|
||||
Public Domain
|
||||
|
||||
stb_image.h
|
||||
-----------
|
||||
https://github.com/nothings/stb
|
||||
Public Domain
|
||||
|
|
|
@ -32,7 +32,7 @@ BINDIR = bin
|
|||
## CHANGE THIS ##
|
||||
|
||||
# CFLAGS, LDFLAGS, CPPFLAGS, PREFIX can be overriden on CLI
|
||||
CFLAGS := $(DEBUG) -I$(SRCDIR) -I$(SRCDIR)/dos -I$(SRCDIR)/gui -I$(SRCDIR)/thirdparty -I$(SRCDIR)/thirdparty/memwatch
|
||||
CFLAGS := $(DEBUG) -I$(SRCDIR) -I$(SRCDIR)/dos -I$(SRCDIR)/gui -I$(SRCDIR)/thirdparty -I$(SRCDIR)/thirdparty/memwatch -I$(SRCDIR)/thirdparty/serial
|
||||
CPPFLAGS :=
|
||||
LDFLAGS :=
|
||||
PREFIX := /usr/local
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
#
|
||||
|
||||
mkdir -p bin obj/dos obj/gui obj/thirdparty/memwatch
|
||||
mkdir -p bin obj/dos obj/gui obj/thirdparty/memwatch obj/thirdparty/serial
|
||||
source /opt/cross/djgpp/setenv
|
||||
make -f Makefile.djgpp
|
||||
rm bin/client
|
||||
|
|
|
@ -21,9 +21,11 @@ CONFIG -= qt
|
|||
|
||||
DESTDIR = $$OUT_PWD/bin
|
||||
|
||||
DOS_HEADERS =
|
||||
DOS_HEADERS = \
|
||||
src/thirdparty/serial/serial.h
|
||||
|
||||
DOS_SOURCES = \
|
||||
src/thirdparty/serial/serial.c \
|
||||
src/dos/keyboard.c \
|
||||
src/dos/mouse.c \
|
||||
src/dos/vesa.c
|
||||
|
@ -45,6 +47,7 @@ INCLUDEPATH += \
|
|||
HEADERS = \
|
||||
$$LINUX_HEADERS \
|
||||
src/gui/listbox.h \
|
||||
src/gui/terminal.h \
|
||||
src/gui/updown.h \
|
||||
src/stddclmr.h \
|
||||
src/thirdparty/stb_ds.h \
|
||||
|
@ -77,6 +80,7 @@ HEADERS = \
|
|||
SOURCES = \
|
||||
$$LINUX_SOURCES \
|
||||
src/gui/listbox.c \
|
||||
src/gui/terminal.c \
|
||||
src/gui/updown.c \
|
||||
src/thirdparty/memwatch/memwatch.c \
|
||||
src/gui/memory.c \
|
||||
|
@ -100,7 +104,8 @@ SOURCES = \
|
|||
src/main.c
|
||||
|
||||
LIBS = \
|
||||
-lSDL2
|
||||
-lSDL2 \
|
||||
-lSDL2_net
|
||||
|
||||
OTHER_FILES = \
|
||||
Makefile.djgpp \
|
||||
|
|
1
client/data/kanga.ans
Normal file
1
client/data/kanga.ans
Normal file
File diff suppressed because one or more lines are too long
|
@ -29,6 +29,9 @@
|
|||
|
||||
int16_t _guiMetric[METRIC_COUNT];
|
||||
ColorT _guiColor[COLOR_COUNT];
|
||||
FontT *_guiFont8 = NULL;
|
||||
FontT *_guiFont14 = NULL;
|
||||
FontT *_guiFont16 = NULL;
|
||||
FontT *_guiFont = NULL;
|
||||
WidgetT *_guiDragWidget = NULL;
|
||||
uint16_t _guiDragOffsetX = 0;
|
||||
|
@ -533,7 +536,12 @@ DesktopT *guiStartup(void) {
|
|||
_guiColor[COLOR_LISTBOX_ARROWS_ACTIVE] = vbeMakeColor(168, 168, 168);
|
||||
_guiColor[COLOR_LISTBOX_ARROWS_INACTIVE] = vbeMakeColor( 80, 84, 80);
|
||||
|
||||
_guiFont = fontLoad("vga8x14.dat");
|
||||
// Load all font sizes.
|
||||
_guiFont8 = fontLoad("vga8x8.dat");
|
||||
_guiFont14 = fontLoad("vga8x14.dat");
|
||||
_guiFont16 = fontLoad("vga8x16.dat");
|
||||
|
||||
_guiFont = _guiFont14; // Font to use for widgets.
|
||||
|
||||
// Create desktop and return it. Remember it for later.
|
||||
_guiDesktop = desktopNew();
|
||||
|
@ -550,7 +558,11 @@ DesktopT *guiStartup(void) {
|
|||
|
||||
|
||||
void guiShutdown(void) {
|
||||
fontUnload(&_guiFont);
|
||||
// Unload fonts.
|
||||
fontUnload(&_guiFont16);
|
||||
fontUnload(&_guiFont14);
|
||||
fontUnload(&_guiFont8);
|
||||
_guiFont = NULL;
|
||||
|
||||
// Delete all widgets in GUI tree.
|
||||
guiDelete((WidgetT **)&_guiDesktop);
|
||||
|
|
|
@ -51,7 +51,7 @@ enum MagicE {
|
|||
MAGIC_TEXTBOX,
|
||||
MAGIC_UPDOWN,
|
||||
MAGIC_LISTBOX,
|
||||
//MAGIC_TERMINAL,
|
||||
MAGIC_TERMINAL,
|
||||
//MAGIC_DROPDOWN,
|
||||
MAGIC_COUNT
|
||||
};
|
||||
|
@ -149,6 +149,9 @@ typedef struct WindowS WindowT;
|
|||
extern int16_t _guiMetric[METRIC_COUNT];
|
||||
extern ColorT _guiColor[COLOR_COUNT];
|
||||
extern FontT *_guiFont;
|
||||
extern FontT *_guiFont8;
|
||||
extern FontT *_guiFont14;
|
||||
extern FontT *_guiFont16;
|
||||
extern WidgetT *_guiDragWidget;
|
||||
extern uint16_t _guiDragOffsetX;
|
||||
extern uint16_t _guiDragOffsetY;
|
||||
|
|
|
@ -48,6 +48,7 @@ ImageT *imageAllocate(uint16_t w, uint16_t h) {
|
|||
for (y=0; y<x; y++) {
|
||||
free(image->pixels[y]);
|
||||
}
|
||||
free(image->pixels);
|
||||
free(image);
|
||||
return NULL;
|
||||
}
|
||||
|
|
649
client/src/gui/terminal.c
Normal file
649
client/src/gui/terminal.c
Normal file
|
@ -0,0 +1,649 @@
|
|||
/*
|
||||
* Kangaroo Punch MultiPlayer Game Server Mark II
|
||||
* Copyright (C) 2020-2021 Scott Duensing
|
||||
*
|
||||
* This program 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 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program 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 this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
// http://www.ansi-bbs.org/BANSI/bansi.txt
|
||||
// http://ansi-bbs.org/ansi-bbs-core-server.html
|
||||
|
||||
|
||||
#include "terminal.h"
|
||||
|
||||
|
||||
#define TERMINAL_CELL_GET_FLAG(t,x,y,f) (((t)->cells[(x)][(y)].flags & (1 << (f))) != 0)
|
||||
#define TERMINAL_CELL_SET_FLAG(t,x,y,f) ((t)->cells[(x)][(y)].flags |= (1 << (f)))
|
||||
#define TERMINAL_CELL_CLEAR_FLAG(t,x,y,f) ((t)->cells[(x)][(y)].flags &= (~(1 << (f))))
|
||||
|
||||
|
||||
static int16_t terminalConvertToInt(char *number, int16_t defaultValue);
|
||||
static void terminalDel(WidgetT **widget);
|
||||
static void terminalMouseEvent(WidgetT *widget, MouseT *mouse, uint16_t x, uint16_t y, uint8_t event);
|
||||
static void terminalPaint(WidgetT *widget, RectT pos);
|
||||
static void terminalSequenceReset(TerminalT *terminal);
|
||||
|
||||
|
||||
void terminalBackgroundSet(TerminalT *terminal, uint8_t color) {
|
||||
terminal->background = color;
|
||||
}
|
||||
|
||||
|
||||
static int16_t terminalConvertToInt(char *number, int16_t defaultValue) {
|
||||
char *end = NULL;
|
||||
int16_t result = (int16_t)strtol(number, &end, 10);
|
||||
|
||||
if (end == NULL) result = defaultValue;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
void terminalCursorMove(TerminalT *terminal, uint16_t col, uint16_t row) {
|
||||
|
||||
// Clamp X.
|
||||
if (col < 1) {
|
||||
terminal->cursorX = 1;
|
||||
} else {
|
||||
if (col > terminal->cols) {
|
||||
terminal->cursorX = terminal->cols;
|
||||
} else {
|
||||
terminal->cursorX = col;
|
||||
}
|
||||
}
|
||||
|
||||
// Clamp Y.
|
||||
if (row < 1) {
|
||||
terminal->cursorY = 1;
|
||||
} else {
|
||||
if (row > terminal->rows) {
|
||||
terminal->cursorY = terminal->rows;
|
||||
} else {
|
||||
terminal->cursorY = row;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void terminalDel(WidgetT **widget) {
|
||||
TerminalT *t = (TerminalT *)*widget;
|
||||
uint16_t x;
|
||||
|
||||
terminalSequenceReset(t);
|
||||
|
||||
for (x=0; x<t->cols; x++) {
|
||||
free(t->cells[x]);
|
||||
}
|
||||
free(t->cells);
|
||||
|
||||
free(t);
|
||||
t = NULL;
|
||||
}
|
||||
|
||||
|
||||
void terminalForegroundSet(TerminalT *terminal, uint8_t color) {
|
||||
terminal->foreground = color;
|
||||
terminal->bold = (color > 7);
|
||||
}
|
||||
|
||||
|
||||
WidgetT *terminalInit(WidgetT *widget, uint16_t cols, uint16_t rows) {
|
||||
TerminalT *t = (TerminalT *)widget;
|
||||
uint16_t x;
|
||||
uint16_t y;
|
||||
|
||||
t->base.delMethod = terminalDel;
|
||||
t->base.paintMethod = terminalPaint;
|
||||
t->base.mouseEventMethod = terminalMouseEvent;
|
||||
t->font = _guiFont8; // Default font. Also see terminalNew.
|
||||
t->cols = cols;
|
||||
t->rows = rows;
|
||||
t->cursorX = 1;
|
||||
t->cursorY = 1;
|
||||
t->saveX = 1;
|
||||
t->saveY = 1;
|
||||
t->bold = 0;
|
||||
t->blink = 0;
|
||||
t->reverse = 0;
|
||||
t->background = TERMINAL_COLOR_BLACK;
|
||||
t->foreground = TERMINAL_COLOR_LIGHT_GRAY;
|
||||
t->escFound = 0;
|
||||
t->inEscape = 0;
|
||||
t->numberIndex = 0;
|
||||
t->number[0] = 0;
|
||||
t->parameters = NULL;
|
||||
|
||||
// Allocate space for column data.
|
||||
t->cells = (CellT **)malloc(sizeof(CellT *) * cols);
|
||||
if (!t->cells) return NULL;
|
||||
// Allocate space for row data.
|
||||
for (x=0; x<cols; x++) {
|
||||
t->cells[x] = (CellT *)malloc(sizeof(CellT) * rows);
|
||||
if (!t->cells[x]) {
|
||||
for (y=0; y<x; y++) {
|
||||
free(t->cells[y]);
|
||||
}
|
||||
free(t->cells);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
// Set up default palette.
|
||||
t->palette[TERMINAL_COLOR_BLACK] = vbeMakeColor(0x00, 0x00, 0x00);
|
||||
t->palette[TERMINAL_COLOR_BLUE] = vbeMakeColor(0x00, 0x00, 0xAA);
|
||||
t->palette[TERMINAL_COLOR_GREEN] = vbeMakeColor(0x00, 0xAA, 0x00);
|
||||
t->palette[TERMINAL_COLOR_CYAN] = vbeMakeColor(0x00, 0xAA, 0xAA);
|
||||
t->palette[TERMINAL_COLOR_RED] = vbeMakeColor(0xAA, 0x00, 0x00);
|
||||
t->palette[TERMINAL_COLOR_MAGENTA] = vbeMakeColor(0xAA, 0x00, 0xAA);
|
||||
t->palette[TERMINAL_COLOR_BROWN] = vbeMakeColor(0xAA, 0x55, 0x00);
|
||||
t->palette[TERMINAL_COLOR_LIGHT_GRAY] = vbeMakeColor(0xAA, 0xAA, 0xAA);
|
||||
t->palette[TERMINAL_COLOR_DARK_GRAY] = vbeMakeColor(0x55, 0x55, 0x55);
|
||||
t->palette[TERMINAL_COLOR_BRIGHT_BLUE] = vbeMakeColor(0x55, 0x55, 0xFF);
|
||||
t->palette[TERMINAL_COLOR_BRIGHT_GREEN] = vbeMakeColor(0x55, 0xFF, 0x55);
|
||||
t->palette[TERMINAL_COLOR_BRIGHT_CYAN] = vbeMakeColor(0x55, 0xFF, 0xFF);
|
||||
t->palette[TERMINAL_COLOR_BRIGHT_RED] = vbeMakeColor(0xFF, 0x55, 0x55);
|
||||
t->palette[TERMINAL_COLOR_BRIGHT_MAGENTA] = vbeMakeColor(0xFF, 0x55, 0xFF);
|
||||
t->palette[TERMINAL_COLOR_YELLOW] = vbeMakeColor(0xFF, 0xFF, 0x55);
|
||||
t->palette[TERMINAL_COLOR_WHITE] = vbeMakeColor(0xFF, 0xFF, 0xFF);
|
||||
|
||||
// Default attributes is gray on black, no bold, no blink, and dirty.
|
||||
for (y=0; y<rows; y++) {
|
||||
for (x=0; x<cols; x++) {
|
||||
t->cells[x][y].character = ' ';
|
||||
t->cells[x][y].background = TERMINAL_COLOR_BLACK;
|
||||
t->cells[x][y].foreground = TERMINAL_COLOR_LIGHT_GRAY;
|
||||
t->cells[x][y].flags = 0;
|
||||
TERMINAL_CELL_SET_FLAG(t, x, y, TERMINAL_FLAG_DIRTY);
|
||||
}
|
||||
}
|
||||
|
||||
return widget;
|
||||
}
|
||||
|
||||
|
||||
static void terminalMouseEvent(WidgetT *widget, MouseT *mouse, uint16_t x, uint16_t y, uint8_t event) {
|
||||
TerminalT *t = (TerminalT *)widget;
|
||||
|
||||
(void)mouse;
|
||||
|
||||
// Fire callback on mouse up.
|
||||
if (event == MOUSE_EVENT_LEFT_UP) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
TerminalT *terminalNew(uint16_t x, uint16_t y, uint16_t cols, uint16_t rows) {
|
||||
TerminalT *terminal = (TerminalT *)malloc(sizeof(TerminalT));
|
||||
WidgetT *widget = NULL;
|
||||
uint16_t w;
|
||||
uint16_t h;
|
||||
|
||||
if (!terminal) return NULL;
|
||||
|
||||
// Default font. Also see terminalInit.
|
||||
w = fontWidthGet(_guiFont8) * cols;
|
||||
h = fontHeightGet(_guiFont8) * rows;
|
||||
|
||||
widget = widgetInit(W(terminal), MAGIC_TERMINAL, x, y, w, h, 0, 0, 0, 0);
|
||||
if (!widget) {
|
||||
free(terminal);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
terminal = (TerminalT *)terminalInit((WidgetT *)terminal, cols, rows);
|
||||
if (!terminal) {
|
||||
free(terminal);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return terminal;
|
||||
}
|
||||
|
||||
|
||||
static void terminalPaint(WidgetT *widget, RectT pos) {
|
||||
TerminalT *t = (TerminalT *)widget;
|
||||
uint16_t x;
|
||||
uint16_t y;
|
||||
uint16_t xp;
|
||||
uint16_t yp;
|
||||
char c[2];
|
||||
|
||||
if (GUI_GET_FLAG(widget, WIDGET_FLAG_DIRTY)) {
|
||||
|
||||
c[1] = 0;
|
||||
|
||||
yp = pos.y;
|
||||
for (y=0; y<t->rows; y++) {
|
||||
xp = pos.x;
|
||||
for (x=0; x<t->cols; x++) {
|
||||
if (TERMINAL_CELL_GET_FLAG(t, x, y, TERMINAL_FLAG_DIRTY)) {
|
||||
c[0] = t->cells[x][y].character;
|
||||
fontRender(t->font, c, t->palette[t->cells[x][y].foreground], t->palette[t->cells[x][y].background], xp, yp);
|
||||
TERMINAL_CELL_CLEAR_FLAG(t, x, y, TERMINAL_FLAG_DIRTY);
|
||||
}
|
||||
xp += fontWidthGet(t->font);
|
||||
}
|
||||
yp += fontHeightGet(t->font);
|
||||
}
|
||||
|
||||
GUI_CLEAR_FLAG(widget, WIDGET_FLAG_DIRTY);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void terminalPrint(TerminalT *terminal, char *string) {
|
||||
uint16_t i;
|
||||
|
||||
for (i=0; i<strlen(string); i++) {
|
||||
terminalPrintChar(terminal, string[i]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void terminalPrintChar(TerminalT *terminal, uint8_t c) {
|
||||
int16_t x;
|
||||
int16_t y;
|
||||
uint16_t p;
|
||||
|
||||
// Find leading ESC.
|
||||
if (c == 27 && !terminal->escFound && !terminal->inEscape) {
|
||||
terminal->escFound = 1;
|
||||
return;
|
||||
}
|
||||
|
||||
// Find [.
|
||||
if (c == '[' && terminal->escFound && !terminal->inEscape) {
|
||||
terminal->inEscape = 1;
|
||||
return;
|
||||
}
|
||||
|
||||
// Is this a sequence that is ESC and then not [ ?
|
||||
if (terminal->escFound && !terminal->inEscape) {
|
||||
terminalSequenceReset(terminal);
|
||||
return;
|
||||
}
|
||||
|
||||
if (terminal->inEscape) {
|
||||
switch (c) {
|
||||
|
||||
case '[':
|
||||
case 27:
|
||||
// ESC sequence inside sequence. Invalid ANSIBBS.
|
||||
//***TODO*** Can stick custom sequences here.
|
||||
break;
|
||||
|
||||
// End of a parameter
|
||||
case ';':
|
||||
arrput(terminal->parameters, strdup(terminal->number));
|
||||
terminal->number[0] = 0;
|
||||
terminal->numberIndex = 0;
|
||||
break;
|
||||
|
||||
// Cursor up.
|
||||
case 'A':
|
||||
y = terminalConvertToInt(terminal->number, 1);
|
||||
terminalCursorMove(terminal, terminal->cursorX, terminal->cursorY - y);
|
||||
terminalSequenceReset(terminal);
|
||||
break;
|
||||
|
||||
// Cursor down.
|
||||
case 'B':
|
||||
y = terminalConvertToInt(terminal->number, 1);
|
||||
terminalCursorMove(terminal, terminal->cursorX, terminal->cursorY + y);
|
||||
terminalSequenceReset(terminal);
|
||||
break;
|
||||
|
||||
// Cursor forward.
|
||||
case 'C':
|
||||
x = terminalConvertToInt(terminal->number, 1);
|
||||
terminalCursorMove(terminal, terminal->cursorX + x, terminal->cursorY);
|
||||
terminalSequenceReset(terminal);
|
||||
break;
|
||||
|
||||
// Cursor backward.
|
||||
case 'D':
|
||||
x = terminalConvertToInt(terminal->number, 1);
|
||||
terminalCursorMove(terminal, terminal->cursorX - x, terminal->cursorY);
|
||||
terminalSequenceReset(terminal);
|
||||
break;
|
||||
|
||||
// Cursor line down.
|
||||
case 'E':
|
||||
y = terminalConvertToInt(terminal->number, 1);
|
||||
terminalCursorMove(terminal, 1, terminal->cursorY + y);
|
||||
//***TODO*** This should allow scrolling.
|
||||
terminalSequenceReset(terminal);
|
||||
break;
|
||||
|
||||
// Cursor line up.
|
||||
case 'F':
|
||||
y = terminalConvertToInt(terminal->number, 1);
|
||||
terminalCursorMove(terminal, 1, terminal->cursorY - y);
|
||||
//***TODO*** This should allow scrolling.
|
||||
terminalSequenceReset(terminal);
|
||||
break;
|
||||
|
||||
// Cursor horizontal absolute.
|
||||
case 'G':
|
||||
x = terminalConvertToInt(terminal->number, 1);
|
||||
terminalCursorMove(terminal, x, terminal->cursorY);
|
||||
terminalSequenceReset(terminal);
|
||||
break;
|
||||
|
||||
// Cursor move.
|
||||
case 'H':
|
||||
case 'f':
|
||||
switch (arrlen(terminal->parameters)) {
|
||||
// Cursor vertical absolute. Kinda. Moves X to 1.
|
||||
case 0:
|
||||
y = terminalConvertToInt(terminal->number, 1);
|
||||
terminalCursorMove(terminal, 1, y);
|
||||
break;
|
||||
|
||||
// Absolute position.
|
||||
case 1:
|
||||
x = terminalConvertToInt(terminal->parameters[0], 1);
|
||||
y = terminalConvertToInt(terminal->number, 1);
|
||||
terminalCursorMove(terminal, x, y);
|
||||
break;
|
||||
|
||||
// Invalid nonsense.
|
||||
default:
|
||||
break;
|
||||
}
|
||||
terminalSequenceReset(terminal);
|
||||
break;
|
||||
|
||||
// Clear display.
|
||||
case 'J':
|
||||
if (arrlen(terminal->parameters) == 0 && terminalConvertToInt(terminal->number, 1) == 2) {
|
||||
terminalScreenClear(terminal);
|
||||
terminalCursorMove(terminal, 1, 1);
|
||||
}
|
||||
terminalSequenceReset(terminal);
|
||||
break;
|
||||
|
||||
// Clear from cursor to end of line.
|
||||
case 'K':
|
||||
x = terminalConvertToInt(terminal->number, 0);
|
||||
if (x == 0) {
|
||||
for (y=terminal->cursorX-1; y<terminal->cols; y++) {
|
||||
terminal->cells[y][terminal->cursorY - 1].character = ' ';
|
||||
TERMINAL_CELL_SET_FLAG(terminal, y, terminal->cursorY - 1, TERMINAL_FLAG_DIRTY);
|
||||
GUI_SET_FLAG((WidgetT *)terminal, WIDGET_FLAG_DIRTY);
|
||||
}
|
||||
} else {
|
||||
//***TODO*** Unimplemented line clear.
|
||||
}
|
||||
terminalSequenceReset(terminal);
|
||||
break;
|
||||
|
||||
// Insert lines.
|
||||
case 'L':
|
||||
//***TODO*** Unimplemented.
|
||||
terminalSequenceReset(terminal);
|
||||
break;
|
||||
|
||||
// Delete lines.
|
||||
case 'M':
|
||||
//***TODO*** Unimplemented.
|
||||
terminalSequenceReset(terminal);
|
||||
break;
|
||||
|
||||
// Delete characters.
|
||||
case 'P':
|
||||
//***TODO*** Unimplemented.
|
||||
terminalSequenceReset(terminal);
|
||||
break;
|
||||
|
||||
// Scroll up.
|
||||
case 'S':
|
||||
//***TODO*** Unimplemented.
|
||||
terminalSequenceReset(terminal);
|
||||
break;
|
||||
|
||||
// Scroll down.
|
||||
case 'T':
|
||||
//***TODO*** Unimplemented.
|
||||
terminalSequenceReset(terminal);
|
||||
break;
|
||||
|
||||
// Clear screen with normal attribute.
|
||||
case 'U':
|
||||
x = terminal->background;
|
||||
terminal->background = TERMINAL_COLOR_BLACK;
|
||||
terminalScreenClear(terminal);
|
||||
terminal->background = x;
|
||||
terminalCursorMove(terminal, 1, 1);
|
||||
terminalSequenceReset(terminal);
|
||||
break;
|
||||
|
||||
// Back-TAB.
|
||||
case 'Z':
|
||||
//***TODO*** Unimplemented.
|
||||
terminalSequenceReset(terminal);
|
||||
break;
|
||||
|
||||
// Set attributes.
|
||||
case 'm':
|
||||
arrput(terminal->parameters, strdup(terminal->number));
|
||||
for (p=0; p<arrlen(terminal->parameters); p++) {
|
||||
x = terminalConvertToInt(terminal->parameters[p], 0);
|
||||
switch (x) {
|
||||
// Reset.
|
||||
case 0:
|
||||
terminal->bold = 0;
|
||||
terminal->blink = 0;
|
||||
terminal->reverse = 0;
|
||||
terminal->foreground = TERMINAL_COLOR_LIGHT_GRAY;
|
||||
terminal->background = TERMINAL_COLOR_BLACK;
|
||||
break;
|
||||
|
||||
// Bold.
|
||||
case 1:
|
||||
terminal->bold = 1;
|
||||
break;
|
||||
|
||||
// Blink slow.
|
||||
case 5:
|
||||
terminal->blink = TERMINAL_FLAG_BLINK_SLOW;
|
||||
break;
|
||||
|
||||
// Blink fast.
|
||||
case 6:
|
||||
terminal->blink = TERMINAL_FLAG_BLINK_FAST;
|
||||
break;
|
||||
|
||||
// Reverse.
|
||||
case 7:
|
||||
if (!terminal->reverse) {
|
||||
x = terminal->foreground;
|
||||
terminal->foreground = terminal->background;
|
||||
terminal->background = x;
|
||||
terminal->reverse = 1;
|
||||
}
|
||||
break;
|
||||
|
||||
// Normal intensity. (22 is the actual code, unsure exactly what 21 is.)
|
||||
case 21:
|
||||
case 22:
|
||||
terminal->bold = 0;
|
||||
break;
|
||||
|
||||
// Steady.
|
||||
case 25:
|
||||
terminal->blink = 0;
|
||||
break;
|
||||
|
||||
// Un-reverse?
|
||||
case 27:
|
||||
if (terminal->reverse) {
|
||||
x = terminal->foreground;
|
||||
terminal->foreground = terminal->background;
|
||||
terminal->background = x;
|
||||
terminal->reverse = 0;
|
||||
}
|
||||
break;
|
||||
|
||||
// Color change.
|
||||
default:
|
||||
if (x > 29 && x < 38) terminal->foreground = x - 30;
|
||||
if (x > 39 && x < 48) terminal->background = x - 40;
|
||||
break;
|
||||
|
||||
} // switch (x)
|
||||
}
|
||||
terminalSequenceReset(terminal);
|
||||
break;
|
||||
|
||||
// Define scroll region.
|
||||
case 'r':
|
||||
//***TODO*** Unimplemented.
|
||||
terminalSequenceReset(terminal);
|
||||
break;
|
||||
|
||||
// Cursor save.
|
||||
case 's':
|
||||
terminal->saveX = terminal->cursorX;
|
||||
terminal->saveY = terminal->cursorY;
|
||||
terminalSequenceReset(terminal);
|
||||
break;
|
||||
|
||||
// Cursor restore.
|
||||
case 'u':
|
||||
terminalCursorMove(terminal, terminal->saveX, terminal->saveY);
|
||||
terminalSequenceReset(terminal);
|
||||
break;
|
||||
|
||||
// Something else.
|
||||
default:
|
||||
// Number?
|
||||
if (c >= '0' && c <= '9') {
|
||||
terminal->number[terminal->numberIndex++] = c;
|
||||
terminal->number[terminal->numberIndex] = 0;
|
||||
} else {
|
||||
// Unknown sequence.
|
||||
terminalSequenceReset(terminal);
|
||||
}
|
||||
|
||||
} // switch (c)
|
||||
|
||||
} else { // inEscape
|
||||
|
||||
switch (c) {
|
||||
|
||||
// Bell.
|
||||
case 7:
|
||||
//***TODO*** Unimplemented.
|
||||
break;
|
||||
|
||||
// Backspace.
|
||||
case 8:
|
||||
case 128:
|
||||
//***TODO*** Unimplemented.
|
||||
break;
|
||||
|
||||
// TAB
|
||||
case 9:
|
||||
//***TODO*** Unimplemented.
|
||||
break;
|
||||
|
||||
// Line feed.
|
||||
case 10:
|
||||
terminal->cursorY++;
|
||||
if (terminal->cursorY > terminal->rows) {
|
||||
terminal->cursorY--;
|
||||
//***TODO*** Scroll.
|
||||
}
|
||||
terminalCursorMove(terminal, terminal->cursorX, terminal->cursorY);
|
||||
break;
|
||||
|
||||
// Clear screen.
|
||||
case 12:
|
||||
x = terminal->background;
|
||||
terminal->background = TERMINAL_COLOR_BLACK;
|
||||
terminalScreenClear(terminal);
|
||||
terminal->background = x;
|
||||
terminalCursorMove(terminal, 1, 1);
|
||||
break;
|
||||
|
||||
// Carrage return.
|
||||
case 13:
|
||||
terminalCursorMove(terminal, 1, terminal->cursorY);
|
||||
break;
|
||||
|
||||
// Non-special character.
|
||||
default:
|
||||
// Render character.
|
||||
terminal->cells[terminal->cursorX - 1][terminal->cursorY - 1].character = c;
|
||||
terminal->cells[terminal->cursorX - 1][terminal->cursorY - 1].background = terminal->background;
|
||||
terminal->cells[terminal->cursorX - 1][terminal->cursorY - 1].foreground = terminal->foreground + (terminal->bold ? 8 : 0);
|
||||
terminal->cells[terminal->cursorX - 1][terminal->cursorY - 1].flags = 0;
|
||||
if (terminal->blink == TERMINAL_FLAG_BLINK_SLOW) TERMINAL_CELL_SET_FLAG(terminal, terminal->cursorX - 1, terminal->cursorY - 1, TERMINAL_FLAG_BLINK_SLOW);
|
||||
if (terminal->blink == TERMINAL_FLAG_BLINK_FAST) TERMINAL_CELL_SET_FLAG(terminal, terminal->cursorX - 1, terminal->cursorY - 1, TERMINAL_FLAG_BLINK_FAST);
|
||||
TERMINAL_CELL_SET_FLAG(terminal, terminal->cursorX - 1, terminal->cursorY - 1, TERMINAL_FLAG_DIRTY);
|
||||
GUI_SET_FLAG((WidgetT *)terminal, WIDGET_FLAG_DIRTY);
|
||||
// Move cursor.
|
||||
terminal->cursorX++;
|
||||
if (terminal->cursorX > terminal->cols) {
|
||||
terminal->cursorX = 1;
|
||||
terminal->cursorY++;
|
||||
if (terminal->cursorY > terminal->rows) {
|
||||
terminal->cursorY--;
|
||||
//***TODO*** Scroll.
|
||||
}
|
||||
}
|
||||
terminalCursorMove(terminal, terminal->cursorX, terminal->cursorY);
|
||||
break;
|
||||
|
||||
} // switch (c)
|
||||
|
||||
} // inEscape
|
||||
}
|
||||
|
||||
|
||||
void terminalScreenClear(TerminalT *terminal) {
|
||||
uint16_t x;
|
||||
uint16_t y;
|
||||
|
||||
// Does not move cursor.
|
||||
// Should this clear the blink flags?
|
||||
|
||||
for (y=0; y<terminal->rows; y++) {
|
||||
for (x=0; x<terminal->cols; x++) {
|
||||
terminal->cells[x][y].character = ' ';
|
||||
TERMINAL_CELL_SET_FLAG(terminal, x, y, TERMINAL_FLAG_DIRTY);
|
||||
}
|
||||
}
|
||||
GUI_SET_FLAG((WidgetT *)terminal, WIDGET_FLAG_DIRTY);
|
||||
|
||||
}
|
||||
|
||||
|
||||
static void terminalSequenceReset(TerminalT *terminal) {
|
||||
terminal->escFound = 0;
|
||||
terminal->inEscape = 0;
|
||||
terminal->number[0] = 0;
|
||||
terminal->numberIndex = 0;
|
||||
|
||||
if (terminal->parameters != NULL) {
|
||||
while (arrlen(terminal->parameters) > 0) {
|
||||
free(arrpop(terminal->parameters));
|
||||
}
|
||||
terminal->parameters = NULL;
|
||||
}
|
||||
}
|
97
client/src/gui/terminal.h
Normal file
97
client/src/gui/terminal.h
Normal file
|
@ -0,0 +1,97 @@
|
|||
/*
|
||||
* Kangaroo Punch MultiPlayer Game Server Mark II
|
||||
* Copyright (C) 2020-2021 Scott Duensing
|
||||
*
|
||||
* This program 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 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program 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 this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#ifndef TERMINAL_H
|
||||
#define TERMINAL_H
|
||||
|
||||
|
||||
#include "gui.h"
|
||||
#include "widget.h"
|
||||
|
||||
|
||||
enum TerminalColorsE {
|
||||
TERMINAL_COLOR_BLACK = 0,
|
||||
TERMINAL_COLOR_BLUE,
|
||||
TERMINAL_COLOR_GREEN,
|
||||
TERMINAL_COLOR_CYAN,
|
||||
TERMINAL_COLOR_RED,
|
||||
TERMINAL_COLOR_MAGENTA,
|
||||
TERMINAL_COLOR_BROWN,
|
||||
TERMINAL_COLOR_LIGHT_GRAY,
|
||||
TERMINAL_COLOR_DARK_GRAY,
|
||||
TERMINAL_COLOR_BRIGHT_BLUE,
|
||||
TERMINAL_COLOR_BRIGHT_GREEN,
|
||||
TERMINAL_COLOR_BRIGHT_CYAN,
|
||||
TERMINAL_COLOR_BRIGHT_RED,
|
||||
TERMINAL_COLOR_BRIGHT_MAGENTA,
|
||||
TERMINAL_COLOR_YELLOW,
|
||||
TERMINAL_COLOR_WHITE,
|
||||
TERMINAL_COLOR_COUNT
|
||||
};
|
||||
|
||||
enum TerminalFlagsE {
|
||||
TERMINAL_FLAG_DIRTY = 0,
|
||||
TERMINAL_FLAG_BLINK_FAST, // Must be = 1, don't move!
|
||||
TERMINAL_FLAG_BLINK_SLOW // Must be = 2, don't move!
|
||||
};
|
||||
|
||||
|
||||
typedef struct CellS {
|
||||
uint8_t character;
|
||||
ColorT foreground;
|
||||
ColorT background;
|
||||
uint8_t flags;
|
||||
} CellT;
|
||||
|
||||
typedef struct TerminalS {
|
||||
WidgetT base; // Must be first in every widget
|
||||
FontT *font;
|
||||
uint8_t foreground;
|
||||
uint8_t background;
|
||||
uint8_t bold;
|
||||
uint8_t blink;
|
||||
uint8_t reverse;
|
||||
uint16_t cursorX; // Cursor positions are 1 based.
|
||||
uint16_t cursorY; // Cursor positions are 1 based.
|
||||
uint16_t saveX; // Cursor positions are 1 based.
|
||||
uint16_t saveY; // Cursor positions are 1 based.
|
||||
uint16_t cols;
|
||||
uint16_t rows;
|
||||
ColorT palette[TERMINAL_COLOR_COUNT];
|
||||
CellT **cells;
|
||||
uint8_t escFound;
|
||||
uint8_t inEscape;
|
||||
char number[7]; // Maximum 6 digits / sign.
|
||||
uint8_t numberIndex;
|
||||
char **parameters;
|
||||
} TerminalT;
|
||||
|
||||
|
||||
void terminalBackgroundSet(TerminalT *terminal, uint8_t color);
|
||||
void terminalCursorMove(TerminalT *terminal, uint16_t col, uint16_t row);
|
||||
void terminalForegroundSet(TerminalT *terminal, uint8_t color);
|
||||
WidgetT *terminalInit(WidgetT *widget, uint16_t cols, uint16_t rows);
|
||||
TerminalT *terminalNew(uint16_t x, uint16_t y, uint16_t cols, uint16_t rows);
|
||||
void terminalPrint(TerminalT *terminal, char *string);
|
||||
void terminalPrintChar(TerminalT *terminal, uint8_t c);
|
||||
void terminalScreenClear(TerminalT *terminal);
|
||||
|
||||
|
||||
#endif // TERMINAL_H
|
|
@ -27,14 +27,12 @@
|
|||
* - Methods that can change the width of a widget (such as setTitle) need to repaint the parent window as well
|
||||
* - Metrics, colors, etc. should be defined in each widget and not in GUI
|
||||
* - Widgets should support a "changed" callback that can cancel the change
|
||||
* - Add pgup/pgdn to UpDown
|
||||
* - Add home/end to Textbox
|
||||
* - Move drawing and surface code into it's own file
|
||||
* - Use LabelT in all widgets that have a label
|
||||
* - Find a light grey to replace white widget data areas
|
||||
* - No thumb in listbox scrollbar
|
||||
*
|
||||
* - Random crash after adding listbox
|
||||
* - Random crash after adding listbox - looks memwatch / task related
|
||||
*/
|
||||
|
||||
|
||||
|
@ -61,6 +59,7 @@
|
|||
#include "textbox.h"
|
||||
#include "updown.h"
|
||||
#include "listbox.h"
|
||||
#include "terminal.h"
|
||||
|
||||
|
||||
void buttonClick(WidgetT *widget) {
|
||||
|
@ -138,6 +137,7 @@ void test(void *data) {
|
|||
WindowT *w1 = NULL;
|
||||
WindowT *w2 = NULL;
|
||||
WindowT *w3 = NULL;
|
||||
WindowT *w4 = NULL;
|
||||
ButtonT *b1 = NULL;
|
||||
LabelT *l1 = NULL;
|
||||
CheckboxT *c1 = NULL;
|
||||
|
@ -149,20 +149,26 @@ void test(void *data) {
|
|||
RadioT *r3b = NULL;
|
||||
PictureT *p1 = NULL;
|
||||
FrameT *f1 = NULL;
|
||||
TextboxT *t1 = NULL;
|
||||
TextboxT *t2 = NULL;
|
||||
TextboxT *tb1 = NULL;
|
||||
TextboxT *tb2 = NULL;
|
||||
UpdownT *u1 = NULL;
|
||||
ListboxT *lb1 = NULL;
|
||||
TerminalT *t1 = NULL;
|
||||
FILE *in = NULL;
|
||||
char *buffer = NULL;
|
||||
uint16_t length = 0;
|
||||
|
||||
(void)data;
|
||||
|
||||
// Windows
|
||||
w1 = windowNew(25, 25, 300, 200, "Window 1");
|
||||
w1 = windowNew(300, 25, 300, 200, "Window 1");
|
||||
guiAttach(W(desktop), W(w1));
|
||||
w2 = windowNew(150, 150, 300, 200, "Window 2");
|
||||
guiAttach(W(desktop), W(w2));
|
||||
w3 = windowNew(300, 300, 300, 200, "Window 3");
|
||||
guiAttach(W(desktop), W(w3));
|
||||
w4 = windowNew(10, 10, 7 + 8 + (80 * 8), 26 + 8 + (24 * 8), "Terminal");
|
||||
guiAttach(W(desktop), W(w4));
|
||||
|
||||
// Window 1
|
||||
p1 = pictureNew(0, 0, "kanga.png");
|
||||
|
@ -196,12 +202,12 @@ void test(void *data) {
|
|||
guiAttach(W(w2), W(r3b));
|
||||
radioSetSelected(r1a);
|
||||
radioSetSelected(r2b);
|
||||
t1 = textboxNew(10, 60, 265, "Test Textbox");
|
||||
textboxSetValue(t1, "Really long text string to edit!");
|
||||
guiAttach(W(w2), W(t1));
|
||||
t2 = textboxNew(10, 85, 265, "Test Textbox");
|
||||
textboxSetValue(t2, "Short string.");
|
||||
guiAttach(W(w2), W(t2));
|
||||
tb1 = textboxNew(10, 60, 265, "Test Textbox");
|
||||
textboxSetValue(tb1, "Really long text string to edit!");
|
||||
guiAttach(W(w2), W(tb1));
|
||||
tb2 = textboxNew(10, 85, 265, "Test Textbox");
|
||||
textboxSetValue(tb2, "Short string.");
|
||||
guiAttach(W(w2), W(tb2));
|
||||
u1 = updownNew(10, 110, 0, 1024, 5, "UpDown");
|
||||
guiAttach(W(w2), W(u1));
|
||||
|
||||
|
@ -214,6 +220,20 @@ void test(void *data) {
|
|||
guiAttach(W(f1), W(l1));
|
||||
c1 = checkboxNew(10, 65, "Test Checkbox");
|
||||
guiAttach(W(f1), W(c1));
|
||||
|
||||
// Window 4 - Terminal
|
||||
t1 = terminalNew(0, 0, 80, 24);
|
||||
guiAttach(W(w4), W(t1));
|
||||
in = fopen("kanga.ans", "rt");
|
||||
fseek(in, 0, SEEK_END);
|
||||
length = ftell(in);
|
||||
fseek(in, 0, SEEK_SET);
|
||||
buffer = (char *)malloc(length + 1);
|
||||
fread(buffer, 1, length, in);
|
||||
fclose(in);
|
||||
buffer[length] = 0;
|
||||
terminalPrint(t1, buffer);
|
||||
free(buffer);
|
||||
}
|
||||
|
||||
|
||||
|
|
48
client/src/thirdparty/serial/README.md
vendored
Normal file
48
client/src/thirdparty/serial/README.md
vendored
Normal file
|
@ -0,0 +1,48 @@
|
|||
DOS Serial Library
|
||||
==================
|
||||
|
||||
A serial port (UART) library for DOS written back in the days when 16-bit
|
||||
systems were still a going concern and far pointers were a thing.
|
||||
|
||||
I'm putting it on Github because I still think it's way cool, and who knows...
|
||||
Perhaps someone, somewhere, is in dire need of a serial library for DOS (I've
|
||||
needed it from time to time to deal with some DOS based embedded piece of crap).
|
||||
|
||||
Supports simultaneous communication over up to 4 serial ports.
|
||||
|
||||
Have a look at term.c for an example of how to use it.
|
||||
|
||||
|
||||
|
||||
How do I build it?
|
||||
==================
|
||||
|
||||
Good question! It was built to compile under Borland C++ 3 and whatever
|
||||
Microsoft compiler happened to be current at the time. It conforms to ANSI C
|
||||
(1989) and it doesn't do anything too crazy, so it shouldn't be too bad in a
|
||||
more modern compiler. Have a go and let me know how it works!
|
||||
|
||||
|
||||
|
||||
License
|
||||
=======
|
||||
|
||||
Copyright 1998 Karl Stenerud
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
1647
client/src/thirdparty/serial/serial.c
vendored
Normal file
1647
client/src/thirdparty/serial/serial.c
vendored
Normal file
File diff suppressed because it is too large
Load diff
195
client/src/thirdparty/serial/serial.h
vendored
Normal file
195
client/src/thirdparty/serial/serial.h
vendored
Normal file
|
@ -0,0 +1,195 @@
|
|||
/* Serial Library 1.4 (22-Jun-2000) (c) 1998 Karl Stenerud
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef SERIAL__HEADER
|
||||
#define SERIAL__HEADER
|
||||
|
||||
/* COM Ports */
|
||||
#define COM_1 0
|
||||
#define COM_2 1
|
||||
#define COM_3 2
|
||||
#define COM_4 3
|
||||
|
||||
/* Handshaking Modes */
|
||||
#define SER_HANDSHAKING_NONE 0
|
||||
#define SER_HANDSHAKING_XONXOFF 1
|
||||
#define SER_HANDSHAKING_RTSCTS 2
|
||||
#define SER_HANDSHAKING_DTRDSR 3
|
||||
|
||||
/* Error Codes */
|
||||
#define SER_SUCCESS 0 /* Function completed successfully */
|
||||
#define SER_ERR_UNKNOWN -1 /* An unknown error occured */
|
||||
#define SER_ERR_NOT_OPEN -2 /* The specified COM port is not opened */
|
||||
#define SER_ERR_ALREADY_OPEN -3 /* The specified COM port is already opened */
|
||||
#define SER_ERR_NO_UART -4 /* Could not find a UART for this COM port */
|
||||
#define SER_ERR_INVALID_COMPORT -5 /* User specified an invalid COM port */
|
||||
#define SER_ERR_INVALID_BASE -6 /* User specified an invalid base address */
|
||||
#define SER_ERR_INVALID_IRQ -7 /* User specified an invalid IRQ number */
|
||||
#define SER_ERR_INVALID_BPS -8 /* User specified an invalid BPS rate */
|
||||
#define SER_ERR_INVALID_DATA_BITS -9 /* User specified an invalid number of data bits */
|
||||
#define SER_ERR_INVALID_PARITY -10 /* User specified an invalid parity type */
|
||||
#define SER_ERR_INVALID_STOP_BITS -11 /* User specified an invalid number of stop bits */
|
||||
#define SER_ERR_INVALID_HANDSHAKING -12 /* User specified an invalid handshaking type */
|
||||
#define SER_ERR_INVALID_FIFO_THRESHOLD -13 /* User specified an invalid fifo threshold value */
|
||||
#define SER_ERR_NULL_PTR -14 /* User specified a buffer address that was NULL */
|
||||
#define SER_ERR_IRQ_NOT_FOUND -15 /* Could not find an IRQ for the specified COM port */
|
||||
#define SER_ERR_LOCK_MEM -16 /* Could not lock memory in DPMI mode */
|
||||
|
||||
|
||||
/* Name: serial_open()
|
||||
*
|
||||
* Desc: Finds and initializes the specified COM port.
|
||||
*
|
||||
* Params: int com: Communications port (COM_1, COM_2, COM_3, COM_4)
|
||||
* long bps: Bits per second.
|
||||
* (50, 75, 110, 150, 300, 600, 1200, 2400, 4800,
|
||||
* 9600, 19200, 38400, 57600, 115200)
|
||||
* int data_bits: Number of data word bits (5-8)
|
||||
* char parity: Parity mode ('e', 'o', 'n', 'm', 's')
|
||||
* int stop_bits: Stop bits (1-2). If data_bits=5 and stop_bits=2,
|
||||
* actual stop bits is 1.5.
|
||||
* int handshaking: Handshaking mode
|
||||
* (SER_HANDSHAKING_NONE, SER_HANDSHAKING_XONXOFF,
|
||||
* SER_HANDSHAKING_RTSCTS, SER_HANDSHAKING_DTRDSR)
|
||||
*
|
||||
* Return: SER_SUCCESS or an error code
|
||||
*/
|
||||
int serial_open(int com, long bps, int data_bits, char parity, int stop_bits, int handshaking);
|
||||
|
||||
|
||||
/* Name: serial_close()
|
||||
*
|
||||
* Desc: Clean up and close the specified serial port.
|
||||
*
|
||||
* Params: int com: Communications port (COM_1, COM_2, COM_3, COM_4)
|
||||
*
|
||||
* Return: SER_SUCCESS or an error code
|
||||
*/
|
||||
int serial_close(int com);
|
||||
|
||||
|
||||
/* Name: serial_read()
|
||||
*
|
||||
* Desc: Read data from the specified serial port buffer.
|
||||
*
|
||||
* Params: int com: Communications port (COM_1, COM_2, COM_3, COM_4)
|
||||
* char* data: Pointer to data buffer
|
||||
* int len: Number of bytes to read
|
||||
*
|
||||
* Return: number of bytes read or an error code
|
||||
*/
|
||||
int serial_read(int com, char* data, int len);
|
||||
|
||||
|
||||
/* Name: serial_write() and serial_write_buffered()
|
||||
*
|
||||
* Desc: Write data to the serial port.
|
||||
* serial_write() will write the data directly to serial port and will
|
||||
* block until it has completely sent the data or handshaking has
|
||||
* stopped output transmission while serial_write_buffered() will copy
|
||||
* as much as possible data bytes to the transmit buffer and will return
|
||||
* immediately enabling asynchronous output.
|
||||
*
|
||||
* Params: int com: Communications port (COM_1, COM_2, COM_3, COM_4)
|
||||
* char* data: Pointer to data buffer
|
||||
* int len: Number of bytes to write
|
||||
*
|
||||
* Return: number of bytes written or an error code
|
||||
*/
|
||||
int serial_write (int com, const char* data, int len);
|
||||
int serial_write_buffered(int com, const char* data, int len);
|
||||
|
||||
|
||||
/* Name: serial_set()
|
||||
*
|
||||
* Desc: Change the specified serial port's settings.
|
||||
*
|
||||
* Params: int com: Communications port (COM_1, COM_2, COM_3, COM_4)
|
||||
* long bps: Bits per second.
|
||||
* (50, 75, 110, 150, 300, 600, 1200, 2400, 4800,
|
||||
* 9600, 19200, 38400, 57600, 115200)
|
||||
* int data_bits: Data bits (5, 6, 7, or 8)
|
||||
* char parity: Parity ('n' = none, 'e' = even, 'o' = odd, 'm' = mark, 's' = space)
|
||||
* int stop_bits: Stop bits (1-2). If data_bits=5 and stop_bits=2,
|
||||
* actual stop bits is 1.5.
|
||||
* int handshaking: Handshaking type (see handshaking modes at top of file)
|
||||
*
|
||||
* Return: SER_SUCCESS or an error code
|
||||
*/
|
||||
int serial_set(int com, long bps, int data_bits, char parity, int stop_bits, int handshaking);
|
||||
|
||||
|
||||
/* serial_set_xxx() functions. These take the same arguments
|
||||
* as the corresponding ones in serial_set() and return either
|
||||
* SER_SUCCESS or an error code.
|
||||
*/
|
||||
int serial_set_bps (int com, long bps);
|
||||
int serial_set_parity (int com, char parity);
|
||||
int serial_set_data (int com, int data);
|
||||
int serial_set_stop (int com, int stop);
|
||||
int serial_set_handshaking (int com, int handshaking);
|
||||
|
||||
/* Advanced settings. Use these only if you know what you are doing. */
|
||||
|
||||
/* UART's FIFO threshold -- 14, 8, 4, 1, or 0 (off) */
|
||||
int serial_set_fifo_threshold(int com, int threshold);
|
||||
/* UART's base address */
|
||||
int serial_set_base (int com, int base);
|
||||
/* UART's IRQ */
|
||||
int serial_set_irq (int com, int base);
|
||||
|
||||
int serial_set_rts(int comport, int rts);
|
||||
int serial_set_dtr(int comport, int dtr);
|
||||
|
||||
int serial_set_mcr(int comport, int mcr);
|
||||
|
||||
|
||||
/* serial_get_xxx() functions. These return the same types as are supplied
|
||||
* to serial_set(). The returned type may be negative, in which case it
|
||||
* is an error code.
|
||||
*/
|
||||
int serial_get_base (int com);
|
||||
int serial_get_irq (int com);
|
||||
long serial_get_bps (int com);
|
||||
char serial_get_parity (int com);
|
||||
int serial_get_data (int com);
|
||||
int serial_get_stop (int com);
|
||||
int serial_get_handshaking (int com);
|
||||
|
||||
|
||||
int serial_get_rts(int comport);
|
||||
int serial_get_dtr(int comport);
|
||||
int serial_get_cts(int comport);
|
||||
int serial_get_dsr(int comport);
|
||||
|
||||
int serial_get_mcr(int comport);
|
||||
int serial_get_msr(int comport);
|
||||
int serial_get_lsr(int comport);
|
||||
|
||||
|
||||
/* get number of bytes or discard data in TX/RX buffers
|
||||
*/
|
||||
int serial_get_tx_buffered(int comport);
|
||||
int serial_get_rx_buffered(int comport);
|
||||
int serial_clear_tx_buffer(int comport);
|
||||
int serial_clear_rx_buffer(int comport);
|
||||
|
||||
#endif
|
104
client/src/thirdparty/serial/term.C
vendored
Normal file
104
client/src/thirdparty/serial/term.C
vendored
Normal file
|
@ -0,0 +1,104 @@
|
|||
/* A simple terminal program for testing the serial library by Karl Stenerud
|
||||
*/
|
||||
|
||||
#include <conio.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <io.h>
|
||||
#include "serial.h"
|
||||
#include <dos.h>
|
||||
|
||||
char* errors[] =
|
||||
{
|
||||
"Successful",
|
||||
"Unknown error",
|
||||
"Port not open",
|
||||
"Port already open",
|
||||
"No UART found on that comport",
|
||||
"Invalid comport",
|
||||
"Invalid BPS",
|
||||
"Invalid data bits",
|
||||
"Invalid parity",
|
||||
"Invalid stop bits",
|
||||
"Invalid handshaking",
|
||||
"Invalid fifo threshold",
|
||||
"Passed in a NULL pointer",
|
||||
"",
|
||||
"",
|
||||
""
|
||||
};
|
||||
|
||||
char* handshaking[] =
|
||||
{
|
||||
"none",
|
||||
"xon/xoff",
|
||||
"rts/cts",
|
||||
"dtr/dsr",
|
||||
"",
|
||||
""
|
||||
};
|
||||
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
int len;
|
||||
char buff[100];
|
||||
char ch;
|
||||
int rc;
|
||||
int com = COM_1;
|
||||
|
||||
if(argc < 2)
|
||||
{
|
||||
printf("Usage: term <com number>\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
switch(atoi(argv[1]))
|
||||
{
|
||||
case 1:
|
||||
com = COM_1;
|
||||
break;
|
||||
case 2:
|
||||
com = COM_2;
|
||||
break;
|
||||
case 3:
|
||||
com = COM_3;
|
||||
break;
|
||||
case 4:
|
||||
com = COM_4;
|
||||
break;
|
||||
default:
|
||||
printf("%s: invalid com port number\n", argv[1]);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if((rc=serial_open(com, 19200L, 8, 'n', 1, SER_HANDSHAKING_XONXOFF)) != SER_SUCCESS)
|
||||
{
|
||||
printf("Can't open port! (%s)\n", errors[-rc]);
|
||||
return 0;
|
||||
}
|
||||
|
||||
printf("Opened COM%d. Base 0x%03x, IRQ %d, %ld %d%c%d, Handshaking %s\n", com+1,
|
||||
serial_get_base(com), serial_get_irq(com), serial_get_bps(com), serial_get_data(com),
|
||||
(char)serial_get_parity(com), serial_get_stop(com), handshaking[serial_get_handshaking(com)]);
|
||||
|
||||
for(;;)
|
||||
{
|
||||
if(kbhit())
|
||||
{
|
||||
if((ch=(char)getch()) == 0x1b)
|
||||
break;
|
||||
if((rc=serial_write(com, &ch, 1)) < 0)
|
||||
printf("Error writing (%s)\n", errors[-rc]);
|
||||
}
|
||||
if((len=serial_read(com, buff, 100)) > 0)
|
||||
write(1, buff, len);
|
||||
else if(len < 0)
|
||||
printf("Error reading (%s)\n", errors[-len]);
|
||||
}
|
||||
|
||||
if((rc=serial_close(com)) != SER_SUCCESS)
|
||||
printf("Can't close serial port! (%s)\n", errors[-rc]);
|
||||
|
||||
return 0;
|
||||
}
|
Loading…
Add table
Reference in a new issue