THRUSTMASTER AN0002A.TXT F22 Programming Notes*** ThrustMaster Application Note AN0002A ***
Advanced Logical Programming Techniques for the F22
Copyright (c) 1996, 1997 Thrustmaster, Inc.
All Rights Reserved
Draft Revision 2.05 - January 11, 1997
Still found here
http://home.arcor.de/ulf.muckel/documentation/an0002a.txtOverview
========
In addition to the normal keyboard programming functions available in
the F22, there is an additional group of functions that provide the
ability to generate several types of advanced operations using the
buttons and analog controls. While the basic BTN statement is effective
in most situations, these extended functions give the F22 additional
capability to handle control problems which cannot be done with the
standard function set.
These additional functions were not intended to be used as the primary
method of programming the F22. BTN-type statements are generally more
efficient in terms of both memory used and execution speed, as well as
being more easily understood. The extended functions should be viewed
as an additional set of tools available for use when the standard
functions cannot accomplish the desired result.
Note
====
This note references functions that were not available in F22 microcode
releases prior to V1.15. some earlier
F22 releases, specifically:
1. The flags references X25..X48.
2. Direct Toggle references (S1*, etc).
3. Assignment of flag references as Type 2 analog characters.
4. The comparator functions CMPLT and CMPGT.
If you use these and receive a message about an unrecognized function,
then you need a compiler update and you probably will also need a chip
update. If the compiler is a revision that supports the functions, but
the chip does not, you'll receive a message about needing a chip update.
Logical Processing
==================
This section explains the basics of the extended programming capabilities
and the functions that pertain to them.
Flags
-----
Central to this extended programming capability are a group of 48 'flags'.
and the statements that are used to control them. Flags are similar to
buttons in that they can be either OFF or ON, but they have no physical
device directly associated with them. Rather, the conditions which cause
them to be either OFF or ON are defined in the F22 file.
The 48 Flags are referenced as X1 through X48. Flags can be referenced
just like any other button or switch on the F22:
BTN X7 /P x /R y
This is a valid statement and will cause the F22 to send a repeating
letter 'x' when the X7 flag turns ON, and a single 'y' when the X7 flag
turns OFF, exactly as it would if it referenced a button. Flags can have
toggles and multi-toggles associated with them, and are affected by IO
and UMD codes in the same manner as the regular buttons.
Logical Flag Control
--------------------
The flags don't have a physical button associated with them. Rather,
they are controlled by a number of statements which allow them to be
turned ON and OFF under a variety of conditions based on the state of
other buttons and flags or on the positions of the digital controls.
The primary statement for defining flag operation is the DEF statement.
It specifies under what conditions the flag will be OFF or ON using the
standard logical operators AND, OR, and NOT, as well as some special
functions which will be discussed later. The general form of the DEF
statement is;
DEF flag_id logical_equation
where the 'flag_id' is one of the valid flag references X1..X48 and
the 'logical_equation' is a valid combination of AND's, OR's, NOT's,
and references to other flags and buttons. For example:
DEF X7 S1 AND S2
would define flag X7 as being ON when both S1 and S2 were pressed, and
OFF otherwise. If we add a BTN statement for X7:
BTN X7 x
we would get a repeating 'x' character so long as both S1 and S2 were
pressed simultaneously.
Other flags may also be referenced in the logical equation. If we added
the line:
DEF X2 X7 OR S3
would cause X2 to be ON whenever either X7 was ON or S3 was pressed.
X7 would need to be defined elsewhere for it to have any meaning. If
we used the one from our previous example then X2 would be ON when S3
was pressed or when S1 and S2 were pressed simultaneously.
Generally DEF statements can be composed of any combination of AND,
OR, and NOT statements, left and right parentheses, and button or
flag references, so long they result in a valid logical equation, for
example:
DEF X1 (S1 AND NOT S2) OR (S3 AND (H1U OR H2U))
would turn X1 ON when S1 was pressed and S2 was released or when S3
and H1U were pressed or when S3 and H2U were pressed.
Toggles
-------
Every button, switch, and flag reference available in the F22 has an
associated 'toggle flag' associated with it. This flag is normally used
to determine the current toggle state for the /T codes. The toggle flag
can be referenced only in the 'logical equation', it cannot be DEF'd
nor can it be reference in a BTN statement.
To reference a toggle, simply use the regular name of the button or flag
with a '*' after it. For example, the toggle flag for S1 is S1*, that
for X27 is X27*, etc.
Toggle flags change state whenever the associated button or flag turns
ON. S1* will turn ON the first time S1 is pressed, OFF the second time,
ON the third time, etc.
This is useful in implementing Push On/Push Off type functions. For
instance:
DEF X1 S1*
BTN X1 a
Pressing S1 the first time would cause S1* to turn ON, in turn causing
X1 to turn ON, and the 'a' character would being to repeat continuously.
The 'a' would continue to repeat until S1 was pressed a second time. That
would set S1* OFF, X1 OFF, and the character would stop.
Analog Flag Control
-------------------
Flags can also be set ON or OFF using a Type 2 analog statement. To
do this, a regular Type 2 statement is written using a flag reference
in place of any or all of the characters. For example:
RNG 2 5 a b X1 d e
In this case, the RNG control would send the normal 'a', 'b', 'd', and
'e' characters for the first, second, fourth, and fifth zones just as a
normal Type 2 statement would. When the RNG control is in zone 3, however,
no character will be sent. Rather, flag X1 will turn ON and stay on so
long as the RNG pot is in the third zone. Moving out of the third zone
will turn X1 OFF again.
When flags are generated by analog controls, there will not be a DEF
statement for that flag. The Type 2 statement is sufficient to define
when the flag is OFF and when it is ON. The flag itself can be
referenced as a BTN macro, or it can be referenced in DEF statements
in combination with other flags and buttons and the logical operators.
Any of the controls that can be programmed as Type 2 can be used to
generate the flags characters.
The Delay Function
------------------
The DELAY function adds a fixed time between the time that the logical
equation produces a true state and the time that the flag actually turns
ON. Syntax is:
DEF X1 DELAY(1000) S1 AND S2
This statement defines X1 to turn on 1 second (1000 milliseconds) after
S1 and S2 are pressed simultaneously. If either S1 or S2 is released,
the delay will be stopped. If X1 has not turned ON yet, it will remain
OFF, if it has turned ON, then it will turn OFF immediately. The delay
will also be reset, so if S1 and S2 are subsequently pressed again. the
entire 1 second delay will start over.
Times are expressed in milliseconds (1/1000ths of a second). The actual
resolution is around 30 milliseconds, and the minimum effective values
is also 30 milliseconds, so any value between 1 and 59 will produce
about a 30 millisecond delay, 60 through 89 will produce a 60
millisecond delay, etc.
The Pulse Function
------------------
The PULSE function sends a repeated ON-OFF sequence while the logical
equation is true. The two numbers in the function define the ON and OFF
periods respectively. For example:
DEF X1 PULSE(100 1000) S1 OR S2
Pressing S1 or S2, will cause X1 to turn ON immediately for a time
period of 1/10th of a second, then OFF for a time period of 1 second,
then ON for 1/10th second, etc. That operation would run continuously
so long as S1 or S2 was held down. Note that a SPACE character must
separate the two numeric values. Using a comma or other separator will
cause a compiler error.
The Comparison Operators
------------------------
There are two analog comparison operators available for use with the
logical processor called CMPLT and CMPGT. They're used to control flags
based on the current position of any of the 8 available analog controls
(JSX, JSY, RDDR, THR, LBRK, RBRK, ANT, and RNG). They compare the current
value of the analog control to a preset value defined in the F22 file
and set the flag based on whether the current value is above or below
that preset.
The preset value is expressed in terms of percent of full travel, 0% being
minimum and 100% being maximum. Bipolar inputs such as the ANT control will
be centered at 50%.
The operators must be assigned to a single flag via a DEF statement. The
syntax is something like this:
DEF X1 CMPLT(THR 50)
DEF X2 CMPGT(RNG 25)
In the first example, flag X1 would be ON when the Throttle was in a
position less than 50% of full forward. In the second, flag X2 would
be ON whenever the Range control was above 25% of full clockwise
rotation. For the functions to work properly, the corresponding input
must be programmed digitally. The RNG and ANT controls are always
digital, but the other inputs depend on how the F22 file is set up.
Using the comparison operators with controls used as analog outputs,
analog throttle for instance, will result in the flag being continually
OFF or continually ON, but it will not track the throttle position.
The Software Reset Function
---------------------------
A Software Reset is one which causes the F22 to go back to it's Reset
Mode. Usually the only way to get to the Reset State is by powering
the unit down, but there are several circumstances where it is desirable
to re-enter Reset Mode, and the F22 makes provision for defining such
a function in the user program. The basic mechanism is to program a
BTN to send the special character F22RST. This isn't a character at
all, it's a special internal command, but you program it as if it were
a character, i.e.:
BTN S1 F22RST
will reset the F22 whenever S1 is pressed. The F22RST function has
several uses that will be discussed in the Examples section.
Notes on Advanced Programming
=============================
In order to fully utilize the logical programming functions of the F22,
there are a few things to keep in mind. The F22 executes a program 'loop'
which is repeated over and over while the unit is running. It's basic
functions, in order, are:
1. Read all the inputs to get new information on the button states,
etc.
2. Process that data to generate the logical outputs based on the
DEF statements in the user program.
3. Process the BTN statements in the user program using the button
states and logical outputs generated in steps 1 and 2 and transmit
any characters or analog button output states that result from that
processing.
4. Go back to Step 1.
The logical programming is primarily concerned with Step 2 during which
time the DEF statements are processed to generate logical outputs. It
is important to remember that processing is not really instantaneous.
In fact, the DEF statements are read and processed one at a time in
the order in which they are encountered in the .F22 file. This is an
important point, it means that the flag values don't necessarily have
the same value throughout the scan of the DEF statements. It is also
this fact that makes it possible to generate some complex functions
which would not be available using the F22 syntax alone.
To better illustrate this fact, consider the following pair of DEF
statements:
DEF X1 S1 AND X2
DEF X2 NOT S1
At first glance, it would seem that X1 will never turn ON. Since X2 is
always in a state opposite that of S1, S1 and X2 can never be ON at
the same time. In fact, if you implement the above, you'll find that
X1 will indeed turn ON, albeit briefly, when you press S1.
Suppose S1 is OFF and we press it. The first time the logic is processed
after that button update, X2 will be ON, since on the last loop S1 was
OFF. Since S1 is ON during the current scan, S1 AND X2 will be true for
this one scan only, consequently X1 will be ON. After the first X1 is
output, the next statement will set X2 OFF, and on subsequent scans X1
will be OFF. If we release S1, X1 will still be OFF (S1 is OFF) and X2
will turn ON again. If we then press S1 again, we will get another single
scan with X1 ON.
Note that if we reverse the order of the two statements:
DEF X2 NOT S1
DEF X1 S1 AND X2
X1 will never turn on since X2 will get processed first and will turn
OFF, thus the X1 DEF would generate an OFF every time.
Execution Speed
---------------
The logical functions don't take much time to execute, typically about
120 microseconds per element, where an element is any of the DEF statement
itself, the keywords AND, OR, and NOT, and the references to the flags
and the buttons in the logical equation. Parenthesis do not take any
execution time. The DELAY, PULSE, CMPLT, and CMPGT functions do take
slightly longer, but they are relatively infrequently used and don't
impact much on the overall scan speed.
Programming Examples
====================
This section includes some examples of what can be done using the F22
extended functions. They are meant to give an idea of what might be
accomplished and to illustrate some of the interactions which can take
place.
Slow Trim Function
------------------
Sometimes the need arises to generate a very slowly repeating
character. For instance, suppose we wanted to implement a very slow
trim function for Microsoft Flight Simulator. The character to trim
the nose down in FS5 is KP7, and after some experimentation we find
that pressing KP7 once every 5 seconds produces a gradual trim that
does not cause instability. One easy way to implement this would be
with the PULSE function:
DEF X1 PULSE (100 5000) H1U*
BTN X1 /N KP7
Note the use of the toggle flag for H1U instead of the button itself.
Using that, the trim function will begin the first time we push H1U
and will continue until H1U is pressed again. That saves having to
hold the hat in the UP position for the duration of the trimming
operation. X1 will turn on for 1/10th of a second every 5 seconds so
long as H1U* is ON, and will generate a KP7 every time it does.
Duplicating these functions on X2 for H1D:
DEF X2 PULSE(100 5000) H1D*
BTN X2 /N KP1
and we have a complete trim control function on H1U and H1D.
Analog Autofire
---------------
In some games, you only get a single shot per trigger pull. Some game
controllers implement a hardware 'autofire' function to pulse the game
port button line rapidly, allowing the user to simply hold down the
trigger to continuously fire the weapon. An analog autofire function
is easily generated using the F22 DEF statements. First, we tie the
primary trigger TG1 to one of the flags through a PULSE function:
DEF X1 PULSE (50 50) TG1 rem Pulse X1 when the trigger is pulled
Now, X1 will pulse ON for 50 milliseconds and OFF for 50 milliseconds
so long as the trigger is pulled. Next, we tie the flag to the analog
port button output:
PORTB1 IS X1 rem Hook X1 to the analog trigger output
Port Button 1 will track X1 and will turn ON and OFF continuously when
the trigger is pulled.
Using the two-stage trigger, this could be expanded to provide a single
firing at the first trigger click and repeated firings at the second
trigger click. First, we set up the pulser on the secondary trigger:
DEF X1 PULSE (50 50) TG2
Next, we set up a flag that is ON when either TG1 is ON or TG2 is
pulsed ON. There's a little problem doing this because in the F22
hardware, TG1 remains on when TG2 is ON. That would mask the TG2
output, so the equation is modified slightly to ignore the TG1 input
whenever TG2 is ON:
DEF X2 X1 OR (TG1 AND NOT TG2)
X2 will turn ON whenever TG1 is ON and TG2 is OFF, or whenever TG2
generates a pulse via X1. Now we just need to tie it to the game port:
PORTB1 IS X2
Now, whenever the trigger is pulled back to the first click, the
game port input will turn ON continuously. If the trigger is pulled
back to the second click, the game port input will start to pulse at
around 10 pulses per second.
Mixed Analog/Digital Trigger
----------------------------
The ability to assign analog outputs to flags and buttons makes it
possible for to make use of inputs in both digital and analog mode in
the same program. One example might be a situation where you want to
use analog trigger for activating guns, but have it generate a
character to fire other sorts of weapons. Suppose the game uses two
keyboard command, FireWeapon1 and FireWeapon2, for the two weapons and an
analog game port input to fire the guns. Using the UMD flags as a sort
of master mode selector, first define a flag to combine the Rocker Up
and TG1 inputs:
DEF X1 TG1 AND T8 rem X1 ON when trigger pulled and rocker up
and assign that output to the game port:
PORTB1 IS X1 rem Hook X1 to the analog trigger output
Now the trigger will activate the game port output, but only when the
Rocker Switch is in the Up position (T8 ON). The rest is easy, just
define a UMD group for TG1 with a non-operational character in the U
position:
BTN TG1 /U NullChr rem NULL char in Up, X1 will send analog
/M FireWeapon1 rem Fire weapon 1
/D FireWeapon2 rem Fire weapon 2
Sequencing Events
-----------------
It is possible to generate sequences of events easily using the flag
logic and the DELAY function. Suppose we want to press one button and
have it execute a set of timed events. One way to do that is to simply
'stack' flags with delay functions:
DEF X1 DELAY(1000) S1
DEF X2 DELAY(1000) X1
DEF X3 DELAY(1000) X2
BTN X1 GearUp
BTN X2 FlapsUp
BTN X3 LightsOff
This is useful not only for sequencing operations, but also for
combining several not-to-critical functions on one button. In the above
example, for instance, you could press the button and hold it and all
three functions would execute in sequence 1 second apart. You could
also press and hold it for 1 second to bring up the gear. Sometime
later, you could press and hold it for 2 seconds to get the flaps up.
It would generate an extraneous gear up command, but that probably
wouldn't have any effect. Finally, you could hold it for 3 seconds to
turn off the strobe. You could do this with multi-toggles, but there
are only 8 of those available. You could do the whole sequence with
the older DLY statement, but you couldn't select the function you
wanted to execute, nor could you use any other digital commands while
you were running it.
Multiple View Sets
------------------
Frequently, one of the hats on the F22 is used for 'view selection'.
Normally this is limited to 4 views, but with the use of the IO codes, it
can be expanded to 8 views. Using the logical functions, it is possible
to generate alternate view sets based on buttons other than S3 (the IO
selector). For example, we could use S4 to expand the set to 12 views.
First, we need to set up the logic to generate the three view selectors:
DEF X1 NOT S3 AND NOT S4
DEF X2 S3 AND NOT S4
DEF X3 NOT S3 AND S4
Basically, this sets up three mutually-exclusive flags which will be
used to enable one of three sets of views. The next step is to generate
flags for each of the view positions:
rem View flags when S3 and S4 are released
DEF X7 H1U AND X1
DEF X8 H1R AND X1
DEF X9 H1D AND X1
DEF X10 H1L AND X1
rem View flags when S3 is pressed
DEF X11 H1U AND X2
DEF X12 H1R AND X2
DEF X13 H1D AND X2
DEF X14 H1L AND X2
rem View flags when S4 is pressed
DEF X15 H1U AND X3
DEF X16 H1R AND X3
DEF X17 H1D AND X3
DEF X18 H1L AND X3
Finally, we just need to assign the correct view characters to the
appropriate view flags:
rem Normal view set
BTN X7 LookUpFront
BTN X8 LookRight
BTN X9 LookBack
BTN X10 LookLeft
rem Up view set
BTN X11 LookUp
BTN X12 LookUpRight
BTN X13 LookUpBack
BTN X14 LookUpLeft
rem Down view set
BTN X15 LookDownFront
BTN X16 LookDownRight
BTN X17 LookDownBack
BTN X18 LookDownLeft
When neither S3 or S4 is pressed, the normal 'level' views will be
available. Pressing S3 will provide a set of UP views for the four
basic direction, pressing S4 will provide a set of DOWN views.
It's not normally possible to use /H codes within an IO or a UMD
structure, but generating the IO or UMD sets using flags will give
the same result and is not subject to the /H limitation since no IO
or UMD codes are involved in the actual BTN statements. If the views
are to use /H codes, though, the selector logic gets a to be a little
more complicated. The reason is for this is due to the fact that when
the F22 processes the BTN statements, it does so in a fixed order
regardless of how they're ordered in the F22 file. This fixed order only
applies to the BTN statements. As stated earlier, the DEF statements
are processed in the same order that they occur in the F22 file.
To see where the problem arises, suppose we've set up two flags which
are to send /H codes. One will be sent when S1 is pressed and S3 is
released, the other will be sent when S1 is pressed and S3 is pressed.
DEF X1 S1 AND NOT S3
DEF X2 S1 AND S3
Now we set up the BTN statements for the two flags:
BTN X1 /H a b
BTN X2 /H b c
Suppose both are released. If we press S1, X1 will turn ON and send the
make codes for 'a' and 'b'. If we subsequently press S3 while S1 is on,
X1 will turn OFF, sending the break codes for 'a' and 'b', and X2 will
turn ON, sending make codes for 'b' and 'c'. The problem is that the
character order will depend on the order in which the F22 processes the
buttons. If the F22 processes BTN X2 before it processes BTN X1, it will
send the X2 'make' characters' before it sends the X1 'break' characters
and the PC will get
'b' make, 'c' make, 'a' break, 'b' break
the 'b' break on X1 will cancel the 'b' make on X2, leaving us with
just the 'c' actually depressed. If we modify the logic and add two
additional flags:
DEF X1 S1 AND NOT S3 AND X3
DEF X2 S1 AND S3 AND X4
DEF X3 S1 AND NOT S3
DEF X4 S1 AND S3
X1 will turn OFF as above when S3 is pressed, but X2 will not turn
on until the following scan because X4 isn't turned ON until after
the X2 logic is complete. Consequently, the X1 'break' characters
will get sent on the current scan, whereas the X2 'make' characters
won't get sent until the next scan. This ensures that the PC sees:
'a' break, 'b' break, 'b' make, 'c' make
which is the desired sequence and leaves both 'b' and 'c' made. This
only affects /H sequences, with the other modes of F22 character output,
i.e. repeating characters, macros, etc. this problem doesn't generally
occur.
For our original example. we'd need to expand to three additional
statements:
DEF X1 NOT S3 AND NOT S4 AND X4
DEF X2 S3 AND NOT S4 AND X5
DEF X3 NOT S3 AND S4 AND X6
DEF X4 NOT S3 AND NOT S4
DEF X5 S3 AND NOT S4
DEF X6 NOT S3 AND S4
Once the additional logic has been added, the statements to set up the
flags for the individual views and the BTN statements to actually send
the view characters would be the same as for the original "non-/H' case.
Air Warrior Views
-----------------
Kesmai's Air Warrior supports a built-in view system that accesses eight
views by using a second button to switch between two sets of four view each.
The built-in support for this set is limited to joysticks which include
an 'analog' hat switch of some sort. While the method shown above can
be used to emulate this built-in support, considerable simplification
is possible. The following code segment will implement an equivalent
set based on H1 and S3:
rem F22 code fragment to generate standard AW 8-view set. Select a
rem generic 2-button joystick in AW Setup.
DEF X1 H1U AND NOT S3
DEF X2 ((H1R OR H1L) AND S3) OR H1D
DEF X3 (H1D AND S3) OR H1U
BTN X1 /H KP8
BTN X2 /H KP2
BTN X3 /H KP5
BTN H1R /H KP6
BTN H1L /H KP4
The logic is perhaps a little obscure, it was generated based on the
observation that 4 of 6 keycodes used were on the same hat position
regardless of the position of the view set selector:
S3 Released S3 Pressed
H1U KP5 KP8 KP5
H1R KP6 KP6 KP2
H1D KP2 KP2 KP5
H1L KP4 KP4 KP5
Because of that, the pressing of S3 need only add (or in one case, H1U,
subtract) a single key code from that generated by the hat position. It
works like this.
X1 adds a KP8 whenever H1 is Up and S3 isn't pressed. Pushing H1U also
generates a KP5 via the X3 definition regardless of the S3 position. The
result is a KP8/KP5 combination when S3 is released and just a KP5 when
S3 is pressed. Pressing S3 moves from a 45 degree Up view to a full Up
view.
X2 adds a KP2 command when H1 is Back or when S3 is pressed while H1 is
Left or Right. The H1R and H1L positions activate KP4 and KP6 commands
directly using BTN statements. When S3 is released, the BTN statements
generate the needed Left/Right commands, when S3 is pressed, the added
KP2 provides the rear quarter views.
The logic for X3 relating to the Up and Up/Forward views was mentioned
above. When S3 is pressed, it is also responsible for adding a KP5 to
the KP2 generated by X2, giving a Look Up and Back combination.
The view set can be placed on any available hat switch and use any
button for view set selection, it's only necessary to change the H1 and
S3 references to match the desired controls. The view set can alos be used
in other games that use a similar method of view selection, the example
given should operate in Warbirds without modification.
16-View Set for Air Warrior and War Birds
-----------------------------------------
A more elaborate 16-view scheme can be implemented with the F22 using
the corner positions. This will also work with both AW and WB and
requires no special 'key map' for use. The basic code looks like this:
DEF X1 (H3U AND NOT S3) OR H3UR OR H3UL rem KP8 if forward quadrant
DEF X2 (S3 AND NOT H3M) OR H3U rem Up if S3 or HU and no S3
DEF X3 H3UR OR H3R OR H3DR rem KP4 on right quadrant
DEF X4 H3DR OR H3D OR H3DL rem KP2 in back quadrant
DEF X5 H3DL OR H3L OR H3UL rem KP4 in left quadrant
BTN X1 /H KP8
BTN X2 /H KP5
BTN X3 /H KP6
BTN X4 /H KP2
BTN X5 /H KP4
This implements the 'intuitive' 8-way level views, pressing S3 adds
'Up' to the selected view. The coding is somewhat obscure. Basically,
it uses flags to generate forward, back, left, and right quadrants.
This works much better than simply assigning single keys to the basic
directions and double-keys to the corners because of the way the keys
'make' and 'break' as the hat moves from a standard postion to a corner
position and vice-versa. Suppose the hat moves from the left to the
left/forward position. If the keys are simply assigned, the left key
will 'break' first, then the left and forward keys will 'make'. The
result is slower since it sends 1 break and 2 makes, and the sim will
want to pass through the forward view when the first key breaks. With
the quadrant approach, the left key will not 'break' when the hat is
moved, the only key stroke sent will be a forward 'make'. Subsequently,
moving to the full forward position will simply 'break' the left key,
rather than, again, breaking both left and forward, then remaking
forward.
The above code segment only works with microcode chips V1.16 and above.
The V1.16 chips made some improvements in the hat-corner logic. With
earlier version of the chip, an additional line of code is required,
it needs to look like this:
DEF X1 H3U AND NOT H3UR rem Fixup for H3U
DEF X2 (X1 AND NOT S3) OR H3UR OR H3UL rem KP8 in forward quadrant
DEF X3 (S3 AND NOT H3M) OR X1 rem Up if S3 or HU and no S3
DEF X4 H3UR OR H3R OR H3DR rem KP4 on right quadrant
DEF X5 H3DR OR H3D OR H3DL rem KP2 in back quadrant
DEF X6 H3DL OR H3L OR H3UL rem KP4 in left quadrant
BTN X2 /H KP8
BTN X3 /H KP5
BTN X4 /H KP6
BTN X5 /H KP2
BTN X6 /H KP4
This latter version should work with any chip revisions.
Converting Panning Views to Fixed Views
---------------------------------------
If a game provides a set of panning views, that feature can generally
be used to generate any view desired using the F22 logic functions.
The basic technique is to hold the panning key down just long enough
for the view to pan to the desired position. Suppose the game provides
three keys, PanLeft, PanRight, and LookForward. Some testing reveals
that it takes approximately 1 second for the view to pan 90 degrees,
and it is desired to implement a pair of views 45 degrees to the right
or left of straight ahead. Several methods can be used to generate the
necessary time period. Here's one:
DEF X1 DELAY(500) H1R
DEF X2 H1R AND NOT X1
DEF X3 DELAY(500) H1L
DEF X4 H1L AND NOT X3
To see how the logic works, consider the first pair of statement. When
H1R is pressed, the timer will start on the DEF X1 statement, but X1
won't actually turn ON for 1/2 second. The DEF X2 statement will cause
X2 to turn ON immediately since H1R is ON and X1 isn't. 1/2 second later,
X1 will turn ON and that will cause X2 to turn OFF. The X3/X4 DEF
statements work similarly for H1L.
Next, we just assign held characters to the X2 and X4 flags:
BTN X2 /H PanRight
BTN X4 /H PanLeft
and we set H1 to generate a LookForward command when it's released:
BTN H1M LookForward
Now, pressing and holding H1R will cause the view to pan right for 1/2
second and stop, H1L will cause a pan left of 1/2 second. If the hat is
released, the view will snap to the forward position immediately. This
technique works pretty well, although the actual time to pan and hence
the final view position may vary somewhat with the instantaneous frame
rate in the game. The variation is usually not too great however.
Implementing Infrequently Used Functions
----------------------------------------
Sometimes there are functions that it would be nice to program onto
the stick, but they are used so seldom or have such dire consequences
that just putting them on a button is not desirable. 'Bailing out' comes
to mind as one such function. One workaround is to define those as a
function of two buttons which are not likely to be pressed at the same
time. For example:
DEF X1 DELAY(1000) H1U AND H4U
BTN X1 BailOut
For the BailOut command to be sent, you need to press both H1U and H4U
(hard to hit those at the same time by accident) and you need to hold
them for 1 second. There's very little chance you would inadvertently
bail out, but when the time came you could be gone in just one second
without having to find the keyboard.
Analog Rate Control
-------------------
There are situations where it is desirable to be able to use one of
the analog inputs to control the rate at which a particular character
is being generated. While most sims will support analog inputs for the
primary X and Y axes, rudder, and throttle inputs, there are other
functions for which some form of proportional control would be desirable.
For example, some sims provide a 'brake' function. Usually, there's a key
to press which, if held down, provides full braking power. Tapping the
key produces a brief full brake pulse, and by repeating the character at
different rates, the overall braking effect can be adjusted.
Using flag references in conjunction with a Type 2 input can be use to
do just that. Suppose we want to program a toe brake on the RCS Pro to
provide proportional braking. The first step is to define the brake
to include as many levels of braking as are desired. Suppose 4 levels
are deemed to be sufficient:
LBRK 2 5 ^ X1 X2 X3 X4
The statement sets up five zones corresponding to 4 levels of braking
and one OFF position. The '^' is seen by the F22 compiler as a Null
Character, it's just used as a place holder so the brake will not send
any characters in the up or OFF position. The flags X1..X4 will be
used to control the four braking rates.
Next we need to set up some way to control the character rates for the
four braking levels. Assuming that X4 will be 'full on', then we really
only have 3 timed intervals. Let's assume that rates of 1 character every
2 seconds will be the slowest, follow by 1 character every second and
finally 2 characters every second for the fastest. Some experimentation
would need to be done, of course, to determine optimum rates for a
particular sim.
To generate the clocks, we'll use the PULSE function. There are various
ways to set it up, but probably the most straightforward is to just load
the brake-controlled flags as inputs to the PULSE function, then pass
those out to a second set of flags:
DEF X5 PULSE (10 2000) X1 rem Once every 2 seconds while X1 is ON
DEF X6 PULSE (10 1000) X2 rem Once every second while X2 is ON
DEF X7 PULSE (10 500) X3 rem Once every half second while X3 is ON
After that, it's only necessary to assign the brake command to the various
flags:
BTN X4 /H LeftBrake
BTN X5 LeftBrake
BTN X6 LeftBrake
BTN X7 LeftBrake
The X4 flag just holds the key down continuously. The X5 through X7
commands pulse the brake at the rates defined by their associated
timers as the pedal passes through their respective zones.
Using UMD and IO Codes with Type 2 Analog Controls
--------------------------------------------------
While it is not normally possible to control the output of the analog
statements using the UMD and IO codes, it can be done with Type 2
analog devices utilizing flag characters since the flags themselves
are subject to UMD and IO modifications:
RNG 2 3 X1 X2 X3
BTN X1 /I a
/O d
BTN X2 /I b
/O e
BTN X3 /I c
/O d
will set the range pot to produce 'abc' when S3 is depressed and 'def'
when S3 is released.
Analog Min/Max Functions
-------------------------
One use of the comparison operators, CMPLT and CMPGT, is to assign Min
and Max characters for Type 1 analog controls. Frequently, the operation
of the Type 1 function is affected by the frame rate in the game and the
Type 1 functions tend to 'get out of sync', the control position doesn't
match the game setting. This generally is most apparent with Type 1
throttles, where after a period of time, going to the maximum power detent
correspond with the games full throttle setting.
Adding Min/Max characters can help in this situation if the game supports
them. These characters can be sent to force the game to it's max or min
setting, and if they can be sent when the control is in that position
the game and control will realign themselves.
For example, take a Type 1 throttle:
THR 1 10 2 a b c d e f
Next, add comparators to generate flags when the throttle is at less
than 5% or greater than 95% of it's maximum travel:
DEF X1 CMPLT(THR 5)
DEF X2 CMPGT(THR 95)
Now, X1 would turn ON when the throttle is near minimum, X2 would turn
ON when it is near maximum.
Finally, program the flags to send the appropriate commands:
BTN X1 /N MinThrottle
BTN X2 /N MaxThrottle
Now, if the throttle and game get out of sync, we can just push it to
the Min or Max positions and the characters will be generated to realign
the throttle and game.
Non-Linear Type 1 Throttle
--------------------------
Another interesting possibility is to generate a non-linear throttle
response. For example, suppose the game requires 30 steps of throttle
for full throttle travel, but the lower third is not particularly
useful and it's desired to maintain a finer degree of control over the
upper two thirds of travel.
First, a throttle statement is set up that generates two-thirds of the
characters:
THR 1 20 1 ThrottleUp ThrottleDn ABOn ABOff ABUp ABDn
Next, a couple of comparisons are done at the 5% and 10% positions:
DEF X1 CMPLT(THR 5)
DEF X2 CMPLT(THR 10)
The two flags are programmed to send 4 characters each:
BTN X1 /P RPT(5) ThrottleDn /R RPT(5) ThrottleUp
BTN X2 /P RPT(5) ThrottleDn /R RPT(5) ThrottleUp
Now the upper 90% of throttle travel will produce 20 throttle steps.
As the throttle is moved back through the 10% position, the X1 flag
will turn ON and generate an additional 5 steps, and as the throttle
is moved back through the 5% position the X2 flag will generate an
additional 5 steps for a total of 30 altogether.
Emulating a CH-Style Hat Switch
-------------------------------
While there is seldom any real reason to do so, it is possible to
program the hats on the F22 to send the chorded-button groups that the
CH Pro Joystick, CH F-16 Joystick, and CH Virtual Pilot Pro Yoke use.
This might be useful in instances where functions are available only
through the use of built-in game support. Basically, both of these
code segments simply OR the appropriate inputs together and then pass
those out to the appropriate buttons. The only piece which does wander
from this straightforward approach a bit is the use of 'NOT H1M' to
replace 'H1U OR H1R OR H1D OR H1L' in the interest of simplifying
the logic.
To emulate the simpler CH Pro joystick, the logic looks like this:
REM Coding to emulate CH FlightStick Pro Hat
REM TG1 is Button A1
REM S2 is Button A2
REM S3 is Button B1
REM S4 is Button B2
REM H1 Is the Hat
DEF X1 TG1 OR NOT H1M
DEF X2 S2 OR NOT H1M
DEF X3 S3 OR H1D OR H1U
DEF X4 S4 OR H1R OR H1U
PORTB1 IS X1
PORTB2 IS X2
PORTB3 IS X3
PORTB4 IS X4
The above logic can be improved a bit. Using the logic shown, it's
possible to hold one view on the hat, then have it change to another
view when S2 or S4 is pressed since they are passed through and will
change the chording arrangement. By changing the DEF statements for X3
and X4 slightly, this condition can be 'locked out':
DEF X3 (S3 AND H1M) OR H1D OR H1U
DEF X4 (S4 AND H1M) OR H1R OR H1U
The addition of the H1M elements forces S3 and S4 to be disabled whenever
the hat is off-center, thus they are inactive whenever the hat is being
used.
Emulating the F-16 or VP Pro is a little more complex, involving two
hats and 6 buttons:
REM Coding to emulate CH FlightStick Pro Hat
REM TG1 is Button A1
REM S2 is Button A2
REM S3 is Button B1
REM S4 is Button B2
REM S1 is Button X1
REM TG2 is Button X2
REM H1 Is the Primary Hat
REM H2 Is the Secondary Hat
DEF X1 TG1 OR TG2 OR S1 OR NOT H1M
DEF X2 S2 OR H2D OR H2R OR H2U OR NOT H1M
DEF X3 S3 OR H1D OR H1U OR H2L OR H2D OR H2U OR S1
DEF X4 S4 OR H1R OR H1U OR H2L OR H2R OR H2U OR TG2
PORTB1 IS X1
PORTB2 IS X2
PORTB3 IS X3
PORTB4 IS X4
The examples use H1 and H2, but any hats or buttons will work, including
those on the TQS or WCS throttle unit. With the TQS, it would also be
possible to use the 4-way switch or the T11..T14 characters as one of the
hat switches. Since they don't have HM position equivalents, that would
have to be done with another flag. For example, a 'hat middle' flag for
the TQS stick-ball characters would look like this:
DEF X5 NOT (T11 OR T12 OR T13 OR T14)
Substituting the correct reference for the HU, HD... codes and the X5
flag for the HM reference would be all that was necessary to allow
the stick-ball to be used as one of the hats.
Using the Software Reset
------------------------
As mentioned previously, there is a software reset function that is
available with the F22. This function resets all variables and returns
the F22 to Reset Mode, requiring that a button be pressed to 'wake it
up' again.
There are several situations in which a Software Reset is very useful.
One such instance is when you need to calibrate a game and the F22 file
for that game defines the trigger or other analog inputs that the game
requires as digital. In that case, you can't progress through the games
calibration routine because the game asks you to press a button and you
don't have a button to press. When the F22 is in Reset Mode, all four
analog axes are passed through, the TG1 input is passed to Button 1 and
the S2 input is passed to Button 2. This setup looks like a standard,
2-button joystick and will all the calibration procedure to progress
normally. Adding a Software Reset to your program will let you put
the stick into this special 'calibrate' mode when necessary.
Some not-so-standard keyboards and BIOS may have trouble when the WCS
is used with the F22 in slave mode. The usual symptom is lost keyboard
characters when you're typing. It's not generally a problem in the game,
the WCS and F22 work fine, but working with the keyboard becomes very
difficult. When the F22 is in Reset Mode, communication with the WCS is
suspended and does not interfere with the keyboard, so implementing
a Software Reset will allow the Control System to be 'shut down' when
not in use.
Last, but certainly not least, a Software Reset is very useful when
developing logical programs. It is very easy to create logical systems
that result in an effectively 'stuck' flag, i.e. one that's always ON.
If there is a key assigned, directly or indirectly, to that flag, the
key is likely to start autorepeating and without a Software Reset, there
is no way to silence it except to turn off the system. The F22 Utility
programs like F22Reset will likely be ineffective in these instance
since they probably won't be able to establish communications with a
an F22 which is transmitting characters.
It's not generally desirable to implement the software reset as a
regular button press since it is too easy to hit it by mistake during
game play. It also wastes a button. A better method is to implement it
like the 'Infrequently Used Functions' mentioned above:
DEF X1 DELAY(1000) H1U AND H2U
BTN X1 F22RST
That way, it's there if you need it, but won't get in the way during
game play.
------------------- End of Document -------------------