Titel-Banner
Programming16.01.2002

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
Basics for any EPIC programming
Powering a ON/OFF switch
Powering an ON/OFF/ON switch
Powering a rotary switch
Powering a LED via Switch
Powering a LED with QProcs
Powering LEDs via Pigeon Holes


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.

EPIC-Schaltbild


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-CallPH-IndexBit(s)s to send
1000,0,0b00000001000000001
2010,0,0b00000010000000010
3020,0,0b00000100000000100
4030,0,0b00001000000001000
5040,0,0b00010000000010000
6050,0,0b00100000000100000
7060,0,0b01000000001000000
8070,0,0b10000000010000000
9100,1,0b00000001100000001
10110,1,0b00000010100000010
11120,1,0b00000100100000100
12130,1,0b00001000100001000
13140,1,0b00010000100010000
14150,1,0b00100000100100000
15160,1,0b01000000101000000
16170,1,0b10000000110000000
17200,2,0b00000001200000001
18210,2,0b00000010200000010
19220,2,0b00000100200000100
20230,2,0b00001000200001000
21240,2,0b00010000200010000
22250,2,0b00100000200100000
23260,2,0b01000000201000000
24270,2,0b10000000210000000
25300,3,0b00000001300000001
26310,3,0b00000010300000010
27320,3,0b00000100300000100
28330,3,0b00001000300001000
29340,3,0b00010000300010000
30350,3,0b00100000300100000
31360,3,0b01000000301000000
32370,3,0b10000000310000000

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 ;-)


 Home  Simulator  Communication  EPIC(c) by Martin "Pegasus" Schmitt