📄 mterm.c
字号:
/*
* MICRO-Terminal:
*
* This is a very simple communications program, which provides
* a subset ANSI (VT100) terminal emulation, and basic XMODEM
* (with checksum) file transfer.
*
* If the '-t' option is given, MICRO-Terminal will install
* itself as a TSR (Ram-Resident) program, which can be invoked
* at any time by pressing both SHIFT keys.
*
* This demonstrates the use of the MICRO-C video interface
* and communications library functions for the IBM/PC, as well
* as the "SAVE_VIDEO", "RESTORE_VIDEO" and "TSR" functions.
*
* Copyright 1990 Dave Dunfield
* All rights reserved.
*/
#include \mc\stdio.h /* Standard I/O definitions */
#include \mc\comm.h /* Comm I/O definitions */
#include \mc\tsr.h /* Tsr function definitions */
#include \mc\video.h /* Video I/O definitions */
/* Screen output positions */
#define SETROW 3 /* Screen row for settings display */
#define MSGROW 20 /* Screen row for messages */
#define MENROW 7 /* Screen row for menu items */
#define MAICOL 0 /* Screen column for main menu */
#define SUBCOL 20 /* Screen column for sub menu */
#define FILCOL 5 /* Screen column for file prompt */
#define FILSIZ 50 /* Maximum size of file name */
/* XMODEM parameters */
#define BLOCK_SIZE 128 /* size of transmit blocks */
#define RETRYS 10 /* maximum number of retrys */
#define SOH_TIMEOUT 10 /* How long to wait for start of packet */
#define RX_TIMEOUT 2 /* How long in wait for chars in packet */
#define ACK_TIMEOUT 15 /* How long to wait for acknowlege */
/* Line control codes */
#define SOH 0x01 /* start of header */
#define ACK 0x06 /* Acknowledge */
#define NAK 0x15 /* Negative acknowledge */
#define CAN 0x18 /* Cancel */
#define EOT 0x04 /* end of text */
/* Menu text tables (Used by 'vmenu') */
char *main_menu[] = {
"Terminal Emulation",
"XMODEM Download",
"XMODEM Upload",
"Serial port config",
"Exit to DOS",
0 };
char *setup_menu[] = {
"Comm port",
"Baudrate",
"Data bits",
"Parity",
"Stop bits",
"Xon/Xoff",
0 };
/* Uart configuration static data tables */
unsigned baudvalue[] =
{ _110, _300, _1200, _2400, _4800, _9600, _19200, _38400 };
char *baudtext[] =
{ "110", "300", "1200", "2400", "4800", "9600", "19200", "38400", 0 };
char *databits[] = { "Five", "Six", "Seven", "Eight", 0 };
char *parity[] = { "Odd", "Even", "Mark", "Space", "None", 0 };
char *onetwo[] = { "One", "Two", 0 };
char *flowctrl[] = { "Disabled", "Enabled", 0 };
/* Communications configuration parameters */
int comm = 0, baud = 5, data = 3, par = 4, stop = 0, flow = 1;
/* Misc global variables */
setup_selection = 0, transfer_selection = 0;
char dfile[FILSIZ+1] = "", ufile[FILSIZ+1] = "";
/* Saved video screens, attributes & cursor position */
char sav_buffer[(25*80)*2], sav_attr;
int sav_xy;
char video_save_area[SCR_BUF];
/*
* Main terminal program menu
*/
tty_main()
{
int i;
i = 0; /* Default to top of menu */
save_video(video_save_area);
redraw:
draw_title();
vdraw_box(0, SETROW, 79, 2);
show_settings();
for(;;) {
message("Select function and press ENTER");
if(vmenu(MAICOL, MENROW, main_menu, 0, &i))
continue;
switch(i) {
case 0 : /* Terminal Emulation */
if(!open_comm(flow))
break;
vcursor_line();
restore_screen();
ansi_term();
save_screen();
vcursor_off();
goto redraw;
case 1 : /* Download a file */
if(open_comm(0))
download(dfile);
break;
case 2 : /* Upload a file */
if(open_comm(0))
upload(dfile);
break;
case 3 : /* Setup serial port */
setup();
break;
case 4 : /* Exit to DOS */
Cclose();
restore_video(video_save_area);
return; } }
}
/*
* Open a file for read or write (with overwrite prompt)
*/
FILE *openf(fname, rw)
char *fname, rw;
{
char c, omsg[80], *mode;
FILE *fp;
mode = "read";
fp = fopen(fname, "r"); /* First try and read the file */
if(rw) { /* If writing the file */
mode = "write";
if(fp) {
fclose(fp);
sprintf(omsg, "Overwrite existing %s (Y/N) ?", fname);
message(omsg);
do {
c = toupper(vgetc());
if((c == 0x1B) || (c == 'N'))
return 0; }
while(c != 'Y'); }
fp = fopen(fname,"w"); }
if(!fp) {
sprintf(omsg,"Cannot %s %s (Press ENTER)", mode, fname);
message(omsg);
while(vgetc() != '\n'); }
return fp;
}
/*
* Open comm port with correct settings
*/
open_comm(flow)
char flow;
{
int mode;
/* Calculate the communications parameter value */
mode = ((par << 4) & 0x30) | /* parity type */
(data & 0x03) | /* # data bits */
((stop << 2) & 0x04) | /* # stop bits */
((par < 4) << 3); /* parity enable */
/* Open the communications port */
if(Copen(comm+1, baudvalue[baud], mode, SET_DTR|SET_RTS|OUTPUT_2)) {
message("Cannot open COM port (Press ENTER)");
while(vgetc() != '\n');
return 0; }
/* Remove transparency if XON/XOFF flow control */
disable();
Cflags = (flow) ? Cflags & ~TRANSPARENT : Cflags | TRANSPARENT;
enable();
return -1;
}
/*
* Draw the title header
*/
draw_title()
{
vopen();
V_ATTR = REVERSE;
vdraw_box(0, 0, 79, 2);
vgotoxy(1, 1);
vputf("", 26);
vputf("MICRO-Terminal Version 1.2", 52);
V_ATTR = NORMAL;
vcursor_off();
}
/*
* Draw the file transfer information box
*/
info_box(mode, filename)
char *mode, *filename;
{
vdraw_box(SUBCOL, MENROW+1, 50, 8);
vgotoxy(SUBCOL+2, MENROW+3);
vprintf("%-19s: %s", mode, filename);
vgotoxy(SUBCOL+2, MENROW+5);
vputs("Blocks transferred : 0");
vgotoxy(SUBCOL+2, MENROW+7);
vputs("Transfer status : ");
message("File transfer in progress (ESCAPE to abort)");
}
/*
* Update the transfer status field
*/
transfer_status(text)
char *text
{
vgotoxy(SUBCOL+23, MENROW+7);
vputf(text,10);
}
/*
* Show the current COM port settings
*/
show_settings()
{
vgotoxy(18, SETROW+1);
vprintf("COM%u: %5s,%2d,%5s,%2d Xon/Xoff %-8s",
comm+1, baudtext[baud], data+5, parity[par], stop+1, flowctrl[flow]);
}
/*
* Display a message
*/
message(ptr)
char *ptr;
{
vgotoxy(0, MSGROW);
vcleos();
vmessage(38 - strlen(ptr)/2, MSGROW, ptr);
}
/*
* Save the MICRO-TERMINAL video screen.
*/
save_screen()
{
sav_xy = V_XY;
sav_attr = V_ATTR;
copy_seg(get_ds(), sav_buffer, V_BASE, 0, (25*80)*2);
}
/*
* Restore the MICRO-TERMINAL video screen
*/
restore_screen()
{
copy_seg(V_BASE, 0, get_ds(), sav_buffer, (25*80)*2);
V_ATTR = sav_attr;
V_XY = sav_xy;
vupdatexy();
}
/*
* Comm port setup menu handler
*/
setup()
{
message("Select setting (ESCAPE to cancel)");
for(;;) {
show_settings();
if(vmenu(SUBCOL, MENROW+1, setup_menu, 0, &setup_selection))
return;
switch(setup_selection) {
case 0 : /* Comm port */
vmenu(SUBCOL+11,MENROW+2,onetwo,-1,&comm);
break;
case 1 : /* baudrate */
vmenu(SUBCOL+11,MENROW+2,baudtext,-1,&baud);
break;
case 2 : /* Data bits */
vmenu(SUBCOL+11,MENROW+2,databits,-1,&data);
break;
case 3 : /* Parity */
vmenu(SUBCOL+11,MENROW+2,parity,-1,&par);
break;
case 4 : /* Stop bits */
vmenu(SUBCOL+11,MENROW+2,onetwo,-1,&stop);
break;
case 5 : /* Flow control */
vmenu(SUBCOL+11,MENROW+2,flowctrl,-1,&flow); } }
}
/*
* ANSI (VT100) Function key translation table
*/
char *ansi_keys[] = {
"\x1B[A", "\x1B[B", "\x1B[D", "\x1B[C", /* Arrow keys */
"\x1BOR", "\x1BOS", "\x1BOP", "\x1BOQ", /* PgUp, Pgdn, Home, End */
"\x1BOM", "\x1BOm", "\x1BOp", /* Keypad '+','-' Insert */
"\x7F", "\x08", /* Delete & Backspace */
"\x1BOq", "\x1BOr", "\x1BOs", "\x1BOt", /* F1, F2, F3 & F4 */
"\x1BOu", "\x1BOv", "\x1BOw", "\x1BOx", /* F5, F6, F7 & F8 */
"\x1BOy", "\x1BOp", /* F9 & F10 */
"\x1BOl", "\X1BOn", 0, 0 }; /* Control: Pgup, Pgdn, Home, End */
/*
* Terminal mode using ANSI (VT100) emulation
*/
ansi_term()
{
char c, xy_flag, *ptr;
unsigned x, y, state, value, parm, parms[5];
xy_flag = -1; /* Force initial cursor update */
state = 0; /* Not receiving a control sequence */
for(;;) {
/* Process any input from the comm port */
if((c = Ctestc()) != -1) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -