Programming the EPIC card
Programming the EPIC once you have understood the system is no longer a problem. Unfortunately not all the
programming-details you need sometimes are given in the documentation. Therefore I would like to give you some
help, showing some programming-examples solving common problems. Just have fun with them.
Connecting switches to the EPIC |
|
For the connection to the EPIC you'll need the basic card, the first expansion module, an ABA module and at
least one 64 BTN module. This module has 64 intakes for wires, to hold buttons, switches, etc. It also has 2
intakes to connect the electric power supply. Now you can connect one pole of the switch to any one of the 64
connectors and the other pole to the power connector. That's all.
If you want to connect more than only one switch, you have to connect one pole of each switch to one of the 64
connectors, and the other pole is connected in serial way (this for the power supply) which is connected to
the 64BTN module.
Connecting switches to the EPIC
|
|
Basics for any EPIC programming |
|
Every EPIC programming can be written with an ASCII editor. Once it is written it is compiled using the
EPL.EXE. This corrects the file and compiles it. The compiled file can now only be downloaded to EPIC
using the LOADEPIC.EXE and becomes active.
The files should not be bigger than 64Kbyte, as EPL.EXE can only handle files up to this size. As
sometimes required files are bigger, I wrote a small program, called XEPL.EXE, which compiles
automatically the file, suppressing unnecessary data, like comments, free spaces and tabulators. After doing
this EPIC's EPL.EXE is started.
All EPIC program file should have the following data:
#define FASTSCAN 0
#define LOWSCAN 1
#define OUTPUT 2
DefineModule(0, FASTSCAN, 0, 16)
DefineModule(1, LOWSCAN, 0, 16)
DefineModule(2, LOWSCAN, 0, 16)
:INIT { Reset }
This program does nothing special at the beginning, it just initiates after download the EPIC card. Also on
these rows that the module 0 should be "FASTSCAN", while modules 1 and 2 should be used with normal speed, as
EPIC only is able to scan up to 16 rows fast.
Powering a ON/OFF switch |
|
First you have to check the connections number of the switch with
TEST128.EXE. In order to do this you
have to compile the file and download it to EPIC. Then start
TEST128.EXE and move the switch. If
nothing is displayed in module 0, select either module 1 or 2 and activate your switch again. Now the display
shows the number of the connection. Green in the ON position and red in the OFF position. Lets say that the
switches number is 192, for example. Using this switch we want to power the
ECM. To do this the switch has to transmit "j" to the Falcon simulation.
Here how to do this:
#define FASTSCAN 0
#define LOWSCAN 1
#define OUTPUT 2
DefineModule(0, FASTSCAN, 0, 16)
DefineModule(1, LOWSCAN, 0, 16)
DefineModule(2, LOWSCAN, 0, 16)
:INIT { Reset }
:ECMToggle { KeyHit(j) } ; ECM togglen
DefineButton(192, ON, ECMToggle)
DefineButton(192, OFF, ECMToggle)
It's easy, isn't it?
Powering an ON/OFF/ON switch |
|
Powering this type of switches is as simple as powering a two way switch. The only difference is that the
switch has 2 ON positions instead of only one. Using
TEST128.EXE you can determine the number of each
connection. Let's suppose that you found out that they are "73" and "74" for the ON positions. Using this
switch we want to power the
Master Arm Switch. The program would look
like this:
#define FASTSCAN 0
#define LOWSCAN 1
#define OUTPUT 2
DefineModule(0, FASTSCAN, 0, 16)
DefineModule(1, LOWSCAN, 0, 16)
DefineModule(2, LOWSCAN, 0, 16)
:INIT { Reset }
:MasterArm { ShiftHit(m) } ; Master Arm to "Arm"
:MasterOff { CtrlHit(m) } ; Master Arm to "Off"
:MasterSim { AltHit(m) } ; Master Arm to "Simulate"
DefineButton(73, ON, MasterArm)
DefineButton(73, OFF, MasterOff)
DefineButton(74, ON, MasterSim)
DefineButton(74, OFF, MasterOff)
Powering a rotary switch |
|
The powering of an incremental switch (I'll just call it rotary) can drive you crazy. If you don't know what
is happening there and you have no information, you'll get into deep trouble. First there are 2 different
types of rotaries, which have to be programmed each on is own way, and as you can't tell which type they are
just by looking at them, there is only one thing to do: test it.
But before we start, what is a rotary, and what is it used for in the F-16? A rotary is a device, which gives
impulses when it is turned in either direction. These controls are for example used at the
HSI to select Course and Heading.
In order to activate a rotary at the rotary module, you have to configure the
MAKEBTN.DAT file first.
Here you have to write the following:
700 BUTTON700 0 1 7
701 BUTTON701 0 2 7
702 BUTTON702 0 4 7
703 BUTTON703 0 8 7
704 BUTTON704 0 16 7
705 BUTTON705 0 32 7
706 BUTTON706 0 64 7
707 BUTTON707 0 128 7
708 BUTTON708 1 1 7
709 BUTTON709 1 2 7
710 BUTTON710 1 4 7
711 BUTTON711 1 8 7
712 BUTTON712 1 16 7
713 BUTTON713 1 32 7
714 BUTTON714 1 64 7
715 BUTTON715 1 128 7
716 BUTTON716 2 1 7
717 BUTTON717 2 2 7
718 BUTTON718 2 4 7
719 BUTTON719 2 8 7
720 BUTTON720 2 16 7
721 BUTTON721 2 32 7
722 BUTTON722 2 64 7
723 BUTTON723 2 128 7
724 BUTTON724 3 1 7
725 BUTTON725 3 2 7
726 BUTTON726 3 4 7
727 BUTTON727 3 8 7
728 BUTTON728 3 16 7
729 BUTTON729 3 32 7
730 BUTTON730 3 64 7
731 BUTTON731 3 128 7
Then you have to make these modifications active using
MAKEBTN.EXE. The connection of the rotaries to
the rotary-module is simple. Just follow the steps on the documentation. Now we have to test the rotary using
TEST128.EXE in module 7 (rotaries are here!). First find out the number of the rotary. When turning the
rotary in either direction, we get also a number. Let's suppose they are "700" for left turn and "701" for
right turn. In this example we want to use the rotary for the Heading button at the
HSI.
Well, now we are ready for the programming of type 1. This should be done like this:
#define FASTSCAN 0
#define LOWSCAN 1
#define OUTPUT 2
DefineModule(0, FASTSCAN, 0, 8)
DefineModule(0, LOWSCAN, 8, 8)
DefineModule(1, LOWSCAN, 0, 16)
DefineModule(2, LOWSCAN, 0, 16)
DefineModule(7, FASTSCAN, 0, 8)
:INIT { Reset SendData(7, 0, 1) }
:HSIHeadingInc { KeyPress(CTRL) AltHit(m) KeyRelease(CTRL) }
:HSIHeadingDec { KeyPress(CTRL) AltHit(n) KeyRelease(CTRL) }
DefineButton(700, ON, HSIHeadingDec)
DefineButton(700, OFF, HSIHeadingDec)
DefineButton(701, ON, HSIHeadingInc)
DefineButton(701, OFF, HSIHeadingInc)
With the command "SendData(7, 0, 1)" you select the rotary-type to 1. It is always better to have these rotary
rows read at high speed and therefore "DefineModule(7, FASTSCAN, 0, 8)" should be selected.
And now the same procedure using the type 2 rotary:
#define FASTSCAN 0
#define LOWSCAN 1
#define OUTPUT 2
DefineModule(0, FASTSCAN, 0, 8)
DefineModule(0, LOWSCAN, 8, 8)
DefineModule(1, LOWSCAN, 0, 16)
DefineModule(2, LOWSCAN, 0, 16)
DefineModule(7, FASTSCAN, 0, 8)
:INIT { Reset SetPoint(7,0,0b00000001) }
:HSIHeadingInc { KeyPress(CTRL) AltHit(m) KeyRelease(CTRL) }
:HSIHeadingDec { KeyPress(CTRL) AltHit(n) KeyRelease(CTRL) }
:HSIHeading { ifactive(701) jump HSIHeadingDec else jump HSIHeadingInc }
DefineButton(700, ON, HSIHeading)
DefineButton(700, OFF, HSIHeading)
Powering a LED via Switch |
|
To power a LED with the output-module of the EPIC is simple. Using this module, up to 32 circuits can be
closed and opened again. Whatever you want to place on these circuits, depends on you. You may power LEDs,
electric motors for ventilation, spotlights and much more. The connection of a LED is simple. The electric
output of the output module is 12VDC. This current can be used to power different things. If you want to power
a LED a resistor has to be used to avoid a burn-out. LEDs are the ideal solution for the F-16 simulator, as
power consumption is low, even if you use several LEDs.
A little bit more complicated is to find the LED's number wich is connected to the Output-module. This cannot
be done with TEST128.EXE, and therefore we have to use an auxiliary program to find this number. Let's
suppose that the ECM's LED is the number 2 of the 5th output row. These number are binary coded, so that the
number will look like this: 0,5,0b00000010. This number is not easy to understand and therefore we will
give it a name with the DEFINE command.
#define LED_ECM 0,5,0b00000010
In our example we will activate this LED by turning the ECM's switch ON and deactivate the LED when the switch
is turned OFF.
#define FASTSCAN 0
#define LOWSCAN 1
#define OUTPUT 2
#define LED_ECM 0,5,0b00000010
DefineModule(0, FASTSCAN, 0, 16)
DefineModule(1, LOWSCAN, 0, 16)
DefineModule(2, LOWSCAN, 0, 16)
:INIT { Reset }
:ECMOn { KeyHit(j) SetPoint(LED_ECM) }
:ECMOff { KeyHit(j) ClearPoint(LED_ECM) }
DefineButton(192, ON, ECMOn)
DefineButton(192, OFF, ECMOff)
As you can see "SetPoint()" turns the LED on and "ClearPoint()" will turn it off. Just one more thing to be
done. When you upload the program to the EPIC the light will remain off, even if the switch is in the on
position. If you want to have the LED always according to the switches position, we have to program the
following:
#define FASTSCAN 0
#define LOWSCAN 1
#define OUTPUT 2
#define LED_ECM 0,5,0b00000010
DefineModule(0, FASTSCAN, 0, 16)
DefineModule(1, LOWSCAN, 0, 16)
DefineModule(2, LOWSCAN, 0, 16)
:INIT { Reset ifactive(192) Call LED_ECMOn }
:LED_ECMOn { SetPoint(LED_ECM) }
:LED_ECMOff { ClearPoint(LED_ECM) }
:ECMOn { KeyHit(j) Call(LED_ECMOn) }
:ECMOff { KeyHit(j) Call(LED_ECMOff) }
DefineButton(192, ON, ECMOn)
DefineButton(192, OFF, ECMOff)
Here I have added the commands "LED_ECMOn" and "LED_ECMOff" which control the on and off condition of the LED.
In the INIT function, which is done with the first uploading to the EPIC, the switches position is checked (No
"192"). If the switch is in on position, the LED will be turned on. That's all.
Powering a LED with QProcs |
|
In the prior
example we have powered a LED directly using the according switch.
Another more elegant way to activate LEDs is using a direct port of the EPIC between the EPIC card and the
simulation. To use this port we need a special program, which is able to transmit data taken from the
simulation. For this purpose I have written the
F4-Reader program, which
can be downloaded as freeware.
In
F4-Reader there are 2 possibilities to transfer data about LED and
other devices to the EPIC card. The first and more easy way to do this, is using the communication via QProcs.
Here you define a channel's number which is used to turn a LED on or off. In our example lets suppose that
channel 20 turns the LED on and the channel 21 turns it off. Which channel is used for a certain LED can be
defined simply with the
F4-Reader.
Here's the corresponding program:
#define FASTSCAN 0
#define LOWSCAN 1
#define OUTPUT 2
#define LED_ECM 0,5,0b00000010
DefineModule(0, FASTSCAN, 0, 16)
DefineModule(1, LOWSCAN, 0, 16)
DefineModule(2, LOWSCAN, 0, 16)
:INIT { Reset }
:LED_ECMOn { SetPoint(LED_ECM) }
:LED_ECMOff { ClearPoint(LED_ECM) }
DefineQProc(20, LED_ECMOn)
DefineQProc(21, LED_ECMOff)
With the command "DefineQProc()" you give the order which QProc is going to be activated.
Powering LEDs via Pigeon Holes |
|
As you could see, powering a LED with
QProcs is not difficult. But if several LEDs are
to be used at the same time, programming might become more complicated. When using QProcs for many LEDs at one
time, will bring the EPIC to "choke" and it will be not able to process all the data at once. The solution is
to use Pigeon-Holes. Unfortunately the description of Pigeon-Holes and their use is not documented by EPIC.
Therefore here you have my information about this:
Using QProc only one digital data can be transferred. If you have analogue data which you want to transfer,
Pigeon-Holes can do this for you. Analogue data from 0 up to 255 can be transferred to the EPIC. This is
useful to us, as we can transmit data about the condition of 32 LED at one time (4 x 8 Bit = 32).
Lets suppose that we want to transmit all the data from the 32 LED of the
caution panels. We have connected these 32 LEDs to an output module. Now
we have to define the corresponding bits of a certain Pigeon-Hole. We choose the pigeon-hole with the number
"10". The binary definition of each row or PH Index is analogue to the definition on the output-module. The
LED 12 (for example) on the output-module would correspond to the bit3 on the 1 output-row. (=0,1,0b00001000).
So this LED would be Bit 3 of the 1 pigeon hole index. Too complicated? I think yes, and therefore the whole 1
output-module with the corresponding location on the
F4-Reader:
LED-# |
Row-# |
Bit-# |
EPIC-Call |
PH-Index |
Bit(s)s to send |
1 |
0 |
0 |
0,0,0b00000001 |
0 |
00000001 |
2 |
0 |
1 |
0,0,0b00000010 |
0 |
00000010 |
3 |
0 |
2 |
0,0,0b00000100 |
0 |
00000100 |
4 |
0 |
3 |
0,0,0b00001000 |
0 |
00001000 |
5 |
0 |
4 |
0,0,0b00010000 |
0 |
00010000 |
6 |
0 |
5 |
0,0,0b00100000 |
0 |
00100000 |
7 |
0 |
6 |
0,0,0b01000000 |
0 |
01000000 |
8 |
0 |
7 |
0,0,0b10000000 |
0 |
10000000 |
9 |
1 |
0 |
0,1,0b00000001 |
1 |
00000001 |
10 |
1 |
1 |
0,1,0b00000010 |
1 |
00000010 |
11 |
1 |
2 |
0,1,0b00000100 |
1 |
00000100 |
12 |
1 |
3 |
0,1,0b00001000 |
1 |
00001000 |
13 |
1 |
4 |
0,1,0b00010000 |
1 |
00010000 |
14 |
1 |
5 |
0,1,0b00100000 |
1 |
00100000 |
15 |
1 |
6 |
0,1,0b01000000 |
1 |
01000000 |
16 |
1 |
7 |
0,1,0b10000000 |
1 |
10000000 |
17 |
2 |
0 |
0,2,0b00000001 |
2 |
00000001 |
18 |
2 |
1 |
0,2,0b00000010 |
2 |
00000010 |
19 |
2 |
2 |
0,2,0b00000100 |
2 |
00000100 |
20 |
2 |
3 |
0,2,0b00001000 |
2 |
00001000 |
21 |
2 |
4 |
0,2,0b00010000 |
2 |
00010000 |
22 |
2 |
5 |
0,2,0b00100000 |
2 |
00100000 |
23 |
2 |
6 |
0,2,0b01000000 |
2 |
01000000 |
24 |
2 |
7 |
0,2,0b10000000 |
2 |
10000000 |
25 |
3 |
0 |
0,3,0b00000001 |
3 |
00000001 |
26 |
3 |
1 |
0,3,0b00000010 |
3 |
00000010 |
27 |
3 |
2 |
0,3,0b00000100 |
3 |
00000100 |
28 |
3 |
3 |
0,3,0b00001000 |
3 |
00001000 |
29 |
3 |
4 |
0,3,0b00010000 |
3 |
00010000 |
30 |
3 |
5 |
0,3,0b00100000 |
3 |
00100000 |
31 |
3 |
6 |
0,3,0b01000000 |
3 |
01000000 |
32 |
3 |
7 |
0,3,0b10000000 |
3 |
10000000 |
Once you have defined the program in the
F4-Reader, we can proceed to the
EPIC program. This would look like this:
#define FASTSCAN 0
#define LOWSCAN 1
#define OUTPUT 2
DefineModule(0, FASTSCAN, 0, 16)
DefineModule(1, LOWSCAN, 0, 16)
DefineModule(2, LOWSCAN, 0, 16)
#macro GetPH8(bytev, phnum)
pushc(phnum)
exec(67)
popv8(bytev)
#endmac
VAR(Var_PHoles) ; declare 8-Bit help variable
:INIT { Reset }
:PH_OutputM0 {
#expand getPH8(Var_PHoles, 0x000A)
ClearPoint(0, 0, 0b11111111)
SetPoint(0, 0, Var_PHoles)
#expand getPH8(Var_PHoles, 0x010A)
ClearPoint(0, 1, 0b11111111)
SetPoint(0, 1, Var_PHoles)
#expand getPH8(Var_PHoles, 0x020A)
ClearPoint(0, 2, 0b11111111)
SetPoint(0, 2, Var_PHoles)
#expand getPH8(Var_PHoles, 0x030A)
ClearPoint(0, 3, 0b11111111)
SetPoint(0, 3, Var_PHoles)
}
DefinePH(10, PH_OutputM0, 0, 0, 0, 0)
That's all. You might have noticed the defined macro "GetPH8", which reads an 8 bit value of the pigeon hole's
memory. This macro is usually delivered with the EPICS software under the name include-file
EpicVXD.inc. In order to make things a bit easier I have included it in the previous program.
The next step will be to declare the variables using the name "Var_PHoles", which we will use later on to read
out the data from the pigeon holes.
Now follows the function for the complete processing of the 1st output-module (No. 0) Here the data of each
Output Row with its corresponding pigeon hole is read. After reading, all the data is erased and set again
according to the new data. This happens so fast, that you will not be able to see it, also because this
updating occurs only when a modification in the data has taken place in one of the 4 Pigeon-Hole's value.
With "DefinePH" you assign the desired "PH_OutputM0" function to the 10th Pigeon-Hole. That's it ;-)