HAND HELD COMPUTER INPUT APPARATUS AND METHOD

Abstract: A method and system for generating command signals for a computer monitor or other equipment. The system includes at least one pressure responsive potentiometer (15) and a device (22) operatively connected with such potentiometer for generating a command signal indicating at least one of the direction, intensity and duration of pressure applied to such potentiometer. The method remotely controls a function of a computer monitor or other equipment in response to signals obtained from pressure sensitive potentiometer manipulated by a user. The method includes the steps of periodically iterating to detect signals present on such pressure sensitive potentiometer, comparing the signals detected on each iteration to determine at least one of the amount and direction of change, generating a control signal reflecting the information determined in the comparison step, then transmitting the control signal to the computer or other equipment in a form acceptable by such computer or other equipment to effect a change in the function being controlled.

Description: HAND HELD COfr-PHIER INPUT APPARATUS AND METHOD BACKGROUND OF THE INVENTION L. FIELD OF INVENTION This invention relates generally to the interaction with and control of computers or other electronic equipment. For example, the invention can be used in conjunction with electronic light and sound equipment, personal computers or video recording and playback equipment. In particular, the present invention relates to a means of generating command and/or cursor position control through the use of a remote manipulandum. When in operation, the apparatus does not require a dedicated surface or placement in a fixed position, thereby providing an arrangement which is portable and convenient. 2. PRIOR ART A typical computer based graphic display unit basically comprises a display screen, a display controller, a data channel and an input device. Computer input devices exist in various forms. For instance, with a standard typewriter-like keyboard, commands are entered by pressing discrete character keys. The commands are then interpreted utilizing corresponding application software. Similarly, a keyboard may be designed to incorporate the use of special function keys which when interpreted through appropriate software, initiate specific actions or cause the computer display cursor to move. Light pens and touch screens permit somewhat more flexible human-computer interactions; however, these devices require the user's hand to be close to the computer display. The most recent innovations in the field of position cursor devices, includes the use of joysticks, trackball devices, ball-type cursor control assemblies and mouses. A mouse device provides cursor positioning, and some control capabilites through buttons or momentary action switches. Simply described, a mouse consists of a ball and case. In use the casing is held by the operator to place the ball against a given dedicated surface. Movement of the case will cause the ball to roll on the surface in any desired two-dimensional direction. The main drawback to the mouse device is that it requires a dedicated, relatively flat and unobstructed area to provide control and cursor position information. Other types of mouses, such as those requiring optical reflective surfaces, require special surface materials. The ball-type cursor control assembly will typically include a relatively freely rotatable control ball supported for rolling movement in frictional engagement with two or more traction devices in the form of wheels, shafts and the like to rotate said traction devices about a horizontal axis in response to the rolling movement of the control ball. These traction devices are in turn coupled to appropriate signal generating components which provide electrical output signals for controlling the position of the cursor within the field of the video display, typically in terms of cartesian coordinates. Joysticks and trackballs provide control and cursor position information without the need for a large dedicated surface area. A joystick is primarily a lever supported by a gimbal mechanism and is tiltable by the operator in any direction of a plane. The direction and angle of the inclination are detected to generate voltages or digital signals representative of the components in the X- and Y-axis directions, respectively. Most joysticks are designed to be placed on a surface, such as a tabletop. The joystick device is also limited by the pivoting range of the lever. In its most basic form a trackball device includes a housing containing a plurality of rotatable supports and a ball seated within the supports. A portion of the ball projects through an opening in the housing to allow for manual rotation by an operator. Trackballs have drawbacks both in design and in operation. The axes of rotation of the rotatable supports of the invention are fixed and proper operation of the device requires manufacture of the parts to very exacting tolerances. Also, trackballs have tended to be unduly noisy and have exhibited poor shock and impact resistance. Finally, while neither joysticks nor trackballs require large dedicated surfaces, many graphically oriented software packages require "dragging" actions which entail simultaneously holding down a button and moving the cursor. Such dragging operations are awkward to perform using trackballs and joysticks. Accordingly, the primary object of the present invention is to provide a computer input apparatus which the user may move about in virtually any dimension while exercising control over the host computer. This flexibility is achieved by means of a physical design which facilitates both hand-held and stationary desktop operations; and by providing electronic support for a plurality of communication modes and control functionality. This invention will also allow the user to perform functions, such as the control of the movement of a cursor on a video display, without the use of a large dedicated surface. Finally, the invention has incorporated many ergonomically advantageous human-computer interactions, such as the provision of a device which can be manipulated by a human user's natural pointing finger to select and control functions of a computer or other apparatus without having to be close to the apparatus being controlled. SUMMARY OF THE INVENTION In a first aspect, the present invention provides a system for the generation of command signals for at least one of a computer and other equipment. This system includes at least one pressure responsive potentiometer. Operatively connected with such potentiometer is a means for generating a command signal indicating at least one of the direction, intensity and duration of pressure applied to such potentiometer. According to a second aspect of this invention, there is provided a system for generating command signals for either a computer or other selected equipment. In this system both a transmitter and a receiver are provided. Further, there is a means for operatively communicating command signals from the receiver to such computer monitor or other preselected equipment. The system also includes means for operatively communicating command signals from the transmitter to the receiver and means in the transmitter for generating a command signal which reflects at least one of the direction, intensity and duration of pressure applied to at least one potentiometer means disposed in such transmitter. A third aspect of the instant invention provides a method for remotely controlling a preselected function of one of a computer and other preselected equipment. Such control being in response to signals generated by pressure sensitive potentiometers which can be manipulated by a user. This method includes the steps of periodically iterating to detect the signals present on such pressure sensitive potentiometer. Thereafter, comparing the signals detected on each iteration with the corresponding signals detected on the last previous iteration to determine at least one of the amount and direction of change. Then generating a control signal which reflects the information determined in the comparison step. Finally, a control signal is transmitted to such computer or other equipment in a form acceptable to such computer or other equipment to effect a change in the function being controlled. In a more limited aspect, the present invention provides a method for remotely controlling the positioning of a cursor on a computer monitor or other selected equipment. Such positioning is in response to signals obtained from pressure sensitive potentiometer means manipulated by a user. This method includes the steps of periodically iterating to detect the signals generated by such pressure sensitive potentiometer means; thereafter comparing the signals detected on each iteration with the corresponding signal detected on the last previous iteration to determine at least one of the amount and direction of change; then generating a control signal reflecting the information determined in the comparison step and finally transmitting the control signal to such computer monitor or other equipment in a form acceptable by the by the computer monitor or other equipment to effect a change in position of the cursor. According to a final aspect, the instant invention provides a hand held device for producing an output reactive to manipulation of a part of such device by the digits of a hand holding the device. Such device includes a case having a generally rectangular head portion and a generally rectangular handle portion rigidly attached to each other and defining an obtuse angle between them. The angle between the head portion and the handle portion is such that the device can be grasped while resting on a flat surface. There is a recess or opening provided in the top surface in such head portion readily accessible to the forefinger of a hand grasping the handle portion. Such part of the device which is manipulated by the digits of a hand includes a control disc located in such recess or opening and is movable therein in a generally rocking motion. Such control disc being movable by manipulation of the forefinger of a hand grasping the handle. OBJECTS OF THE INVENTION It is, therefore, one of the primary objects of the present invention to provide a system to improve control of at least one of a computer, a computer monitor and other selected equipment. Another object of the present invention is to provide a system for generating command signals for one of a computer monitor or other equipment which signals reflect at least one of the direction, intensity, and duration of pressure being applied to a potentiometer. Still another object of the present invention is to provide a system for generating command signals for one of a computer monitor and other equipment which system includes two pressure responsive potentiometers that are inter-connected in a manner to represent X and Y axis of a cartesian coordinate system. Yet another object of the present invention is to provide a system for generating command signals for a computer monitor which provides improved control of a cursor. A further object of the present invention is to provide a system for generating command signals for one of a computer monitor or other equipment in which a transmitter for the command signals can be hand held thereby enabling the user of the system more freedom of movement. Another object of the invention is to provide a system for generating command signals for a computer which system includes a portable transmitter which can be held in the hand of a user and operated and which can also be grasped and operated while it is resting on a flat surface. It is also an object of the invention to provide a system in which signals for moving a cursor on a display screen and for performing "clicking" and "dragging" operations can all be initiated by a single digit of the hand of an operator. An additional object of the present invention is to provide a system for generating command signals for one of a computer monitor or other equipment which provides faster response times. Still yet another object of the present invention is to provide a system for generating command signals for one of a computer monitor or other equipment in which the receiver portion of such system serves as a cradle for the transmitter portion of such system when the system is not in use. It is another object of the present invention to provide a method for remotely controlling a preselected function of one of a computer monitor and other equipment which provides . faster response time in performing such function. Another object of the present invention is to provide a method of and a system for generating command signals for one of a computer monitor and other equipment which utilizes a microcontroller and dedicated software. In addition to the various objects and advantages of the present invention which has been described in detail above, it should be obvious that other objects and advantages of the present invention will become apparent to these persons who are skilled in the control art from the following more detailed description of the invention, particularly, when such description is taken in conjunction with the attached drawing figures. BRIEF DESCRIPTION OF THE DRAWINGS . Figure 1 is a pictorial representation of the invention in association with a computer. Figure 2 shows one form of the physical construction of the transmitter of the invention. Figure 3 shows the transducer of the invention. Figure 4 illustrates the electrical equivalent of the transducer. Figure 5 is a schematic of one form of the transmitter of the invention. Figure 6 is a block diagram of one form of the transmitter. Figure 7 is a schematic of one form of a receiver of the invention. Figure 8 is a block diagram of one form of the receiver. Figure 9 shows the unassembled parts of the transducer shown in Figure 3. Figures 10-14 make up a flow chart of the logic of the software controlling the transmitter shown in Figures 5 and 6. Figures 15-20 are a flow chart of the logic of the software for the analog to digital channels of Figure 11. Figure 21 shows an alternative physical construction of the transmitter. Figures 22 and 23 respectively show the form of transmitter depicted in Figure 21 being supported in the hand of a user and being grasped in the hand of a user while the transmitter is supported on a substantially flat surface. Figure 24 is a block diagram of a modified form of transmitter designed for operation by a single digit of the hand of an operator. Figure 25 is a schematic circuit diagram of the modified form of transmitter depicted in Figure 24. Figure 26 is a schematic circuit diagram of a form of receiver intended for use with the transmitter of Figures 24 and 25. Figure 27 illustrates the physical construction of the form of resilient pad used with the form of position control illustrated in Figure 21. Figure 28 is a perspective view of the control disc used in the position control of Figure 21. Figure 29 is a cross-sectional view taken along the line A-A in Figure 28. Figures 30-34 comprise a flow chart of the logic of the software controlling the transmitter which employs the position control of Figure 21. Figures 35-40 comprise a flow chart of the logic of the software for the analog to digital converter channels. DESCRIPTION OF THE PREFERRED EMBODIMENTS Referring now to Figure 1 of the drawings, a computer 1 is shown connected to a receiver 2 which in turn is associated with a transmitter 3. The receiver is shown connected to the computer by means of a cable 4 but it can be housed in the same housing as the computer. As can readily be seen, the transmitter comprises a case 5 which includes a head portion 6 and a handle portion 7 disposed at an angle to the head so that the operating portions of the head can be easily reached and manipulated by the fingers of a person holding the transmitter in his hand. Further the ends 8 and 9 of the head and handle respectively of the transmitter can be used to rest the transmitter in a stable manner on a suitable surface. As seen in Figure 2, the transmitter case may be made in two pieces, an upper part 10 and a bottom part 11 suitably joined together to retain the various operating parts hereinafter described. Included in the transmitter case is a cursor position control 12, comprising a thick film position transducer 15 located and electrically connected to represent the X and Y axes of a cartesian coordinate system. Associated with the position transducer are molded disc 13 and a resilient pad 14 permanently secured to said disc 13. Alternatively resilient pad 14 may be placed between disc 13 and transducer 15 but not secured to disc 13. When pressure is applied to disc 13 in a given orientation a corresponding change in the voltage on the legs of the transducer occur which can be converted to position information on the screen of the computer. By virtue of the shape and resilience of pad 14, when pressure is released from the disc 13, the disc 13 will be returned to its neutral position in which no signal is generated by the position transducer. As seen in Figure 3, the position transducer comprises an X axis resistance strip 16 and a Y axis resistance strip 17 which when assembled form a cruciform pattern resembling a formee cross or rosette and electrically provide a potentiometer circuit equivalent electrically to the circuit shown in Figure 4. It is obvious that the resistances may be shaped and assembled to resemble other patterns and shapes. Referring to Figures 3 and 9, the transducer is constructed as follows: A substantially circular disc 55 of polyester or the like of appropriate size for insertion in the opening 48 in the transmitter housing has deposited on it the conductors 49 in the configuration shown. Next, a layer of carbon 50 is deposited in the shape and orientation shown to form a part of the potentiometer for one axis. Then a dielectric ring 51 and dielectric center block 52 are laid in place and a second carbon layer 53 is deposited forming a part of the potentiometer for the other axis. Terminal 54 is then put in place followed by a ring 60 of polyester or the like and conductors 57 and silver layer 56 which overlays carbon 50 to complete the potentiometer for the first axis. Dielectric ring 58 and dielectric block 59, both oriented as shown, are put in position and then silver layer 61 completing the potentiometer for the second axis. A top disc 35 of polyester or the like similar to disc 55 is placed on top of the transducer thus formed and the whole assembly is sealed by suitable means. Mechanically the five electrical connections are brought out in a flexible ribbon cable 160 with a connector, not shown, at the end or flexible ribbon cable 160 may plug directly into connector 161. For both axes, when resistive elements are polarized, the overlay potential is one-half the total voltage when no pressure is applied. Therefore, it is possible to generate voltages corresponding to a four quadrant cartesian system with its origin at 1/2 Vx and 1/2 Vy. Pressure responsive resistance material of the type herein described and used to form the potentiometer as hereinafter described is available as a SoftPot (trademark) membrane potentiometer from Spectra Symbol Cor ., Salt Lake City, Utah. Also included in the transmitter of the invention are four momentary contact switches 18, two of which are shown schematically, designated for operation by either the right or left hand thumb or finger while the transmitter is being held in the right or left hand, respectively. These switches are used in conjunction with the cursor position control to provide a dragging operation on the screen and/or may be assigned to control other operations similar to those produced with a mouse button. Switch caps 19 are made of a plastic or other material and so arranged that deformation of the cap or a portion thereof must occur in order to operate one of the switches or movement of the switches is otherwise biased so that the switches will not be accidentally operated merely by the user grasping and picking up the transmitter. Alternatively, switch caps 19 are recessed in the transmitter housing to avoid accidental or inadvertent operation. The transmitter assembly also includes an initiation or "wake up" switch 20 and a switch cap or actuator 21 therefor and a battery pack or other source of electrical power 28. A lens 29 through which infrared signals are transmitted is provided and an infrared signal ' source 32 is located inside the transmitter head behind the lens 29. The transmitter may be powered by dry cell batteries or a similar source of portable electric power, such as four size AAA batteries as shown in Figure 21. Transmitter functions are executed by a microcontroller represented by the block 22. Software for the microcontroller is stored in a Read Only Memory (ROM) . A printout of each of two of the computer program listings which may be used to control the microcontroller are appended to this specification. Transmitter function sequence begins when the initiation switch is actuated. As will appear from the description of transmitter function and control, the logic and software utilized in this invention are unique and novel. The logic and software are designed to respond to the probable intent of the user in operating the control as. well as the specific action taken by him. At the same time, the invention is compatible with existing host computer software and can be used with computers having mouse and/or trackball pointing devices without modification to the host computer or with minimal retrofit modification. A flow chart of the software program logic is shown in Figures 10 through 14. A flow chart of the process within the analog to digital channel is shown in Figures 15 through 21. Every transmitter unit has a unique hardware encoded identifying number. When power is first applied to the transmitter, for example when batteries are first inserted, the identifying number is read and stored in Random Access Memory (RAM) in the transmitter. All subsequent communications sent from that transmitter will contain that identifier. This affords a means of identifying the source of a communication sent to a receiver and to a host computer and also provides a means for rejecting data sent from a transmitter not intended to be in communication with a computer already in communication with another transmitter. Returning to Figure 2, it can be seen that disc 13 has a generally concave top surface 23 and a generally convex bottom surface 24. The bottom surface also has molded projecting surfaces 25 resembling a formee cross and generally congruent with and overlying the resistance strips 16,17 shown in Figure 3. Alternately bottom surface 24 may be made without the molded projecting surfaces 25. Pad 14 has a generally concave top surface 26 of substantially the same size and shape as bottom surface 24 of the disc 13 and a substantially flat bottom surface 27 which is in contact with the top surface of the polyester disc 35 of the top one of pressure responsive resistance strips 16,17 but does not apply sufficient pressure thereto to affect the resistance thereof unless pressure is being applied to disc 13. Switches 18 and 20 and microcontroller 22 are indicated schematically only in the drawings. When pressure is applied to disc 13 on a portion thereof corresponding generally to the direction in which it is desired to move the cursor, the disc will move in a generally rocking motion, compressing a portion of one or both of the resistance strips 16,17 and changing the voltages at the corresponding voltage terminals 37, 38, 39 or 40. In an alternate construction and orientation of the position control and transmitter as shown in Figure 21 initiation or wake up switch 120 and dragging or clicking switch 218 have their operators 121 and 219 respectively located underneath position control 112. A substantially rigid plate 110 is positioned between the thick film position transducer 15 and the switch operators 121 and 219. Plate 110 may be made of plastic or similar material and is adhered or otherwise secured to transducer 15. Switches 120 and 218 offer sufficient resistance to operation by switch operators 121 and 219 that they are not inadvertently operated by normal pressure on control disc 113 to effect cursor movement. However, by pressing with slightly greater force the initiation switch or the clicking or dragging switch can be actuated when desired. As can be seen this can all be accomplished using only a single digit of the hand. This is particularly useful when using the invention with software for computer graphics. Completing the construction of the position control 112 are pad 114 and control disc 113. As may be best seen in Figure 27, pad 114 is a relatively thick cylindrical pad which has a relatively flat top surface 126 shown in Figure 27B and a bottom surface 127 which has relatively flat lobes 227 which outline a recessed formee cross 125 and which lobes overlie the formee cross shape of the position transducer 15. As shown in Figure 27 the recess forming the formee cross 125 increases in depth from the outer diameter of the pad 114 to a predetermined maximum depth at its center. Pad 114 is made of a relatively soft, yielding and resilient material so that pressure applied to disc 113 will be transmitted to a relatively broad surface of potentiometer 15 through the material of the pad. As seen in Figure 27 the pad 114 has a series of apertures 201 which are used in a manner hereinafter described to keep the lobes 227 in alignment over the legs of the potentiometer and with the corresponding sectors of disc 113 so that pressure in a given orientation of the control disc 113 will result in a signal to move the cursor in the corresponding direction. Control disc 113 is actually a flanged, cup-shaped member made in one piece of a plastic or similar material as seen in Figure 28. Looking now at Figure 29, the disc 113 is seen to have a series of projecting pins 202 corresponding in number and placement to the apertures 201 in pad 114. For ease of insertion in the apertures 201, pins 202 may be slightly smaller at their free ends than at their bases. Disc 113 also has a flange 203 around its circumference. Flange 203 is provided with one or more alignment notches 206 which keep the position control 112 properly oriented within the transmitter housing by mating with corresponding registry ridges or splines, not shown, on the inside of the transmitter housing. The top surface 204 of control disc 113 is slightly convex and the bottom surface 205 is generally flat to provide even contact with the top surface of pad 114. Switch 120 and its operator 121 are located substantially under the center of plate 110 and position control 112 so that operator 121 serves as a pivot point for plate 110. Pressure on a given sector of control disc 113 will cause the assembly comprising position control 112 to rock gently over the pivot point formed by switch operator 121. As can best be seen in Figure 21, when the type of position control 112 is used then the opening 48 in the top half 10 of the transmitter housing is a through opening and the position control 112 rests on switch operators 121 and 219 with the control assembly being retained in the housing by disc 113 and the cooperating elements of transmitter case 6. It is to be understood that the outer diameter 230 of pad 114 is slightly smaller than the inner diameter 231 of disc 113 and that the inner diameter 232 of opening 48 is slightly larger than the outer diameter 233 of disc 113 but smaller than the outer diameter of the flange 203. Position control 112 can be assembled by positioning and cementing potentiometer 15 on disc 110, placing pad 114 on potentiometer 15 with lobes 227 overlying the corresponding lobes of the formee cross sectors of potentiometer 15 and then placing disc 113 over pad 114 with pins 210 aligned with apertures 201 and with notches 206 aligned with the guide splines in the transmitter housing. Position data and control can be sent from the transmitter 3 to the receiver 2, clicking and dragging operations can be controlled and the transmitter can be activated, all by manipulation of control 112 and all by the use of a single digit of the hand of the user. It is contemplated that the user will use his forefinger, but it is obvious that any digit may be used which is comfortable or more desirable for the user. In the form of transmitter and control shown in Figure 21, switches 119 are provided which are comparable to switches 19 in the form of transmitter shown in Figure 2 but all four switches are available for uses other than clicking or dragging operations which in this form of the invention are performed through control 112 and switch 218. Figure 21 shows an alternative construction of the transmitter housing. In this embodiment, case 105 includes a longer head portion 106 and a shorter handle portion 107 which make it more comfortable to hold in the hand for operation with a forefinger as shown in Figure 22. This also seems to make it more convenient to use,the transmitter when it is resting on a flat surface as shown in Figure 23. The microcontroller in the transmitter controls the content and transmission of data and protocol packets, the frequency and timing of control loop iterations, computation of position data during control loop execution and the logic used in such computations. Information is sent to the receiver which converts it to a form which can be utilized by the host computer. Position data is sampled at frequent intervals but data is sent to the receiver once in every two or three of the sampling intervals. This is based on an estimate of an interval which would satisfactorily capture the action of a user who is manipulating the position controller. Transmitter circuitry is shown in Figure 5 and a block diagram of the transmitter circuit is shown in Figure 6. The transmitter is normally in a low power consumption or dormant state and is activated when the initiation switch 20 is closed. The transmitter control software is configured so that closing switch 20 at any other time will not affect operation of the system. As long as the switch 20 is held closed the transmitter sends a special connect packet which includes the transmitter identifier as previously described. At intervals determined by the program, position data is obtained and sent to the receiver. In one embodiment, the iteration intervals may for example be on the order of 60 milliseconds and the transmittal intervals may for example be on the order of 120 or 180 milliseconds. In the second embodiment the iteration interval, which is constant in the first embodiment, is assigned one of two values (a "high value" and a "low value"), selected from the range of 30 milliseconds to 180 milliseconds, depending on the force applied to the transducer. We prefer to use a high value of 130 milliseconds when a large force is applied to the transducer and a low value of 50 milliseconds when a low force is applied to the transducer. In this second embodiment, position data is transmitted at each iteration. In both embodiments, position information is derived from a voltage taken from the potentiometers which is dependent on the force and position of pressure applied to the resistance element through disc 13 and which is read by analog to digital converters (A/D) attached to each resistance element and from a duration counter which is incremental on each iteration of the control loop during which the disc 13 has been held down. When the disc 13 is pressed, the elastic pad 14 acts to distribute the force over a wider area. In particular, if force is not applied directly over one of the resistive elements, the pad 14 acts to distribute the force onto both elements. Furthermore, as additional force is applied the convex bottom of the disc 13 causes the disc to move in a rocking motion and the primary point of application of the force to move toward an outer edge 36 of resistance strips 16, 17. As the point of application moves, the transducer yields corresponding voltage changes. Voltage levels, which range from 0 to a maximum determined by circuit parameters, reflect the direction and magnitude of force applied to the disc. Voltages between 0 and a voltage somewhat below one-half of maximum represent movement in the negative direction of the corresponding axis. Voltages between a voltage somewhat greater than one-half of maximum and approximately the maximum represent movement in the positive direction of the corresponding axis. The band between the two ranges or neutral band assures that low-level noise inherent in the A/D converters does not result in the generation of spurious position data while the disc is in its neutral position. The distances along the X and Y axes are divided into arbitrary units such as mickeys or pixels or other units. To obtain baseline position data or unit count, voltages outside the neutral band are divided into several bands which correspond to ranges of applied forces. Bands closer to the neutral band correspond to lower applied forces. Each band has an associated unit count; for computational efficiency counts for adjacent bands differ by factors of 2. If the current value from an A/D channel lies within the neutral band, the duration counter and the unit count are both reset to zero. A voltage level that does not lie within the neutral band determines the current baseline unit count. First, the value of the previous reading is checked. If the previous reading was within the neutral band, the current unit count is set to one, and the previous reading is updated with the current reading value. This logic assures that it is possible to generate a 1 unit position increment. If the previous reading was not within the neutral band, the current baseline unit count is set to correspond to the current reading. For example, ±8 units for the second band away from the neutral band. The current reading is then compared to the previous reading. If the previous reading equals the current reading, the baseline unit count is not changed. If the previous reading is less than the current reading, the unit count is halved. If the previous reading is greater than the current reading, the unit count is doubled. To accomplish unit count decrease the baseline unit count is shifted to the right and to accomplish unit count increase the baseline is shifted to the left. After the unit count has been adjusted for voltage levels, if necessary it is then adjusted to reflect the length of time that force has been applied. Each time a voltage outside the neutral band is detected, a duration counter is incremented. When the duration counter crosses a first threshold value predetermined in the software, the baseline unit is doubled. When the duration count exceeds a second higher threshold value, the baseline unit count derived from the A/D value is no longer adjusted for duration count. This adjustment logic facilitates more rapid movements of the cursor across large screen areas in the middle of the screen, but prevents overshooting by slowing movement of the cursor as it presumably approaches the users desired target. This adjustment logic attempts to account for the reaction time of a user and assumes that as the distance remaining to be traversed across the screen becomes shorter, the user will want to slow down movement of the cursor so he has greater control. Control information sent by the transmitter also reflects the state of the momentary action switches located on the sides of the transmitter module. To provide maximum flexibility of operation by a user, four electrically independent switches are provided. Any one or combination of switches can be assigned to be the logical left mouse/trackball button, with the remaining switches assigned to be the logical right mouse/trackball button. Activating a switch causes a "button down" signal to be generated; releasing a switch causes a "button up" signal to be generated. If a button and the positioning knob are simultaneously pressed, both position data and button status data are transmitted to the computer, thus producing manipulation substantially like the familiar mouse "dragging" operation. The state of each switch is read upon every iteration of the main program control loop, after the A/D converters are read. At the end of each control loop iteration, if either position data or button status data requires transmission to the host computer, a protocol packet is formed and sent. A protocol packet consists of a byte stream that begins with an ASCII standard SOH flag and terminates with a checksum byte. The second byte of a packet is a type byte which indicates the packet type and a sequence number. Potential packet types include but are not limited to a connect packet, a position p acket, a voice communication packet and other data packets. Each packet type has a predefined fixed length. Therefore the type implicitly specifies the packet's total length. The sequence number is used for message synchronization. Every packet also contains a status byte and the two-byte identifying number of the transmitter unit. The status byte indicates the state of each button and whether or not the battery voltage is below either of two threshold voltages. Position packets contain an additional two bytes of relative position information. One byte indicates relative X coordinate changes since the last report; the second byte indicates Y coordinate changes since the last report. Each time a protocol packet is formed, it is transmitted three times in a burst, then there is a random delay before a second burst is sent. The random time interval assures that two transmitter units do not become synchronized and continuously interfere with each other. Bursts of the same packet are periodically sent with increasing time intervals between each transmission until either new data are generated or a timeout period elapses, in which case the transmitter goes into its low power consumption state. The frequency and intervals between transmissions is determined by the software as is the duration of the timeout period during which no transmission occurs which will produce a shutdown of the transmitter. As seen in Figure 1, receiver 2 has a generally flat bottom surface which will rest stably on a table top or the like and an angular top surface, complementary to the bottom surfaces of the handle and head portions of transmitter 3. This permits the transmitter and receiver to be nested for compact storage or the transmitter may be set on the receiver during operation when it is not desired to hand-hold the transmitter. Receiver functions are executed by a microcontroller whose software is stored in ROM. The receiver detects Pulse Code Modulated Infrared (IR) data streams sent by the transmitter, verifies that the transmitter ID contained in the protocol pack is valid, decodes position and status information from the packet, and translates the resulting information into signals which can be directly applied to an interface port on the host computer. The logical connection between a transmitter and a receiver is established during an authentication process which involves pointing the transmitter at the receiver and generating a special "connect" packet by momentarily pressing the initiation or wake- p switch actuator 21 on the transmitter. The logical connection is maintained until the receiver is powered off or until another communication initialization packet is detected. Each time the receiver detects and validates an incoming IR data stream, an LED indicator 46 shown on the receiver circuit diagram controlled by the microcontroller is intermittently flashed. Also, if the incoming data stream indicates that transmitter batteries are low, a second LED indicator 47 shown on the receiver circuit diagram is turned on. Although the invention has been shown and described in part as being a position control for a computer monitor cursor, it is obvious that the invention can be used for other purposes and in other contexts. For example, it may be used to control lights, sound or communication equipment or any other device having a variable and capable of producing a change therein in response to an electrical, infrared or electronic signal. Although certain preferred embodiments have been shown and described, it should be understood that many changes and modifications may be made therein without departing from the scope of the appended claims. BAT.ASM - (09-16-91 REV 0.76 10:04 PM) 0.75incorporated absolute band values 0.76turned off A/D prior to sleeping Copyright 1991 MioroMed Systems Inc. All Rights Reserved NAME BAT TRANSMITTER $INCLUDE(TLCS47.II) DSEG ABS TRANSMITTER DATΛ( 0 ) RAM MEMORY ALLOCATION PAGE ZERO: RES 16 reserve 16 nibbles for page 0 SAVE EQU ; looation to save 1IL register ; and for temporary storage start of transmit buffer packet PACKET 1 nibble for packet type and flags SEQUENCE :+l ; 1 nibble for sequence number STATUS / 1 nibble (low) for button status BATTERY 1 nibble (high) for battery status TEMP use battery nibble for temp storage X_MICK 2 nibbles for x axis mickey count Y_MICK 2 nibbles for y axis mickey count SENDER 4 nibbles for transmitter ID CHECKSUM .+4 ; 2 nibbles for checksum ;14 nibbles total for packet PAGE 0 Boundary X AND Y AXIS FORCE BAND THRESHOLD VALUES (6 bytes per axis) ?_BΛNDS[5] negative band 3 (highest memory address) 7_BANDS[4] negative band 2 ?_BΛNDS[3] negative band 1 neutral band ?_BΛNDS[2] positive band 1 7_BΛNDS[1] positive band 2 7 BANDS[0] positive band 3 (lowest memory address) XJ3ΛNDS EQU CHECKSUMS ; 12 nibbles for x axis values Y BANDS EQU X_BΛNDS+12 ; 12 nibbles for y axis values PAGE 1 Boundary at Y_BΛNDS+4 ; 24 nibbles total for bands CURRENT AND PREVIOUS BAND INFORMATION BAND EQU Y BΛNDS+12 1 nibble for new band / direction OLDX EQU BAND+1 ,' 1 nibble for old x band / direction OLDY EQU OLDX+1 ; 1 nibble for old y band / direction MOVEMENT DURATION COUNTERS X_MOVE EQU OLDY+1 ; 1 nibble for x movement duration Y MOVE EQU X MOVE+1 ,* 1 nibble for y movement duration ; TRANSMIT COUNTERS DOZE_CTR EQU Y_MOVE+l ; 3 nibbles for sleep counter ; HIGH BIT RESERVED- max value is 2047 RXMT_CTR EQU DpZE_CTR+3 ; 2 nibbles for retransmit counter ;11 nibbles total for miscellaneous ; PAGE 2 Boundary READ_CTR EQU RXMT_CTR+2 ; 1 nibble for read loop counter TOTAL RAM REQUIRED 49 nibbles COUNTER AND TIMER CONSTANTS TIMER1_REGISTER EQU 0F4H timer 1 register (3 nibbles) TIMER1 FLAG EQU 0F7H last nibble (of 4) allocated to timer 1 is used for flag TIMERl FLAG BIT EQU bit 0 clr indicates timer active bit 0 set indicates timer done TIMERl PRESET EQU 0F56H , ♦ timer 1 preset (0F16H is 60 ms) 0F26H is max acceptable (9/2/91) MAX NUMBER EQU OFH maximum packet sequence number READ COUNT EQU 02H ; number of main (button and A/D) ; read loop iterations before ; checking movement duration counters ; to determine whether new position ,' data should be transmitted DOZE CYCLE EQU 1800 number of READ_COUNT iterations, during which no new position or button data was obtained, to execute before going to sleep MUST NOT EXCEED 2047- highest order bit used as an axis lag MOVE CYCLE EQU 15 maximum number of READ_COUNT iterations in which a force is applied along an axis (X_MOVE and Y_MOVE are clamped) RXMT CYCLE EQU number of READ__COUNT interations before most recent packet is resent XMIT FLAG BIT MASKS XMIT_NOW_BIT bit position for transmit now flag XMIT_NOW mask for transmit now flag } XMIT_DONE_BIT bit position for transmit done flag XMIT DONE mask for new transmission complete PACKET TYPES SOH EQU 01H ; SOH for protocol packet CONNECT wakeup / connect packet POSITION position / status packet XMIT FLAG XMIT NOW I POSITION AXIS BIT EQU DOZE_CTR high nibble bit for channel clear for X axis set for Y axis EOC BIT EQU bit which indicates when A/D conversion has ended BAND BIT MASKS B1_BIT bit 0 corresponds to band 1 B2_BIT bit 1 corresponds to band 2 B3_BIT bit 2 corresponds to band 3 DIRECTION bit in BAND to indicate direction BAND_1 current force is in band 1 BAND_2 current force is in band 2 BAND_3 current force is in band 2 NEGATIVE current direction is negative BAND MICKEY COUNTS BAND1_MICK EQU 1 base mickey value for band 1 BAND2_MICK EQU 4 base mickey value for band 2 BAND3 MICK EQU 8 base mickey value for band 3 YP controls this screen direction (negative mickeys) XN controls XP controls this screen direction this screen I (positive mickeys) direction (negative mickeys) YN controls this screen direction (positive mickeys) X BAND THRESHOLD LEVELS (124 base) X_3N_VALUE X_2N_VALUE X_1N_VALUE X_1P_VALUE X_2P_VALUE X 3P VALUE Y BAND THRESHOLD LEVELS (135 base) Y_3N_VALUE Y_2N_VALUE Y IN VALUE Y_1P_VALUE Y_2P_VALUE Y 3P VALUE BATTERY STATUS BITS BATTERY WEAK EQU 04H ; battery marginal bit BATTERY LOW EQU 08H ; battery low bit BUTTON STATUS BITS RIGHT_BUTTONS EQU 03H logical right mouse buttons LEFT BUTTONS EQU 0CH logical left mouse buttons HOLD MODE EQU 1100B level release mode/ 65.5 wake up CODE SEGMENT INTERRUPT .HANDLERS INTERRUPT CODE( OH ) ; execution starts here on power up POWER UP ; branch to power up code ORG 06H ; execution starts here for ; timer 1 interrupt B TIMERl HANDLER ; branch to timer 1 handler ORG 10H to prevent **GAP** message in map CSEG REL STANDARD CODE(IOH) POWER UP BATTERY_GOOD: DATA 0C8H marginal battery threshold DATA 096H low battery threshold POWER_UP: LD A,#12 ST A,OFFH ;SET PSW (STACK PTR) get 16 bits of transmitter ID LD LD ST INC ST INC ST INC ST initialize timer 1 NOTE the low order bit (bit 0) of the high order nibble of the stack location reserved for timer 1 is used as a timer done flag while bit 0 is clear the timer is active when bit 0 is set a timer period has elapsed (the timer 1 interrupt handler sets bit 0) W AKE U P CODE WAKE UP: OUT #0, %OP01 turn on A/D LD HL, #TIMER1_REGISTER ; point to timer 1 register ST #NLL TIMER1_PRESET, @HL+ ST #NLH TIMER1_PRESET, @HL+ ST #NHL TIMER1_PRESET, @HL+ CLR @HL, TIMER1_FLAG_BIT ; clear timer done flag set count rate enable interrupt 4 and start counter ; wait a while ; wait a while start of protocol packet ; set packet type to connect packet sequence number set sequence number to 1 clear A clear button status zero battery status zero X_MICK low nibble zero XJMICK high nibble zero Y_MICK low nibble zero Y_MICK high nibble wait here until switch pressed read wakeup switch is it down? branch if not (initialization) send a wake up packet ; and wait a while read wakeup switch if bit is clear (switch closed) WAKE LOOP END: LD HL, #X_BANDS+6 ; low nibble of first negative band LD A, #NLL X_1N_VALUE low nibble of first offset ST A, @HL+ ,* store value LD A, #NLH X_1N_VALUE ; high nibble of first offset ST A, @HL+ ; store value LD A, #NLL x_2N_VALUE ; low nibble of second offset ST A, @HL+ ; store value LD A, #NLH X_2N_VALUE ; high nibble of second offset ST A, SHL+ ; store value LD A, #NLL X 3N VALUE ; low nibble of band 3 value ST A, @HL+ ; store it LD A, #NLH X_3N_VALUE ; high nibble of band 3 value ST A, '@HL+ ; store it LD HL, #X_BANDS ; point to low nibble of last ; positive band LD A, #NLL X_3P_VALUE ; low nibble of band 3 value ST A, 6HL+ ; store it LD A, #NLH X_3P_VALUE ; high nibble of band 3 value ST A, ΘHL+ ; store it LD A, #NLL X_2P_VALUE ; low nibble of band 2 offset ST A, @HL+ ; store low nibble result LD A, #NLH X_2P_VALUE ; high nibble of band 2 offset ST A, ΘHL+ LD A, #NLL X_1P_VALUE ; low nibble of band 1 offset ST A, SHL+ ; -store low nibble result LD A, #NLH X_1P_VALUE ; high nibble of band 1 offset ST A, GHL LD HL, #Y_BANDS+6 ; low nibble of first negative band LD A, #NLL Y_1N_VALUE ; low nibble of first offset ST A, SHL+ ; store value LD A, #NLH Y_1N_VALUE ; high nibble of first offset ST A, @HL+ ; store value LD A, #NLL Y_2N_VALUE ; add low nibble of second offset ST A, @HL+ ; store value LD A, #NLH Y_2N_VALUE ; high nibble of second offset ST A, @HL+ ; store value LD A, #NLL Y_3N_VALUE ; low nibble of band 3 value ST A, @HL+ ; store it LD A, #NLH Y_3N_VALUE ; high nibble of band 3 value ST A, @HL+ ; store it LD HL, #Y BANDS ; point to low nibble of last positive band LD A, #NLL Y_3P_VALUE ; low nibble of band 3 value ST A, @HL+ ; store it LD A, #NLH Y_3P_VALUE ; high nibble of band 3 value ST A, @HL+ ; store it LD A, #NLL Y_2P_VALUE ; low nibble of band 2 offset ST A, @HL+ ; store low nibble result LD A, #NLH Y_2P_VALUE ; high nibble of band 2 o fset ST A, @HL LD HL, #Y_BANDS+4 ; point to low nibble of first ; positive band UE ; low nibble of band 1 offset ; store low nibble result location for old X band initialize to zero memory zero OLDX zero OLDY zero X_MOVE zero Y_MOVE location of start of packet ; set XMIT_NOW and POSITION bits zero sequence number STATUS was cleared above ; load address of READ_CTR initialize counter with zero to ensure mickey count is updated on first transmission get current state of all buttons complement the bits compare new state with old make SF «= ZF ; now branch if new status = old update button status D ; set transmit immediate flag GET AXIS DATA: in first call to DO CHANNEL high bit in DOZEjCTR is 0 for X axis CALL DO_CHANNEL get X axis data LD HL, #DOZE_CTR+2 ; point to high order nibble SET @HL, AXIS_BIT ; set high order bit CALL DO_CHANNEL get Y axis data LD HL, #DOZE__CTR+2 ; point to.high order nibble CLR @HL, AXIS BIT ; clear high^ ' order bit TEST PACKET, XMIT_NOW_BIT ; transmit immediate bit set? B CHECK XMIT COUNTER ; branch if not set ADD SEQUENCE, fl increment sequence number B SEND_IMMEDIATE_PACKET ; branch if no carry (SF = ~CF) ADD SEQUENCE, #1 start over with sequence number 1 SEND_IMMEDIATE_PACKET: ST #POSITION, PACKET ; clear XMIT_NOW_BIT CALL SEND PACKET ; send the packet ST #XMIT_DONE, PACKET ; set XMIT_DONE bit (clears type) ; (may not be necessary 7/24/91) LD HL, #READ_CTR ; load address of READ_CTR ST #READ COUNT, @HL+ ; reset counter LD HL, #DOZE_CTR ; load address of DOZE_CTR ST #NLL DOZE_CYCLE, @HL+ ; low nibble of low byte ST #NLH DOZE_CYCLE, @HL+ ; high nibble of low byte ST #NHL DOZE_CYCLE, @HL+ ; low nibble of high byte CALL RESET RXMT CTR ; reset the retransmit counter BR BOTTOM_XMIT_LOOP; branch to decrement READ_CTR and ; and delay ; (skip checking for retransmit ; or sleep) DETERMINE WHETHER TIME TO TRANSMIT e A for several comparisons load address of READ_CTR es READ_CTR = 0? ; branch if not (not time to xmit) ST #READ COUNT, @HL+ ; reset READ CTR LD HL, #X_MOVE ; load address of X_MOVE CMPR A, GHL ; is X_MOVE 0 ? B UPDATE SEQUENCE NUMBER ; branch if not (send buffer) LD HL, #Y_MOVE load address of Y_MOVE CMPR A, @HL is Y_MOVE 0 ? TESTP ZF make SF = ZF B DEC DOZE CTR ; branch if 0 (nothing to transmit) UPDATE_SEQUENCE_NUMBER: ADD SEQUENCE, #1 ; increment sequence number B SEND_TIMED_PACKET ; branch if no carry (SF = ~CF) ADD SEQUENCE, #1 ; start over with sequence number 1 SEND_TIMED_PACKET: ST #POSITION, PACKET ; clear XMIT_NOW_BIT CALL SEND_PACKET ; send the packet ST #XMIT_DONE, PACKET ; set XMIT_DONE bit (clears type) ; (may not be necessary 7/24/91) LD HL, #DOZE_CTR ; load address of DOZEJCTR ST #NLL DOZE CYCLE, @HL+ ; store sleep count low nibble ST #NLH DOZEJYCLE, 8HL+ ; store middle nibble ST #NHL DOZEJCYCLE, 8HL+ ; store high nibble CALIr RESET RXMT CTR ; reset the retransmit counter if READ_CTR == 0 (if time to check for transmission) if X_MOVE or Y_MOVE 0 (if movement on either axis) if SEQUENCE MAX_NUMBER increment SEQUENCE else set SEQUENCE = 1 call SEND_PACKET set XMITJTLAG -- DONE set READ_CTR * READ_COUNT set DOZEjCTR -- DOZEJCYCLE reset RXMT CTR (use random number generator) fall through to decrement DOZEjCTR and RXMTjCTR DEC_DOZE_CTR: LD HL, #DOZEJCTR ; point to DOZEJCTR low nibble DEC 8HL ; decrement low nibble B DEC_RXMT_CTR ; branch if no carry INC L ; point to middle nibble DEC @HL ; decrement middle nibble B DEC_RXMT_CTR ; branch if no carry INC L ; point to high nibble DEC @HL ; decrement high nibble DEC_RXMT__CTR: LD HL, #RXMT_CTR ; point to RXMTJCTR low nibble ; TEMPORARY BR CHECK_RXMTJ TR TEMPORARY ! ! 7/28/91 DEC 8HL decrement low nibble TESTP CF make SF = CF B CHECKJRXMTJCTR ; branch if no carry LD HL, #RXMT_CTR+1 ; point to-RXMTjCTR high nibble DEC 8HL decrement high- ' nibble DETERMINE WHETHER TIME TO RETRANSMIT CHECKJRXMTJCTR: LD HL r #RXMT_CTR point to RXMTjCTR low nibble LD A, 8HL get low nibble CMPR A, #0 is it zero B CHECK DOZE CTR branch if not zero LD HL, #RXMT_CTR+1 point to RXMTjCTR high nibble LD A, ' 8HL get high nibble CMPR A, #0 is it zero B CHECK_DOZE_CTR ; branch if not zero CALL SEND_PACKET send the existing packet CALL RESET RXMT CTR ; reset the retransmit counter DETERMINE WHETHER TIME TO SLEEP CHECK_DOZE_CTR: ;BR BOTTOM_XMIT_LOOP ; !!!!!! TEMPORARY 7/29/91 LD HL, #DOZE_CTR ; point to DOZEjCTR low nibble LD A, 8HL ; get low nibble CMPR A, #0 ; is it zero B BOTTOM_XMIT_LOOP; branch if not zero LD HL, #DOZE_CTR+l ; point to DOZEjCTR middle nibble LD A, 8HL ; get middle nibble CMPR A, #0 ; is it zero B BOTTOM_XMIT_LOOP; branch if not zero LD HL, #DOZE_CTR+2 ; point to DOZEjCTR high nibble LD A, 6HL ; get high nibble CMPR A, #0 ; is it zero B BOTTOM XMIT LOOP; branch if not zero LOAD_DOZE: OUT #1, %OP01 ; turn off A/D LD A, #HOLD_MODE OUT A, %OP10 . BR WAKE UP ; branch to reinitialize BOTTOM_XMIT_LOOP: LD HL, #READ_CTR ; point to READjCTR DEC GHL decrement it CALL WAIT_F0R_TIMER1 ; wait a while BR XMIT LOOP TOP ; go back and do it again SEND PACKET: ASSUMES: buffer is correct except for battery status and checksum ACTIONS: fills in battery status bits computes checksum ( ith an assumed SOH byte) sends bit stream out IR emitter returns to point of invocation 1. read battery A/D channel 2. set battery status bits as appropriate 3. compute checksum using SOH (01H) as first byte 4. send bit stream via IR emitter ST #0, BATTERY ; assume battery is OK CALL GET BATTERY AD ; read A/D channel for battery level LD HL, #BATTERYJ300D ; initialize for good battery CALL ISJ..ESS ; is CHECKSUM less than BATTERYJ300D B BATTERY DONE ; branch if so ST #BATTERY_WEAK, BATTERY INC L INC L CALL IS_LESS B BATTERY_DONE ST #(BATTERY LOW OR BATTERY WEAK) , BATTERY BATTERY_DONE: LD A, #SOH ; SOH is first byte TEMPORARILY CREATE MICROSOFT FORMAT HERE LD A, STATUS get status ST A, PACKET save it for later ST #4, BATTERY set bit 6 of STATUS byte LD HL, #STATUS point to button status LD A, 6HL get button status AND A, #RIGHT_BUTTONS ; check for either right button TESTP ZF B LBJCHECK branch if no right buttons set INC L point to BATTERY OR 8HL, #1 set right button bit DEC L ; back to STATUS LBJCHECK: LD A, 8HL ; get button status AND A, #LEFT_BUTTONS; check for either left button TESTP ZF ; set SF = ZF B ADJUSTJMICKEYS ; branch if no left buttons set INC L ; point to BATTERY OR GHL, #2 ; set left button bit ADJUSTJMICKEYS; LD HL, #X_MICK+1 ; point to -XJICK high nibble LD A, 8HL get nibble AND A, #0CH clear low bits TEST CF clear carry RORC A shift right RORC A shift right ST A, STATUS put in low bits of STATUS (killing original button status) ; point to YJMICK high nibble ; get nibble ; clear low bits ; point to STATUS ; combine bits ; and save result ; point to XJMICK high nibble ; kill high bits of high nibble ; and replace high nibble ; point to YJMICK high nibble ; kill high bits of high nibble ; and replace high nibble using Richter send function ; point to first byte ; send the leader ; send first byte ; next byte ; send it ; last byte ; send it restore status for next process ; return to caller end SEND PACKET DOjCHANNEL — the following logic assumes that when highest order bit of DOZEjCTR is clear the X axis A/D should be read (GETJ?OSITION_AD maps bit to correct physical channel) compare current value to ?_BANDS+6 (threshold for + band 1) if value ?_BANDS+6 set BAND = BAND_1 if value 7JBANDS+8 set BAND = BAND_2 if value ? BANDS+10 set BAND = BAND_3 goto BANDJDONE else if value 7J3ANDS+4 set BAND = BAND_1 if value 7JBANDS+2 set BAND = BAND_2 if value ?J3ANDS_3 set BAND = BAND_3 set BAND I NEGATIVE (set NEGATIVE bit with OR) goto BANDJDONE otherwise do nothing (BAND == 0 from initialization) get address of BAND make sure band is zero CALL GET_POSITI0N_AD ; get value and store in CHECKSUM load HL with high nibble of counter check for axis if bit is clear, SF = 1 Y axis LD A, OLDY get previous Y band ST A, TEMP store in battery status nibble temporarily LD HL, #Y_BANDS+7 ; point to high nibble of negative BAND_1 is CHECKSUM BAND_1 branch if not ; set band to band 1 ; point to high nibble of ; negative band 2 ; is CHECKSUM BAND_2 ; branch if not ; set band to band 2 ; point to high nibble of ; negative band 3 ; is CHECKSUM BAND 2 ; set band to band 3 LD HL, #Y BANDS+5 ; point to high nibble of ; positive BAND_1 ; is CHECKSUM BAND_1 ; branch if not ΘHL+ ; set band to band 1 ; point to high nibble of ; positive band 2 ; is CHECKSUM BAND_2 ; branch if not 8HL+ ; set band to band 2 ; point to high nibble of ; positive band 3 ; is CHECKSUM BAND 2 @HL+ ; set band to band 3 get previous X band store in battery status nibble temporarily LD HL, #X BANDS+7 ; point to high nibble of ; negative BAND_1 ; is CHECKSUM BAND_1 ; branch if not 8HL+ ; set band to band 1 ; point to high nibble of ; negative band 2 ; is CHECKSUM BAND_2 ; branch if not 8HL+ ; set band to band 2 ; point to high nibble of ; negative band 3 ; is CHECKSUM BAND 2 8HL+ ; set band to band 3 ; point to high nibble of positive BAND_1 is CHECKSUM BAND_1 branch if not ; set band to band 1 ; point to high nibble of positive band 2 is CHECKSUM BAND_2 branch if not ; set band to band 2 ; point to high nibble of positive band 3 is CHECKSUM BAND 2 ; set band to band 3 BAND_DONE: ; If both current and previous bands are zero, branch to update old ; with new (they are both zero) get current band is current band 0 ? ; branch if not get old band make SF = ZF branch if zero to update band BAND == 0 previous band was not 0 LD HL, #D0ZE_CTR+2 ; get high nibble of counter TEST 8HL, AXISJBIT ; check axis B X BAND 0 ; branch for X (SF = -AXIS BIT) LD HL, #Y_MOVE ; point to YJOVE LD A, 8HL ; get value • TESTP ZF ; is it zero B YJOVE D ; branch if so (Y axis jog) ST #0, 8HL+ ; zero YJMOVE TEST PACKET, XMIT_N0WJ3IT ; was XMIT_NOW previously set B BANDJUPDATE ; branch if not (SF = ~XMIT_N0WJ3IT) ; (leave YJMICK alone for RXMT) ST #0, Y_MICK ; ensure no further Y axis movement ST #0, YJMICK+1 LD HL, #X_MOVE ; point to X axis movement LD A, 8HL ; get value TESTP ZF ; is it zero B Y_X_MOVE_0 ; branch if so (XMITJOW may have ; been set by buttons) BR BAND UPDATE r ; set XMITJ0WJ3IT point to YJMICK get old band ; is it negative ; branch if so (SF = ~ZF) 1 mickey (positive) clear high nibble 1 mickey (negative) extend sign ; point to high nibble get value is it negative branch if not (SF = -DIRECTION bit) complement high nibble store value and point to low nibble get low nibble complement it zero ? ; branch if so point to high nibble again get high nibble adjust it is I XJMICK I 8 ; branch if so (SF = -ZF) get low nibble is I XJMICK I 1 ; set SF.= CF branch if not clear XJMICK low nibble ; clear XJMICK high nibble either 1 or zero ; point to XJMOVE ; get value ; is it zero ; branch if so (X axis jog) ; set XJMOVE to zero ; ensure no future X movement ; and branch to update band ; force X axis jog by 1 mickey ■ CET ; set XMIT_NOW_BIT ; point to XJMICK ; get old band ; is it negative ; branch if so (SF = -ZF) ; 1 mickey (positive) ; clear high nibble ; branch to update band ; 1 mickey (negative) ; extend sign ; branch to update band If current band equals zero and previous band was not zero for the current channel, the action required depends on the channel. The intent is to ensure that no more than a 1 mickey movement is reported whenever a transition to band zero occurs and less than READjCOUNT * TIMEJOELAY milliseconds have elapsed since the movement was first detected. The logic below permits a 1 mickey "jog" when the user presses and releases the control knob in under READjCOUNT * TIME_DELAY milliseconds. The logic is complicated by the fact that XJMICK and YJMICK must not be changed until a transmission is certain (to ensure that retransmissions contain correct data) . That is, when an X axis transition from a non-zero band to the zero band occurs the XJMICK count cannot be changed because after the Y channel is checked the end result may be to do nothing but keep the transmit buffer intact for retransmissions if (axis bit == 0 and OLDX == 0) or (axis bit »== 1 and OLDY == 0) goto BANDJCJPDATE BAND == 0 and axis bit == 0 x axis if XJMOVE « 0 ; no display yet set XMIT FLAG XMIT NOW if OLDX & NEGATIVE set XJMICK = -1 else set XJMICK = 1 - if XJMOVE 0 leave mickey count alone but don't set XMITJJLAG in both cases, fall through set XJMOVE = 0 ; always set = goto BANDJJPDATE ; and update band BAND 0 and axis bit ∞ 1 y axis if YJMOVE == 0 ; no display yet set XMIT FLAG XMIT NOW if OLDY & NEGATIVE set YJMICK = -1 else set YJMICK = 1 the following logic ensures that if x reading didn't cause a jog, transmit buffer XJMICK count is set to zero if (XJMOVE == 0 and XJMICK 1) or (XJMOVE == 0 and XJMICK -1) set XJMICK = 0 else -y axis movement didn't cause jog; if XMIT_FLAG is set to XMIT_NOW, YJMICK must be cleared; if button status change caused XMITJOW setting XJMICK count must also be cleared if XMIT_FLAG & XMITJOW if (XJMOVE •== 0 and XJMICK 1) or (XJMOVE == 0 and XJMICK -1) set XJMICK = 0 set YJMICK ■= 0 - otherwise (XMIT_NOW not set) leave YJMICK alone set YJMOVE ■= 0 goto BANDJJPDATE end BAND «= 0 DISPLAY CHECK: only process current A/D channel value if XMIT_NOW bit is set or it is time to transmit an updated mickey count (READJCTR == 0) determine whether previous band for current axis was zero; if so, make sure its direction corresponds to current BAND direction get old band was it zero? branch if not address of current band current direction negative? branch if not store NEGATIVE flag in old band NZ 0: if (axis bit = 0) set YJMICK = 0 if (axis bit == 1) and (XJMOVE «= 0) set XJMICK = 0 ( no current movement in X direction, so zero XJMICK ) then update movement duration counters LD A, #0 ; initialize for later ; get high nibble of counter check axis branch if zero (SF = 1) Y axis ; is X duration counter 0? ; branch if not ; zero XJMICK low nibble ; zero XJMICK high nibble NZ 1: CALL GET DIRECTION ; determine whether old and new directions are the same branch if so ; initialize YJMOVE for ; movement in opposite direction BR PROCESS BANDS ; branch to continue Z 0: point to current Y duration increment ; branch if no carry return to 0FH ; branch to continue CH 00: process x axis ; zero YJMICK low nibble ; zero YJMICK high nibble ; determine whether old and new ; directions are the same ; branch if so ; initialize XJMOVE for ; movement in opposite direction BR PROCESS BANDS ; branch to continue Z 1: LD HL, #XJMOVE ; point to current X duration INC 8HL ; increment B PROCESS 3ANDS ; branch if no carry DEC 8HL ; return to OFH BEGIN PROCESSING CURRENT VALUE PR0CESSJ3ANDS : LD HL, #BAND ; point to new band TEST 8HL, B1J3IT ; is it band 1 B CHECKJ3ANDJTW0 ; branch if not (HL points to BAND) LD A, TEMP ; get old band AND A, #07H ; mask off direction B Bl PREVIOUS NOT ZERO ; branch if old band was not zero LD HL, #X MICK ; assume update X mickeys LD A, DOZEjCTR+2 ; get high nibble of counter TEST A, AXISJ3IT ; check axis B Bl ONE MICKEY UPDATE ; branch if X (SF = 1) LD HL, #YJMICK ; must be Y mickeys BljDNEJMICKEY_UPDATE: ; previous (X or Y) band was zero so use a 1 mickey move ; get current band ; is it negative ; branch if so ; 1 mickey (positive) ; clear high nibble ; branch to update band ; 1 mickey (negative) ; extend sign ; branch to update band Bl PREVIOUS NOT ZERO: BAND == 1 PREVIOUS != 0 CALL GET DIRECTION ; determine whether old and new ; directions are the same B DO BAND 1 ; branch if so if current movement is opposite direction from previous movement update will use base band 1 mickey count and the current direction LD HL, #XJMICK ; assume X mickey update LD A, DOZEjCTR+2 ; get high nibble of sleep counter TEST A, AXISJ3IT ; check axis B Bl STANDARD UPDATE ; branch for X (SF= 1) LD HL, #Y MICK ; must be Y mickey update BljSTANDARDJUPDATE: LD A, BAND ; get current band AND A, #NEGATIVE ; is it negative B BIJMINUSJSTANDARD ; branch if so ST #BAND1JMICK, 8HL+ ; band 1 base mickeys (positive) ST #0, @HL+ ; clear high nibble BR BAND_UPDATE ; branch to update band BIJMINUSJSTANDARD: ST #-BANDl_MICK, 8HL+ ; band 1 base mickeys (negative) ST #-1, 0HL+- ; extend sign BR BAND UPDATE ; branch to update band DO_BAND_l: if current movement is same direction as previous movement start with base mickey count for band 1 and adjust depending on previous band ST #BAND1JMICK, CHECKSUM ; use checksum as temp variable ST #0, CHECKSUM+1 ; clear high nibble LD HL, #TEMP get old band TEST 8HL, B1J3IT was old band 1? B B1_N1 branch if not BR MICKEYJUPDATE ; branch to update mickey count Bl Nl: TEST CF clear carry flag LD A, CHECKSUM get mickey value ROLC A shift left TEST 8HL, B2J3IT was old band 2? B B1_N2 branch if not ST A, CHECKSUM save adjusted mickeys BR MICKEY UPDATE ; branch to update mickey count Bl N2: ROLC bit gets shifted into CF LD A, CHECKSUM+1 ; load high nibble of CHECKSUM ROLC A shift CF into bit 0 of high nibble ST A, CHECKSUM+1 ; and replace it BR MICKEY UPDATE ; branch to update mickey count CHECK FOR BAND TWO CHECKJ3ANDJTWO: TEST 8HL, B2J3IT ; is current band band 2? B BAND THREE ; branch if not LD A, TEMP ; get old band AND A, #07H ; mask off direction B B2 PREVIOUS NOT ZERO ; branch if old band was not zero LD HL, tXJMICK ; assume update X mickeys LD A, DOZE j CTR+2 ; get high nibble of counter TEST A, AXISJ3IT ; check axis B B2 ONE MICKEY UPDATE ; branch if X (SF = 1) LD HL, #YJMICK ; must be Y mickeys B2JDNEJMICKEYJJPDATE: ; previous (X or Y) band was zero so use a 1 mickey move get current band ; is it negative ; branch if so 1 mickey (positive) clear high nibble branch to update band 1 mickey (negative) extend sign branch to update band B2 PREVIOUS NOT ZERO: BAND >== 2 PREVIOUS != 0 CALL GET DIRECTION ; determine whether old and new ; directions are the same B DO BAND 2 ; branch if so if current movement is opposite direction from previous movement update will use base band 2 mickey count and the current direction LD HL, #X MICK ; assume X mickey update LD A, DOZEJCTR+2 ; get high nibble of sleep counter TEST A, AXISJ3IT ; check axis B B2 STANDARD UPDATE ; branch for X (SF= 1) LD HL, #Y MICK ; must be Y mickey update B2_STANDARD_UPDATE: LD A, BAND ; get current band AND A, #NEGATIVE ; is it negative B B2 MINUS STANDARD ; branch if so BR BANDJPDATE ; branch to update band ST #BAND2_MICK, @HL+ ; band 2 base mickeys (positive) ST #0, 8HL+ ; clear high nibble B2JMINUSJ3TANDARD: ST #-BAND2_MICK, 8HL+ ; band 2 base mickeys (negative) ST #-1, 8HL+ ; extend sign BR BAND UPDATE ; branch to update band DO_BAND_2: ; if current movement is same direction as previous movement ; start with base mickey count for band 2 and and adjust depending ; on previous band LD A, #BAND2_MICK ; get band 2 standard value ST #0, CHECKSUM+1 ; ensure high nibble is clear LD HL, #TEMP get old band TEST 8HL, B1J3IT was old band 1? B B2_N1 branch if not TEST CF clear carry flag RORC A divide by two ST A, CHECKSUM save result BR MICKEYJJPDATE ; branch to update mickey count B2 Nl: TEST 8HL, B2J3IT was old band 2? B B2_N2 branch if not ST A, CHECKSUM use unadjusted standard value BR MICKEY UPDATE ; branch to update B2 N2: TEST CF clear carry flag ROLC A shift left ST A, CHECKSUM save adjusted value LD A, CHECKSUM+1 ; get high nibble ROLC A rotate carry into high nibble ST A, CHECKSUM+1 ; and store it BR MICKEY UPDATE ; branch to update mickey count BAND THREE BANDJTHREE: LD A, TEMP ; get old. band AND A, #07H ; mask off direction B B3 PREVIOUS NOT ZERO ; branch if old band was not zero LD HL, #XJMICK assume update X mickeys LD A, DOZEJCTR+2 ; get high nibble of counter TEST A, AXISJ3IT ; check axis B B3 ONE MICKEY UPDATE ; branch if X (SF = 1) LD HL, #Y MICK must be Y mickeys B3 ONE MICKEY UPDATE: previous band zero- use 1 mickey LD A, BAND get current band AND A, #NEGATIVE ; is it negative ; branch if so 1 mickey (positive) clear high nibble branch to update band 1 mickey (negative) extend sign branch to update band B3 PREVIOUS NOT ZERO: BAND == 3 PREVIOUS != 0 CALL GET DIRECTION ; determine whether old and new ; directions are the same B DO BAND 3 ; branch if so if current movement is opposite direction from previous movement update will use base band 3 mickey count and the current direction LD HL, #X MICK ; assume X mickey update LD A, DOZEjTR+2 ; get high nibble of sleep counter TEST A, AXISJ3ΪT ; check axis B B3_S ANDARD_UPDATE ; branch for X (SF= 1) LD HL, #Y_MICK ; must be Y mickey update B3_STANDARD_UPDATE: LD A, BAND ; get current band AND A, #NEGATIVE ; is it negative B B3 MINUS STANDARD ; branch if not ST #NLL BAND3JMICK, 8HL+ ; band 3 base mickeys ST #NLH BAND3JMICK, 8HL+ ; high nibble BR BANDJJPDATE ; branch to update band B3JMINUSJ3TANDARD: LD A, #NLL (-BAND3JMICK) ; band 3 base mickeys ST A, @HL+ ; store lo nibble LD A, #NLH (-BAND3JMICK) ; band 3 base mickeys ST A, @HL ; store low nibble BR BANDJJPDATE ; branch to update band DO_BAND_3: if current movement is same direction as previous movement start with base mickey count for band 3 and adjust depending on previous band ST #NLL BAND3JMICK, CHECKSUM LD A, #NLH BAND3JMICK ; get band 3 high- nibble MICKEYJJPDATE: ; move value from CHECKSUM into the appropriate position update ; byte in packet (using two's complement for negative numbers) LD HL, #X_MICK ; assume X mickey update ; get high nibble of sleep counter ; check axis ; branch for X (SF= 1) ; must be Y mickey update MU 00: ; get current band ; is it negative ; branch if so ; get low nibble of mickey count ; store low nibble ; get high nibble of mickey count ; store it ,* branch to update band information MUN: ; get low nibble of mickey count ; make two's complement ; branch if no borrow ST A, GHL+ store low nibble LD A, CHECKSUM+1 ; get high nibble of mickey count SUBR A, #0 two's complement of high nibble DEC A extend sign of low nibble BR STOREJHIGH_NIBBLE ; branch to store it- N0J30RR0W: ST A, GHL+ store low nibble LD A, CHECKSUM+1 ; get high nibble of mickey count SUBR A, #0 two's complement of high nibble STORE_HIGH_NIBBLE: ST A, @HL ; store high nibble BANDJJPDATE: LD HL, #OLDX assume X axis band update LD A, DOZE j CTR+2 ; get high nibble of sleep counter TEST A, AXISJ3IT ; check axis B BU 00 ; branch for X (SF= 1) ; must be Y axis band update ; get current band ; save in OLDY ; return to caller determine whether value 8 bit stored in CHECKSUM is greater than 8 bit value pointed to by HL and HL+1 ASSUMES: both numbers are positive (i.e. values from A/D) on entry, HL points to high nibble of byte RETURNS! SF set if CHECKSUM >= QHL SF clear if CHECKSUM < 8HL ISJ3REATER: LD A, 8HL get high nibble of value CMPR A, CHECKSUM+1 ; compare high nibble of CHECKSUM to high nibble of value CHK GSGN branch to check sign if result not zero t get low nibble ; compare with low nibble ; make SF = -CF determine whether value 8 bit stored in CHECKSUM is less than 8 bit value pointed to by HL and HL+1 ASSUMES: both numbers are positive (i.e. values from A/D) on entry, HL points to high nibble of byte ECKSUM = 8HL 8HL get high nibble of value ; compare high nibble of CHECKSUM to high nibble of value branch to check sign if result not zero ; high nibbles both zero ; point to low nibble ; branch if no borrow ; swap A and H ; decrement A ; swap A and H ; get low nibble ; compare with low nibble ; make SF = CF GET DIRECTION determine whether old and new bands represent same direction ASSUMES: old band info is in TEMP variable new (current) band info is in BAND variable RETURNS: SF set if directions the same SF clear if directions different ; get old band ; mask off band info make sure CF is clear put old direction in CF point to new band get new band mask off band info- bits 3 and 2 are directions old and new positive? make SF = ZF branch if so (SF is 1) old and new negative? make SF = ZF GD 0: RET GET POSITION AD read an axis A/D channel and store result in CHECKSUM ASSUMES: HL points to high nibble of DOZEjCTR on entry Axis ID is in high bit of high nibble 0 is X axis 1 is Y axis RETURNS: the 8 bit value in CHECKSUM GET_POSITION_AD: LD A, #1 assume X axis LD HL, #DOZE_CTR+2 load HL with high nibble of counter TEST 8HL, AXISJ3IT check axis B SELECTjCHANNEL branch if bit clear (X axis) DEC A must be Y axis SELECTJCHANNE : LD HL, #CHECKSUM ; location to store data ; MUST BE ON EVEN NIBBLE BOUNDARY ! ! OUT A,%OP12 ; select channel LD A,#l OUT A,%OP13 ; start conversion POSITION CONVERSION LOOP: TEST %IP0C, E0CJ3IT ; wait for EOC B POSITIONjCONVERSION_LOOP ; L register low bit MUST be 0 IN %IP0D, 8HL ; get low nibble INC L ; point to high nibble IN %IP0D, GHL ; get high nibble RET ; GET BATTERY AD read battery status A/D channel and stores result in CHECKSUM ASSUMES: battery status is A/D channel 2 RETURNS: the 8 bit value in CHECKSUM ; assume battery status channel ; select channel ; start conversion LD HL, #CHECKSUM ; location to store data ; MUST BE ON EVEN NIBBLE BOUNDARY ! ! BATTERY_CONVERSION_LOO : TEST %IP0C, E0CJ3IT ; wait for EOC B BATTERY CONVERSION LOOP WAIT FOR TIMERl wait until timer 1 interrupt handler clears timer active flag RETURNS: nothing WAITJFORJTIMERl: LD HL, #TIMER1_FLAG; point to flag nibble TIMER_LOOP: TEST 8HL, TIMER1_FLAG_BIT ; is timer active B TIMER LOOP ; branch if so CLR GHL, TIMERlJFLAGJ3IT ; clear flag for next period RET ; and return ; TIMERl HANDLER interrupt handler for timer 1 resets counter sets bit 0 in high order nibble of timer 1 stack location to indicate a timer period has elapsed RETURNS: nothing TIMER1JHANDLER: XCH HL, SAVE ; save HL register LD HL, #TIMER1_REGISTER ; point to TCI register ST #NLL TIMER1_PRESET, @HL+ ST #NLH TIMERlJ?RESET, @HL+ ST #NHL TIMERl PRESET, @HL+ SET 8HL, TIMERl FLAG BIT ; set done flag XCH HL, SAVE ; restore HL RETI and return from interrupt RESET RXMT CTR reset the retransmit counter RETURNS: nothing RESET_RXMT_CTR: LD HL, #RXMT CTR eventually this will be replaced by a random number generator ST #NLL RXMTJCYCLE, @HL+ store low nibble ST #NLH RXMT CYCLE, @HL+ store high nibble RET SEND BYTE: ASSUMES: HL points to low nibble of byte ; send low nibble of byte ; branch if on same page ; adjust H for next page ASSUMES: HL points to nibble TRASHES: RXMT CTR (it is reset after every transmission) LD A, #4 ST A, RXMTJCTR use low nibble for counter LD A, @HL get nibble to send ST A, RXMTjCTR+1 ; use high nibble for temp storage NIBBLE_LOO : LD A, RXMTjCTR+1 ; get the nibble RORC A get first bit ST A, RXMTjCTR+1 ; save altered nibble TESTP CF set SF = CF B SEND_AJ0NE if carry set send a 1 bit CALL DOZERO send a zero bit BR CHECK_FOR_END SEND_A_ONE: CALL DOONE ; send a one bit CHECK_FOR_END: LD A, RXMTJCTR ; get counter DEC A ; and decrement TESTP ZF ; set SF = ZF B ENDJ0F_NIBBLE ; branch if done ST A, RXMTJCTR ; save counter BR NIBBLE LOOP ; and branch for next bit ENDJ3F_NIBBLE: RET PCKT: LD A,#06H ; changed from 05 8/14/91 LOOP: OUT #0,%OP02 NOP NOP NOP NOP OUT #1,%OP02 NOP NOP DEC A CMPR A,#0 B LOOP RET LTIMEO:LD A,#09H B LLUP LTIME1:LD A,#0FH LLUP: NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP DEC A CMPR A,#0 B LLUP RET DO LEADER: ASSUMES: nothing TRASHES: RXMTJCTR (it is reset after every transmission) LD A, #0FH ; load count ST A, RXMT CTR ; save it DO_LEADER_LOOP: CALL PCKT send a few dummy packets CALL PCKT LD A, RXMTJCTR load counter DEC A decrement ST A, RXMTJCTR store for next CMPR A,#0 is it zero (done) B DO_LEADER_LOOP ; branch if not CALL LTIME1 wait a while CALL LTIME1 RET END IMP.ASM Imp Transmitter Control Program Copyright (c) 1992 MicroMed Systems Inc. Pittsburgh PA All Rights Reserved No part of this program may be reproduced, stored in a retrieval system, or transmitted, in any form or by any means, electronic, mechanical, photocopying, recording, or otherwise, without the prior written permission of the author, MicroMed Systems Inc. CONFIDENTIAL This file contains non-published TRADE SECRETS owned by MicroMed Systems Inc. incorporated absolute band values turned off A/D prior to sleeping turned on A/D at top of loop changed hold mode command to edge added delay after wakeup (09/22/91) began timer revisions (11/14/91) revised PCKT for 60KHz carrier revised timing logic- wait after reading buttons and A/D (12/14/91) added code to use Watchdog Timer (01/11/92) completed revisions to use profiles for mickey count updates (1/20/92) 0.83 added code to read Dallas Semiconductor Serial Number (1/30/92) 0.84 changed sense of button bits for second generation prototypes added code to read. R82 for main control button added RETI to handle dummy interrupt (3/22/92) 0.85 separated x and y profiles added code to vary time delay depending on highest band (3/25/92) NAME IMP TRANSMITTER $INCLUDE(TLCS47.H) ; include symbols after NAME directive DSEG ABS TRANSMITTER DATA( 0 ) RAM MEMORY ALLOCATION PAGE ZERO: RES 16 reserve 16 nibbles for page 0 SAVE EQU ; 2 nibbles for exchanging HL and for temporary storage start of transmit buffer packet 1 nibble for packet type and flags 1 nibble for sequence number ; 1 nibble (low) for button status 1 nibble (high) for battery status use battery nibble for temp storage 2 nibbles for x axis mickey count 2 nibbles for y axis mickey count 4 nibbles for transmitter ID 2 nibbles for checksum ;14 nibbles for packet (total) PAGE 0 Boundary (16 nibbles total) X AND Y AXIS FORCE BAND THRESHOLD VALUES (6 bytes per axis) ?JBANDS[5] negative band 3 (highest memory address) ?JBANDS[4] negative band 2 ?_BANDS[3] negative band 1 neutral band ?_BANDS[2] positive band 1 ?JBANDS[1] positive band 2 ? BANDS[0] positive band 3 (lowest memory address) XJ3ANDS EQU CHECKSUM+2 ; 12 nibbles for x axis values Y BANDS EQU X BANDS+12 ; 12 nibbles for y axis values PAGE 1 Boundary at YJ3ANDS+4 ; 24 nibbles total for bands CURRENT AND PREVIOUS BAND INFORMATION BAND 1 nibble for new band / direction OLDX 1 nibble for old x band / direction OLDY 1 nibble for old y band / direction MOVEMENT DURATION COUNTERS ; 1 nibble for x movement duration 1 nibble for y movement duration 1 nibble for x axis profile index L ; 1 nibble for y axis profile index L ; 1 nibble for current axis pointer HIGH BIT RESERVED 2 nibbles for retransmit counter XMIT NBR EQU RXMT CTR+2 ;14 nibbles for serial number / CRC TOTAL RAM REQUIRED 64 nibbles COUNTER AND TIMER CONSTANTS TIMERJCOUNT_REGISTER EQU 0F4H; timer 1 register (3 nibbles) TIMER FLAGS REGISTER EQU 0F7H; last nibble (of 4) allocated ; to timer 1 is used for flag bits TIMER DONE BIT EQU bit 0 clr indicates timer active bit 0 set indicates timer done SLEEP FLAG BIT EQU ; bit 3 clr indicates sleep timer is ; not active ; bit 3 set indicates sleep timer is ; active STOP TIMER RATE EQU 0000B ; stop timer (disable all interrupts) DOZE TIMER RATE EQU 1010B timer mode and internal rate 16 XMIT TIMER RATE EQU 100OB ; timer mode and internal rate 4096 TIMER INTERRUPT EQU 0100B ; enable timer 1 interrupt TIMER PRESET VALUES NOTE: 3 bytes 6 1200 baud require 21 MS to get from receiver to host- with additional processing overhead delay between transmissions should not be less than 29ms (by experiment) ; 30 milliseconds ; 40 milliseconds ; 50 milliseconds ; 60 milliseconds ; 80 milliseconds 100 milliseconds ; 120 milliseconds ; 150 milliseconds PRESET_200MS EQU 0CF2H ; 200 milliseconds PRESET_250MS EQU 0C2FH ; 250 milliseconds HOLDJMODE EQU 010OB edge release mode / 65.5 wake up DATAJCOUNTER EQU 0FCH ; low nibble of data counter register MAX_NUMBER EQU 0FH ; maximum packet sequence number READ COUNT EQU 01H ; number of main (button and A/D) ; read loop iterations before ; checking movement duration counters ; to determine whether new position ; data should be transmitted MOVE CYCLE EQU 15 maximum number of READjCOUNT iterations in which a force is applied along an axis (XJMOVE and YJMOVE are clamped) RXMT CYCLE EQU number of READjCOUNT interations before most recent packet is resent XMIT FLAG BIT MASKS bit position for transmit now flag mask for transmit now flag bit position for transmit done flag mask for new transmission complete PACKET TYPES SOH EQU 01H ; SOH for protocol packet CONNECT ; wakeup / connect packet POSITION ; position / status packet XMIT FLAG ; XMIT NOW | POSITION AXIS BIT EQU AXISJPTR high nibble bit for channel clear for X axis set for Y axis EOC BIT EQU bit which indicates when A/D conversion has ended BAND BIT MASKS B1J3IT ; bit 0 corresponds to band 1 B2J3IT ; bit 1 corresponds to band.2 B3J3IT ; bit 2 corresponds to band 3 DIRECTION ; bit in BAND to indicate direction BAND_1 ; current force is in band 1 BAND_2 ; current force is in band 2 BAND_3 ; current force is in band 2 NEGATIVE ; current direction is negative BAND MICKEY COUNTS BANDIJMICK EQU 1 base mickey value for band 1 BAND2JMICK EQU 2 base mickey value for band 2 BAND3 MICK EQU 4 base mickey value for band 3 YP controls this screen direction (negative mickeys) XN controls XP controls this screen direction this screen | (positive mickeys) direction | (negative mickeys) I YN controls this screen direction (positive mickeys) X BAND THRESHOLD LEVELS (124 base) Y BAND THRESHOLD LEVELS (135 base) BATTERY STATUS BITS BATTERYJSEAK EQU 04H battery marginal bit BATTERY LOW EQU 08H battery low bit BUTTON STATUS BITS MAINJ3UTTONJ3IT IP08 bit 2 is R82 (INTl) WAKEJ3UTT0NJ3IT IPOE bit 0 is KEO (HOLD) LEFTJ3UTT0NS SI / S2 RIGHT BUTTONS S3 / S4 CODE SEGMENT INTERRUPT HANDLERS CSEG ABS INTERRUPT CODE( OH ) ORG OH interrupt vector for power up/reset B POWER UP branch to start program execution ORG 02H interrupt vector for INTl (pin R82) RETI (simply return) ORG 06H interrupt vector for timer 1 B TIMER HANDLER ; branch to timer 1 handler ORG OCH interrupt vector for INT2 (pin R80) RETI (simply return) ORG 10H to prevent **GAP** message in map ; CSEG REL STANDARD CODE(IOH) BATTERY THRESHOLD VALUES marginal battery threshold low battery threshold TIMING ROUTINE FOR DALLAS PART DALLASJTIMER: XCH A, SAVE save A register for caller LD A, #3 3 timing iterations DTJL.OOP: DEC decrement counter NOP do nothing NOP again NOP and again CMPR A, #0 last time? B DT_LOOP branch if not XCH A, SAVE restore A register for caller RET and return get 4 bits (a hex digit) GET4: LD A, #4 initialize counter XCH A, CHECKSUM use CHECKSUM as temp variable here TEST CF clear the carry flag LD A, #0 clear accumulator ST A, 8HL clear address pointed to by HL FOURL :CLR %OP09, 0 ; start read period SET %OP09, 0 IN %IP09, A ; get a bit RORC A ; put it in carry flag LD A, 8HL ; get current nibble value RORC A ; rotate carry bit into nibble ST A, 0HL ; and save the nibble for next time CALL DALLASJIIMER ; wait a while XCH A, CHECKSUM ; get current value of counter DEC A ; decrement it ST A, CHECKSUM ; save it CMPR A, #0 ; are we done? B FOURLP ; branch if not RET ; otherwise return to caller BEGIN EXECUTION AFTER POWER UP/RESET POWERJJP: LD A,#12 ; provide 12 nibbles of stack space ST A,0FFH ; set up stack pointer get 16 bits of transmitter ID CLR %OP09, 0 ; send logic low to DS2400 LD A,#8 ; load counter (must hold low for ; 480 microseconds) START_RESET: CALL DALLASJTIMER ; delay for 60 microseconds DEC A CMPR A,#0 ; have we waited long enough B START_RESET ; branch if not SET %OP09, 0 ; send logic high to DS2 00 CHECKJRESET: TESTP %IP09, 0 ; is bit still high B CHECK RESET ; loop if so ; DS2400 pulls line low for min 60 ; max 240 microseconds to indicate ; that DS2400 is present is line still low branch if so ; when line goes high reset is done ; next write OxOF command word ; (four ones then four zeroes) ; load counter to write 4 ones ; pull line low ; set line high ; wait a while ; decrement counter ; all done? ; branch if not ; load counter to write 4 zeroes ; pull line low ; wait a while ; set line high ; decrement counter ; all done? ; branch if not ; point to serial number buffer ; get nibble ; next location ; get type ID (ignored) ; set HL back to start of buffer counter for 7 bytes (6 S/N + CRC) use TEMP as temporary variable here GET4 trashes A register ! get low nibble (placed in @HL) increment pointer get high nibble increment pointer get counter decrement it and save it are we done? branch if not ; save low order 16 bits of DALLAS ID ; point to transmitter ID buffer in ; communication packet ; get lowest nibble of ID ; store it ; get next nibble of ID ; store it ; get next nibble of ID start timer 1 as sleep timer in case wake up switch is not pressed after batteries are inserted NOTE i I Bit 0 of the high order nibble of the stack location used by timer 1 serves (when set) as the timer done flag Bit 3 (when set) indicates that the timer was started to determine when it is time to sleep (the timer 1 interrupt handler sets bit 0) WAKE UP CODE ; turn on A/D IR ; start timer to determine when to ; sleep ; point to start of protocol packet ; set packet type to connect ; packet sequence number ; set sequence number to 1 ; clear A ; clear button status ; zero battery status ; zero XJMICK low nibble ; zero XJMICK high nibble ; zero YJMICK low nibble ; zero YJMICK high nibble LD HL, #TIMER_FLAGS_REGTSTER ; point to timer flags WAKE LOOP 0: wait here until switch pressed TEST 8HL, TIMERJONEJ3IT ; time to go to sleep ? B CHECK_WAKEUP_SWITCH ; branch if not BR GO TO SLEEP ; otherwise go to sleep CHECK WAKEUP SWITCH: this code handles case of power on after batteries inserted IN %IP0E, A read wake up switch AND A, #1 is it down? B WAKE LOOP 0 loop if not LD A, #0 turn off timer OUT A, %0P1C turn off timer ST A, ΘHL clear timer flags WAKE_LOOP_l: CALL SENDJPACKET ; send a wake up packet CALL START_30MS ; start timer CALL WAIT FOR TIMER ; and wait IN %IP0E, A ; read wakeup switch TEST A, WAKEJ3UTT0NJ3IT ; if bit is clear (switch closed) B WAKE LOOP 1 ; send another packet WAKE_LOOP_END: LD HL, #X_BANDS+6 ; low nibble of first negative band LD A, #NLL X_1N_VALUE ; low nibble of first offset ST A, @HL+ ; store value LD A, #NLH X_1N_VALUE ; high nibble of first offset ST A, GHL+ ; store value LD A, #NLL X_2N_VALUE ; low nibble of second offset ST A, 8HL+ ; store value LD A, #NLH X_2N_VALUE ; high nibble of second offset ST A, @HL+ ; store value LD A, #NLL X_3N_VALUE ; low nibble of band 3 value ST A, ΘHL+ ; store it LD A, #NLH X_3N_VALUE ; high nibble of band 3 value ST A, @HL+ ; store it LD HL, #X BANDS ; point to low nibble of last positive band LD A, #NLL X_3P_VALUE ; low nibble of band 3 value ST A, 6HL+ ; store it LD A, #NLH X_3P_VALUE ; high nibble of band 3 value ST A, 8HL+ ; store it LD A, #NLL X_2P_VALUE ; low nibble of band 2 offset ST A, 8HL+ ; store low nibble result LD A, #NLH X_2P_VALUE ; high nibble of band 2 offset ST A, @HL+ LD A, #NLL X_1P_VALUE ; low nibble of band 1 offset ST A, 8HL+ ; store low nibble result LD A, #NLH X_1P_VALUE ; high nibble of band 1 offset ST A, 8HL LD HL, #YJ3ANDS+6 ; low nibble of first negative band LD A, #NLL ' Y_1N_VALUE ; low nibble of first offset ST A, 8HL+ ; store value LD A, #NLH Y_1N_VALUE ; high nibble of first offset ST A, 8HL+ ; store value LD A, #NLL Y_2N_VALUE ; add low nibble of second offset ST A, 8HL+ ; store value LD A, #NLH Y_2N_VALUE ; high nibble of second offset ST A, 8HL+ ; store value LD A, #NLL Y_3N_VALUE ; low nibble of band 3 value ST A, 8HL+ ; store it LD A, #NLH Y_3N_VALUE ; high nibble of band 3 value ST A, 8HL+ ; store it LD HL, #Y_BANDS ; point to low nibble of last ; positive band LD A, #NLL Y_3P_VALUE ; low nibble of band 3 value ST A, GHL+ ; store it LD A, #NLH Y_3P_VALUE ; high nibble of band 3 value ST A, 8HL+ ; store it LD A, #NLL Y_2P_VALUE ; low nibble of band 2 of set ST A, 8HL+ ; store low nibble result LD A, #NLH Y_2P_VALUE ; high nibble of band 2 offset ST A, 8HL LD HL, #Y_BANDS+4 ; point to low nibble of first r positive band LD A, #NLL Y_1P_VALUE ; low nibble of band 1 offset ST A, 8HL+ ; store low nibble result LD A, #NLH Y_1P_VALUE ; high nibble of band 1 offset ST A, 8HL LD HL, #OLDX ; location for old X band initialize to zero memory zero OLDX zero OLDY . zero XJMOVE zero YJMOVE location of start of packet ; set XMIT_NOW and POSITION bits zero sequence number STATUS was cleared above initial delay is short load mask to disable WDT and set detection time to 500ms do it load mask to enable WDT and set detection time to 500ms do it make sure A/D is on get current state of all buttons a zero bit indicates the corresponding button is down SUBR A, #0FH complement bits for Microsoft this code added for new main button R8x == 1 when button released (up) R8x == 0 when button pressed (down) LD HL, #CHECKSUM ; temporary storage for button status ST A, @HL ; save left and right button status IN %IP08, A ; get main button status TEST A, MAINJ3UTT0NJ3IT ; is button pressed ? B BIT_IS_CLEAR ; branch if so LD A, #0 ; clear bit 0 to indicate button up BR BUTTON DONE ; and branch to continue •BIT_IS_CLEAR: LD A, #1 ; set bit 0 to indicate button down BUTTONJOONE: OR A, 8HL get left and right button status ompare new state with old ake SF = ZF ; now branch if new status = old pdate button status set transmit immediate flag GET AXIS DATA: high bit in AXIS_PTR is 0 for X axis get X axis data ; load axis pointer address ; set high order bit get Y axis data ; load axis pointer address ; clear high order bit ; branch if not UPDATE_SEQUENCE_NUMBER: LD HL, #TIMER_FLAGS_REGISTER ; point to timer flags TEST 8HL, SLEEPJJLAGJ3IT ; is sleep timer active B SET SEQUENCE ; branch if not active LD A, #STOP_TIMER_RATE ; command to turn off timer (0) OUT A, %0P1C ; do it LD HL, #TIMER_FLAGS_REGISTER ; point to timer flags ST A, 0HL ; clear all flags SET SEQUENCE: ADD SEQUENCE, #1 increment sequence number B SET_PACKET_TYPE branch if no carry (SF = ~CF) ADD SEQUENCE, #1 start over with sequence number 1 SET_PACKET_TYPE: ST ♦POSITION, PACKET ; clear XMIT_NOW_BIT CALL SEND_PACKET ; send the packet ST #XMIT_DONE, PACKET ; set XMITJDONE bit (clears type) ; (may not be necessary 7/24/91) CALL RESET_RXMT_CTR ; reset the retransmit counter determine delay based on highest band LD A, OLDX ,* get x band CMPR A, BAND ; compare x to BAND (BAND == OLDY) TEST CF ; make SF = inverse CF B G0TJ3AND ; branch if set (x band is higher) LD A, BAND ; y band is higher G0TJ3AND: TEST A, 2 ; is highest band 3 ? B L0WJ3AND ; branch if not CALL START_150MS ; start xmit timer BR TRANSMITJOELAY ; and branch to wait L0WJ3AND: CALL START aOMS ; longer delay TRANSMITJOELA : CALL AITJBORJTIMER ; wait for xmit timer to end BR XMIT LOOP TOP ; go back and do it again DETERMINE WHETHER TIME TO SLEEP CHECK_SLEEP_STATUS: LD HL, #TIMER_FLAGS_REGISTER ; point to timer flags TEST @HL, SLEEP_FLAG_BIT ; is sleep timer active B INITIALIZE_SLEEP_TIMER ; branch if not active TEST @HL, TIMERJ00NEJ3IT ; time to sleep ? B DEC_RXMT_CTR ; branch if not BR GO TO SLEEP ; otherwise go to sleep INITIALIZE_SLEEP_TIMER: CALL WAIT_FOR_TIMER allow xmit timer to complete CALL START SLEEP TIMER then start sleep timer DEC_RXMT_CTR: LD HL, #RXMT_CTR ; point to RXMTJCTR low nibble BR CHECK_RXMT_CTR TEMPORARY ! ! 7/28/91 ! ! ! ! ! DEC 8HL decrement low nibble TESTP CF make SF = CF B CHECK_RXMT_CTR ; branch if no carry LD HL, #RXMT_CTR+1 ; point to RXMTjCTR high nibble DEC 8HL decrement high nibble DETERMINE WHETHER TIME TO RETRANSMIT CHECK_RXMT_CTR: LD HL, #RXMT_CTR ; point to RXMTJCTR low nibble LD A, 6HL get low nibble CMPR A, #0 is it zero B XMIT LOOP TOP ; branch if not zero LD HL, #RXMT_CTR+1 ; point to RXMTJCTR high nibble LD A, 0HL get high nibble CMPR A, #0 is it zero B XMIT_LOOP_TOP ; branch if not zero CALL SEND_PACKET send the existing packet CALL RESET RXMT CTR ; reset the retransmit counter BR XMIT LOOP TOP ; branch if not zero SEND PACKET: ASSUMES: buffer is correct except for battery status and checksum ACTIONS: fills in battery status bits computes checksum (with an assumed SOH byte) sends bit stream out IR emitter returns to point of invocation 1. read battery A/D channel 2. set battery status bits as appropriate 3. compute checksum using SOH (01H) as first byte 4. send bit stream via IR emitter ST #0, BATTERY ; assume battery is OK CALL GET BATTERY AD ; read A/D channel for battery level LD HL, #BATTERYJ300D ; initialize for good battery CALL IS_LESS ; is CHECKSUM less than BATTERYJ300D B BATTERY DONE ; branch if so ST #BATTERY_WEAK, BATTERY INC L INC L CALL IS_LESS B BATTERYJOONE ST #(BATTERY LOW OR BATTERY WEAK) , BATTERY BATTERYJOONE: LD A, #SOH SOH is first byte TEMPORARILY CREATE MICROSOFT FORMAT HERE LD A, STATUS get status ST A, PACKET save it for later ST #4, BATTERY ; set bit 6 of STATUS byte LD HL, #STATUS ; point to button status LD A, 8HL ; get button status AND A, #RIGHTJ3UTT0NS ; check for either right button TESTP ZF B LBJCHECK ; branch if no right buttons set INC L ; point to BATTERY OR 8HL, #1 ; set right button bit DEC L ; back to STATUS LBJCHECK: LD A, @HL ; get button status AND A, #LEFT_BUTT0NS; check for either left button TESTP ZF ; set SF = ZF B ADJUSTJMICKEYS ; branch if no left buttons set INC L ; point to BATTERY OR @HL, #2 ; set left button bit ADJUSTJMICKEYS: LD HL, #XJMICK+1 ,* point to XJMICK high nibble LD A, 8HL ; get nibble AND A, #0CH ; clear low bits TEST CF ; clear carry RORC A ; shift right ; shift right ; put in low bits of STATUS ; (killing original button status) ; point to YJMICK high nibble ; get nibble ; clear low bits ; point to STATUS ; combine bits ; and save result ; point to XJMICK high nibble ; kill high bits of high nibble ; and replace high nibble ; point to YJMICK high nibble ; kill high bits of high nibble ; and replace high nibble using Richter send function point to first byte send the leader send first byte next byte send it last byte send it restore status for next process ; return to caller end SEND PACKET DOJCHANNEL — when high order bit of AXISJPTR is clear the X axis A/D should be read (GET_POSITION_AD maps bit to correct physical channel) if value ?J3ANDS+6 (compare value to threshold for positive band 1) set BAND = BAND_1 if value ?_BANDS+8 set BAND = BAND 2 if value ?_BANDS+10 set BAND = BAND_3 goto BANDJONE else if value ?J3ANDS+4 (compare value to threshold for negative band 1) set BAND = BAND_1 if value ?_BANDS+2 set BAND = BANDJ2 if value ?_BANDS_3 set BAND = BANDJ3 set BAND 1 NEGATIVE (set NEGATIVE bit with OR) goto BANDJOONE otherwise do nothing (BAND == 0 from initialization) make sure band is zero CALL GET POSITION AD get value and store in CHECKSUM LD HL, #AXIS_PTR ; load axis pointer address TEST 8HL, AXISJ3IT ; check axis B X AXIS ; branch if axis bit is zero (SF = 1) Y axis LD A, OLDY get previous Y band ST A, TEMP store in battery status nibble temporarily LD HL, #Y BANDS+7 ; point to high nibble of ; negative BAND_1 ; is CHECKSUM BAND_1 ; branch if not ; set band to band 1 ; point to high nibble of ; negative band 2 ; is CHECKSUM BAND_2 ; branch if not ; set band to band 2 ; point to high nibble of ; negative band 3 ; is CHECKSUM BAND 2 ; set band to band 3 ; point to high nibble of ; positive BAND_1 ; is CHECKSUM BAND_1 ; branch if not @HL+ ; set band to band 1 ; point to high nibble of ; positive band 2 ; is CHECKSUM BAND_2 ; branch if not @HL+ ; set band to band 2 ; point to high nibble of ; positive band 3 ; is CHECKSUM BAND 2 @HL+ ; set band to band 3 get previous X band store in battery status nibble temporarily LD HL, #X BANDS+7 ; point to high nibble of ; negative BAND_1 ; is CHECKSUM BAND_1 ; branch if not @HL+ ; set band to band 1 ; point to high nibble of ; negative band 2 ; is CHECKSUM BAND_2 ; branch if not 8HL+ ; set band to band 2 ; point to high nibble of ; negative band 3 ; is CHECKSUM BAND 2 8HL+ ; set band to band 3 ; point to high nibble of positive BAND_1 is CHECKSUM BAND_1 branch if not ; set band to band 1 ; point to high nibble of positive band 2 is CHECKSUM BAND_2 branch if not ; set band to band 2 ; point to high nibble of positive band 3 is CHECKSUM BAND 2 set band to band 3 BANDJOONE: ; If current band is zero, reset the appropriate profile index ; so that next movement in current direction will be correct, then ; branch to update old band ; get current band ; is current it 0? ; branch if not ; load axis pointer address ; check axis ϊ branch if axis bit is zero(SF = 1) reset Y profile index and Y duration counter branch to update band ; reset X profile index and X duration counter branch to update band DISPLAY CHECK: current BAND != 0 set flag bit to ensure data transmission determine whether previous band for current axis was zero; if so make sure previous direction corresponds to current BAND direction set XMIT NOW BIT ; get old band ; was it zero? ; branch if not ; load current band address ; current direction negative? B NZ_0 branch if not ST ♦NEGA IVE, TEMP ; store NEGATIVE flag in old band NZ 0: if (axis bit == 0) set YJMICK = 0 if (axis bit == 1) and (XJMOVE == 0) set XJMICK = 0 ( no current movement in X direction, so zero XJMICK ) then update movement duration counters LD A, #0 ; initialize for later load axis pointer address check axis branch if axis bit is zero(SF = 1) ; is X duration counter 0? ; branch if not ; zero XJMICK low nibble ; zero XJMICK high nibble NZ 1: CALL GET DIRECTION ; determine whether old and new ; directions are the same ; branch if so ; initialize YJMOVE for ; movement in opposite direction BR PROCESS BANDS ; branch to continue Z 0: ; point to current Y duration ; increment ; branch if no carry ; return to 0FH ; branch to continue ; process x axis ; zero YJMICK low nibble ; zero YJMICK high nibble ; determine whether old and new ; directions are the same ; branch if so ; initialize XJMOVE for ; movement in opposite direction ; branch to continue point to current X duration INC 6HL ; increment B PR0CESSJ3ANDS ; branch if no carry DEC 8HL ; return to OFH BEGIN PROCESSING CURRENT VALUE PR0CESSJ3ANDS: LD HL, #BAND ; point to new band TEST 8HL, Bl _BIT ; is it band 1 B CHECK BAND TWO ; branch if not (HL points to BAND) LD A, TEMP ; get old band AND A, #07H ; mask off direction B Bl PREVIOUS NOT ZERO ; branch if old band was not zero LD HL, #X MICK ; assume update X mickeys LD A, AXIS_PTR ; load axis index TEST A, AXISJ3IT ; check axis B Bl ONE MICKEY UPDATE ; branch if axis bit is zero(SF = 1) LD HL, #Y_MICK ; must be Y mickeys BljONEJMICKEYJJPDATE: ; previous (X or Y) band was zero so use a 1 mickey move get current band ; is it negative ; branch if so 1 mickey (positive) clear high nibble branch to update band 1 mickey (negative) extend sign branch to update band Bl PREVIOUS NOT ZERO: BAND 1 PREVIOUS != 0 CALL GET DIRECTION ; determine whether old and new directions are the same B DO BAND 1 ; branch if so if current movement is opposite direction from previous movement update will use initial band profile value and the current direction LD HL, #X PROFILE assume X axis LD A, AXISJPTR ; load axis index TEST A, AXISJ3IT ; check axis B Bl STANDARD UPDATE ; branch if axis bit is zero(SF = 1) LD HL, #Y PROFILE vst be Y axis B1_STANDARD_UPDATE : ST #0 , 8HL+ clear profile index BR MICKEY UPDATE ; branch to update mickey count DO_BAND_l: if current movement is same direction as previous movement start with current profile index for band 1 and adjust depending on previous band get old band was old band 1? branch if not ; branch to update mickey count was old band 2? branch if not ; assume X axis load axis index check axis branch if axis bit is zero (SF = 1) ; must be Y if previous band was 2, reset current profile index to zero BR MICKEY UPDATE • ; branch to update mickey count Bl N2: ; assume X axis load axis index check axis branch if axis bit is zero (SF = 1) ; must be Y DO B13; if previous band was 3, reset current profile index to middle BR MICKEY UPDATE ; branch to update mickey count CHECK FOR BAND TWO is current band band 2? branch if not ; get old band ; mask off direction NOT ZERO ; branch if old band was not zero assume update X mickeys LD A, AXIS_PTR ; load axis index TEST A, AXISJ3IT ; check axis B B2 ONE MICKEY UPDATE ; branch if axis bit is zero(SF = 1) LD HL, #YJMICK ; must be Y mickeys B2JDNEJMICKEYJJPDATE: ; previous (X or Y) band was zero so use a 1 mickey move get current band ; is it negative ; branch if so 1 mickey (positive) clear high nibble branch to update band 1 mickey (negative) extend sign branch to update band B2 PREVIOUS NOT ZERO: BAND == 2 PREVIOUS >= 0 CALL GET DIRECTION determine whether old and new directions are the same B DO BAND 2 branch if so if current movement is opposite direction from previous movement update will use initial band profile value and the current direction LD HL, #X PROFILE assume X axis LD A, AXIS_PTR ; load axis index TEST A, AXISJ3IT ; check axis B B2 STANDARD UPDATE ; branch if axis bit is zero(SF= 1) LD HL, #Y PROFILE ; must be Y axis B2JSTANDARDJJPDATE: ST #0, 8HL+ clear profile index BR MICKEY UPDATE ; branch to update mickey count D0_BAND_2: if current movement is same direction as previous movement start with current profile index for band 2 and adjust depending on previous band ; get old band ; was old band 2? ; branch if not ; branch to update mickey count B2 N2 : was old band 1? branch if not ; assume X axis load axis index check axis branch if axis bit is zero (SF = 1) ; must be Y if previous band was 1, reset current profile index to zero BR MICKEY UPDATE ; branch to update mickey count B2 Nl: ; assume X axis load axis index check axis branch if axis bit is zero (SF 1) ; must be Y DO B23: if previous band was 3, reset current profile index to middle BR MICKEY UPDATE ; branch to update mickey count BAND THREE BANDJTHREE: LD A, TEMP ; get old band AND A, #07H ; mask off direction B B3 PREVIOUS NOT ZERO ; branch if old band was not zero LD HL, #XJMICK ; assume update X mickeys LD A, AXISJPTR ; get high nibble of counter TEST A, AXISJ3IT ; check axis B B3 ONE MICKEY UPDATE ; branch if X (SF = 1) LD HL, #Y MICK ; must be Y mickeys B3JDNEJMICKEYJJPDATE: ; previous band zero- use 1 mickey ; previous (X or Y) band was zero so use a 1 mickey move get current band ; is it negative ; branch if so 1 mickey (positive) clear high nibble branch to update band 1 mickey (negative) extend sign BR BAND UPDATE ; branch to update band B3 PREVIOUS NOT ZERO: BAND == 3 PREVIOUS != 0 CALL GET IRECTION ; determine whether old and new ; directions are the same B DO_BAND_3 ; branch if so ; if current movement is opposite direction from previous movement ; update will use initial band profile value and the current direction LD HL, #X_PROFILE ; assume X axis LD A, AXISJPTR ; load axis index TEST A, AXISJ3IT ; check axis B B3_STANDARD_UPDATE ; branch if axis bit is zero (SF= 1) LD HL, #Y_PROFILE ; must be Y axis B3 3TANDARDJJPDATE: ST #0, GHL+ ; clear profile index BR MICKEYJJPDATE ; branch to update mickey count ; DO_BAND_3: if current movement is same direction as previous movement start with current profile index for band 3 and adjust depending on previous band ; get old band ; was old band 3? ; branch if not ; branch to update mickey count ; assume X axis ; load axis index ; check axis ; branch if axis bit is zero (SF = 1) ; must be Y ; current is 3 previous was 1 or 2 ST #8, GHL+ ; set current profile index to 8 MICKEYJJPDATE: ; move value from CHECKSUM into the appropriate position update ; byte in packet (using two's complement for negative numbers) LD HL, #DATA_COUNTER . ; point to data counter LD A, AXIS_PTR load axis index TEST A, AXISJ3IT check axis B MU 00 branch if axis bit is zero (SF = 1) LD A, Y_PROFI E ; load current value of Y profile ST A, @HL+ store in low nibble of data counter INC update Y profile index B NO_Y_OVERFLOW ; branch if not OxF DEC A back to OxF NO_Y_OVERFLOW: ST A, Y PROFILE ; save for next iteration LD A, BAND ; get new band TEST A, B1J3IT is it band 1 B Y BAND 2 branch if not (A contains BAND) ST #NLH Y_BAND_1J?R0FILE, GHL+ BR LOAD Y POINTER Y_BAND_2: TEST A, B2J3IT is it band 2 B Y BAND 3 branch if not (A contains BAND) ST #NLH Y_BAND_2J?R0FILE, ΘHL+ BR LOAD_Y_POINTER YJ3AND_3: ST #NLH YJBAND_3_PROFILE, ΘHL+ LOAD_Y_POINTER: ST #NHL YJ3AND_1_PR0FILE, ΘHL+ LD HL, #YJMICK ; prepare to update Ϋ mickey count BR MUT ; branch to do it MU 00: ; load current value of X profile ; store in low nibble of data counter ; update X profile index ; branch if not OxF ; back to OxF ; save for next iteration ; get current band ; is it band 1 ; branch if not (A contains BAND) TEST A, B2J3IT ; is it band 2 B X BAND 3 ; branch if not (A contains BAND) ST #NLH X_BAND_2_PROFILE, GHL+ BR LOADJX_POINTER X_BAND_3: ST #NLH X 3AND_3_PROFILE, ΘHL+ LOAD_X_POINTER: ST #NHL X_BAND_l_PROFILE, ΘHL+ LD HL, #XJMICK ; prepare to update X mickey count MUT: LD A, BAND get current band AND A, #NEGATIVE ; is it negative B MUN branch if so LDL A, GDC ST A, ΘHL+ ; store low nibble LDH A, GDC+ ST A, GHL ; store it BR BAND UPDATE ; branch to update band information MUN: LDL A, GDC SUBR A, #0 make two's complement B N0J30RR0W branch if no borrow ST A, GHL+ store low nibble LDH A, 8DC+ SUBR A, #0 two's complement of high nibble DEC A extend sign of low nibble BR STORE HIGH NIBBLE ; branch to store it N0J30RR0W: ST A, 8HL+ ; store low nibble LDH A, ΘDC+ SUBR A, #0 ; two's complement of high nibble STORE_HIGH_NIBBLE: ST A, GHL ; store high nibble BANDJJPDATE: LD HL, #OLDX assume X axis band update LD A, AXIS_PTR get high nibble of sleep counter TEST A, AXISJ3IT check axis B BU 00 branch for X (SF= 1) LD HL, #OLDY ; must be Y axis band update BU 00: LD A, BAND ; get current band ST A, GHL ; save in OLDY EXITJOOjCHANNEL: RET ; return to caller IS GREATER determine whether value 8 bit stored in CHECKSUM is greater than 8 bit value pointed to by HL and HL+1 ASSUMES: both numbers are positive (i.e. values from A/D) on entry, HL points to high nibble of byte RETURNS: SF set if CHECKSUM <= 8HL SF clear if CHECKSUM >ΘHL ISJΞREATER: LD A, GHL get high nibble of value . ' CMPR A, CHECKSUM+1 ; compare high nibble of CHECKSUM to high nibble of value CHK GSGN branch to check sign if result not zero high nibbles both zero point to low nibble branch if no borrow swap A and H decrement A swap A and H ; get low nibble ; compare with low nibble ; make SF = -CF determine whether value 8 bit stored in CHECKSUM is less than 8 bit value pointed to by HL and HL+1 ASSUMES: both numbers are positive (i.e. values from A/D) on entry, HL points to high nibble of byte RETURNS: SF set if CHECKSUM = GHL SF clear if CHECKSUM GHL IS_LESS: LD A, GHL get high nibble of value : CMPR A, CHECKSUM+1 ; compare high nibble of CHECKSUM to high nibble of value B CHK LSGN branch to check sign if result not zero ; high nibbles both zero ; point to low nibble ; branch if no borrow ; swap A and H ; decrement A ; swap A and H ; get low nibble ; compare with low nibble ; make SF = CF GET DIRECTION determine whether old and new bands represent same direction ASSUMES: old band info is in TEMP variable new (current) band info is in BAND variable RETURNS: SF set if directions the same SF clear if directions different get old band mask off band info make sure CF is clear put old direction in CF point to new band get new band mask off band info bits 3 and 2 are directions old and new positive? make SF = ZF branch if so (SF is 1) old and new negative? make SF = ZF GD 0: RET GET POSITION AD read an axis A/D channel and store result in CHECKSUM ASSUMES: HL points to high nibble of AXISJPTR on entry Axis ID is in high bit of high nibble 0 is X axis 1 is Y axis RETURNS: the 8 bit value in CHECKSUM GET_POSITION_AD : LD A, #1 ; assume X axis LD HL, #AXIS_PTR ; load HL with high nibble of counter TEST GHL, AXISJ3IT ; check axis B SELECTjCHANNEL ; branch if bit clear (X axis) DEC A ; must be Y axis SELECTjCHANNEL: LD HL, #CHECKSUM ; location to store data MUST BE ON EVEN NIBBLE BOUNDARY ! ! OUT A,%0P1 ' 2 select channel LD A,#l OUT A,%OP13 start conversion POSITION CONVERSION LOOP: TEST %IP0C, E0CJ3IT ; wait for EOC B POSITIONJCONVERSION_LOOP ; L register low bit MUST be 0 ! ! IN %IPθD, GHL ; get low nibble INC L ; point to high nibble IN %IP0D, GHL ; get high nibble RET GET BATTERY AD read battery status A/D channel and stores result in CHECKSUM ASSUMES: battery status is A/D channel 2 RETURNS: the 8 bit value in CHECKSUM GET_BATTERY_AD: LD A, #2 assume battery status channel OUT A,%OP12 select channel LD A,#l OUT A,%OP13 start conversion LD HL, #CHECKSUM ; location to store data ; MUST BE ON EVEN NIBBLE BOUNDARY ! ! BATTERY_CONVERSION_LOOP: TEST %IP0C, E0CJ3IT ; wait for EOC B BATTERY CONVERSION LOOP START xxMS start timer 1 for an xx millisecond delay STARTJ250MS: LD HL, #TIMERjCOUNT_REGISTER point to timer 1 counter ST #NLL PRESETJ250MS, ΘHL+ ST #NLH PRESETJ250MS, GHL+ ST #NHL PRESETJ250MS, ΘHL+ B START TIMER STARTJ200MS: LD HL, #TIMERjCOUNT_REGISTER point to timer 1 counter ST #NLL PRESET_200MS, GHL+ ST #NLH PRESETJ200MS, GHL+ ST #NHL PRESET_200MS, GHL+ B START TIMER STARTJL50MS: LD HL, #TIMERjCOUNT_REGISTER point to timer 1 counter ST #NLL PRESET_150MS, 0HL+ ST #NLH PRESETJL50MS, ΘHL+ ST #NHL PRESET_150MS, ΘHL+ B START TIMER START_120MS: LD HL, #TIMERjCOUNT_REGISTER ; point to timer 1 counter ST #NLL PRESET_120MS, ΘHL+ ST #NLH PRESET_120MS, GHL+ ST #NHL PRESET_120MS, 8HL+ B START TIMER START_100MS: LD HL, #TIMERjCOUNTJREGISTER point to timer 1 counter ST #NLL PRESET_100MS, ΘHL+ ST #NLH PRESET_100MS, GHL+ ST #NHL PRESET_100MS, GHL+ B START TIMER STARTJ30MS: LD HL, #TIMER_COUNT_REGISTER point to timer 1 counter ST #NLL PRESETJ30MS, GHL+ ST #NLH PRESETJ30MS, ΘHL+ ST #NHL PRESETJ30MS, ΘHL+ B START TIMER START_60MS: LD HL, #TIMER_COUNT_REGISTER point to timer 1 counter ST #NLL PRESET_60MS, GHL+ ST #NLH PRESET 60MS, GHL+ ST #NHL PRESET SOMS, ΘHL+ B START TIMER START_50MS: LD HL, #TIMER_COUNT_REGISTER point to timer 1 counter ST #NLL PRESET_50MS, ΘHL+ ST #NLH PRESET_50MS, ΘHL+ ST #NHL PRESETJ50MS, ΘHL+ B START TIMER START_40MS: LD HL, #TIMER_COUNT_REGISTER point to timer 1 counter ST #NLL PRESET_40MS, ΘHL+ ST #NLH PRESET_40MS, ΘHL+ ST #NHL PRESET_40MS, ΘHL+ B START TIMER START_30MS: LD HL, #TIMER_COUNT_REGISTER point to timer 1 counter ST #NLL PRESET_30MS, ΘHL+ ST #NLH PRESET_30MS, GHL+ ST #NHL PRESET 30MS, ΘHL+ STARTJTIMER: ; HL points to flag register here CLR GHL, TIMERJ00NEJ3IT ; clear timer done flag LD A, #XMIT_TIMER_RATE ; get mode and rate OUT A, %0P1C ; set mode and rate LD A, #TIMER_INTERRUPT ; get timer 1 enable bit XCH A, EIR ; enable timer 1 interrupts EICLR IL, 111111B ; enable master interrupt flip-flop RET ; and return WAIT FOR TIMER wait for timer 1 to time out (handler sets done bit) WAIT_FOR_TIME : LD HL, #TIMERJFLAGS_REGISTER ; point to flags nibble TIMER_LOOP: TEST GHL, TIMERJ00NEJ3IT ; is timer done ? B TIMER LOOP ; loop if not RET START SLEEP TIMER initialize timer 1 to determine when cpu should go to sleep 86 RETURNS: nothing STARTJSLEEPJIIMER: LD HL, #TIMER_COUNT_REGISTER ; point to timer 1. counter ST #0, ΘHL+ ; start from 0 for maximum time ST #0, 8HL+ ST #0, ΘHL+ LD A, #DOZE_TIMER_RATE ; get mode and rate OUT A, %0P1C ; set mode and rate LD A, #TIMER_INTERRUPT ; get timer 1 enable bit XCH A, EIR ; enable timer 1 interrupts EICLR IL, 111111B ; enable master interrupt flip-flop SET GHL, SLEEP_FLAG_BIT ; set flag indicating ; sleep counter is active CLR GHL, TIMERJ00NEJ3IT ; clear timer done flag RET ; and return TIMER HANDLER process timer 1 interrupts TIMER HANDLER: XCH A, SAVE ; save A register LD A, #STOPJTIMER_RATE ; get mode and rate (0) OUT A, %OPlC ; set mode and rate XCH A, EIR ; disable timer 1 interrupts XCH A, SAVE ; restore A register XCH HL, SAVE ; save HL register LD HL, #TIMER_FLAGS_REGISTER ; point to timer 1 flags SET GHL, TIMERJ00NEJ3IT ; set flag indicating timer done XCH HL, SAVE ; restore HL RETI ; and return .from interrupt RESET RXMT CTR reset the retransmit counter RETURNS: nothing RESET_RXMTJCTR: LD HL, #RXMT CTR eventually this will be replaced by a random number generator ST #NLL RXMTJCYCLE, GHL+ store low nibble ST #NLH RXMT CYCLE, 8HL+ store high nibble RET SEND BYTE: ASSUMES: HL points to low nibble of byte ; send low nibble of byte ; branch if on same page ; adjust H for next page ; send high nibble of byte ASSUMES: HL points to nibble TRASHES: RXMT CTR (it is reset after every transmission) use low nibble for counter get nibble to send ; use high nibble for temp storage ; get the nibble get first bit ; save altered nibble set SF = CF if carry set send a 1 bit send a zero bit ; send a one bit ; get counter ; and decrement ; set SF = ZF ; branch if done ; save counter ; and branch for next bit DOONE: CALL PCKT CALL LTIME1 CALL PCKT CALL LTIMEO 88 RET DOZERO : CALL PCKT CALL LTIMEO CALL PCKT CALL LTIMEO RET PCKT: ; changed from 06 12/10/91 LD A,#0AH ; per John, should be A for 60kHz LOOP: OUT #0,%OP02 ; removed 3 NOPs 12/10/91 NOP OUT #1,%OP02 ; removed 2 NOPs 12/10/91 DEC A CMPR A,#0 B LOOP RET LTIMEO:LD A,#09H B LLUP LTIME1:LD A,#0FH LLUP: NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP DEC A CMPR A,#0 B LLUP RET DO LEADER: ASSUMES: nothing TRASHES: CHECKSUM **************** 12/91 NOTE ! ! when 7 byte protocol and checksum implemented, revise logic of SENDJPACKET so that CHECKSUM is correct before the packet is sent ! ! ; load count (changed from F 12/10) ; save it ; send a few dummy packets ; load counter ; decrement ; store for next ; is it zero (done) ; branch if not ; wait a while ORG 07A0H X_BAND_l_PROFILE: DATA 1, 1, 2, 2, 4, 4, 4, 4, 4, 4, 4, 4, 2, 2, 1, 1 XJ3AND_2_PR0FILE: DATA 1, 1, 2, 2, 4, 8, 16, 16, 8, 8, 8, 4, 4, 4, 4, 2 X_BAND_3_PROFILE: DATA 1, 4, 8, 10, 12, 16, 16, 16, 16, 16, 12, 12, 12,12,12,12 Y_BAND_l_PROFILE: DATA 1, 1, 2, 2, 4, 4, 4, 4, 4, 4, 4, 4, 2, 2, 1, 1 Y_BAND_2_PROFILE: DATA 1, 1, 2, 2, 4, 6, 8, 8, 8, 8, 8, 4, 4, 4, 4, 2 Y_BAND_3_PROFILE: DATA 1, 4, 8, 10, 12, 12, 12, 12, 12, 12,- 12, 12, 12,12,12,12 END

Claims: We claim: 1. Xn a system for generating command signals for a computer monitor or other equipment, at least one pressure responsive potentiometer, means operatively connected with said potentiometer for generating a command signal reflecting at least one of the direction, intensity and -duration of pressure applied to said potentiometer. 2. In a system as described in Claim 1, said at least one pressure responsive potentiometer comprising two pressure responsive potentiometers arranged in cruciform relationship. 3. In a system as described in Claim 2, said two pressure responsive potentiometers being interconnected to represent x and y axes of a cartesian coordinate system. 4. In a system as described in Claim 3 for generating cursor position command signals, said two pressure responsive potentiometers each being of increasingly greater width f om center to each end and having their αenters connected to represent 0 in said coordinate system and wherein values taken from one end of one resistance represents signals to move the cursor in a direction of increasing value along the corresponding axis and values taken from the other end of said one resistance representing signals to move the cursor in the opposite direction of decreasing value along that axis. 5. In a system for generating command signals for a computer monitor or other equipment, a transmitter and a receiver, means for operatively communicating command signals from said receiver to said computer monitor or other equipment, means for operatively communicating command signals from said transmitter to said receiver and means in said transmitter r which means include at least one pressure responsive potentiometer, for generating a command signal reflecting at least one of the direction, intensity and duration of pressure applied to said potentiometer. 6. In a system as described in Claim 5, wherein said means in said transmitter further comprises a microcontroller. 7. In a system as described in Claim 6, wherein said means in said transmitter further comprises dedicated software. 8. A method for remotely controlling a function of a computer monitor or other equipment in response to signals obtained from pressure sensitive potentiometers manipulated by a user, including the steps of (a) periodically iterating to detect the signals present on said pressure sensitive potentiometers (b) comparing the signals detected on each iteration with the corresponding signal detected on the last previous iteration to determine at least one of the amount and direction of change, (c) generating a control signal reflecting the information determined in step (b) and (d) transmitting said control signal to said computer or other equipment in a form acceptable by said computer or other equipment to effect a change in the function being controlled. 9. In a method as described in Claim 8, the method including the additional steps of (e) sensing the duration of time that pressure was applied to said pressure sensitive potentiometers and (f) modifying the control signal generated in step (c) by a factor reflecting the information obtained in step (e) . 10. A method for remotely controlling the positioning of a cursor on a computer monitor or other equipment in response to signals obtained from a pressure sensitive potentiometer manipulated by a user, including the steps of (a) periodically iterating to detect the signals generated by said pressure sensitive potentiometer (b) comparing the signals detected on each iteration with the corresponding signal detected on the last previous iteration to determine at least one of the amount and direction of change, (c) generating a control signal reflecting the information determined in step (b) and (d) transmitting said control signal to said computer monitor or other equipment in a form acceptable by said computer monitor or other equipment to effect a change in position of the cursor. 11. In a method as described in Claim 10, the method including the additional steps of (e) sensing the duration of time that pressure was applied to said pressure sensitive potentiometer and (f) modifying the control signal generated in step (c) by a factor reflecting the information obtained i step (e). 12. A hand held device for producing a output reactive to manipulation of a part of said device by the digits of a hand holding said device, said device comprising: a case having a generally rectangular head portion and generally rectangular handle portion rigidly attached to each other and defining an obtuse angle between them, a recess in the top surface in said head portion readily accessible to the forefinger of a hand grasping said handle portion, said part of said device comprising a control disc located in said recess and movable therein in a generally rocking motion, and said control disc being movable by manipulation of the forefinger of a hand grasping said handle. 13. A system as described in Claim 5 in which the transmitter includes a battery pack and said system including means for recharging batteries in said battery pack. 14. A system as described in Claim 5 in which said transmitter is enclosed in a case, said receiver is enclosed in a case and-said cases having complimentary surfaces which permit nesting or cradling one on the other. 15. A hand held device as described in Claim 12 further comprising at least one momentary action switch located in proximity to said control and readily accessible for manipulation by a thumb or finger of a hand holding the device. 16. A hand held device as described in Claim 12 further comprising at least one momentary action switch located beneath said control disc and operable by downward pressure on said control disc. 17. A hand held device as described in Claim 16, wherein said at least one momentary action switch is operated by pressure applied by the digit manipulating said control disc. 18. A hand held device as described in Claim 12, wherein said case further includes portions engageable with a relatively flat surface whereby said device may be supported on such relatively flat surface while being operated by a digit of a hand grasping said handle portion. 19. A hand held device as described in Claim 18, wherein said digit of a hand grasping said handle portion is the forefinger. 20. In a system as described in Claim 1, further comprising switch means selectively responsive to a predetermined level of the intensity of pressure applied to said potentiometer..

Inventors: BALLY ALEX, COPPER JOHN M, RICHTER JOHN M, BALLY, ALEX, COPPER, JOHN, M., RICHTER, JOHN, M.
Applicants: MICROMED SYSTEMS INC, MICROMED SYSTEMS, INC.
Application year: 1992
Main classification: G06F3
IPC codes: G06F3