home *** CD-ROM | disk | FTP | other *** search
/ Amiga Developer CD v1.2 / amidev_cd_12.iso / reference / amiga_mail_vol1 / input / inputresource < prev    next >
Text File  |  1990-01-26  |  21KB  |  716 lines

  1. (c)  Copyright 1989 Commodore-Amiga, Inc.   All rights reserved.
  2. The information contained herein is subject to change without notice, and 
  3. is provided "as is" without warranty of any kind, either expressed or implied.  
  4. The entire risk as to the use of this information is assumed by the user.
  5.  
  6.  
  7.        
  8.                        Allocation of Input and 
  9.                        Other System Resources
  10.                
  11.                             by Bob Burns
  12.  
  13.     
  14. In most system designs there is a trade-off between ease of use and 
  15. performance.  The Amiga is no exception.  Historically, high performance 
  16. applications have resorted to taking over the machine in order to get direct 
  17. access to system resources.  This is something we would like to avoid because 
  18. once the machine is taken over, there is no exit.  The user must reboot. 
  19. The purpose of this article is to present some techniques that let games
  20. and other special applications take over those portions of the system that 
  21. they need, yet gracefully return them when no longer needed.
  22.  
  23.  
  24. Input Resources
  25. ---------------
  26.  
  27. The Input Task 
  28.  
  29. A useful metaphor for describing the input task on the Amiga is the 
  30. "food-chain".  Raw input events are passed through a linked list of handlers.
  31. Each handler processes the input events it receives and returns a new set to 
  32. be "consumed" by the next input handler in the chain.  
  33.  
  34. The primal input events are designated RAWKEY, RAWMOUSE, TIMER and  DISK.  
  35. The RAWKEY, RAWMOUSE and TIMER input events are started up the food chain by 
  36. the input.device itself in response to its continuing IO requests to the 
  37. keyboard, gameport, and timer devices.  The DISK events are inserted into 
  38. the chain by the DOS.
  39.  
  40. The two standard consumers in the food chain are Intuition and the console 
  41. device.  Intuition in particular is prolific in the variety of new input 
  42. events it may produce in response to a primal event.  Another consumer often 
  43. found in the food chain is a generic hotkey program.  These insert themselves 
  44. in the food chain before either Intuition or the console.  
  45.  
  46. The food chain is implemented as a a prioritized list, with Intuition at a 
  47. priority of 50 and the console device at 20.  For more on input events, see 
  48. the devices/inputevents.h header.
  49.  
  50.  
  51. Input Device Commands
  52.  
  53. Let's quickly review the input device commands you can use to control the 
  54. food chain.  Insertion and removal of a new consumer in the input device food 
  55. chain is performed by the input.device commands AddHandler and RemHandler.
  56.  
  57. The command WriteEvent is used to propagate an event through the input food 
  58. chain without being on it.
  59.  
  60. The commands SetThresh and SetPeriod are used to modifiy the key repeat rate.
  61.  
  62. Finally, the commands SetMPort, SetMType, and SetMTrig are used to modify the 
  63. gameport controller that is to be used for mouse input.  The use of these 
  64. commands is illustrated in the example code shown below.
  65.  
  66. The joymouse.c example uses the commands to move the mouse to the second 
  67. gameport device so that the first gameport can be used with a lightpen.  This 
  68. is useful for owners of the original model A1000 and A2000s.  
  69.  
  70. The joymouse.c example also shows how to change the first gameport to work 
  71. with a joystick, or remove it from the input food chain entirely so both 
  72. ports can be used for other purposes.
  73.  
  74. You need only disable the mouse to use the gameports for your special purposes. 
  75. You don't need to take over the whole machine.  The gameport.device can then 
  76. be used to gather data from the port, or the hardware can be read directly.
  77.  
  78.  
  79.  
  80. Gameport Input
  81.  
  82. The gameport.device contains two units, one for each gameport.  The original 
  83. Amiga design called for game controllers to be allocated to applications as 
  84. follows:
  85.  
  86.         1.  Let multiple opens of gameport.device occur.
  87.  
  88.         2.  Follow a high level protocol for determining if the 
  89.             gameport is in use: check via AskCType for the flag
  90.             GPCT_NOCONTROLLER.  If set, then no one else is using it.
  91.  
  92. There are some problems with this scheme.  First, there is no protection 
  93. between SetCType and AskCType.  So two tasks can AskCType, see NO, and
  94. both SetCType.  Second, because games often go directly to the hardware, 
  95. the gameport.device became just a spoon-feeder to the input.device for mouse 
  96. input.
  97.     
  98. Despite these problems, the gameports can still be shared between applications
  99. in a system-compatible way.  Neither the SetCType nor AskCType commands are 
  100. deferred, nor do they wait and thus break a Forbid.   This means you can use 
  101. the following code to get a gameport:
  102.  
  103.         Forbid
  104.         AskCType
  105.         if(GPCT_NOCONTROLLER){
  106.             SetCType
  107.             owned = TRUE      }
  108.         else
  109.             owned = FALSE
  110.         endif
  111.         Permit
  112.  
  113. We normally try to discourage counting on this kind of side effect, but in 
  114. this case, it's the only way.  If the port is being allocated, but not for 
  115. one of the supported controller types, then set the controller to the 
  116. catch-all value GPCT_ALLOCATED.
  117.  
  118.  
  119.  
  120. Joysticks
  121.  
  122. To read a joystick, there are three choices.  The first is to change the 
  123. mouse port to a joystick port and capture events from the input device food 
  124. chain as a handler.  This is not recommended.
  125.     
  126. The second choice is to read the joystick port directly from the hardware 
  127. registers.  It's fairly easy to do and we cannot fault folks for doing it 
  128. this way - just make sure to allocate the gameport unit so other applications
  129. know you've got the port.  You should also allocate the POTGO resource bits 
  130. to acquire buttons 2 & 3.
  131.  
  132. The third choice is to use the gameport device.  This polls every vertical 
  133. blank and only satisfies requests when trigger conditions are met.  It's 
  134. advantages are that the polling runs out of the contention-free ROMs, and 
  135. when combined with certain reply port types (e.g. the direct call action), 
  136. can be efficient for your application.
  137.  
  138.  
  139.  
  140. Proportional Controller
  141.  
  142. Unfortunately, support for proportional controllers in the gameport device 
  143. was removed in one of the early code crunches.  This occurred after support 
  144. for Coleco-style controllers had already been removed.  The example program
  145. propjoy.c shown below demonstrates how to use the potgo resource and some 
  146. vblank interrupt routines to track proportional controllers.
  147.  
  148.  
  149.  
  150. Keyboard Input
  151.  
  152. The input device IO requests to the gameport can be shut down but IO requests 
  153. to the keyboard cannot.  If an application requests key events from the 
  154. keyboard, it will probably get about half of them: every other one going to 
  155. the input device.  So, to learn about all the key states an application can 
  156. either poll the keyboard with the ReadMatrix command, or insert itself as a 
  157. handler in the food chain.  If you use the ReadMatrix command, note that
  158. io_Length MUST be exactly 13.
  159.  
  160.  
  161.  
  162.  
  163. Other System Resources
  164. ----------------------
  165.  
  166. Misc
  167.  
  168. Whenever using serial or parallel port resources, they must be acquired from 
  169. the misc.resource.  The misc.resource oversees usage of the serial data port, 
  170. the serial communication bits, the parallel data and handshake port, and the 
  171. parallel communication bits.  The parallel communication bits double as the 
  172. Commodore serial bus interface bits for those who want to connect a 1541 to 
  173. the Amiga.
  174.  
  175. The serial and parallel devices both use the misc.resource.  If the Exec 
  176. device is opened and closed, the appropriate two misc resources will be 
  177. allocated then freed.  Unfortunately, if the DOS devices SER: or PAR: have
  178. been opened, they will open the device and thus the corresponding resource 
  179. pair forever.  For more information on this problem see the article on the
  180. parallel and serial resources elsewhere in this issue.
  181.  
  182.  
  183. Disk
  184.  
  185. Whenever using floppy disk resources, they must be acquired from the disk 
  186. resource.  The disk resource provides both a gross and a fine unit allocation
  187. scheme.  AllocUnit and FreeUnit are used to claim a unit for long term use, 
  188. and GetUnit and GiveUnit are used to claim a unit for shorter periods.
  189.  
  190. The trackdisk.device uses and abides by both allocation schemes.  Because a 
  191. trackdisk unit is never closed for Amiga 3.5" drives, since the file system 
  192. keeps them open, the associated resource units will always be allocated for 
  193. these drives.  GetUnit and GiveUnit can still be used, however, by other 
  194. applications that have not succeeded with AllocUnit.
  195.  
  196. It is therefore possible to prevent the trackdisk device from using units that
  197. have not been mounted yet by successfully performing an AllocUnit for that 
  198. unit.  It is also possible to starve trackdisk usage by performing a GetUnit.
  199. The appropriate companion routine (FreeUnit or GiveUnit) should be called to 
  200. restore the resource at the end of its use.
  201.  
  202.  
  203. CIA
  204.  
  205. CIA resources not associated with the misc and disk resources are the joystick
  206. fire buttons, which are acquired with the appropriate gameport.device unit, 
  207. the LED/audio filter, which is catch-as-catch-can, the memory overlay bit 
  208. and the keyboard serial interface, which is defined to be allocated by the 
  209. keyboard.device when it is running.  The CIAB timers are available to be 
  210. allocated and are associated with an interrupt.  It is therefore allocated by
  211. successfully adding a vector for that interrupt with AddICRVector.
  212.  
  213.  
  214.         Amiga CIA Timer Allocation
  215.  
  216.         CIAA (int 2)
  217.             timerA      Used for keyboard handshake
  218.             timerB      Used for uSec timer.device
  219.             TOD         Used for 60Hz timer.device
  220.  
  221.          CIAB (int 6)
  222.             timerA      Commodore serial bus communication, usually not used
  223.             timerB      Not used
  224.             TOD         Used for graphics.library beam counter
  225.  
  226.  
  227. By using the techniques outlined above, you can often avoid taking over the 
  228. whole system in your high-performance applications.  Allocate only the 
  229. resources you need and return them when you are done.
  230.  
  231.  
  232.   Copyright (c) 1988 Commodore-Amiga, Inc.
  233.  
  234.   Executables based on this information may be used in software
  235.   for Commodore Amiga computers.  All other rights reserved.
  236.  
  237.   This information is provided "as is"; no warranties are made.
  238.   All use is at your own risk, and no liability or responsibility is assumed.
  239.  
  240.  
  241. ;=============================================================
  242. ; makefile - requires Manx 3.6
  243. ;=============================================================
  244. ;
  245. ;joymouse:    joymouse.o32 iefa.o
  246. ;    ln joymouse.o32 iefa.o -lc32 -o joymouse
  247. ;
  248. ;joymouse.o32:    joymouse.c
  249. ;    cc +L +C +D +p -B -S -L100 -o joymouse.o32 joymouse.c
  250. ;
  251. ;iefa.o:        iefa.asm
  252. ;    as -o iefa.o iefa.asm
  253. ;
  254. ;=============================================================
  255. ; joymouse.c
  256. ;=============================================================
  257. #define    DEBUG
  258. #include    "exec/types.h"
  259. #include    "exec/nodes.h"
  260. #include    "exec/lists.h"
  261. #include    "exec/ports.h"
  262. #include    "exec/interrupts.h"
  263. #include    "devices/gameport.h"
  264. #include    "devices/input.h"
  265. #include    "devices/inputevent.h"
  266. #include    "libraries/dos.h"
  267.  
  268. struct Task *FindTask();
  269.  
  270. struct MsgPort iorp = {
  271.     {0, 0, NT_MSGPORT, 0, 0}, 0, SIGF_SINGLE, 0, {0, 0, 0, 0, 0}
  272. };
  273.  
  274. struct IOStdReq ior = {
  275.     {{0, 0, NT_MESSAGE, 0, 0}, &iorp, 0},
  276.     0, 0, 0, 0, 0, 0, 0, 0, 0
  277. };
  278.  
  279. struct InputEvent nullEvent = {
  280.     NULL, IECLASS_NULL
  281. };
  282.  
  283. struct GamePortTrigger joyTrigger = {
  284.     GPTF_DOWNKEYS|GPTF_UPKEYS, 1, 1, 1
  285. };
  286.  
  287. struct GamePortTrigger mouseTrigger = {
  288.     GPTF_DOWNKEYS|GPTF_UPKEYS, 0, 1, 1
  289. };
  290.  
  291. extern VOID eventAFunction();
  292.  
  293. struct Interrupt inputHandler = {
  294.     {0, 0, NT_INTERRUPT, 100, 0}, 0, eventAFunction
  295. };
  296.  
  297. #define    MAXDELTA    255
  298. #define    DELTASHIFT    4
  299.  
  300. int deltaX = 0;
  301. int deltaY = 0;
  302.  
  303. struct InputEvent *
  304. eventFunction(event, data)
  305. struct InputEvent *event;
  306. {
  307.     struct InputEvent *loopevent;
  308.  
  309. #ifdef    DEBUG
  310. kprintf(".");
  311. #endif
  312.  
  313.     loopevent = event;
  314.     do {
  315.     if (loopevent->ie_Class == IECLASS_RAWMOUSE) {
  316.         /* handle X, then Y.  slow down faster than speed up */
  317.         /* this could use another iteration to get it to "feel" right */
  318.         if (loopevent->ie_X < 0) {
  319. #ifdef    DEBUG
  320. kprintf("<");
  321. #endif
  322.         if (deltaX <= 0) {
  323.             if (deltaX > -MAXDELTA) deltaX--;
  324.         }
  325.         else deltaX = deltaX/2;
  326.         }
  327.         else if (loopevent->ie_X > 0) {
  328. #ifdef    DEBUG
  329.  
  330. kprintf(">");
  331. #endif
  332.         if (deltaX >= 0) {
  333.             if (deltaX < MAXDELTA) deltaX++;
  334.         }
  335.         else deltaX = deltaX/2;
  336.         }
  337.         else if (loopevent->ie_Y != 0) {
  338.         if (deltaX != 0) deltaX += (deltaX<0)?1:-1;
  339.         }
  340.         else deltaX = deltaX/2;
  341.         if (deltaX < 0)
  342.         loopevent->ie_X = (deltaX-((1<<DELTASHIFT)+1))>>DELTASHIFT;
  343.         else
  344.         loopevent->ie_X = (deltaX+((1<<DELTASHIFT)-1))>>DELTASHIFT;
  345.  
  346.         if (loopevent->ie_Y < 0) {
  347. #ifdef    DEBUG
  348. kprintf("v");
  349. #endif
  350.         if (deltaY <= 0) {
  351.             if (deltaY > -MAXDELTA) deltaY--;
  352.         }
  353.         else deltaY = deltaY/2;
  354.         }
  355.         else if (loopevent->ie_Y > 0) {
  356. #ifdef    DEBUG
  357. kprintf("^");
  358. #endif
  359.         if (deltaY >= 0) {
  360.             if (deltaY < MAXDELTA) deltaY++;
  361.         }
  362.         else deltaY = deltaY/2;
  363.         }
  364.         else if (loopevent->ie_X != 0) {
  365.         if (deltaY != 0) deltaY += (deltaY<0)?1:-1;
  366.         }
  367.         else deltaY = deltaY/2;
  368.         if (deltaY < 0)
  369.         loopevent->ie_Y = (deltaY-((1<<DELTASHIFT)+1))>>DELTASHIFT;
  370.         else
  371.         loopevent->ie_Y = (deltaY+((1<<DELTASHIFT)-1))>>DELTASHIFT;
  372.     }
  373.     }
  374.     while ((loopevent = loopevent->ie_NextEvent) != 0);
  375.     return(event);
  376. }
  377.  
  378.  
  379. main(argc, argv)
  380. int argc;
  381. char *argv[];
  382. {
  383.     char c;
  384.     int result;
  385.  
  386.     NewList(&iorp.mp_MsgList);
  387.     iorp.mp_SigTask = (struct Task *) FindTask((char *) NULL);
  388.  
  389.     if (OpenDevice("input.device", 0, &ior, 0)) exit(20);
  390.  
  391.     /* free this controller */
  392.     c = GPCT_NOCONTROLLER;
  393.     ior.io_Command = IND_SETMTYPE;
  394.     ior.io_Length = 1;
  395.     ior.io_Data = (APTR) &c;
  396.     DoIO(&ior);
  397.  
  398.     /* wait for the SETM to take effect with a side effect */
  399.     ior.io_Command = IND_WRITEEVENT;
  400.     ior.io_Length = (LONG) sizeof(nullEvent);
  401.     ior.io_Data = (APTR) &nullEvent;
  402.     DoIO(&ior);
  403.  
  404.     /* switch to the right game port */
  405.     c = 1;
  406.     ior.io_Command = IND_SETMPORT;
  407.     ior.io_Length = 1;
  408.     ior.io_Data = (APTR) &c;
  409.     DoIO(&ior);
  410.  
  411.     /* set this controller to a joystick */
  412.     c = GPCT_ABSJOYSTICK;
  413.     ior.io_Command = IND_SETMTYPE;
  414.     ior.io_Length = 1;
  415.     ior.io_Data = (APTR) &c;
  416.     DoIO(&ior);
  417.  
  418.     /* set the trigger for the joystick */
  419.     ior.io_Command = IND_SETMTRIG;
  420.     ior.io_Length = (LONG) sizeof(joyTrigger);
  421.     ior.io_Data = (APTR) &joyTrigger;
  422.     DoIO(&ior);
  423.  
  424.     /* insert the accellerator handler into the food chain */
  425.     ior.io_Command = IND_ADDHANDLER;
  426.     ior.io_Data = (APTR) &inputHandler;
  427.     ior.io_Length = (LONG) sizeof(struct Interrupt);
  428.     DoIO(&ior);
  429.  
  430.     /* wait for this program to terminate */
  431.     Wait(SIGBREAKF_CTRL_C);
  432.  
  433.     /* free this controller */
  434.     c = GPCT_NOCONTROLLER;
  435.     ior.io_Command = IND_SETMTYPE;
  436.     ior.io_Length = 1;
  437.     ior.io_Data = (APTR) &c;
  438.     DoIO(&ior);
  439.  
  440.     /* remove the accellerator handler from the food chain */
  441.     ior.io_Command = IND_REMHANDLER;
  442.     ior.io_Data = (APTR) &inputHandler;
  443.     ior.io_Length = (LONG) sizeof(struct Interrupt);
  444.     DoIO(&ior);
  445.  
  446.     /* switch to the left game port */
  447.     c = 0;
  448.     ior.io_Command = IND_SETMPORT;
  449.     ior.io_Length = 1;
  450.     ior.io_Data = (APTR) &c;
  451.     result = DoIO(&ior);
  452.  
  453.     /* set the trigger for a mouse */
  454.     ior.io_Command = IND_SETMTRIG;
  455.     ior.io_Length = sizeof(mouseTrigger);
  456.     ior.io_Data = (APTR) &mouseTrigger;
  457.     DoIO(&ior);
  458.  
  459.     /* set this controller to a mouse */
  460.     c = GPCT_MOUSE;
  461.     ior.io_Command = IND_SETMTYPE;
  462.     ior.io_Length = 1;
  463.     ior.io_Data = (APTR) &c;
  464.     result = DoIO(&ior);
  465. }
  466.  
  467. ;=============================================================
  468. ; iefa.asm
  469. ;=============================================================
  470. ;
  471. ; Copyright (c) 1988 Commodore-Amiga, Inc.
  472. ;
  473. ; Executables based on this information may be used in software
  474. ; for Commodore Amiga computers.  All other rights reserved.
  475. ;
  476. ; This information is provided "as is"; no warranties are made.
  477. ; All use is at your own risk, and no liability or responsibility is assumed.
  478. ;
  479.     XREF        _eventFunction
  480.  
  481.     XDEF        _eventAFunction
  482. _eventAFunction:
  483.         MOVEM.L    A0/A1,-(A7)
  484.         JSR    _eventFunction
  485.         ADDQ.L    #8,A7
  486.         RTS
  487.  
  488.         END
  489.  
  490.  
  491. /******************************************************************************
  492. *
  493. *   Source Control
  494. *   --------------
  495. *   $Header: propjoy.c,v 34.1 85/11/24 17:59:44 bart Exp $
  496. *
  497. *   $Locker:  $
  498. *
  499. *   $Log:   propjoy.c,v $
  500. *   Revision 34.1  85/11/24  17:59:44  bart
  501. *   be system compatible
  502. *   
  503. *   Revision 34.0  86/11/21  16:35:51  bart
  504. *   added to rcs for updating
  505. *
  506. * Copyright (c) 1988 Commodore-Amiga, Inc.
  507. * Executables based on this information may be used in software
  508. * for Commodore Amiga computers.  All other rights reserved.
  509. * This information is provided "as is"; no warranties are made.
  510. * All use is at your own risk, and no liability or responsibility is assumed.
  511. *
  512. ******************************************************************************/
  513.  
  514. /* main.c - test program for add/rem tof task - bart - 05.19.86 */
  515. /* propjoy.c modified program for proportional controller - bart - 11.21.86 */
  516.  
  517. ;=============================================================
  518. ; propjoy.c
  519. ;=============================================================
  520.  
  521. #include <exec/types.h>
  522. #include <exec/nodes.h>
  523. #include <exec/execbase.h>
  524. #include <exec/execname.h>
  525.  
  526. #include <graphics/gfxbase.h>
  527. #include <graphics/graphint.h>
  528.  
  529. #include <hardware/cia.h>
  530. #include <hardware/custom.h>
  531. #include <hardware/intbits.h>
  532.  
  533. #include <resources/potgo.h>
  534.  
  535. #define V1_POINT_2  33
  536.  
  537. #define NUM_SERVERS 2
  538.  
  539. #define MAX_COUNT   (UWORD)~1        /* do it for a while */
  540.  
  541. /* use system defined hard addresses */
  542.  
  543. extern struct Custom custom;
  544.  
  545. /* use system defined addresses for potgo and pot1dat */
  546.  
  547. #define POTGO        &custom.potgo
  548. #define POT0DAT        &custom.pot0dat
  549. #define POT1DAT        &custom.pot1dat
  550.  
  551. /* vertical blank interrupt server priority   */
  552.  
  553. #define HIGHINTPRI 127L        /* needs to be replaced with priority relative */
  554. #define LOWINTPRI -127L        /* needs to be replaced with priority relative */
  555.  
  556. /* bit number defines for potgo ... */
  557.  
  558. #define START_B        0    
  559.  
  560. #define DATRX_B        8    
  561. #define DATRY_B        10
  562.  
  563. #define DATLX_B        12    
  564. #define DATLY_B        14
  565.  
  566. /* masks ... */
  567.  
  568. #define START_F        (1L << START_B)
  569. #define DATRX_F        (1L << DATRX_B)
  570. #define DATRY_F        (1L << DATRY_B) 
  571. #define DATLX_F        (1L << DATLX_B)
  572. #define DATLY_F        (1L << DATLY_B) 
  573.  
  574. #define RPOTX        (START_F | DATRX_F) 
  575. #define RPOTY        (START_F | DATRY_F) 
  576. #define RPOTXY        (START_F | DATRX_F | DATRY_F) 
  577.  
  578. #define LPOTX        (START_F | DATLX_F) 
  579. #define LPOTY        (START_F | DATLY_F) 
  580. #define LPOTXY        (START_F | DATLX_F | DATLY_F) 
  581.  
  582. struct ExecBase *ExecBase = NULL;
  583. struct GfxBase *GfxBase = NULL;
  584. struct PotgoBase *PotgoBase = NULL;
  585.  
  586. /* global storage for potdat */
  587.  
  588. UWORD oldbits = NULL;
  589. UWORD potbits = NULL;
  590. ULONG potdat = NULL;
  591.  
  592. /* create server-task to read the proportional joysticks,*/ 
  593. /* update potdat, and then poke potgo to start next data read */
  594.  
  595. /* reserve space for the interrupt servers */
  596. struct Isrvstr server[NUM_SERVERS] = {NULL};
  597.  
  598. first_server(i)
  599. int i;
  600. {
  601.     /* read previous proportional joystick values */
  602.     potdat = *(ULONG *)POT0DAT;
  603.  
  604.     /* poke potgo, restore old bits */
  605.     WritePotgo(oldbits,((~1)<<8)|oldbits);
  606.  
  607.     /* be nice -- let other servers run, too */
  608.     return(NULL);
  609. }
  610.  
  611. second_server(i)
  612. int i;
  613. {
  614.     /* poke potgo, start prop joystick read  */
  615.     WritePotgo(potbits,((~1)<<8)|potbits);
  616.  
  617.     /* be nice -- let other servers run, too */
  618.     return(NULL);
  619. }
  620.  
  621.  
  622. main()
  623. {
  624.     LONG error = FALSE;
  625.     struct Isrvstr *iserver[NUM_SERVERS];
  626.     LONG i;
  627.  
  628.     /* set server priorities */ 
  629.     server[0].is_Node.ln_Pri = HIGHINTPRI;  
  630.     server[1].is_Node.ln_Pri = LOWINTPRI;   
  631.  
  632.     /* set up server pointers */
  633.     iserver[0] = &server[0];
  634.     iserver[1] = &server[1];
  635.  
  636.     if((ExecBase = (struct ExecBase *)OpenLibrary(EXECNAME,V1_POINT_2)) != NULL)
  637.     {
  638.     if((GfxBase = (struct GfxBase *)
  639.         OpenLibrary("graphics.library",V1_POINT_2)) != NULL)
  640.     {
  641.  
  642.         if((PotgoBase = OpenResource(POTGONAME,V1_POINT_2)) != NULL)
  643.         {
  644.  
  645.         /* remember currently used bits */
  646.         oldbits = ~(AllocPotBits(~1));
  647.  
  648.         /* restore previous state of bit allocation */
  649.         FreePotBits(~oldbits);
  650.  
  651.         /* now attempt to allocate start potbit */
  652.         potbits = AllocPotBits(START_F);
  653.  
  654.         Forbid();   
  655.  
  656.         /* add interrupt servers */
  657.  
  658.         AddTOF(iserver[0],first_server,0);
  659.  
  660.         AddTOF(iserver[1],second_server,1);
  661.  
  662.         Permit();
  663.  
  664.         /* loop until done */
  665.  
  666.         for(i=0; i < MAX_COUNT; i++)
  667.         {
  668.             /* wait for server to update pot values */
  669.             WaitTOF();
  670.  
  671.             /* only output information once every second */
  672.             if(!(i %  ExecBase->VBlankFrequency))
  673.             {
  674.             }
  675.         }
  676.  
  677.         Forbid();   
  678.  
  679.         for(i=0; i < NUM_SERVERS; i++)
  680.         {
  681.             RemTOF(iserver[i]);
  682.         }
  683.  
  684.         Permit();
  685.  
  686.         /* free potbits */
  687.  
  688.         FreePotBits(potbits);
  689.  
  690.         CloseLibrary(GfxBase);
  691.         }
  692.         else
  693.         {
  694.         error = TRUE;
  695.         }
  696.     }
  697.     else
  698.     {
  699.         error = TRUE;
  700.     }
  701.  
  702.     CloseLibrary(ExecBase);
  703.  
  704.     }
  705.     else
  706.     {
  707.     error = TRUE;
  708.     }
  709.  
  710.     /* return error code */
  711.     exit(error);
  712. }
  713.