|
|
1.1 root 1: /***
2: *
3: * TITLE
4: *
5: * terminal.c
6: * Copyright (C) Microsoft Corporation 1987
7: * March 1987
8: *
9: * DESCRIPTION
10: *
11: * This program emulates an ANSI terminal device.
12: *
13: * The device driver COM.SYS must be installed at IPL (Initial Program
14: * Load) by specifying the following in config.sys:
15: * device = COM01.SYS
16: *
17: * To run this program, type the following to the MS OS/2 prompt:
18: *
19: * terminal [filename]
20: *
21: * If a filename is specified, the initialisation of the COM port and
22: * the MODEM will be performed as indicated in the file (creation of this
23: * file is described in options.c). For more details on setting options
24: * pertaining to the COM port and the MODEM, see options.c
25: *
26: * To exit the terminal emulator, type ALT F1.
27: *
28: ***/
29:
30: #include <stdio.h>
31: #include <doscalls.h>
32: #include <subcalls.h>
33: #include <malloc.h>
34: #include <string.h>
35: #include <memory.h>
36: #include <conio.h>
37: #include "term.h"
38:
39: extern void get_options(int, char *[]); /* get com port and modem options */
40: extern void get_com_options(structComOptions *); /* get com options */
41: extern make_modem_conn(void); /* make modem connection */
42: extern modem(void); /* returns TRUE if modem connection was requested */
43: extern void discon_modem(void); /* disconnect modem */
44:
45: void init_com_port(void); /* initialise com port */
46: void far read_com_port(void); /* routine addr for a thread */
47: void write_com_port(void); /* routine addr for another thread */
48: void far pascal handle_signals(int, int); /* BREAK signals handler */
49: void close_conn(void); /*close modem connection & com port*/
50: void far xit(void); /* exit routine for this program */
51:
52: char *ErrMsg[] = {
53: "VIOGETCONFIG",
54: "KBDSETSTATUS",
55: "OUT OF MEMORY",
56: "DOSCREATETHREAD",
57: "DOSCLOSE COMPORT",
58: "DOSDEVIOCTL SETDCB",
59: "DOSREAD",
60: "VIOWRTTTY",
61: "DOSOPEN: check if COM driver is installed",
62: "DOSDEVIOCTL SETBAUD",
63: "DOSDEVIOCTL SETLINECHAR",
64: "DOSDEVIOCTL GETDCB",
65: "KBDCHARIN",
66: "DOSWRITE",
67: "VIOWRTCHARSTRATT",
68: "VIOWRTNCELL",
69: "DOSEXITLIST ADD_ADDR",
70: "VIOSETCURPOS",
71: "VIOGETMODE",
72: "DOSDEVIOCTL FLUSH_XMIT_RECV_QUEUE",
73: "DOSDEVIOCTL GETCOM",
74: "DOSSETSIGHANDLER",
75: "DOSDEVIOCTL SETBREAKON",
76: "DOSDEVIOCTL SETBREAKOFF",
77: "INVALID SIGNAL",
78: "do_option: invalid option type",
79: "mod_option: invalid option type",
80: "show_option: invalid option type"
81: };
82: unsigned FileHndl = NULL; /* COM port file handle */
83:
84: static char ExitPgm = FALSE; /* indicate if program should terminate */
85: static int ErrorNumber = -1, /* used as index to ErrMsg array */
86: ReturnCode = -1; /* retcode from system/subsystem call */
87:
88:
89:
90:
91: /*** main - entry point to TERMINAL program
92: *
93: * This routine obtains the com port and the modem options from the file
94: * (specified in the command line) or directly from the user. It opens and
95: * initialises the com port. It sets up the modem connection (if one was
96: * requested). It creates a thread which loops continuously waiting to
97: * receive data from the com port and writing it out to the display. It
98: * loops continuosly waiting for an input from the keyboard and writing
99: * it out to the com port. Both the loops terminate when the user presses
100: * ALT-F1. It closes the modem connection (if one was made), and the com
101: * port and then terminates.
102: *
103: * main(argc, argv)
104: *
105: * ENTRY
106: * argc - number of command line arguments
107: * argv - pointer to an array of pointers (to command line args)
108: *
109: * EXIT
110: * the program terminates
111: *
112: * WARNING
113: *
114: * EFFECTS
115: *
116: ***/
117:
118: main(argc,argv)
119: int argc;
120: char *argv[];
121: {
122: unsigned char *Stack1; /* stack for a thread */
123: unsigned ThreadID,
124: RetCode, /* return code */
125: NumBytes, /* number of bytes to be written */
126: Result = TRUE;
127: long PrevAddress;
128: unsigned PrevAction;
129: static struct KbdStatus OurKbdStatus =
130: {sizeof(OurKbdStatus),KBD_BITMASK,};
131:
132: /* get COM port and modem options */
133: get_options(argc, argv);
134:
135: /* open and initialise COM port */
136: init_com_port();
137:
138: /* establish xit() as the exit routine */
139: if ((RetCode = DOSEXITLIST(ADD_ADDR, xit)) != 0)
140: error(ERR_DOSEXITLIST, RetCode);
141:
142: /* make modem connection if requested */
143: if (modem())
144: Result = make_modem_conn();
145:
146: if (Result) {
147: /* allocate memory for separate thread execution */
148: if (!(Stack1 = (char *) _nmalloc(STACKSIZE)))
149: error(ERR_OUTOFMEMORY, NO_RETCODE);
150:
151: /* create a thread that will execute the read_com_port() */
152: Stack1 += STACKSIZE;
153: if ((RetCode = DOSCREATETHREAD(read_com_port, &ThreadID,
154: Stack1)) != 0)
155: error(ERR_DOSCREATETHREAD, RetCode);
156:
157: /* set the keyboard status */
158: if ((RetCode = KBDSETSTATUS((struct KbdStatus *) (&OurKbdStatus),
159: RESERVED)) != 0)
160: error(ERR_KBDSETSTATUS, RetCode);
161:
162: /* set signal handler for BREAK signal */
163: if ((RetCode = DOSSETSIGHANDLER(handle_signals,
164: &PrevAddress,
165: &PrevAction,
166: RECV_CTRL, BREAK)) != 0)
167: error(ERR_DOSSETSIGHANDLER, RetCode);
168:
169: /* display "connected" message */
170: printf("connected... \n");
171:
172: /* read chars from the keyboard and write to COM port */
173: write_com_port();
174: } /* if (Result) */
175: }
176:
177:
178:
179:
180: /*** init_com_port - open the COM port and initialise line charecteristics
181: *
182: * This routine opens the com port. It sets the com port options
183: * BaudRate, DataBits, Parity and the StopBits. It sets the read timeout.
184: * It enables the automatic transmit and receive flow control.
185: *
186: * init_com_port()
187: *
188: * ENTRY
189: *
190: * EXIT
191: * FileHndl = handle to com port
192: *
193: * WARNING
194: *
195: * EFFECTS
196: *
197: ***/
198:
199: void init_com_port()
200: {
201: unsigned ActionTaken, /* action: file existed,created,replaced */
202: RetCode;
203: structLineChar sLineChar; /* line characteristics */
204: structDCB sDCB; /* device control block information */
205: structComOptions sComOptions;
206:
207: get_com_options(&sComOptions);
208:
209: /* open the com port */
210: if ((RetCode = DOSOPEN(sComOptions.pPortName, &FileHndl,
211: &ActionTaken, 0L, 0, 0x0001, 0x0042, 0L)) != 0)
212: error(ERR_DOSOPEN, RetCode);
213:
214: /* set the baud rate */
215: if ((RetCode = DOSDEVIOCTL(0L, (char *) &(sComOptions.iBaudRate),
216: SETBAUD, SERIAL, FileHndl)) != 0)
217: error(ERR_IOCTLSETBAUD, RetCode);
218:
219: /* set Data Bits, Stop Bits, Parity */
220: sLineChar.DataBits = sComOptions.chDataBits;
221: sLineChar.Parity = sComOptions.chParity;
222: sLineChar.StopBits = sComOptions.chStopBits;
223: if ((RetCode = DOSDEVIOCTL(0L, (char *) &sLineChar, SETLINECHAR,
224: SERIAL, FileHndl)) != 0)
225: error(ERR_IOCTLSETLINECHAR, RetCode);
226:
227: /* get device control block info */
228: if ((RetCode = DOSDEVIOCTL((char *) &sDCB, 0L, GETDCB, SERIAL,
229: FileHndl)) != 0)
230: error(ERR_IOCTLGETDCB, RetCode);
231:
232: sDCB.Flags2 |= 0x03; /* enable auto Xmit and recv flow control */
233: sDCB.Flags3 &= 0xf9; /* clear read timeout flags */
234: sDCB.Flags3 |= 0x04; /* set wait for something read timeout */
235: sDCB.ReadTimeOut = READTIMEOUT; /* set read timout value */
236:
237: /* set device control block info */
238: if ((RetCode = DOSDEVIOCTL(0L, (char *) &sDCB, SETDCB, SERIAL,
239: FileHndl)) != 0)
240: error(ERR_IOCTLSETDCB, RetCode);
241: }
242:
243:
244:
245:
246: /*** write_com_port - read chars from the keyboard and write to COM port
247: *
248: * This routine loops continuosly waiting for a keyboard input and
249: * writing it out to the com port. The loop terminates when the user
250: * presses the ALT-F1.
251: *
252: * write_com_port()
253: *
254: * ENTRY
255: *
256: * EXIT
257: *
258: * WARNING
259: *
260: * EFFECTS
261: *
262: ***/
263:
264: void write_com_port()
265: {
266: unsigned NumBytes, /* number of bytes actually written */
267: RetCode;
268: char OutBuffer; /* output buffer */
269: struct KeyData OurKeyData; /* struc to read a char from kbd */
270:
271:
272: while (!ExitPgm) {
273: /* read input from the keyboard */
274: if ((RetCode = KBDCHARIN((struct KeyData *) (&OurKeyData),
275: IOWAIT, RESERVED)) != 0)
276: error(ERR_KBDCHARIN, RetCode);
277: OutBuffer = OurKeyData.char_code;
278: if ((OutBuffer == 0) || (OutBuffer == 0xE0)) {
279: OutBuffer = OurKeyData.scan_code;
280: switch (OutBuffer) {
281: case DEL_SCAN : OutBuffer = DEL_ASCII;
282: break;
283: case ALT_F1 : ExitPgm = TRUE;
284: break;
285: default : break;
286: };
287: if (OutBuffer != ALT_F1)
288: /* write the input from the keyboard to the com port */
289: if ((RetCode = DOSWRITE(FileHndl, &OutBuffer, 1,
290: &NumBytes)) != 0)
291: error(ERR_DOSWRITE, RetCode);
292: }
293: else {
294: /* write the input from the keyboard to the com port */
295: if ((RetCode = DOSWRITE(FileHndl, &OutBuffer, 1,
296: &NumBytes)) != 0)
297: error(ERR_DOSWRITE, RetCode);
298: };
299: };
300: }
301:
302:
303:
304:
305: /*** read_com_port - read chars from com port and display on CRT screen
306: *
307: * This routine is executed by a thread. It loops continuously waiting
308: * to receive data from the com port and writing it out to the display.
309: * The loop terminates when the user presses ALT-F1.
310: *
311: * read_com_port()
312: *
313: * ENTRY
314: * FileHndl (handle to com port) setup
315: *
316: * EXIT
317: *
318: * WARNING
319: *
320: * EFFECTS
321: *
322: ***/
323:
324: void far read_com_port()
325: {
326: unsigned NumBytes, /* number of bytes actually read */
327: RetCode;
328: struct CharsInQue { /*data ret'ned by get num chars in que IOCTL*/
329: unsigned NumCharsInQue;
330: unsigned SizeQue;
331: } sCharsInQue;
332: char InBuffer[INBUFLENGTH]; /* input buffer */
333:
334: while (!ExitPgm) {
335: /* get number of characters in receive queue */
336: if ((RetCode = DOSDEVIOCTL((char *) &sCharsInQue, 0L, GETNUMCHARS,
337: SERIAL, FileHndl)) != 0)
338: setup_error_msg(ERR_IOCTLSETDCB, RetCode);
339:
340: if (sCharsInQue.NumCharsInQue == 0)
341: sCharsInQue.NumCharsInQue++;
342:
343: if ((RetCode = DOSREAD(FileHndl, InBuffer, sCharsInQue.NumCharsInQue,
344: &NumBytes)) != 0)
345: setup_error_msg(ERR_DOSREAD, RetCode);
346:
347: if (NumBytes) {
348: /* write to the tty display */
349: if ((RetCode = VIOWRTTTY(InBuffer, NumBytes, RESERVED)) != 0)
350: setup_error_msg(ERR_VIOWRTTTY, RetCode);
351: }
352: }
353: }
354:
355:
356:
357:
358: /*** handle_signals - handle BREAK signal
359: *
360: * This routine is the handler for the BREAK signal. When the user presses
361: * the BREAK key, this routine sends a BREAK on the com line.
362: *
363: * handle_signals(SigArg, SigNumber)
364: *
365: * ENTRY
366: * SigArg - not used
367: * SigNumber - signal number being processed
368: *
369: * EXIT
370: *
371: * WARNING
372: *
373: * EFFECTS
374: * Since this is a signal handler it must be declared FAR.
375: *
376: ***/
377:
378: void far pascal handle_signals(SigArg, SigNumber)
379: int SigArg,
380: SigNumber;
381: {
382: unsigned RetCode,
383: NumBytes,
384: Status;
385: char OutBuffer;
386:
387: switch (SigNumber) {
388: case BREAK :/* send BREAK to the com port */
389: if ((RetCode = DOSDEVIOCTL((char *) &Status, 0L,
390: SETBREAKON, SERIAL, FileHndl)) != 0)
391: error(ERR_IOCTLSETBREAKON, RetCode);
392: DOSSLEEP((long) 1);
393: if ((RetCode = DOSDEVIOCTL((char *) &Status, 0L,
394: SETBREAKOFF, SERIAL, FileHndl)) != 0)
395: error(ERR_IOCTLSETBREAKOFF, RetCode);
396: break;
397: default :
398: error(ERR_INVALIDSIGNAL, NO_RETCODE);
399: break;
400: }
401: }
402:
403:
404:
405:
406: /*** close_conn - close modem connection and the com port
407: *
408: * This routine closes the modem connection if one was made and then
409: * closes the com port.
410: *
411: * close_conn()
412: *
413: * ENTRY
414: *
415: * EXIT
416: *
417: * WARNING
418: *
419: * EFFECTS
420: *
421: ***/
422:
423: void close_conn()
424: {
425: int RetCode;
426: static char CloseMsg[] = "exiting terminal...";
427:
428: /* send closing message to the display */
429: if ((RetCode = VIOWRTTTY(CloseMsg, sizeof(CloseMsg), RESERVED)) != 0)
430: print_err_msg(ErrMsg[ERR_VIOWRTTTY], RetCode);
431:
432: /* if modem connection was made, close it */
433: if (modem())
434: discon_modem();
435:
436: /* close the com port */
437: if ((RetCode = DOSCLOSE(FileHndl)) != 0)
438: print_err_msg(ErrMsg[ERR_DOSCLOSECOMPORT], RetCode);
439: }
440:
441:
442:
443:
444: /*** ERROR HANDLING
445: *
446: * There are two error handling routines:
447: * - error() which is invoked from the main thread
448: * - setup_err_msg() which is invoked from the thread executing
449: * the read_com_port() routine
450: * The two routines perform different functions (described below). This
451: * is done so that if an error is encountered "simultaneously" in both
452: * the threads, there will be no race condition in error reporting.
453: *
454: * The following routines are also part of the error handling:
455: * - xit() is a DOSEXITLIST routine
456: * - print_err_msg() does the actual printing of the error message
457: *
458: * All the routines discussed above are defined below.
459: *
460: ***/
461:
462:
463:
464: /*** error
465: *
466: * This routine is invoked when there is an error. It prints an
467: * an error message and calls DOSEXIT.
468: *
469: * error(ErrNum, RetCode)
470: *
471: * ENTRY
472: * ErrNum - error number (used as index to error message array)
473: * RetCode - return code from a DOS system/subsystem call
474: *
475: * EXIT
476: * global variables ErrorNumber & ReturnCode still contain the
477: * initial value of -1. At program termination (via DOSEXIT call)
478: * the DOSEXITLIST routine xit() is invoked (described below).
479: * On return from xit(), this program will terminate.
480: *
481: * WARNING
482: *
483: * EFFECTS
484: *
485: ***/
486:
487: error(ErrNum, RetCode)
488: int ErrNum;
489: int RetCode;
490: {
491: print_err_msg(ErrMsg[ErrNum], RetCode);
492: DOSEXIT(1, 1);
493: }
494:
495:
496:
497:
498: /*** setup_error_msg - setup error message
499: *
500: * Sets up the global ErrorNumber and ReturnCode. It then calls DOSEXIT.
501: *
502: * setup_error_msg(ErrNum, RetCode)
503: *
504: * ENTRY
505: * ErrNum - error number (used as index to error message array)
506: * RetCode - return code from a DOS system/subsystem call
507: *
508: * EXIT
509: * global variables ErrorNumber & ReturnCode are setup. At
510: * program termination (via DOSEXIT call) the DOSEXITLIST
511: * routine xit() is invoked (described below). xit() will print
512: * an error message. On return from xit(), this program will
513: * terminate.
514: *
515: * WARNING
516: *
517: * EFFECTS
518: *
519: ***/
520:
521: setup_error_msg(ErrNum, RetCode)
522: int ErrNum,
523: RetCode;
524: {
525: ErrorNumber = ErrNum;
526: ReturnCode = RetCode;
527: DOSEXIT(1, 1);
528: }
529:
530:
531:
532:
533: /*** xit - exit function executed at program termination
534: *
535: * This is a DOSEXITLIST routine. It prints an error message if
536: * the global variable ErrorNumber is non-negative.
537: *
538: * xit()
539: *
540: * ENTRY
541: *
542: * EXIT
543: * If ErrorNumber is non-negative, an error message is printed.
544: * The program will then terminate.
545: *
546: * WARNING
547: *
548: * EFFECTS
549: *
550: ***/
551:
552: void far xit()
553: {
554: if (ErrorNumber != -1)
555: print_err_msg(ErrMsg[ErrorNumber], ReturnCode);
556: close_conn(); /* close modem connection and the com port */
557: DOSEXITLIST(XFER, 0L);
558: }
559:
560:
561:
562:
563: /*** print_err_msg - print error mesage
564: *
565: * This routine prints an error message and the returncode.
566: *
567: * print_err_msg(Msg, Retcode)
568: *
569: * ENTRY
570: * Msg - error message string
571: * Retcode - returncode from DOS system/subsystem call
572: *
573: * EXIT
574: *
575: * WARNING
576: *
577: * EFFECTS
578: *
579: ***/
580:
581: print_err_msg(Msg, RetCode)
582: char *Msg;
583: int RetCode;
584:
585: {
586: printf("*** ERROR %s *** ", Msg);
587: if (RetCode != -1)
588: printf("ReturnCode = %d ", RetCode);
589: printf("\n");
590: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.