home *** CD-ROM | disk | FTP | other *** search
/ C!T ROM 2 / ctrom_ii_b.zip / ctrom_ii_b / PROGRAM / C / ISC365 / README.TXT < prev    next >
Text File  |  1993-08-04  |  15KB  |  285 lines

  1. ----------------------------------------------------------------------------
  2.                    ISC V3.65-  by Ofer Laor (AKA LeucroTTA)
  3. ----------------------------------------------------------------------------
  4.  
  5.  
  6.                     ISC- Interrupt Service Class
  7.            -----------------------------------------------
  8.             hooking interrupts into C++ objects made easy
  9.            -----------------------------------------------
  10.  
  11. ----------------------------------------------------------------------------
  12.                            OVERVIEW
  13. ----------------------------------------------------------------------------
  14.  
  15.   This article describes a class for Turbo / Borland C++ (checked with
  16. versions 3.x), for hooking interrupts into C++ objects. For those of us
  17. who need to write heavy TSRs or regular programs that need interrupt
  18. handlers - hooking the interrupt handlers into the C++ code was a bit of
  19. a fuss. Borland made it easy enough for us to hook interrupts into C code
  20. through the "interrupt" keyword, but objects could not use this feature.
  21.   The reason for this is that every C++ object needs an identifier to be passed
  22. to it when using one of it's functions. This identifier (called "this") is the
  23. real name of the object and is used by it to access data and function members.
  24.   When a member function is called - (a.foo() for example) a is the "this" and
  25. foo() is the function to be called. When the actual call is made - a is
  26. pushed unto the stack and foo() is called. Now, foo() uses data members
  27. through "this" and knows it's own name through it. If you could somehow
  28. get foo's address and called it (something that C++ prohibits and protects
  29. its programmers from) you would not pass on the right "this" and cause a
  30. malfunction when foo() accesses an internal data member or calls a
  31. virtual function. What people would usually do is to make a static interrupt
  32. function for each of the interrupts in the system. This is a common solution
  33. (in lack of a better one). ISC offers a different approach - and a more useful
  34. one.
  35.  
  36.   A class that uses ISC will derive from it and overload a function called
  37. isr() - (Interrupt Service Routine). Now all that needs doing is activating
  38. the interrupt (activate(int_num)) and the interrupt is hooked into that
  39. OBJECT!!! What this means is that if you have a class for Serial
  40. communications that works through interrupts - you don't have to make a
  41. different interrupt function for each of the possible ports you'd be using-
  42. you would write the class as you would any other. Each of the instances of
  43. the Serial class you are writing will hook into a different interrupt (or the
  44. same one if needs be).
  45.  
  46.   ISC works in a simple way, it produces what Windows 3.x programmers call
  47. a thunk (a small piece of code that contains your data segment and sets it
  48. just before the real call is made- or in this case the id of your object) for
  49. each of the objects that are currently hooked into interrupts through ISC.
  50.   ISC reproduces the thunk for each object. Each Thunk contains in it's code
  51. - the id of the object that owns it. Then it calls a special dispatcher that
  52. handles the call to the right ISC derived object. The dispatcher also sets
  53. up the stack for all the ISC users (so that no stack cramming is needed in
  54. your interrupt routines). The dispatcher also sets up a structure that
  55. contains the registers that the interrupt entered through (so you may modify
  56. them or use them if they are needed).
  57.  
  58.   In the first two versions of this class I tried to utilize (without much
  59. success) properties in the local C++ compilers (how the virtual function
  60. tables work) and tried to call virtual functions directly from ASM. While
  61. this was fairly easy to do (a bit of reverse engineering) - it was compiler
  62. dependent (and even compiler version dependent). I have seen the light and
  63. this version is COMPILER INDEPENDENT (although the ASM routines are written
  64. to work specifically under tasm - and a bit of semantic changes might be
  65. needed to make it work under different assemblers). A close look will have
  66. taught you that porting the code to your local machine, and compiler is a
  67. simple enough task!
  68.  
  69.  Since the ISC class is mainly for use in TSRs (although it is usable in
  70. regular programs just as well)- these are some of the pitfalls that TSR
  71. writers in C++ will encounter:
  72.  
  73.  ■ I strongly advise you TSR writers to use ASSUME DS!=SS in SMALL, MEDIUM
  74.    models. Also - turn off the CHECK STACK OVERFLOW option if you turned it
  75.    on - it sometimes causes trouble in the interrupt routine.
  76.  
  77.  ■ ISC CANNOT be compiled under the TINY memory model (the linker will not
  78.   work correctly in the asm module). Presently I havn't found an answer
  79.   to this problem. Hope it doesn't spoil it for you.
  80.  
  81. ----------------------------------------------------------------------------
  82.                             ISC functions.
  83. ----------------------------------------------------------------------------
  84.   ISC provides your classes with the ability to hook into hardware and
  85. software interrupts.
  86.  
  87. it does this by providing 2 "overloadable" functions: both named isr.
  88.  
  89.  
  90.   * HARDWARE INTERRUPTS: virtual void isr(void);
  91.  
  92.    just overload this function and when your class is activated the isr will
  93.    be called whenever the hardware calls it.
  94.  
  95.   * SOFTWARE INTERRUPTS: virtual void isr(IREGS& regs);
  96.  
  97.    IREGS is NOT compatible with the regular REGS union although it is very
  98. close to it (it has MORE registers than REGS). The 32 bit option is not
  99. supported in the interrupt keyword - so I have not incorporated it into ISC.
  100.  
  101.   * IREGS contains two structures:
  102.  
  103.     struct IBYTEREGS  {
  104.            unsigned char  al, ah, bl, bh;
  105.            unsigned char  cl, ch, dl, dh;
  106.     };
  107.  
  108.     struct IWORDREGS  {
  109.            unsigned int  ax, bx, cx, dx;
  110.            unsigned int  si, di, ds, es, cs, flags, ip, bp;
  111.     };
  112.  
  113.   you may access IWORDREGS and IBYTEREGS through .x and .h :-
  114.  
  115.       IREGS regs;
  116.          ...
  117.       regs.x.ax= regs.h.bl+ regs.h.dl;
  118.  
  119.   all of these registers are what the register situation was BEFORE the
  120. interrupt was called.
  121.  
  122.   if you change the content of the regs parameter that is passed to you in
  123. the isr function - this will be the value of that register when the
  124. interrupt exits.
  125.  
  126.   * void activate(const int in_num) - will hook the interrupt handler to the
  127. function isr (software). The default software isr calls the hardware isr,
  128. so that if you hook to the hardware isr - you will be called as required.
  129. But if you overload both - you must literally call the hardware interrupt
  130. handler in order for it to work. This function prevents the programmer
  131. from activating an ISC derived class twice (you must deactivate it first).
  132.  
  133.   * void deactivate(void) - will unhook you from the interrupt. The destructor
  134. of ISC also does that - so unless you'd like to unhook and rehook to another
  135. interrupt - you shouldn't need this function. The function enables you to call
  136. activate again (for rehooking to another interrupt, for example).
  137.  
  138.   some GENERAL PURPOSE functions are also available here as part of ISC -
  139. since I use ISC to build TSR's in C++ (for example a real time communication
  140. program that runs in the background)- I though it useful to provide TSR
  141. functions here as well. These STATIC functions ( is_TSR and TSR) take care
  142. of managing your TSR needs (the most basic ones).
  143.  
  144.   * static int is_TSR(const char *app_name)- will figure out if your program is
  145. running already as a TSR. You must choose a unique application name and put
  146. it's name as parameter. Returns (1) if you are RESIDENT already and (0) if
  147. you're not. I used a simple method for this - (for more info. read the
  148. source file).
  149.  
  150.   * static int TSR(const int exit_code= 0, unsigned long extra_heap= 0)- will
  151. keep you resident in memory. if you call TSR() it will attempt to stay
  152. resident (minimal memory possible) and return 0 to DOS. You can return any
  153. exit code by calling TSR(1) for example. If your TSR needs more room to grow
  154. (extra interrupt-time heap for example) put the extra heap (in bytes) in the
  155. second parameter. Remember that in the LARGER models malloc and new use the
  156. far heap so that you may not be able to use your preallocated memory in them
  157. (and most likely no heap at all will be available in those memory models at
  158. all). Problem with run time heap (SMALLER MEMORY MODELS ONLY) is that when
  159. you allocate past the max heap you declared (in parameter extra_heap) the
  160. program will crash (in a probably very bizarre way!!!). USE THOUGHTFULLY.
  161.  
  162.   The method for finding the minimum memory necessary for reallocation is
  163. an algorithm I am quite proud of- it works in all the memory models and with
  164. a lot less memory that the sources Borland provides in their help of KEEP.
  165. It can be converted to C very easily (change new into malloc!). This is a
  166. brand new method (new from V3.6) and is not prone to heap failures and
  167. possible problems (as the previous versions were).
  168.  
  169.  ■ One ISC specific static function is reallocStack(unsigned long stacklen):-
  170.  
  171.   * static int reallocStack(unsigned stackLen)- will reallocate the hardware
  172. interrupt stack frame to the specified size. If you need to call this
  173. function you must:- either call it while no ISC derived class is active or
  174. simply disable interrupts before you call it (don't forget to re-enable them).
  175.  
  176. ----------------------------------------------------------------------------
  177.                              ISC data members.
  178. ----------------------------------------------------------------------------
  179.  ■* There are 2 data members of major importance - int_num and old_vect;
  180.  
  181.   both must not be changed (since deactivate uses them to recover the state
  182. of the interrupt as it was before ISC was used.
  183.  
  184.    int_num - contains the number of the interrupt hook.
  185.  
  186.    old_vect - is a pointer to the function that was the previous interrupt
  187. vector. It can be called - by -> old_vect();
  188.              DO NOT CALL IT WITH PARAMETERS!!!!
  189.   To get the registers to be as they were use PSEUDO VARIABLE (_AX, _BX...)
  190. or call the vector in some alternative way!!!
  191.  
  192.  *■ There are 3 static data members that refer to the hardware stack frame:-
  193.  
  194.    StackFrame- points to the actual stack frame.
  195.  
  196.    StackFrameLen- contains the current stack frame length.
  197.  
  198.    ISCcount- holds the number of ISC objects that currently exist in the
  199. system.
  200.  
  201. ----------------------------------------------------------------------------
  202.                               EXAMPLES.
  203. ----------------------------------------------------------------------------
  204.  ■ There are 4 examples:-
  205.  
  206.  ■■ EXAMPLE1:- is a resident that keeps a timer tick watcher on screen (by
  207.     incrementing the first char on the top left of the screen once every timer
  208.     tick). Also, it keeps a keyboard interrupt watcher right next to it. This
  209.     example shows how to make an ISC derivative- how to check if already
  210.     resident. How to use 2 ISCs together...
  211.  
  212.  ■■ EXAMPLE2:- is an example of a software interrupt - it is a software
  213.     interrupt that beeps with a length and pitch which are passed as register
  214.     parameters. The main routine will test it and verify that it had not
  215.     failed through return values (also through register as well as flags).
  216.  
  217.     ** - when using ISC classes on automatic (local vars) rememeber:- NOT ALL
  218.     COMPILERS call DESTRUCTORS for automatic vars if exit() or do-alike funcs
  219.     (like abort()) run (they simply do not call the destructors), so that loca
  220.     ISC vars might not be freed and the interrupt will stay hooked, resulting
  221.     in a crash in most cases). So, using stack ISC (or derivitives) is ill
  222.     advised unless you know what you're doing...
  223.  
  224.  ■■ EXAMPLE3:- is a more complex example of a class that has to do a lot of
  225.   processing (each one taking longer than the timer tick interval).
  226.   it slows the computer down (so <mark> before running it).
  227.  
  228.  ■■ EXAMPLE4:- sends a novell look alike "send" message onto the screen (which
  229.   stops the forground and waits for the user to free it). Pretty annonying
  230.   program, so <mark> it before running.
  231.  
  232. ----------------------------------------------------------------------------
  233.                          MORE DIRECTORIES.
  234. ----------------------------------------------------------------------------
  235.  ■ Also included are some more files and directories:-
  236.  
  237.  ■■ ISC :- This directory contains all that you need in order to work with
  238.     ISC. (Include ISC.cpp and ISCSERVE.asm into your project and #include
  239.          ISC.h in your source files).
  240.  
  241.  ■■ DOSFREE :- allows you to execute dos functions (except 0-ch meaning that
  242.     line input through scanf is forbidden) - such as opening a file and reading
  243.     writing or deleting it.
  244.  
  245.  ■■ SERIAL :- Some more advanced ISC derivative classes that handle interrupt
  246.     driven serial and modem communications. Although ISC has changed in the
  247.     past year - no changes have been made to these sources. Previously these
  248.     sources were distributed under XSERIAL.arj and XSERIAL1.arj. Also included
  249.     is a sample of a Buffer class I used that a colleague of mine wrote...
  250.     ■ there are two examples in serial- RECEIVE and TRANSMIT:- RECEIVE
  251.       will set COM1 to 9600baud, 8bytes, 1stopbit, No parity- and put on the
  252.       screen anything that comes in from the port. The program will stop if
  253.       a key is typed in, as well as if the string "hello there!!!" is entered
  254.       from the com port.
  255.       TRANSMIT will transmit the string "hello there!!!" to com1 (same port
  256.       settings as receive), wait until the string is completely sent and exit.
  257.  
  258.     These classes works great in TSRs (that's what I use it for).
  259.  
  260. ----------------------------------------------------------------------------
  261.                               NOTE.
  262. ----------------------------------------------------------------------------
  263.  ■ If you need to hook with ISC to a software interrupt like int13h or int21h
  264.    don't forget that when you call { old_vect() } you must set the correct
  265.    registers to what they were after the isr was called (these register values
  266.    are in the IREGS parameter passed to isr). Usually the pseudo variables
  267.    _AX, _BX, _FLAGS, etc... will do just fine. Also remember that the values
  268.    of the registers after the software interrupts are called might be needed
  269.    by the forground too (so you can put them back into the IREGS parameter).
  270.    WARNING- if you do not do these things you will probably either crash the
  271.    forground or mash things up.
  272.  
  273.  ■ Use and abuse!!!
  274.  examples, bugs, and large donations only by writing to:
  275.  
  276.   +++++
  277.   |_ -|             Ofer Laor (AKA LeucroTTa)
  278.  @|+ o|@            27 KKL St., Kiriat Bialik (27000)
  279.   | ^ |             Israel.
  280.   |---|             telephone @ work (972) - 3 - 9684643
  281.     -                         @ home (972) - 4 - 701845
  282.  
  283.  
  284.  
  285.