WASA Report 13/99
Visual C++ software for testing the discriminators in the WASA-experiment. a, b
Henrik Renström
a) Work done at the Department of Radiation Sciences, Uppsala University, Sweden.
b) M.Sc. Thesis Work in Engineering Physics at Uppsala University.
Abstract: Discriminators are an important component in the process of triggering data
acquisition from an advanced particle physics detector. Fast electronic trigger decisions
make it possible to extract the vital events from a huge amount of background events
through pattern recognition. Discriminators generate the logical signal patterns used in
the trigger process. We describe the creation of a computer program designed to provide
for test and control of all 16-channel discriminators in the trigger system for the WASA
experiment, at the CELSIUS storage ring in Uppsala. The programming language used is
Visual C++. The program scans through a crate with discriminators checking how many
there are installed. Then on user command, the program executes a setup and test on each
discriminator controlling that all channels are working. Displaying them in chart form
against different input voltages shows the threshold uniformity of the channels. Using
their internal addresses performs the identification of the discriminators. A Graphical
User Interface provides the information to the user.
CONTENTS
1. Introduction ……… 3
1.1 General ... 3
1.2 The Trigger system ... 3
1.3 The Discriminators ... 4
1.4 The Program ... 5
2. The discriminator test program ……... 6
2.1 Documentation …...…………... 6
2.2 Notes ………..… 9
3. Classes ……… 10
3.1 General ……… 10
3.2 CAboutDlg class ………. 10
3.3 CChannelsDlg class ……… 11
3.4 CCrates class ………... 11
3.5 CHistogramCtrl class ……….. 12
3.6 CI2C_DebugApp class ……… 12
3.7 CI2C_DebugDoc class ……… 12
3.8 CI2C_DebugView class ………….. 13
3.9 CMainFrame class ………... 13
3.10 CPatternDebug class ……… 13
3.11 CSetup class ………. 13
3.12 CSingleDebug class ………. 14
3.13 CTestTrgLog class ………... 15
3.14 SingleDiscrim class ………. 15
3.15 Extra files ………. 15
4. Results and discussion ………... 16
4.1 GUI ………... 16
4.2 Discriminator test …….……..…….. 18
4.3 General notes ……… 18
5. Conclusion ……….. 20
References ……….. 21
Acknowledgements ……… 21
Appendix A (Program code) …... 22
1. INTRODUCTION
1.1 General
At the CELSIUS storage ring in Uppsala an experiment called WASA is under
preparation. The goal of this experiment is to investigate the production and decays of light neutral mesons [1]. When reconstructing all the particles in a meson production event a large amount of measurements of track positions and of deposited energies are required. This is done by using a large number of sensors, about 5000, with attached signal handling devices. One of the devices extensively used in the experiment is a specially designed 16-channel discriminator. A discriminator compares the amplitude of a signal with a predefined value. The output can only be true or false, i.e. 1 or 0. There are about 60 discriminator cards to be arranged in different crates (card holders ).
Together with the discriminators there will be other types of cards. There will be nine crates in the experiment, each holding between 14 to 21 cards. To the crates a computer is connected for control and monitoring of all cards in the system for triggering the readout of data. A GUI (Graphical User Interface) of the crates and their contents is provided to simplify the monitoring. The whole setup can be seen schematically in figure 1.
crate crate CPU user
Figure 1. Setup of cards, crates and computer.
The interface between the computer and the crates consists of I
2C interfaces. Philips semiconductors developed the I
2C interface standard. It is a simple bi-directional 2-wire, serial data and serial clock bus for inter-IC control [1].
1.2 The Trigger system
A trigger system initiates the collection of data. It is required for extracting interesting events from an often high level of background events. A matrix of CsI scintillating crystals is used to detect primarly the meson decay photons. High energy photon cause showers of secondary electron; positrons and photons in the CsI. This may result in signals from several crystals for a single incoming photon. Discriminators are connected to the CsI crystals to compare the signals with preset thresholds. The discriminators are connected to cluster multiplicity modules and adders [2]. The last two components mentioned are not being further discussed in this report [1]. When hits occur in the CsI matrix the discriminators generate patterns resembling the position of the decay particles.
Then pattern recognition is used to decide if the data in an event is of interest or not, see
figure 2.
CsI crystal matrix discriminators
Figure 2. Block diagram of a trigger. The cluster in the bottom of the CsI matrix is of interest.
As seen in figure 2 several hits have occurred (grayed). The trigger suppresses the two
“single” hits but the cluster of hits is considered as interesting data. The trigger system consists of different levels. In the first level one finds out if there are any interesting data in fast plastic scintillators. The decision time is about 150 ns. The slower detectors signals can then be used in level two decisions that take 300-500 ns. It is very important to keep the handling time as short as possible and that the efficiency of the trigger is high because new events can occur during the data handling. The data handling time is
sometimes called deadtime (means busy not dead).
1.3 The Discriminators
Another name for a discriminator is comparator. A comparator compares a preset value with an input signal and the output is true or false. True if the input signal amplitude is higher than the preset value or the threshold, see figure 3.
a) b)
noise discriminator signal discriminator
false true
Figure 3. Output from a discriminator.
a) Noise with lower amplitude than threshold.
b) Signal with higher amplitude than threshold.
For the WASA experiment a special type of discriminator boards has been built
consisting of 16 discriminator channels. The discriminator boards are placed in crates. A crate is a cardholder often used with a bus system connected to it, allowing users to access specific card(s) register and memories. The bus system used with the discriminator cards is following the I
2C standard developed by Philips [1]. Each card has its own
internal board address. The addresses are set manually when installing the cards. This way it is possible to access a specific card. The crates used can hold 14 – 21 cards. One crate can hold different types of cards depending on what measurement or experiment being executed. There are nine crates connected to each other, each crate holding its own set of cards.
Cluster multiplicity modules and adders
1.4 The Program
A program can be used to test and control the discriminator cards. Each card type has its own range of addresses. By scanning through the crate the program can detect different cards by the addresses they are responding to. Providing the users with a GUI with this information and other tests it is possible to check if all channels in a card are working.
Sending a test-pulse with known amplitude to all discriminator channels performs a test.
If one or more channels are “dead” a pop-up window alarms the user. The program also provides the users with the ability to perform a visual check of when the channels react.
This gives the information of which channels are “dead” and if all channels react uniformly. All channels on a card are drawn in a chart form that is presented in a new pop-up window. A specific card chart can be viewed on user command.
The programming language used in building the discriminator control program was Visual C++ [3, 4]. Visual C++ is event driven, which means that the user or inner events like interrupts etc steers the route a program takes. The program waits for an event to happen. When an event occurs, e.g. a user selects a menu option the program executes this request. See figure 4.
1. Waits for an event 2. Gets a request and executes it 3. Waits for an event request
Figure 4. Execution of a request in an event driven program.
A single event can trigger off several other events. Drawing a line in a paint program triggers an event to redraw the window updating the window with the line in it.
A Visual C++ program contains different classes depending on what type of program is created. Each class is like a small program. There is no main() function as there is in C/C++. In Visual C++ the on-going loop polling for events could be called the main function but that part is hidden for the user and a programmer do not have to bother about it. Each class is started on request. Because Visual C++ is a windows program it is often used when creating GUIs. It has many predefined classes as windows, buttons and user friendly controls collected in what is called the MFC library (Microsoft Foundation Classes). If the program is created in a pedagogical way it is very self-instructing. Hence users does not need to have much experience about programming or computers to use the program.
The goal of the design of the computer program interfacing the discriminator boards has been to monitor and control each crate over the I
2C bus. Each I
2C bus is connected to a PC-station or a VME-station, making it possible to reach the system from any terminal on an Ethernet network. This part is not described here but is a very important part.
idling execute idling
2. THE DISCRIMINATOR TEST PROGRAM
2.1 Documentation
The program provides the user with a GUI of a crate and its contents. It also provides a way to test the 16-channel discriminator cards in a crate. The test comprises of checking that all channels are working and that they are uniform. The channels on each card can be graphically displayed. Allowing a clear picture of when the channels reacted, and also providing a check of the channels threshold uniformity. Due to the fact that there can be different cards in the crate, the program has to identify the different types. The
programming was divided into three different stages. The first was to design the different GUI’s. The second was to determine what type of cards there were in the crate. And the third was to handle the testing of a 16-channel discriminator card.
In designing the GUI, Visual C++ is a very powerful tool. The predefined dialog
windows are modified with buttons, bitmaps and edit boxes to fit the different purposes.
This is very user friendly and self-instructing if made in a pedagogic manner. The first view the user will see is the different crates. Drawing a bitmap of the crate and displaying it in a dialog window did this. The bitmap was drawn to look as close as possible to the racks of crates used. The dialog window shown for the user can be seen in figure 5.
Figure 5. The crate dialog window.
Because the crate can take up to 21 cards the inside view was divided into 21 slots. At each slot there is a button that is colored in different colors depending on what type of card there is. See figure 6.
Figure 6. Dialog window showing the contents of a crate selected by the user.
This crate content is ten 16-channel discriminator-, one 16-channel delay- and one universal trigger logic card(s).
The reason why a button is used is because the button properties are very dynamic and therefore easy to manipulate. But it is not a button in the sense that something happens if a user press it.
The content of the crate is also displayed in a dialog window. It contains bitmaps, buttons and information for the setup and testing of the 16-channel discriminator cards.
To determine what types of cards there are in the crate, the program uses the cards
different addresses. Each card has its own internal address for reading and writing. The
program scans through the crate putting all valid card addresses in an array. Different
types of card have a specific range of addresses assigned to them. So by checking the
address the program can tell what type of card it is. The program then goes through the
array checking every address and sorting out what type and how many there are of the
different cards.
In the inside view of a crate a user has the option to do a setup and test the
16-channel discriminator cards. Pressing a button does this. When a user chose this option a new popup window appears offering various settings for the setup and test, see figure 7.
Figure 7. Setup and test dialog window for the 16-channel discriminators.
This test is to check if every channel is working in the discriminators. When executing the setup/test program the response shall be none if all the channels are okay. But if one or more channels are dead on a card the user will be told to check that specific
discriminator. A new pop-up dialog window providing the address of that discriminator
does this. A user then can bring up a graphical view of the channels in that discriminator
and check what is wrong on the card or just check the uniformity of when the channels
reacted. See figure 8 and figure 9.
Figure 9. Dialog window of a discriminator board with working and uniform channels.
The program generates an error message if there is one or more channels that are dead.
The uniformity check is something the user has to do manually at this point.
2.2 Notes
Something that could be confusing is the use of global variables. In this program there are two kinds of global variables. The ones defined in the header file of each class is a class global variable. Any members of the class can access this variable, but not by other classes. To create a “real” global variable a new header file was created, global.h. This file defines some variables with static values. Including the global.h in the classes .cpp files makes these variables accessible from all classes. In the program all the variables defined in global.h is written in capitals, e.g. NR_OF_CARDS. If some of these global variables need to be changed, they are just edited in the global.h file.
The global variable NR_OF_CARDS are set to be 21. This is due to the fact that no crate
takes more than 21 cards. However this requires the 16-channel discriminators board
addresses to be between 0 and 20. The program uses a matrix for holding the values used
in producing the graphical view of the channels. This way it is easy to see the connection
between an error and its board address. This solution will be discussed in chapter 4.
3. CLASSES
3.1 General
The program contains 13 different classes:
- CAboutDlg - CChannelsDlg - CCrates
- CHistogramCtrl - CI2C_DebugApp - CI2C_DebugDoc - CI2C_DebugView - CMainFrame - CPatternDebug - CSetup
- CSingleDebug - CTestTrgLog - SingleDiscrim
The classes that were generated by the Class Wizard are CAboutDlg, CI2C_DebugApp, CI2C_DebugDoc, CI2C_DebugView and CMainFrame. Those are standard classes for a SDI application. Then Pawel Marciniewski had predefined the following classes,
CPatternDebug, CSingleDebug, CTestTrgLog and SingleDiscrim. The author modified the CSingleDebug, and the SingleDiscrim class. Hence the author created
CChannelsDlg, CCrates, CHistogramCtrl and CSetup. In the following sub chapters the classes will be explained. What they do and how they work. Classes not created by the author will be briefly explained.
3.2 CAboutDlg class
This class is generated by the class wizard when a SDI-application is created [4, 5]. It
only contains information for the ABOUT I2C_Debug dialog window. This is a pop-up
dialog window showing which version and who created the program.
3.3 CChannelsDlg class
The author created this class. It contains information about the dialog window for displaying low threshold checks, see figure 9. The class prepares the drawing area for displaying the graph the CHistogramCtrl class produces. Because the class needs to exchange information with the CHistogramCtrl class, there is a member variable of type CHistogramCtrl added to this class. This gives the CChannelsDlg class access to public members in the CHistogramCtrl class. The black rectangle in figure 10 is the drawing area where the graph is placed.
Figure 10. Drawing area for the graph fo the channels.
The program code for this class can be seen in appendix A.
3.4 CCrates class
The author created this class. It contains information about a GUI in form of a dialog
window, see figure 5. This dialog window shows the crates in the rack and give the user
two different options to choose from. One is to open a specific crate and the other is to
exit the program. The dialog window was created with a bitmap drawn by the user. The
bitmap is designed to look like crates in a rack. Then there is a couple of buttons added
for the different actions the user can do. The bitmap is placed on the buttons, letting the
user push the specific crate to open. If the user choose to open a crate, a new dialog
window is displayed showing the “inside” of the crate, see figure 6. If the user choose
Exit the program is terminated. The program code for this class can be seen in appendix
A.
3.5 CHistogramCtrl class
This class was first created by Ken C. Len, and then modified by the author to be used in this program [3]. At first this class showed a scrolling spike (right to left), with different amplitudes in a dialog window. Each time the DrawSpike function was called a new spike was drawn and the previous spike was moved one step to the left. The idea is to have each channel represented in a spike. So by deleting the timer function, setting the same amplitude for all spikes, and call DrawSpike 16 times 16 equally high spikes were produced in a chart form. When placing the chart in the drawing area that was prepared in CChannelsDlg, the result looked like figure 11.
Figure 11. Dialog window of 16 channels in a chart form.
Then every spike was divided into ten different segments, one segment for each
amplitude of the test pulse. The lowest amplitude was the bottom segment and the highest amplitude was the top segment. Each segment then was colored depending on if the channel had reacted on the test pulse. Red if it do not react and green if it react. The final result of this class when doing a run on a working discriminator board looks like figure 9.
The program code for this class can be seen in appendix A.
3.6 CI2C_DebugApp class
The Class Wizard generates this class when a SDI-application is created [4, 5]. It receives all event messages and then passes the message to the proper class.
3.7 CI2C_DebugDoc class
The Class Wizard generates this class when a SDI-application is created [4, 5]. It houses
the document, and is also responsible for saving and retrieving the document data from
files.
3.8 CI2C_DebugView class
The Class Wizard generates this class when a SDI-application is created [4, 5]. It displays a visual representation for the user. The class passes input information to the
CI2C_DebugDoc class and receives display information from the CI2C_DebugDoc class.
3.9 CMainFrame class
The Class Wizard generates this class when a SDI-application is created. It is the starting window frame. This window holds the menu; toolbar and other visual objects attached to the frame. See figure 12.
Figure 12. The first dialog window the user sees when launching the program.
This is the first window the user sees when launching the program. From here the user can launch different programs, and all other “classical” operations, i.e. open a file. The author has added a function for launching the program in the menu. The function code can be seen in appendix A.
3.10 CPatternDebug class
This class is a pattern generator used for testing.
3.11 CSetup class
The class is created by the author and contains a GUI of the crate inside, see figure 4. The
dialog window gives the user several different options to choose from. The class uses the
OnNrofcards function in the CSingleDebug class to retrieve the number of cards in the
crate. The GUI is only a true picture of what type and how many cards there are in the
crate not a true picture of how these cards are placed in the crate.
The program cannot tell in which slot the specific card is sitting. This is due to the fact that the crate does not have any ID number or address at each slot. All cards are just connected on the same bus waiting to be “called”, see figure 13.
a) b)
Crate CPU Crate CPU
Figure 13. A computer scans a crate for its contents.
a) Cards in order in the crate.
b) Cards not in order in the crate.
The program illustrates what type and how many cards there are in a crate, but not the cards geographical position. For testing of the 16-channels discriminator cards it makes no difference. The cards can be tested no matter where they are in a crate. But there is one important thing to mention, and that is that all the cards are set to different board addresses. If two cards have the same board address one of them is not “seen”.
Another option for the user is to launch the SingleDiscrim class. This class provides setup and testing of the 16-channel discriminator cards. When viewing the output from the setup and testing, the specific board address is chosen and the “graph-button” is clicked.
This provides the user with a graphical status of all the channels in a specific card, see figure 9. The program code for this class can be seen in appendix A.
3.12 CSingleDebug class
This class provides a GUI, and different functions. This class is used when finding the board address of a card. It can also be used when testing read/write to the cards. The author has added two functions that are used by the CSetup class. One is the function OnNrofcards that receives an array of integers from the CSetup class and then
manipulates it. By default the array is filled with zeros, symbolizing that there is no cards in the crate. The OnNrofcards function now calls the other member function, nextcard.
This function finds the board address of the card. In a while-loop this continues until there is no more valid address. Each new valid address found is saved in an array. The function nextcard is a modified copy of an already existing function OnNextaddr. The reason for this is because the CSingleDebug class is not intended to run as a program.
The object is to use some functions in the class without having to launch the whole class.
The already existing function was written to have its own dialog window, and to display information for the user. To avoid these dialogs the nextcard function was created. The program code for these functions can be seen in appendix A.
a a b b c
?
a,a,b,b,c b a c b a
? a,a,b,b,c
3.13 CTestTrgLog class
This class is used when testing the trigger logic cards.
3.14 SingleDiscrim class
This class contains a GUI and different options for setup and testing of the 16-channel discriminator cards. When a user in the CSetup dialog windows chooses the “setup and test” button a pop-up dialog window for the SingleDiscrim class is launched, see figure 7.
The author has added one function Crate. The author has also added code for already existing functions. The function Crate receives an array from the CSetup class, holding information about how many cards there are in the crate. The function copies the arra y into a new class global array for the SingleDiscrim class. This information is later used in a member function OnTest. In the beginning the class was able to setup and test a specific card which the user selected. But when there is 20 or some cards the program should provide a way for the user to test all cards. It is not possible to do the setup on all cards first, and then test them. A for-loop was created going through each card, performing the setup and test as the cards were looped through. In the GUI a checkbox was added for the option of setup and testing of all the cards, see figure 7. Before performing the setup and test the user could set low threshold, high threshold and pulse duration time.
In the OnRunSetup function the checkbox for setup and test of all cards is checked if been marked. If marked the program loops through all the cards performing setup and tests on all of them. Calling another member function OnTest that executes the test. The input to this function is the cards board address. If the checkbox is unmarked a setup and test is performed on the specified card. The program code for this class can be seen in appendix A.
3.15 Extra files
The program also includes three files that do not belong to any class. Those are
I2C_util.cpp, I2C_util.h and Global.h. The I2C_util.h and I2C_util.cpp are c++ files that are used for reading and writing with the I2C interface. Global.h defines some global variables for a more dynamic program. Global in the sense that all classes can access them. The Global.h file is included in the header- or source-files for the class using these variables.
The program uses a Windows NT driver called MapMemPlus. The driver allows the
program to access the IO-bus and access directly to all the busses. These operations are
normal unauthorized by the system.
4. RESULT S AND DISCUSSION
4.1 GUI
The GUI’s that the program provides are designed without any definitions. The programming language VC++ is very dynamical in the designing of different dialog windows. All the GUI’s can easily be changed for later purposes, e.g. adding buttons, windows and more functions. Such changes might be needed if later some standard in the way the crates are setup in the rack is stated. A new bitmap of the crates in the rack can be designed to give a more exact view of the real setup. As for the GUI of the crate contents a new bitmap of crates with 14 card places can be designed for giving a more exact view.
For the GUI of the inside of the crates there is a problem to handle. Due to the fact that the 16-channel discriminator cards are located very close to each other, it is impossible to read the board address of a specific card without taking it out. As the virtual view is not a true view of the crate there could be some identification problems. When performing a test of the 16-channel discriminator cards, the user is prompted with a board address in case of a broken card. The board address tells the user which card is broken, but does not provide the information where in the crate the card is located. If each card is properly marked with its specific board address there is no problem. But if the markings are not properly made or mixed in some way the user would change the wrong card. This of course will be discovered when doing a new test of the cards. If the broken card still is there the same error message appears again. So the worst case scenario is that of lost time. A way to avoid this problem would be not to mark the cards. Then the user would manually have to remove a card and checking its board address, but when having several cards this procedure is very time consuming.
There is a way to speed up this “fool proof” identification. By placing all cards in increasing order due to their board addresses counting from left to right. Then bo ard address number n is card number n+1 (board address starts with 0) in the crate, counting from left to right. This way the user can find the specific card right away. This however requires that there is no other card placed among the 16-channel discriminator cards. And that the 16-channel discriminator cards are placed first, counting left to right. For every new solution comes a new problem. So when taking all things in account the best way is to have every card marked with its board address and making sure that the markings are properly executed.
Preferably the “inside” view should be a true view, a card in slot number n should appear
in the GUI’s slot number n making the identification of the card much easier. When a
user gets an error message explaining that card at slot n is broke, then the user knows
exactly where in the crate the card is located. So the problem of knowing which card to
The only way to communicate with the slots is through the bus, and it is the same bus for every slot.
Is it possible to get a true “inside” view of a crate?
There are some solutions to this problem. One way is to use a database [6] for holding information of the cards position in the crate. The person who installs the card then also should update the database with the “true” card positions. When the program is executed it would retrieve the true values from the database showing the user a correct view of the crate inside, see figure 14.
crate technician database computer user
Figure 14. Using a database for storing a cards geographical position.
This solution requires a third party though, someone who maintains the database. It also requires the technician to be familiar with computers and databases. A nice thing with this solution would be that the system could be online the whole time. If there were any changes made in the crate the program would immediately update the view. Always showing the “true” view for the user. There is a way to avoid the extra work with a complete database. The information could be put in a simple text file. Then in the other end the computer extracts the information through this file. Some kind of a protocol would be needed for entering the data into the text file allowing the computer to know how to extract the information. The text file solution have been tested and worked okay.
The broken card was marked in its true position in the crate.
Another solution would be to assign some kind of number/address to each slot in the crate. Mounting extra hardware on the crate such as a multiplexer could carry this out.
This would be a one-time operation and would not require any maintenance except the one for broken parts. This solution is more fool proof than the previous, and does not require the same amount of maintenance. Except for the job of mounting the new hardware a third party is later not necessary.
The easiest solution would be to have the card mounted in order in the crate. This means
in slot number 1 a card with board address number 1 is placed. This way the program
would know in advance how the cards are installed making it possible to point out the
location of the malfunctioning card.
4.2 Discriminator test
During the testing of the 16-channel discriminator cards a strange situation occurred while checking the uniformity of the channels, using the graphical view. Once in a while a strange phenomenon occurred. When viewing the channels graphical and testing the channel with increasing test-pulse amplitude the following was discovered. First the channel could react, then it did not and for the next amplitude it reacted again. This gave the following graphical view. Red…, green, red and then green again, see figure 15.
Figure 15. Graph with noise.
This is believed to be caused by noise due to the very small increase between every test- pulse amplitude noise can sometimes trigger a channel. The increase of the amplitude is only a couple of mV. This is not an indication that a channel is wrong. But if there was channels looking like this: Red…, green, red, red, green…, there would be trouble.
Fortunately this has never been discovered.
In later versions of the test program more error handling could be performed. For
example the test program could automatically check the uniformity of the channels. And the ultimate goal is to have the program provide a “true” view of the crate contents, i.e.
geographical placing of the cards.
4.3 General notes
When performing a setup and test of all cards, it is not possible to change the setup
during the loop. If for example one setup is wanted for the first five cards and another
setup on the rest, the setup and test has to be performed card by card. This is a static
solution. But since all cards probably will have the same setup during the experiment, no
time was spent developing a more dynamic setup and test.
This version of the discriminator test program only displays low threshold checks. There is also a high threshold check that can be performed. Allowing a higher value to be compared with the test pulse amplitude. Everything is prepared for the high threshold check except the actual drawing of the graph. Every value for the high threshold check of the channels is stored in a matrix similar to the matrix used for low threshold checks. So by following the steps of drawing the graph for the low threshold check, a similar graph of the high threshold check is created. If the user should be able to see both high/low threshold check or if the user should select which one to view is not made up at this point.
If higher board addresses than 21 are used some modification must be performed. Now the program requires the different internal board address to range between 1 and 21 i.e.
the same as the number of cards. So by increasing the global variable NR_OF_CARDS the range of the board addresses is expanded. Another solution is not using the board addresses as index in the matrix. That is making some changes in the program that uses other numbers as index in the matrix. All the values are stored in a three dimensional matrix holding board address, channel and the amplitude of the test pulse. See figure 16.
board address
channel channel
test-pulse amplitude test-pulse amplitude
Figure 16. Matrix used for storing discriminator values in the program.
When building applications with Visual C++ the MFC Winsock (Windows Sockets) classes can be used to add network communication capabilities. Winsock makes it
possible to perform network communications regardless of the networking software used.
The network communication works with the TCP/IP network protocol. This makes it possible to enhance the program so it can be accessible over the Internet.
0 ... 20
0 ... 15
1 ... 10
0 ... 15
1 ... 10
5. CONCLUSION
The project has lead to improvements of the WASA experiment on several points. The single discriminator test program has improved the testing of the discriminators.
Allowing a user to perform setup and test of all cards at once and the graphical chart form presented provides a way to check the uniformity of the channels that could not be
performed before. Testing of the discriminators is now faster and more thorough than before.
All solutions about the GUI discussed in chapter 4.1 requires someone/something to be performed in order for the program to create a true view of the “inside” of a crat e. There are many steps on the road that could lead to that the program does not show a true view for the user. The user relies on the program to provide a true view, and will not question the information he receives. With this projects program the user can rely on getting the most important information correct. The most important information will always be what type of cards there are and how many there are of each type. Furthermore the “sticker”
solution does not depend on a technician writing the vital information into a text file or a
database. When the program executes it scans through the crate and delivers just that
information without any need for a database or an existing text file. This leads to the
conclusion that the solution presented in this report is most suitable for now.
REFERENCES
[1] P.Marciniewski, Electronic instrumentation for high energy physics, 1997 Department of Radiation Sciences, Uppsala University, Sweden.
[2] TSL progress report 1996-1997, The Svedberg Laboratory, Uppsala, Sweden.
[3] “http://www.codeguru.com/controls/histogram_control.shtml”
[4] D.Chapman, Teach Yourself Visual C++ 6 in 21 Days, 1998 Sams Publishing.
[5] C.Sphar, Learn Microsoft Visual C++ 6.0 Now, 1999 Microsoft Press.
[6] L.Robison, Teach Yourself Database Programming with Visual C++ 6 in 21 Days, 1999 Sams Publishing.
S.R.Davis, C++ FOR DUMMIES 3
RDEDITION, 1998 IDG Books Worldwide.
D.McCombs, Detecting the world, 1999 R&D Books.
R.Enander, Föreläsningsanteckningar i C++, 1994 TDB Uppsala University, Sweden.
ACKNOWLEDGEMENTS
The author has had help and guidance during this project. The author would like to
mention these people and thank them for their most appreciated help. First of all the
supervisor of this project Leif Gustafsson, Leif has guided the author along this project
and report, supporting and giving useful tips. Pawel Marciniewski has explained and
helped concerning the hardware used in this project. Mikael Pettersson and Ulf Sporrong
have helped with their knowledge in software and the Visual C++ language.
APPENDIX A
Program code
When the author creates a whole class both header- and source files are presented here. If code have been added in existing functions the source file is presented here. When functions have been added to an already existing class only the function code in the source file is presented here.
Global.h
// HR. Define global variables
#define NR_OF_CARDS 21
#define NR_OF_ADDRESSES 100
#define CHANNELS 16
#define TESTPULSE 0x03
#define TP_AMPLITUDE 10 // Means that it increases 10 times
CChannelsDlg class
Channels1Dlg.h
#if !defined(AFX_CHANNELSDLG1_H__510524F2_604D_11D3_8022_00C04F435307__INCLUDED_)
#define AFX_CHANNELSDLG1_H__510524F2_604D_11D3_8022_00C04F435307__INCLUDED_
#include "HistogramCtrl.h" // Added by ClassView
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000 // ChannelsDlg1.h : header file //
/////////////////////////////////////////////////////////////////////////////
// CChannelsDlg dialog
class CChannelsDlg : public CDialog {
// Construction public:
CChannelsDlg(CWnd* pParent = NULL); // standard constructor // Dialog Data
//{{AFX_DATA(CChannelsDlg) enum { IDD = IDD_CHANNELS };
// NOTE: the ClassWizard will add data members here //}}AFX_DATA
// Overrides
// ClassWizard generated virtual function overrides //{{AFX_VIRTUAL(CChannelsDlg)
protected:
virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support //}}AFX_VIRTUAL
// Implementation protected:
CHistogramCtrl m_CHistogramCtrl; // Variable to get access to public functions in HistogramCtrl class // Generated message map functions
//{{AFX_MSG(CChannelsDlg) virtual BOOL OnInitDialog();
//}}AFX_MSG
// Microsoft Visual C++ will insert additional declarations immediately before the previous line.
#endif // !defined(AFX_CHANNELSDLG1_H__510524F2_604D_11D3_8022_00C04F435307__INCLUDED_)
Channels1Dlg.cpp
// ChannelsDlg1.cpp : implementation file
#include "stdafx.h"
#include "I2C_Debug.h"
#include "ChannelsDlg1.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
/////////////////////////////////////////////////////////////////////////////
// CChannelsDlg dialog
CChannelsDlg::CChannelsDlg(CWnd* pParent /*=NULL*/): CDialog(CChannelsDlg::IDD, pParent) {
//{{AFX_DATA_INIT(CChannelsDlg)
// NOTE: the ClassWizard will add member initialization here //}}AFX_DATA_INIT
}
void CChannelsDlg::DoDataExchange(CDataExchange* pDX) {
CDialog::DoDataExchange(pDX);
//{{AFX_DATA_MAP(CChannelsDlg)
// NOTE: the ClassWizard will add DDX and DDV calls here //}}AFX_DATA_MAP
}
BEGIN_MESSAGE_MAP(CChannelsDlg, CDialog) //{{AFX_MSG_MAP(CChannelsDlg)
//}}AFX_MSG_MAP END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// CChannelsDlg message handlers BOOL CChannelsDlg::OnInitDialog() {
CDialog::OnInitDialog();
// TODO: Add extra initialization here
CRect rect; // Window area for LTC
GetDlgItem(IDC_STATIC_CHANNELS)->GetWindowRect(rect); // Put window area in IDC_STATIC_CHANNELS ScreenToClient(rect);
m_CHistogramCtrl.Create(WS_VISIBLE | WS_CHILD, rect, this, 100); // Create the HistogramCtrl window
m_CHistogramCtrl.SetRange(0,100); // Set range, max=100 and min=0
for (int i=0; i<=15; i++) // Call the SetPos 16 times, one for each channel m_CHistogramCtrl.SetPos(100, i); // Channel number i
return TRUE; // return TRUE unless you set the focus to a control // EXCEPTION: OCX Property Pages should return FALSE }
CCrates class
Crates.h
#if !defined(AFX_CRATES_H__99C80C21_69AA_11D3_8022_00C04F435307__INCLUDED_)
#define AFX_CRATES_H__99C80C21_69AA_11D3_8022_00C04F435307__INCLUDED_
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000 // Crates.h : header file
/////////////////////////////////////////////////////////////////////////////
// CCrates dialog
class CCrates : public CDialog {
// Construction public:
CCrates(CWnd* pParent = NULL); // standard constructor
// Dialog Data
//{{AFX_DATA(CCrates) enum { IDD = IDD_CRATES };
CButton m_CBCrate9; // Adding variables to the buttons
CButton m_CBCrate8;
CButton m_CBCrate7;
CButton m_CBCrate6;
CButton m_CBCrate5;
CButton m_CBCrate4;
CButton m_CBCrate3;
CButton m_CBCrate2;
CButton m_CBCrate1;
//}}AFX_DATA // Overrides
// ClassWizard generated virtual function overrides //{{AFX_VIRTUAL(CCrates)
protected:
virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support //}}AFX_VIRTUAL
// Implementation protected:
// Generated message map functions //{{AFX_MSG(CCrates)
afx_msg void OnExit();
afx_msg void OnBcrate1();
virtual BOOL OnInitDialog();
//}}AFX_MSG
DECLARE_MESSAGE_MAP() };
//{{AFX_INSERT_LOCATION}}
// Microsoft Visual C++ will insert additional declarations immediately before the previous line.
#endif // !defined(AFX_CRATES_H__99C80C21_69AA_11D3_8022_00C04F435307__INCLUDED_) Crates.cpp
// Crates.cpp : implementation file
#include "stdafx.h"
#include "i2c_debug.h"
#include "Setup.h"
#include "Crates.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
/////////////////////////////////////////////////////////////////////////////
// CCrates dialog
CCrates::CCrates(CWnd* pParent /*=NULL*/): CDialog(CCrates::IDD, pParent) {
//{{AFX_DATA_INIT(CCrates)
// NOTE: the ClassWizard will add member initialization here //}}AFX_DATA_INIT
}
void CCrates::DoDataExchange(CDataExchange* pDX) {
DDX_Control(pDX, IDC_BCRATE6, m_CBCrate6);
DDX_Control(pDX, IDC_BCRATE5, m_CBCrate5);
DDX_Control(pDX, IDC_BCRATE4, m_CBCrate4);
DDX_Control(pDX, IDC_BCRATE3, m_CBCrate3);
DDX_Control(pDX, IDC_BCRATE2, m_CBCrate2);
DDX_Control(pDX, IDC_BCRATE1, m_CBCrate1);
//}}AFX_DATA_MAP }
BEGIN_MESSAGE_MAP(CCrates, CDialog) //{{AFX_MSG_MAP(CCrates)
ON_BN_CLICKED(IDEXIT, OnExit)
ON_BN_CLICKED(IDC_BCRATE1, OnBcrate1) //}}AFX_MSG_MAP
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// CCrates message handlers void CCrates::OnExit() {
// TODO: Add your control notification handler code here OnOK();
}
// Function that opens up the Setup dialog when the crate1 button is pressed void CCrates::OnBcrate1()
{
// TODO: Add your control notification handler code here CSetup Setup;
Setup.DoModal();
}
BOOL CCrates::OnInitDialog() {
CDialog::OnInitDialog();
// TODO: Add extra initialization here
HBITMAP hBitmap = (HBITMAP) ::LoadImage(AfxGetInstanceHandle(), "res/crate.bmp", IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);
HBITMAP hBitmap1 = (HBITMAP) ::LoadImage(AfxGetInstanceHandle(), "res/discrate.bmp", IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);
m_CBCrate1.SetBitmap(hBitmap);
m_CBCrate2.SetBitmap(hBitmap);
m_CBCrate3.SetBitmap(hBitmap);
m_CBCrate4.SetBitmap(hBitmap);
m_CBCrate5.SetBitmap(hBitmap);
m_CBCrate6.SetBitmap(hBitmap);
m_CBCrate7.SetBitmap(hBitmap);
m_CBCrate8.SetBitmap(hBitmap);
m_CBCrate9.SetBitmap(hBitmap);
return TRUE; // return TRUE unless you set the focus to a control // EXCEPTION: OCX Property Pages should return FALSE }
CHistogramCtrl class
HistogramCtrl.h // HistogramCtrl.h : header file
#ifndef __HISTOGRAMCTRL_H__
#define __HISTOGRAMCTRL_H__
#include "Global.h"
/////////////////////////////////////////////////////////////////////////////
// CHistogramCtrl window
class CHistogramCtrl : public CDialog {
// Construction
public:
CHistogramCtrl();
UINT m_nVertical;
// Attributes public:
UINT SetPos(UINT nPos, int i);
void SetRange(UINT nLower, UINT nUpper);
void InvalidateCtrl();
void DrawSpike(int j);
// Operations public:
void StepIt();
// Overrides
// ClassWizard generated virtual function overrides //{{AFX_VIRTUAL(CHistogramCtrl)
public:
virtual BOOL Create(DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID, CCreateContext* pContext
= NULL);
//}}AFX_VIRTUAL // Implementation public:
void WichGraph(int g);
void Matrix(int h, int m[NR_OF_CARDS][TP_AMPLITUDE][CHANNELS]);
virtual ~CHistogramCtrl();
// Generated message map functions protected:
//{{AFX_MSG(CHistogramCtrl) afx_msg void OnPaint();
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
UINT m_nLower; // lower bounds UINT m_nUpper; // upper bounds
UINT m_nPos; // current position within bounds CDC m_MemDC;
CBitmap m_Bitmap;
};
/////////////////////////////////////////////////////////////////////////////
#endif
HistogramCtrl.cpp
// HistogramCtrl.cpp : implementation file
// stdafx.cpp : source file that includes just the standard includes // CPanel.pch will be the pre-compiled header
// stdafx.obj will contain the pre-compiled type information
#include "stdafx.h"
#include "HistogramCtrl.h"
//#include "Global.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
int ltc[NR_OF_CARDS][TP_AMPLITUDE][CHANNELS]; // HR. Global variable from Matrix to DrawSpike()
int h; // HR. Global variable from WichGraph to DrawSpike()
/////////////////////////////////////////////////////////////////////////////
// CHistogramCtrl
CHistogramCtrl::CHistogramCtrl() {
m_nPos = 0;
m_nLower = 0;
m_nUpper = 100;
}
BEGIN_MESSAGE_MAP(CHistogramCtrl, CWnd) //{{AFX_MSG_MAP(CHistogramCtrl)
ON_WM_PAINT()
//}}AFX_MSG_MAP END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// CSpikeCtrl message handlers
BOOL CHistogramCtrl::Create(DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID, CCreateContext* pContext) {
// TODO: Add your specialized code here and/or call the base class
static CString className = AfxRegisterWndClass(CS_HREDRAW | CS_VREDRAW);
return CWnd::CreateEx(WS_EX_CLIENTEDGE | WS_EX_STATICEDGE, className, NULL, dwStyle, rect.left, rect.top, rect.right-rect.left, rect.bottom-rect.top,
pParentWnd->GetSafeHwnd(), (HMENU) nID);
}
void CHistogramCtrl::SetRange(UINT nLower, UINT nUpper) {
ASSERT(nLower >= 0 && nLower < 0xffff);
ASSERT(nUpper > nLower && nUpper < 0xffff);
m_nLower = nLower;
m_nUpper = nUpper;
InvalidateCtrl();
}
void CHistogramCtrl::InvalidateCtrl() {
// Small optimization that just invalidates the client area // (The borders don’t usually need updating)
CClientDC dc(this);
CRect rcClient;
GetClientRect(rcClient);
if (m_MemDC.GetSafeHdc() == NULL) {
m_MemDC.CreateCompatibleDC(&dc);
m_Bitmap.CreateCompatibleBitmap(&dc,rcClient.Width(),rcClient.Height());
m_MemDC.SelectObject(m_Bitmap);
// draw scale
m_MemDC.SetBkColor(RGB(0,0,0));
CBrush bkBrush(HS_HORIZONTAL,RGB(0,128,0));
m_MemDC.FillRect(rcClient,&bkBrush);
}
InvalidateRect(rcClient);
}
UINT CHistogramCtrl::SetPos(UINT nPos, int i) // HR. Added int i., the channel number {
if (nPos > m_nUpper) nPos = m_nUpper;
if (nPos < m_nLower) nPos = m_nLower;
UINT nOld = m_nPos;
m_nPos = nPos;
int j = i; // HR
DrawSpike(j); // HR. Added j, channel number
Invalidate();
return nOld;
}
void CHistogramCtrl::OnPaint() {
CPaintDC dc(this); // device context for painting
// TODO: Add your message handler code here // Do not call CWnd::OnPaint() for painting messages // draw scale
CRect rcClient;
GetClientRect(rcClient);
// draw scale
if (m_MemDC.GetSafeHdc() != NULL)
{
dc.BitBlt(0, 0, rcClient.Width(), rcClient.Height(), &m_MemDC, 0, 0, SRCCOPY);
} }
void CHistogramCtrl::DrawSpike(int j) {
//CClientDC dc(this);
UINT nRange = m_nUpper - m_nLower;
CRect rcClient;
GetClientRect(rcClient);
if (m_MemDC.GetSafeHdc() != NULL) {
// HR Widht, 16 was original 4
m_MemDC.BitBlt(0, 0, rcClient.Width(), rcClient.Height(), &m_MemDC, 16, 0, SRCCOPY);
// Following three lines is “marked out” by HR
//CRect rcTop(rcClient.right - 4, 0, rcClient.right - 2, rcClient.bottom);
//rcTop.top = (long) (((float) (m_nPos - m_nLower) / nRange) * rcClient.Height());
//rcTop.top = rcClient.bottom - rcTop.top;
// draw scale
CRect rcRight = rcClient;
rcRight.left = rcRight.right - 4;
m_MemDC.SetBkColor(RGB(0,0,0));
CBrush bkBrush(HS_HORIZONTAL,RGB(0,128,0)); // RGB(0,128,0) m_MemDC.FillRect(rcRight,&bkBrush);
int H=5; // HR Variables to split spike in 10 segments
int B=50; // HR. - || -
// HR. Looping through each segment and fill with the right color for (int i=0; i<TP_AMPLITUDE; i++)
{
CRect rcTop(rcClient.right - 9, 0, rcClient.right - 2, B); // Was rcClient.bottom);
// (left, top, right, bottom) of the rectangle rcTop.top = (long) (((float) (m_nPos - m_nLower) / nRange) * H); // Was rcClient.Height());
rcTop.top = rcClient.bottom - rcTop.top;
// draw current spike, h=cardnumber, i=testpulse amplitud, j=channelnumber
if (ltc[h][i][j]==0) // If channel not reacted fill with red {
CBrush rbrush(RGB(255,0,0)); // Create red brush m_MemDC.FillRect(rcTop, &rbrush); // Fill rectangle }
if (ltc[h][i][j]==1) // If channel reacted fill with green {
CBrush brush(RGB(0,255,0)); // Create green brush m_MemDC.FillRect(rcTop, &brush); // Fill rectangle }
H+=5;
B-=5;
} }
}
// Function that saves matrix LTC from SingleDiscrim::OnTest to gloabal variable (matrix) ltc
void CHistogramCtrl::Matrix(int h, int m[NR_OF_CARDS][TP_AMPLITUDE][CHANNELS]) // h==cardnumber {
for (int i=0; i<TP_AMPLITUDE; i++) for (int j=0; j<CHANNELS; j++)
ltc[h][i][j]=m[h][i][j];
}
// Function that receives the number of the selected card
void CHistogramCtrl::WichGraph(int g) // g==selected boardaddress
{
h = g; // saves boardaddress into global variable h for use in DrawSpike(int j) }
CMainFrame class
MainFrame.cpp
void CMainFrame::OnAppCrates() {
// TODO: Add your command handler code here CCrates Crates;
Crates.DoModal();
}
CSetup class
Setup,h
#if !defined(AFX_SETUP_H__10CA0023_5ECD_11D3_8022_00C04F435307__INCLUDED_)
#define AFX_SETUP_H__10CA0023_5ECD_11D3_8022_00C04F435307__INCLUDED_
#include "SingleDebug.h" // Added by ClassView
#include "ChannelsDlg1.h" // Added by ClassView
#include "SingleDiscrim.h" // Added by ClassView
#include "HistogramCtrl.h" // Added by ClassView
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000 // Setup.h : header file //
/////////////////////////////////////////////////////////////////////////////
// CSetup dialog
class CSetup : public CDialog {
// Construction public:
CSetup(CWnd* pParent = NULL); // standard constructor // Dialog Data
//{{AFX_DATA(CSetup) enum { IDD = IDD_SETUP };
CButton m_CBSlot21;
CButton m_CBSlot20;
CButton m_CBSlot19;
CButton m_CBSlot18;
CButton m_CBSlot17;
CButton m_CBSlot16;
CButton m_CBSlot15;
CButton m_CBSlot14;
CButton m_CBSlot13;
CButton m_CBSlot12;
CButton m_CBSlot11;
CButton m_CBSlot9;
CButton m_CBSlot8;
CButton m_CBSlot7;
CButton m_CBSlot6;
CButton m_CBSlot10;
CButton m_CBView;
CSpinButtonCtrl m_BaddrSpin;
CButton m_CBSlot5;
CButton m_CBSlot4;
CButton m_CBSlot3;
CButton m_CBSlot2;
CButton m_CBSlot1;
int m_i16ChDelay;
int m_i16ChDiscrim;
int m_iBoardaddr;
int m_iUtl;
//}}AFX_DATA
// Overrides
// ClassWizard generated virtual function overrides //{{AFX_VIRTUAL(CSetup)
protected:
virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support //}}AFX_VIRTUAL
// Implementation protected:
void OnOff(int c);
CSingleDebug m_CSingleDebug; // To be able to see how many cards there is CChannelsDlg m_CChannelsDlg; // To be able to open the CChannelsDlg dialog SingleDiscrim m_CSingleDiscrim; // To be able to open the CSingleDiscrim dialog CHistogramCtrl m_CHistogramCtrl;
// Generated message map functions //{{AFX_MSG(CSetup)
afx_msg void OnExit();
virtual BOOL OnInitDialog();
afx_msg void OnSetupTest();
afx_msg void OnView();
//}}AFX_MSG
DECLARE_MESSAGE_MAP() };
//{{AFX_INSERT_LOCATION}}
// Microsoft Visual C++ will insert additional declarations immediately before the previous line.
#endif // !defined(AFX_SETUP_H__10CA0023_5ECD_11D3_8022_00C04F435307__INCLUDED_) Setup.cpp
// Setup.cpp : implementation file //
#include "stdafx.h"
#include "I2C_Debug.h"
#include "Global.h" // Includes global variables
#include "Setup.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
// Array for holding type of cards in the crate
int crate[NR_OF_CARDS]; // NR_OF_CARDS is a global variable
/////////////////////////////////////////////////////////////////////////////
// CSetup dialog
CSetup::CSetup(CWnd* pParent /*=NULL*/): CDialog(CSetup::IDD, pParent) {
//{{AFX_DATA_INIT(CSetup)
m_i16ChDelay = 0; // Default value
m_i16ChDiscrim = 0;
m_iBoardaddr = 0;
m_iUtl = 0;
//}}AFX_DATA_INIT }
void CSetup::DoDataExchange(CDataExchange* pDX) {
CDialog::DoDataExchange(pDX);
//{{AFX_DATA_MAP(CSetup)
DDX_Control(pDX, IDC_ONOFFC21, m_CBSlot21);
DDX_Control(pDX, IDC_ONOFFC20, m_CBSlot20);
DDX_Control(pDX, IDC_ONOFFC19, m_CBSlot19);
DDX_Control(pDX, IDC_ONOFFC18, m_CBSlot18);
DDX_Control(pDX, IDC_ONOFFC17, m_CBSlot17);
DDX_Control(pDX, IDC_ONOFFC11, m_CBSlot11);
DDX_Control(pDX, IDC_ONOFFC9, m_CBSlot9);
DDX_Control(pDX, IDC_ONOFFC8, m_CBSlot8);
DDX_Control(pDX, IDC_ONOFFC7, m_CBSlot7);
DDX_Control(pDX, IDC_ONOFFC6, m_CBSlot6);
DDX_Control(pDX, IDC_ONOFFC10, m_CBSlot10);
DDX_Control(pDX, IDC_VIEW, m_CBView);
DDX_Control(pDX, IDC_BADDRSPIN, m_BaddrSpin);
DDX_Control(pDX, IDC_ONOFFC5, m_CBSlot5);
DDX_Control(pDX, IDC_ONOFFC4, m_CBSlot4);
DDX_Control(pDX, IDC_ONOFFC3, m_CBSlot3);
DDX_Control(pDX, IDC_ONOFFC2, m_CBSlot2);
DDX_Control(pDX, IDC_ONOFFC1, m_CBSlot1);
DDX_Text(pDX, IDC_E16CHDELAY, m_i16ChDelay);
DDX_Text(pDX, IDC_E16CHDISCRIM, m_i16ChDiscrim);
DDX_Text(pDX, IDC_BOARDADDR, m_iBoardaddr);
DDX_Text(pDX, IDC_EUTL, m_iUtl);
//}}AFX_DATA_MAP }
BEGIN_MESSAGE_MAP(CSetup, CDialog) //{{AFX_MSG_MAP(CSetup)
ON_BN_CLICKED(IDEXIT, OnExit)
ON_BN_CLICKED(IDC_SETUP_TEST, OnSetupTest) ON_BN_CLICKED(IDC_VIEW, OnView)
//}}AFX_MSG_MAP END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// CSetup message handlers
void CSetup::OnExit() // Exits the program
{
// TODO: Add your control notification handler code here OnOK();
}
BOOL CSetup::OnInitDialog() {
CDialog::OnInitDialog();
// TODO: Add extra initialization here // Set the default values
m_i16ChDiscrim = 0;
m_i16ChDelay = 0;
m_iUtl = 0;
m_iBoardaddr = 0;
m_BaddrSpin.SetRange(0,20);
m_BaddrSpin.SetPos(0);
for (int i=0; i<NR_OF_CARDS; i++) // Fill crate array with zeros as default crate[i]=0;
m_CSingleDebug.OnNrofcards(crate); // Get the number of addresses in crate from CSingleDebug for (i=0; i<NR_OF_CARDS; i++) // Loop to set the values of the slots {
if (crate[i] == 1) // If 16-channel discriminator card
m_i16ChDiscrim++;
if (crate[i] == 2) // If 16-channel delay card
m_i16ChDelay++;
if (crate[i] == 3 ) // If universal trigger logic card
m_iUtl++;
OnOff(i); // Call OnOff to color the slots in the crate showing the type of card in slot number i }
// Get handle to the bitmap and put it on the view button
HBITMAP hBitmap = (HBITMAP) ::LoadImage(AfxGetInstanceHandle(), "res/graph.bmp", IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);
m_CBView.SetBitmap(hBitmap);
UpdateData(FALSE); // Updates the dialog window values
return TRUE; // return TRUE unless you set the focus to a control // EXCEPTION: OCX Property Pages should return FALSE }
// Function that colors the slots in the crate
void CSetup::OnOff(int c) // Variable c is the current slot
{
// Get handle to the different bitmaps
HBITMAP hBitmapG = (HBITMAP) ::LoadImage(AfxGetInstanceHandle(), "res/discrim.bmp", IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);
HBITMAP hBitmapC = (HBITMAP) ::LoadImage(AfxGetInstanceHandle(), "res/delay.bmp", IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);
HBITMAP hBitmapY = (HBITMAP) ::LoadImage(AfxGetInstanceHandle(), "res/tlogic.bmp", IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);
switch (c) // c is the slot number
{
case 0:
{
if (crate[c] == 1) // 16-channel discriminator
m_CBSlot1.SetBitmap(hBitmapG); // Green bitmap
if (crate[c] == 2) // 16-channel delay
m_CBSlot1.SetBitmap(hBitmapC); // Cyan bitmap
if (crate[c] == 3) // Universal trigger logic
m_CBSlot1.SetBitmap(hBitmapY); // Yellow bitmap }
break;
case 1:
{
if (crate[c] == 1)
m_CBSlot2.SetBitmap(hBitmapG);
if (crate[c] == 2)
m_CBSlot2.SetBitmap(hBitmapC);
if (crate[c] == 3)
m_CBSlot2.SetBitmap(hBitmapY);
} break;
case 2:
{
if (crate[c] == 1)
m_CBSlot3.SetBitmap(hBitmapG);
if (crate[c] == 2)
m_CBSlot3.SetBitmap(hBitmapC);
if (crate[c] == 3)
m_CBSlot3.SetBitmap(hBitmapY);
} break;
case 3:
{
if (crate[c] == 1)
m_CBSlot4.SetBitmap(hBitmapG);
if (crate[c] == 2)
m_CBSlot4.SetBitmap(hBitmapC);
if (crate[c] == 3)
m_CBSlot4.SetBitmap(hBitmapY);
} break;
case 4:
{
if (crate[c] == 1)
m_CBSlot5.SetBitmap(hBitmapG);
if (crate[c] == 2)
m_CBSlot5.SetBitmap(hBitmapC);
if (crate[c] == 3)
m_CBSlot5.SetBitmap(hBitmapY);
} break;
case 5:
{
if (crate[c] == 1)
} break;
case 6:
{
if (crate[c] == 1)
m_CBSlot7.SetBitmap(hBitmapG);
if (crate[c] == 2)
m_CBSlot7.SetBitmap(hBitmapC);
if (crate[c] == 3)
m_CBSlot7.SetBitmap(hBitmapY);
} break;
case 7:
{
if (crate[c] == 1)
m_CBSlot8.SetBitmap(hBitmapG);
if (crate[c] == 2)
m_CBSlot8.SetBitmap(hBitmapC);
if (crate[c] == 3)
m_CBSlot8.SetBitmap(hBitmapY);
} break;
case 8:
{
if (crate[c] == 1)
m_CBSlot9.SetBitmap(hBitmapG);
if (crate[c] == 2)
m_CBSlot9.SetBitmap(hBitmapC);
if (crate[c] == 3)
m_CBSlot9.SetBitmap(hBitmapY);
} break;
case 9:
{
if (crate[c] == 1)
m_CBSlot10.SetBitmap(hBitmapG);
if (crate[c] == 2)
m_CBSlot10.SetBitmap(hBitmapC);
if (crate[c] == 3)
m_CBSlot10.SetBitmap(hBitmapY);
} break;
case 10:
{
if (crate[c] == 1)
m_CBSlot11.SetBitmap(hBitmapG);
if (crate[c] == 2)
m_CBSlot11.SetBitmap(hBitmapC);
if (crate[c] == 3)
m_CBSlot11.SetBitmap(hBitmapY);
} break;
case 11:
{
if (crate[c] == 1)
m_CBSlot12.SetBitmap(hBitmapG);
if (crate[c] == 2)
m_CBSlot12.SetBitmap(hBitmapC);
if (crate[c] == 3)
m_CBSlot12.SetBitmap(hBitmapY);
} break;
case 12:
{
if (crate[c] == 1)
m_CBSlot13.SetBitmap(hBitmapG);
if (crate[c] == 2)
m_CBSlot13.SetBitmap(hBitmapC);
if (crate[c] == 3)
m_CBSlot13.SetBitmap(hBitmapY);
} break;
case 13:
{
if (crate[c] == 1)
m_CBSlot14.SetBitmap(hBitmapG);
if (crate[c] == 2)
m_CBSlot14.SetBitmap(hBitmapC);
if (crate[c] == 3)
m_CBSlot14.SetBitmap(hBitmapY);
} break;
case 14:
{
if (crate[c] == 1)
m_CBSlot15.SetBitmap(hBitmapG);
if (crate[c] == 2)
m_CBSlot15.SetBitmap(hBitmapC);
if (crate[c] == 3)
m_CBSlot15.SetBitmap(hBitmapY);
} break;
case 15:
{
if (crate[c] == 1)
m_CBSlot16.SetBitmap(hBitmapG);
if (crate[c] == 2)
m_CBSlot16.SetBitmap(hBitmapC);
if (crate[c] == 3)
m_CBSlot16.SetBitmap(hBitmapY);
} break;
case 16:
{
if (crate[c] == 1)
m_CBSlot17.SetBitmap(hBitmapG);
if (crate[c] == 2)
m_CBSlot17.SetBitmap(hBitmapC);
if (crate[c] == 3)
m_CBSlot17.SetBitmap(hBitmapY);
} break;
case 17:
{
if (crate[c] == 1)
m_CBSlot18.SetBitmap(hBitmapG);
if (crate[c] == 2)
m_CBSlot18.SetBitmap(hBitmapC);
if (crate[c] == 3)
m_CBSlot18.SetBitmap(hBitmapY);
} break;
case 18:
{
if (crate[c] == 1)
m_CBSlot19.SetBitmap(hBitmapG);
if (crate[c] == 2)
m_CBSlot19.SetBitmap(hBitmapC);
if (crate[c] == 3)
m_CBSlot19.SetBitmap(hBitmapY);
} break;
case 19:
{
if (crate[c] == 1)
} break;
case 20:
{
if (crate[c] == 1)
m_CBSlot21.SetBitmap(hBitmapG);
if (crate[c] == 2)
m_CBSlot21.SetBitmap(hBitmapC);
if (crate[c] == 3)
m_CBSlot21.SetBitmap(hBitmapY);
} break;
default:
break;
} }
// Function that launches the SingleDiscrim class for setup and testing of the cards void CSetup::OnSetupTest()
{
// TODO: Add your control notification handler code here m_CSingleDiscrim.DoModal();
}
void CSetup::OnView() {
// TODO: Add your control notification handler code here UpdateData(TRUE);
m_CHistogramCtrl.WichGraph(m_iBoardaddr); // Sends the board address of the card for showing the graph m_CChannelsDlg.DoModal();
}
CSingleDegub class
SingleDebug.cpp
void CSingleDebug::OnNrofcards(int crate[NR_OF_CARDS]) {
// TODO: Add your control notification handler code here
ofstream outFile("addresses.txt"); // Creating an text file for writing
int addresses[NR_OF_ADDRESSES]; // NR_OF_ADDRESSES is a global variable for (int i=0; i<NR_OF_ADDRESSES; i++) // Fill with zeros as default
addresses[i] = 0;
int n = -1;
int addr = 0;
m_strAddr1Single = "0x00";
m_strAddr2Single = "0x00";
while (err == 0) {
nextcard();
if (err == 0) {
n++;
// Creating one hex number out of two. addr1 higher bits and addr2 lower bits. OR is used addr = (addr1<<8) | addr2;
addresses[n] = addr;
} }
err = 0;
for (i=0; i<=n; i++)
outFile << addresses[i] << "\n"; // print every board address to the text file outFile.close();
n = 0;
for (i=0; i<NR_OF_ADDRESSES; i++) {
if ((addresses[i] >= 0xf000) && (addresses[i]<0xf0ff)) // if 16-ch discrim card put a 1 in crate[n]
if ((addresses[i]-0xf000)%4 == 0) {
crate[n] = 1;
n++;
}
if ((addresses[i] >= 0xfa10) && (addresses[i]<0xfaff)) // if 16-ch delay card put a 2 in crate[n]
if ((addresses[i]-0xfa10)%16 == 0) {
crate[n] = 2;
n++;
}
if ((addresses[i] >= 0xf4e0) && (addresses[i]<0xfa00)) // if universal trigger logic card put a 3 in crate[n]
if ((addresses[i]-0xfa10)%16 == 0) {
crate[n] = 3;
n++;
} }
m_CSingleDiscrim.Boardaddr(addresses); // Sends the addresses to SingleDiscrim class }
void CSingleDebug::OnNextaddr() {
// TODO: Add your control notification handler code here
UpdateData(TRUE); // update the variables
//the input string is returned as hex
sscanf(m_strAddr1Single, "%x", &address1);
sscanf(m_strAddr2Single, "%x", &address2);
address2 = address2 + 1 ;
for (addr1 = address1; addr1<=0xff; addr1++) {
result = div (addr1,2);
if(result.rem==0) // Only even address1 is processed {
err = I2C_openbus() ; if (err == 1) {
mes = MessageBox ("Power is off", "Error",MB_ICONHAND) ; I2C_closebus() ;
UpdateData(FALSE);
return ; }
err = I2C_write(addr1,speed) ; I2C_closebus() ;
if (err == 0) {
// write m_strI2CAdr1 in the dialog wsprintf(szMsg, "%x", addr1);
m_strAddr1Single = szMsg;
for (addr2 = address2; addr2<=0xff; ++addr2) {
I2C_openbus() ;
err = I2C_write(addr1,speed);
err = I2C_write(addr2,speed);
I2C_closebus() ; if (err == 0) {
// write m_strI2CAdr2 in the dialog wsprintf(szMsg, "%x", addr2);
m_strAddr2Single = szMsg;
UpdateData(FALSE);
return ; }
if (err == 2) {