home *** CD-ROM | disk | FTP | other *** search
/ Phoenix CD 2.0 / Phoenix_CD.cdr / 24b / microc.zip / REAL-38.FIG < prev   
Text File  |  1987-10-28  |  19KB  |  452 lines

  1. /* this file contains TSR.C, WINDOWS.C, and WINDOWS.H */
  2.  
  3.  
  4.  
  5.  
  6.  
  7. /* Figure 6a -- TSR.C */
  8.  
  9. /* TSR.C: Terminate and Stay Resident (TSR) program written entirely in Turbo C
  10. *  ("look, ma, no assembly language!").  Bruce Eckel, Eisys Consulting,
  11. *  1009 N. 36th St., Seattle, WA 98103.  7/87.
  12. *      The interrupt line on the parallel printer card (-ACK: pin 10 on the
  13. *  DB-25 connector) is allowed through to IRQ7, and the 8259A is configured to
  14. *  service the interrupt when -ACK is pulled to ground using a simple switch,
  15. *  TTL or CMOS logic.
  16. *      This was tested with an EGA monitor in color mode, so it probably works
  17. *  with a color monitor or a monochrome monitor (for mono, change SCREEN_BASE
  18. *  to 0xB000.  Note I have gotten around using any DOS or BIOS calls by writing
  19. *  direct screen driver routines -- this prevents any possible collision
  20. *  with the program being interrupted.
  21. *      I tried using the interrupt while running an EGA program (Dr Halo).  The
  22. *  results were...interesting.  Someday maybe I'll figure that one out
  23. *  (Sidekick worked, but it left garbage on the canvas).
  24. */
  25. /* #include <dos.h> */
  26. #define INT_NUMBER 15    /* interrupt number to install this function into.
  27.                            Note IRQ7 on the PC card bus corresponds to interrupt
  28.                            handler 15 in the interrupt vector table.  */
  29. #define PROG_SIZE 0x1E10/* Run the Turbo C compiler with the options:linker:mapfile
  30.                            set to "segments."  Look at the mapfile generated
  31.                            for this program.  The "stop" address for the
  32.                            stack is the highest adress used -- set PROG_SIZE
  33.                            to this value for use with the "keep()" command */
  34. /*  I tried using the "tiny" model instead of the "small" model, since it is
  35.     supposed to be more size-efficient.  The map showed the size to be LARGER,
  36.     even though it didn't create a stack and the small model did.  Seems odd. */
  37.  
  38. #include "colors.h"   /* color definitions */
  39. #include "windows.h"  /* prototypes for window function definitions.
  40.  These tell the compiler: (A) not to panic if a function is called for which
  41.  it hasn't seen the definition, and (B) what the function's calling convention
  42.  is, so the compiler can tell you if you're doing it right (helps find errors).*/
  43.  
  44. #define BASE 0x378    /* Parallel port board base address, established for
  45.                            LPT1.  Change this if you're using LPT2 or you
  46.                            changed the jumpers on the cheap card.  */
  47.  
  48. #define PIC_OCW1 0x21   /* 8259A Programmable Interrupt Controller
  49.                            Operation Control Word 1 (see issue 36, page 36 */
  50.  
  51. /* macro to read value of ACK line */
  52. #define ACK (inportb(BASE + 1) & BIT6)
  53.  
  54. /**************************************************************************/
  55. /*  Macro (with parameters) to read values at any pin location.  Returns  */
  56. /*  "1" if a logical one comes back from the masked pin, and "0" if a     */
  57. /*  logical zero comes back.  Note inversions due to hardware logic are   */
  58. /*  not considered, so some pins may be seeing a TTL "1" and return a     */
  59. /*  zero (see circuit).    */
  60. #define READ_BIT(port_address,bit) (inportb(port_address) & bit ? 1 : 0)
  61.  
  62. /**************************************************************************/
  63. /*  The interrupt handler.  Notice the 'interrupt' compiler directive,    */
  64. /*  which tells the compiler to save and restore all the registers and    */
  65. /*  use interrupt code instead of normal subroutine code.                 */
  66. void interrupt int_handler()
  67. {
  68. #define LEFT_X   5    /* Window boundaries */
  69. #define RIGHT_X  75
  70. #define TOP_Y    5
  71. #define BOTTOM_Y 20
  72. /* Function prototype, to allow compiler to flag improper function calls: */
  73. void window_put_binary (int window_number, int value, unsigned char attribute);
  74.  
  75. /* save the user's screen and put ours up instead */
  76. save_screen();
  77. define_window(0,LEFT_X,TOP_Y,RIGHT_X,BOTTOM_Y, YELLOW_CHAR | BROWN_BACK);
  78. draw_window(0);
  79. title_window(0,"Process Monitor Interrupt", RED_CHAR | GREEN_BACK);
  80.  
  81. /* If you want to add sound here, see the Turbo C user's guide, page 275 */
  82.  
  83. /* wait for the -ACK line to rise before returning.  Meanwhile, read all
  84.    the input lines (for example) with pullup resistors on them.   */
  85.    while (!ACK) {    /* see how much neater the macro makes things? */
  86.          window_gotoXY(0,LEFT_X+3,TOP_Y+2);
  87.          window_puts (0,"pin 1 : ", BLACK_CHAR | BROWN_BACK);
  88.          window_put_binary (0,READ_BIT(BASE+2,BIT0),
  89.                            BLUE_CHAR | BROWN_BACK);
  90.          window_gotoXY(0,LEFT_X+35,TOP_Y+2);
  91.          window_puts (0,"pin 14 : ", BLACK_CHAR | BROWN_BACK);
  92.          window_put_binary (0,READ_BIT(BASE+2,BIT1),
  93.                            BLUE_CHAR | BROWN_BACK);
  94.          window_gotoXY(0,LEFT_X+3,TOP_Y+7);
  95.          window_puts (0,"pin 16 : ", BLACK_CHAR | BROWN_BACK);
  96.          window_put_binary (0,READ_BIT(BASE+2,BIT2),
  97.                            BLUE_CHAR | BROWN_BACK);
  98.          window_gotoXY(0,LEFT_X+35,TOP_Y+7);
  99.          window_puts (0,"pin 17 : ", BLACK_CHAR | BROWN_BACK);
  100.          window_put_binary (0,READ_BIT(BASE+2,BIT3),
  101.                            BLUE_CHAR | BROWN_BACK);
  102.    }
  103.  
  104.    /* restore the user's previous screen */
  105.    restore_screen();
  106.  
  107.    /* tell the 8259A Interrupt Controller we are finished executing IRQ7 */
  108.    outportb(0x20,0x67); /* specific EOI for IRQ7 */
  109. }
  110.  
  111. /**************************************************************************/
  112. /*  main() for TSR.  This installs the interrupt, sets up the hardware,   */
  113. /*  and exits leaving the program resident.  Main is never used again.    */
  114. main()
  115. {
  116.     setvect(INT_NUMBER,int_handler);  /* passes the ADDRESS of the beginning
  117.                                          of the int_handler() function.
  118.                                          setvect() is a Borland function.  */
  119.  
  120.    /* change the bit on the parallel board to allow the -ACK interrupt to pass
  121.       through to IRQ7 on the PC card bus.  BIT4 allows the interrupt to pass;
  122.       BIT2 allows pin 16 to be read.  See circuit diagram. */
  123.       outportb(BASE + 2, BIT4 | BIT2);
  124.  
  125.    /* zero top bit of OCW1 to allow IRQ7 to be serviced.  Note we get the
  126.       current OCW1, force the top bit to 0 and put it back out -- this retains
  127.       the rest of the word (which affects other aspects of the machine) to
  128.       prevent undesirable side effects. */
  129.       outportb(PIC_OCW1, inportb(PIC_OCW1) & 0x7f);
  130.  
  131.       keep(0,PROG_SIZE);  /* first parameter is exit status. See Ref. Manual. */
  132. }
  133.  
  134. /**************************************************************************/
  135. /*  Takes the bottom bit of an integer and prints it as an ascii string   */
  136. /*  either "0" or "1".  For some reason, I had trouble passing string     */
  137. /*  pointers inside the TSR -- it would modify the save_buf[] array -- so */
  138. /*  it seems I can only use literals.  Be aware of this quirk -- I spent  */
  139. /*  awhile chasing it and couldn't find out what it was.                  */
  140. void
  141. window_put_binary (int window_number, int value, unsigned char attribute)
  142. {
  143.  if (value & 1)
  144.     window_puts (window_number,"1 ", attribute);
  145.  else
  146.     window_puts (window_number,"0 ", attribute);
  147. }
  148.  
  149.  
  150.  
  151.  
  152.  
  153.  
  154.  
  155.  
  156. /* Figure 6b -- WINDOWS.C */
  157.  
  158. /* WINDOWS.C: custom screen functions to prevent DOS collisions inside the TSR.
  159. *  Bruce Eckel, Eisys Consulting, 1009 N. 36th St. Seattle, WA 98103  7/87
  160. * "DOS calls!?  We don't need no steenkin DOS calls!..."  You can bet if
  161. *  Borland had made DOS, it would have been re-entrant and relocatable, and we
  162. *  wouldn't have this problem, or be limited to 640K on an AT.
  163. *  Note I haven't put anything in to change the screen modes -- you are assumed
  164. *  to already be in CGA.  I also haven't turned the cursor off and on.
  165. */
  166.  
  167. #undef TEST      /* '#define' this to make a stand-alone test program */
  168. #include "colors.h"  /* CGA color #defines */
  169. /* global place to save the screen so we can restore it when we're done: */
  170. unsigned char save_buf[SCREEN_CHARS];
  171.  
  172. /* Now, a place for all the global attributes for each window: */
  173. struct window_def {  /* coordinates start at upper left corner as 0,0 */
  174.        int left_x;   /* left-most extent of window */
  175.        int top_y;    /* upper limit of window */
  176.        int right_x;  /* right-most extent of window */
  177.        int bottom_y; /* lower limit of window */
  178.        unsigned char attributes;  /* default char and background colors */
  179.        int cursor_x; /* for functions which need cursors in the window */
  180.        int cursor_y;
  181.        } window[3];  /* To add more windows, increase the array size */
  182.  
  183. #define WINDW window[window_number]  /* saves typing and makes things clearer */
  184.  
  185. /**************************************************************************/
  186. /*  This function simply initializes a window[] structure, so all other   */
  187. /*  functions told to do something to that window can look up all the     */
  188. /*  necessary information about it.                                       */
  189. void define_window(int window_number, int left_x, int top_y, int right_x,
  190.                  int bottom_y, unsigned char attribute)
  191. {
  192. WINDW.left_x = left_x;  /* establish global window values */
  193. WINDW.top_y = top_y;
  194. WINDW.right_x = right_x;
  195. WINDW.bottom_y = bottom_y;
  196. WINDW.attributes = attribute;
  197. WINDW.cursor_x = left_x + 1; /* put cursor inside box */
  198. WINDW.cursor_y = top_y + 1;
  199. }
  200.  
  201. /**************************************************************************/
  202. /* Puts a character and its attribute anywhere on the screen.             */
  203. void putc_at_location(char ch, int x, int y, unsigned char attribute)
  204. {
  205. pokeb(SCREEN_BASE,((y * SCREEN_WIDTH) + x) * 2,ch);
  206. pokeb (SCREEN_BASE,(((y * SCREEN_WIDTH) + x) * 2) + 1, attribute);
  207. }
  208.  
  209. /**************************************************************************/
  210. /* Clears a window (including the border), retaining it's attributes.     */
  211. void clear_window(int window_number)
  212. {
  213. unsigned int x,y;
  214.    for (y = WINDW.top_y; y <= WINDW.bottom_y ; y++){
  215.        for (x = WINDW.left_x; x <= WINDW.right_x; x++){
  216.        putc_at_location(' ',x,y,WINDW.attributes);
  217.       }
  218.    }
  219. }
  220.  
  221. /**************************************************************************/
  222. /* Puts a string in a window, wrapping if it hits a border and refusing   */
  223. /* to go past the lower right corner.  For some reason, the string must   */
  224. /* be a literal (i.e. '"a string"', rather than a pointer you pass)       */
  225. /* embedded in the function call or bad things happen when the            */
  226. /* interrupted screen is restored.                                        */
  227. window_puts(int window_number, char *string, unsigned char attribute)
  228. {
  229. int cursor_offset;
  230. do {
  231.     if (*string == 10) { /* check for newline */
  232.        WINDW.cursor_x = WINDW.left_x + 1;
  233.        WINDW.cursor_y += 1;
  234.        if (WINDW.cursor_y > WINDW.bottom_y - 1)
  235.           WINDW.cursor_y -= 1; /* just bump against the bottom if you run out */
  236.     }
  237.     else
  238.     {
  239.      putc_at_location(*string, WINDW.cursor_x, WINDW.cursor_y, attribute);
  240.      /* Move cursor ahead, but keep it inside window */
  241.      if (++WINDW.cursor_x > WINDW.right_x -1) {
  242.         WINDW.cursor_x = WINDW.left_x + 1;
  243.         if (++WINDW.cursor_y > WINDW.bottom_y -1)
  244.             WINDW.cursor_y--;
  245.      }}}
  246. while (*++string); /* stops at the string's null terminator */
  247. }
  248.  
  249. /**************************************************************************/
  250. /* Saves the screen we just interrupted into a global array.              */
  251. void
  252. save_screen()
  253. {
  254. int scr_offset;
  255.    for(scr_offset = 0; scr_offset < SCREEN_CHARS; scr_offset++) {
  256.       save_buf[scr_offset] = peekb(SCREEN_BASE,scr_offset);
  257.    }
  258. }
  259.  
  260. /**************************************************************************/
  261. /* Restores the interrupted screen from the global array.                 */
  262. void
  263. restore_screen()
  264. {
  265. int scr_offset;
  266.    for(scr_offset = 0; scr_offset < SCREEN_CHARS; scr_offset++) {
  267.       pokeb(SCREEN_BASE,scr_offset,save_buf[scr_offset]);
  268.    }
  269. }
  270.  
  271. /**************************************************************************/
  272. /* Puts a box of double bars (like Sidekick) around the window, using the */
  273. /* window's pre-defined character and background colors.                  */
  274. void make_box(int window_number)
  275. {
  276. int x,y;
  277.  
  278. for (x=WINDW.left_x, y=WINDW.top_y; x++ < WINDW.right_x; )      /* top bar */
  279.     putc_at_location(0xCD,x,y,WINDW.attributes);
  280. for (x=WINDW.left_x, y=WINDW.bottom_y; x++ < WINDW.right_x; )  /* bottom bar */
  281.     putc_at_location(0xCD,x,y,WINDW.attributes);
  282. for (x=WINDW.left_x, y=WINDW.top_y; y++ < WINDW.bottom_y; )     /* left bar */
  283.     putc_at_location(0xBA,x,y,WINDW.attributes);
  284. for (x=WINDW.right_x, y=WINDW.top_y; y++ < WINDW.bottom_y; )   /* right bar */
  285.     putc_at_location(0xBA,x,y,WINDW.attributes);
  286.  
  287.     /* bottom left corner */
  288. putc_at_location(0xC8, WINDW.left_x, WINDW.bottom_y, WINDW.attributes);
  289.    /* top left corner */
  290. putc_at_location(0xC9, WINDW.left_x, WINDW.top_y, WINDW.attributes);
  291.     /* top right corner */
  292. putc_at_location(0xBB, WINDW.right_x, WINDW.top_y, WINDW.attributes);
  293.    /* bottom right corner */
  294. putc_at_location(0xBC, WINDW.right_x, WINDW.bottom_y, WINDW.attributes);
  295. }
  296.  
  297. /**************************************************************************/
  298. /*  Puts window up if it isn't already; clears it if it is.               */
  299. void draw_window(int window_number)
  300. {
  301. clear_window(window_number);
  302. make_box(window_number);
  303. }
  304.  
  305. /**************************************************************************/
  306. /*  Centers a title in the foreground and background colors of your choce.*/
  307. /*  Title is placed in the top bar of the window.                         */
  308. void title_window(int window_number, char *title, unsigned char attribute)
  309. {
  310. char *title_ptr;
  311. int title_count, x;
  312. make_box(window_number); /* redraw box if new title is smaller than old one */
  313. for (title_ptr = title, title_count = 1; *++title_ptr; title_count++)
  314.     ; /* count number of chars in string (stops when *title_ptr == '\0') */
  315.  /* starting x value to center the title */
  316. x = (WINDW.right_x - WINDW.left_x - title_count)/2 + WINDW.left_x + 1;
  317. while (*title)  /* stops when *title == '\0' */
  318.       putc_at_location(*title++,x++,WINDW.top_y,attribute);
  319. }
  320.  
  321. /**************************************************************************/
  322. /* Move the window cursor within the window, repecting the boundaries.    */
  323. void window_gotoXY(int window_number, int X, int Y)
  324. {
  325. /* If X isn't outside of the window bounds, set cursor
  326.    to X, else set it to just inside the window bounds */
  327. if (X > WINDW.left_x && X < WINDW.right_x )
  328.    WINDW.cursor_x = X;
  329. else
  330.    if (X <= WINDW.left_x)
  331.       WINDW.cursor_x = WINDW.left_x +1;
  332.    else
  333.       WINDW.cursor_x = WINDW.right_x -1;
  334.  
  335. /* same for y */
  336. if (Y > WINDW.top_y && Y < WINDW.bottom_y )
  337.    WINDW.cursor_y = Y;
  338. else
  339.    if (Y <= WINDW.top_y)
  340.       WINDW.cursor_y = WINDW.top_y +1;
  341.    else
  342.       WINDW.cursor_y = WINDW.bottom_y -1;
  343. }
  344.  
  345. #ifdef TEST
  346. main()
  347. {
  348. /* Here's where you put calls to window routines when performing stand-alone
  349. *  tests.  Of course, just because they work here doesn't mean they will work
  350. *  in a TSR.  You also need a '#define TEST' at the beginning of this file.
  351. */
  352. }
  353. #endif
  354.  
  355.  
  356.  
  357.  
  358.  
  359.  
  360.  
  361.  
  362. /* Figure 6c -- COLORS.H */
  363.  
  364. /* COLORS.H: definitions for CGA screen characteristics and colors */
  365. #define SCREEN_BASE 0xb800   /* base address of color graphics card (and EGA
  366.                                 in color graphics mode  */
  367. #define SCREEN_HEIGHT 25
  368. #define SCREEN_WIDTH 80
  369. #define SCREEN_CHARS (SCREEN_WIDTH * SCREEN_HEIGHT * 2)
  370.                                /* number of chars and attributes in a screen */
  371.  
  372. #define BIT0 0x01    /* bit masks */
  373. #define BIT1 0x02
  374. #define BIT2 0x04
  375. #define BIT3 0x08
  376. #define BIT4 0x10
  377. #define BIT5 0x20
  378. #define BIT6 0x40
  379. #define BIT7 0x80
  380.  
  381. /* Make a complete attribute by ORing a CHARacter type with a BACKground type */
  382. #define BLUE_CHAR  BIT0
  383. #define GREEN_CHAR BIT1
  384. #define RED_CHAR   BIT2
  385. #define INTENSE    BIT3
  386. #define BLUE_BACK  BIT4
  387. #define GREEN_BACK BIT5
  388. #define RED_BACK   BIT6
  389. #define BLINKING   BIT7
  390.  
  391. #define BLACK_CHAR 0
  392. #define CYAN_CHAR (GREEN_CHAR | BLUE_CHAR)
  393. #define MAGENTA_CHAR (RED_CHAR | BLUE_CHAR)
  394. #define BROWN_CHAR (RED_CHAR | GREEN_CHAR)
  395. #define WHITE_CHAR (RED_CHAR | GREEN_CHAR | BLUE_CHAR)
  396. #define GRAY_CHAR (INTENSE | BLACK_CHAR)
  397. #define LIGHT_BLUE_CHAR (INTENSE | BLUE_CHAR)
  398. #define LIGHT_GREEN_CHAR (INTENSE | GREEN_CHAR)
  399. #define LIGHT_CYAN_CHAR (INTENSE | CYAN_CHAR)
  400. #define LIGHT_RED_CHAR (INTENSE | RED_CHAR)
  401. #define LIGHT_MAGENTA_CHAR (INTENSE | MAGENTA_CHAR)
  402. #define YELLOW_CHAR (INTENSE | BROWN_CHAR)
  403. #define BRIGHT_WHITE_CHAR ( INTENSE | WHITE_CHAR)
  404.  
  405. #define BLACK_BACK 0
  406. #define CYAN_BACK (GREEN_BACK | BLUE_BACK)
  407. #define MAGENTA_BACK (RED_BACK | BLUE_BACK)
  408. #define BROWN_BACK (RED_BACK | GREEN_BACK)
  409. #define WHITE_BACK (RED_BACK | GREEN_BACK | BLUE_BACK)
  410. #define GRAY_BACK (INTENSE | BLACK_BACK)
  411. #define LIGHT_BLUE_BACK (INTENSE | BLUE_BACK)
  412. #define LIGHT_GREEN_BACK (INTENSE | GREEN_BACK)
  413. #define LIGHT_CYAN_BACK (INTENSE | CYAN_BACK)
  414. #define LIGHT_RED_BACK (INTENSE | RED_CHAR)
  415. #define LIGHT_MAGENTA_BACK (INTENSE | MAGENTA_CHAR)
  416. #define YELLOW_BACK (INTENSE | BROWN_BACK)
  417. #define BRIGHT_WHITE_BACK ( INTENSE | WHITE_BACK)
  418.  
  419.  
  420.  
  421.  
  422. /* Figure 6d -- WINDOWS.H */
  423.  
  424. /*  WINDOWS.H: #include these function prototypes at the beginning of any file
  425. *   where you use windows functions.  Turbo C will then catch errors if you
  426. *   call the functions improperly.  (to "make" properly, you also need to
  427. *   mention windows.c in your "project" file).
  428. */
  429.  
  430. extern void define_window(int window_number, int left_x, int top_y, int right_x,
  431.                  int bottom_y, unsigned char attribute);
  432.  
  433. extern void putc_at_location(char ch, int x, int y, unsigned char attribute);
  434.  
  435. extern void clear_window(int window_number);
  436.  
  437. window_puts(int window_number, char *string, unsigned char attribute);
  438.  
  439. extern void save_screen();
  440.  
  441. extern void restore_screen();
  442.  
  443. extern void make_box(int window_number);
  444.  
  445. extern void draw_window(int window_number);
  446.  
  447. extern void title_window(int window_number, char *title,
  448.                           unsigned char attribute);
  449.  
  450. extern void window_gotoXY(int window_number, int X, int Y);
  451.  
  452.