Conception et réalisation d`un driver pour carte PSFEE du détecteur

Transcription

Conception et réalisation d`un driver pour carte PSFEE du détecteur
INSTITUT SUPERIEUR
LABORATOIRE
D'INFORMATIQUE
DE MODELISATION
ET DE LEURS APPLICATIONS
DE PHYSIQUE
CORPUSCULAIRE
DE CLERMONT-FERRAND
COMPLEXE DES CEZEAUX
BP 10125 - 63173 AUBIERE CEDEX
24, AVENUE DES LANDAIS
63177 AUBIERE CEDEX
Conception et réalisation d'un driver pour
carte PSFEE du détecteur LHCb
Rapport de stage 3ème année
Réalisé par :
Maxime Fiandino
Responsables du stage :
Laboratoire: M. Rémi CORNAT
ISIMA: M. Emanuel Mesnard
Avril-septembre 2002
1
INSTITUT SUPERIEUR
LABORATOIRE
D'INFORMATIQUE
DE MODELISATION
ET DE LEURS APPLICATIONS
DE PHYSIQUE
CORPUSCULAIRE
DE CLERMONT-FERRAND
COMPLEXE DES CEZEAUX
BP 10125 - 63173 AUBIERE CEDEX
24, AVENUE DES LANDAIS
63177 AUBIERE CEDEX
Conception et réalisation d'un driver
pour carte PSFEE du détecteur LHCb
Rapport de stage 3
ème
année
Réalisé par :
Maxime Fiandino
Responsables du stage :
Laboratoire: M. Rémi CORNAT
ISIMA: M. Emanuel Mesnard
Avril-septembre 2002
1
Remerciements
Je remercie Cristina Cârloganu pour tout le travail d'équipe réalisé sur le logiciel au cour du
stage, et pour toute l'aide qu'elle m'a apportée.
Monsieur Rémi Cornat qui m'a apporter des renseignements et des explications précieux sur le
fonctionnement interne de la carte Front-End.
Monsieur Pascal Perret qui m'a permis de m'intégrer dans le groupe de travail du LPC sur le
calorimètre du futur LHCb.
Mes remerciments vont également à Régis Lefevre pour ses explications sur la chaîne de
mesure utilisée lors des faisceaux tests au CERN à Genève.
Je tiens à remercier Stéphane Monteil et Olivier Deschamps pour leurs tentatives à m'inculquer
les principes et les grandes théories de la physique des particules, notemment au cour des discutions sur
la difficulté à mettre à mal le modèle standard.
Messieurs Gérard Bohner et Jacques Lecoq pour leur aide précieuse au niveau de l'électronique,
pour les simulations de l'acquisition nécessaires à la mise au point et au test du logiciel.
Je remercie Cécile Rimbault pour sa relecture et sa correction attentive du rapport.
2
Résumé
Le but de cette réalisation est la création d'une bibliothèque de contrôle d'un prototype
d'une carte électronique (nommée PSFEE) qui assure la lecture d'une partie du détecteur LHCb
(le détecteur de pied de gerbe). LHCb est un des quatres détecteurs (ALICE, ATLAS, CMS,
LHCb) du futur collisionneur de particules LHC en construction au CERN à Genève.
Les particularités de cette bibliothèque sont : l'exigeance de sa gestion de la
communication entre la carte et un ordinateur au travers d'un bus VME et sa gestion de la
parallélisation de l'acquisition grâce aux threads. La partie graphique (interface utilisateur) du
logiciel de contrôle de la carte étant réalisée à partir de la bibliothèque C++ ROOT notre
bibliothèque a été également écrite en C++, language très pratique pour la gestion des exceptions.
L'interface entre l'ordinateur et le bus VME est une carte PCI-MXI2 de National Instrument. Le
driver NIVXI du même fabricant est utilisé pour communiquer à travers le bus.
Pour sa conception, le programme a du prendre en compte la possibilité de changement de
support (et donc de type de bus) pour la communication carte ordinateur. Une classe interface a
donc du être crée en conséquence. Il a fallu aussi pouvoir gérer simultanément plusieurs cartes
en tenant compte au dépouillement des données d'un problème de désynchronisation de ces
cartes (problème complètement indépendant du logiciel de contrôle des cartes).
Des tests ont pu être réalisés sur faiceau à Genève et ont conclu à la bonne marche du
programme dans son ensemble. La bibliothèque de contrôle de la carte ainsi que la
comminication avec l'interface graphique fonctionnent de manière très satisfaisantes.
Mots-clés :
LHCb, bus VME, thread, carte PSFEE
Abstract
The purpose of this work is to control an acquisition electronic board (named PSFEE) for the
LHCb preshower detector. LHCb, a CP violation detector is one of the four detectors to be built on the
future LHC collider, under construction at CERN.
The main features of this library are given by the requirement to communicate with the PSFEE
board through the VME bus, and from the parallelisation of the acquisition and of the graphics. The
library was written in C++ language for two main reasons. On one hand for facility sake, since a
complete graphical and data analysis library (ROOT) was available under C++, and on the other hand
for the exception handling in this language. The PCI-MXI2 board from National Instrument handles the
communication between the VME bus and the computer. So the nivxxi driver of National Instrument
had to be used.
The software design has to include the possibility of a different bus for the comunication with
the PSFEE board. A special class interface was created in this purpose. It is also possible to use a
multiple boards acquisition mode, provided that the present syncronisation problem for the hardware is
solved.
All the acquisition chain was succesfully tested in real conditions during two testbeam periods
at CERN (near Geneva). We can therefore conclude that the software does function well.
Keywords :
LHCb, VME bus, thread, Font-End board
3
Table des matières
Remerciements................................................................................................................................................2
Résumé............................................................................................................................................................3
Abstract...........................................................................................................................................................3
Glossaire..........................................................................................................................................................6
Introduction.....................................................................................................................................................8
1 Contexte et analyse de l'existant.................................................................................................................9
1.1 L'expérience LHCb..............................................................................................................................9
1.2 Le détecteur LHCb..............................................................................................................................9
1.3 L'électronique.....................................................................................................................................11
1.4 La chaîne d'acquisition du détecteur de pied de gerbe....................................................................11
1.4.1 Les photo-multiplicateurs..........................................................................................................12
1.4.2 Les circuits Very Front-End......................................................................................................12
1.4.3 Les cartes Front-End..................................................................................................................12
1.5 Vu générale du logiciel d'acquisition et d'affichage........................................................................13
1.6 La bibliothèque NIVXI.....................................................................................................................13
2 Etude des besoins et des contraintes du logiciel......................................................................................14
2.1 Possibilité de changement de support pour la carte.........................................................................14
2.2 Nécessité d'une gestion du hardware................................................................................................15
2.2.1 Gestion et installation du driver VME......................................................................................15
2.2.2 Installation de bibliothèque supplémentaire.............................................................................15
2.2.3 La sauvegarde des données.......................................................................................................15
2.3 Choix du langage de programmation................................................................................................16
2.4 Interface graphique interactive durant l'acquisition.........................................................................16
2.5 Gestion de la mémoire de la carte.....................................................................................................17
2.6 Gestion de plusieurs cartes et des FPGAs en simultané..................................................................18
2.7 Vitesse de lecture écriture sur Bus VME.........................................................................................18
2.8 Gestion des exceptions......................................................................................................................19
3 Réalisations................................................................................................................................................20
3.1 Classes utilisées.................................................................................................................................20
3.1.1 Classes BusInterface et BusVME.............................................................................................20
3.1.2 Classe Carte................................................................................................................................21
3.1.3 Classe Acquisition.....................................................................................................................21
3.2 Algorithmes de lecture sur la carte...................................................................................................21
3.2.1 Récupération sur chaque carte..................................................................................................21
3.2.2 Tri et gestion des données demandées......................................................................................22
3.3.3 Modification des paramètres (nombre de voies et de cartes)..................................................23
3.3 Réactions en cas d'erreur...................................................................................................................24
3.4 Résultats de la campagne d'essai......................................................................................................24
3.4.1 Campagne de juin......................................................................................................................24
3.4.2 Campagne d'aout........................................................................................................................26
Conclusion.....................................................................................................................................................27
Bibliographie.................................................................................................................................................28
Annexe..........................................................................................................................................................29
4
Table des figures
Détecteur LHCb et ses sous détecteurs........................................................................................................10
Un photomultiplicateur.................................................................................................................................12
Chassis VME................................................................................................................................................14
Threads et Processus.....................................................................................................................................17
Liste des exceptions principales...................................................................................................................19
Diagramme UML simplifié des classes utilisées........................................................................................20
Dispositif pour les tests en faisceau.............................................................................................................25
5
Glossaire
Antimatière : À toute particule de matière correspond une antiparticule. Une antiparticule possède les
propriétés suivantes: Ses nombres quantiques (charges, spin, etc..) ont une valeur opposée à ceux de la
particule de la matière correspondante. Par contre les masses de la particule et de son antiparticule sont
identiques.
Calorimètre : En physique des particules le calorimètre est un détecteur qui sert essentiellement à la
mesure de l'énergie des particules. La mesure est destructive: la particule incidente interagit avec le
milieu et s'arrette. L'énergie qu'elle dépose est transformée dans des signaux mesurables (lumière,
charge électrique).
CERN : Conseil Européen pour la Recherche Nucléaire
Détecteur de pied de gerbe (Preshower) : Détecteur qui fournit de l'information sur le début des
gerbes dans le calorimètre. Il permet de connaître plus précisément le point d'impact de la particule
incidente et aide à l'identification de son type.
Diaphonie : Brouillage d'une voie par les signaux présents sur les voies adjacentes d'un équipement
FPGA (Field Programmable Gate Arrey) : Composant électronique numérique programmable.
Grâce, par exemple, au language VHDL, des circuits sont conçus puis implantés au coeur des FPGA.
Ils deviennent alors des composants personnalisés qui sont de plus reprogrammables.
Front-End (Frontal) : On parle d'électronique Front-End pour définir les dispositifs électroniques
relativement proches du détecteur dans la chaîne de traitement des données.
LHC (Large Hadron Collider) : Grand collisionneur de hadrons. Il s'agit d'un accélérateur circulaire
de 27 kilomètres de circonférence qui sera mis en service en 2007 au CERN de Genève. Il disposera
d'une grande puissance électromagnétique permettant d'accélérer un faisceau de protons et donc de
provoquer des collisions entre protons à haute énergie. Plusieurs expériences et donc plusieurs
détecteurs (LHCb, ALICE, ATLAS, CMS) se partagent le faisceau..
LHCb (LHC beauty experiment) : Détecteur présent dans une des cavernes du LHC. Il a pour but
d'identifier les particules dites "belles" afin d'expliquer l'asymétrie entre matière et antimatière.
Photo multiplicateur (ou PM) : Dispositif permettant de transformer un signal optique en un signal
électrique.
ROOT : Bibliothèque (sous le language C++) de fonctionnalités graphiques et d'analyse de données
utilisée dans la physique des particules.
STL (Standard Template Library) : Bibliothèque standard du C++ permettant de manipuler un grand
nombre de structure de données (file, vecteur, liste, pile...).
6
Thread : Les threads sont des chemins d'exécution au sein d'un programme, contenus dans un
processus. On parle de processus multithreads ou single-thread quand il y a respectivement plusieurs ou
un seul thread dans le processus. Les threads sont donc des parties de code exécutées indépendamment
mais qui accèdent au même espace mémoire. Ils peuvent donc accéder aux même variables et
structures globales.
Transtypage : Transformation de la valeur d'une variable informatique d'un certain type (int, float,
char...) vers un autre type.
Violation de symétrie CP (Charge-parité) : Il y a violation de symétrie CP par un phénomène
physique quand son comportement change lors de l'inversion simultanée des antiparticules avec leurs
particules. La violation de CP est l'une des conditions nécessaires pour créer l'asymétrie matière
antimatière.
Very Front-End : En physique des particules, on parle d'électronique ou de cartes Very Front-End
pour définir les dispositifs électroniques à la suite des capteurs et de la mise en forme analogique.
VHDL (Very high scale integrated circuit Hardware description Langage) : Langage de
description de circuits intégrés. On peut ensuite le synthétiser sous forme de circuits logiques. Le
VHDL permet une description comportementale d'un composant numérique. Afin de simuler le
fonctionnement d'une carte, on peut non-seulement inclure le code des FPGA mais aussi celui d'autres
composants se trouvant sur la carte.
VME (Versa Module Eurocard) : Le VME est un bus informatique de la norme IEEE P1014
(Institute of Electrical and Electronics Engineers). La communication entre le bus et les cartes se fait
par l'intermédiaire d'une carte appelée 'maitre VME'.
7
Introduction
La violation de symétrie CP a déjà été observée sur dans le système des mésons K neutre en
1964. Cette violation de symétrie serait à l'origine de l'assymétrie matière-antimatière de l'univers. A
l'heure actuelle, les mécanismes physiques à l'origine de ce phénomène sont mal connues. Pour
progresser dans ce domaine il faudrait étudier des particules plus lourdes comme les mésons beaux
(particules composées de deux quarks avec un quark ou antiquark b).
Le.futur collisionneur proton-proton LHC, prévu pour 2007, produira en grand nombre des
mésons beaux (100000 par seconde). Un détecteur dédié à la violation de symétrie CP, LHCb y est
donc prévu.
L'énergie des particules subatomiques est mesurée essentiellement à l'aide des calorimètres,
détecteurs qui dans le cas de l'expérience LHCb transforment l'énergie incidente en lumière. Par la suite
cette lumière est enregistrée grâce à des photomultiplicateurs. La fréquence très rapide des collisions
protons-protons au LHC (une toutes les 25 nanosecondes) et le grand nombre de voies de lecture
imposent des contraintes particulières sur l'électronique du détecteur. Les signaux analogiques des
photoamplificateurs sont numérisés et triés pour éliminer les bruits et les événements non désirés. Des
logiciels spécifiques d'acquisition et de dépouillement des données sont prévus.
Un prototype du système électronique de lecture d'une partie du calorimètre LHCb, le détecteur
de pied de gerbe, a été réalisé au LPC. Nous avons travaillé sur le logiciel qui contrôle ce prototype.
Ce logiciel a des contraintes spécifiques. En cas de problème sur l'acquisition (par exemple arrêt
du faisceau pendant les tests du prototype en faisceau au CERN), il faut pouvoir arréter l'acquisition et
sauvegarder les données déja prises. Il est alors important de séparer l'acquisition de l'affichage et du
traitement des données. Ces deux fonctions séparées devraient idéalement se dérouler en parallèle.
Actuellement l'utilisation d'un systeme multi-tâche Linux permet de les ajancer au mieux. Le but de ce
stage sera donc la réalisation d'une bibliothèque C++ qui gère l'acquisition. Celle-ci devra se derouler
en parallèle du programme appelant. Elle devra pouvoir utiliser plusieurs cartes d'acquisition en
simultanné et gérer les problèmes physique à travers des exceptions.
8
1 Contexte et analyse de l'existant
1.1 L'expérience LHCb
Cette expérience a pour vocation l'étude de la violation de symétrie charge parité ou symétrie
l'image d'une
CP. La particule et son antiparticule ont une charge opposée, et la parité correspond
particule dans un miroir (symétrie spatiale).
L'étude de cette violation de symétrie a deux objectifs:
- Les théories actuelles du big bang prévoient la création, en égale quantité, de matière et
d'antimatière à l'origine de l'univers. La violation de CP est une des explications avancées afin
d'expliquer la prédominance de la matière.
- La théorie physique actuelle, soit le modèle standard, prévoie cette violation et ses effets. Cette
expérience devrait permettre de valider les résultats obtenus.
Les physiciens pensent que la violation de symétrie CP devrait être observable lors des
désintégrations mettant en cause des particules comportant le quark 'beau'. Ces événements seront
produits en grandes quantités dans le collisionneur de particule LHC. Un détecteur dédié à l'étude de la
violation de CP dans le système des mésons b (LHCb) y est prévu.
1.2 Le détecteur LHCb
Le détecteur LHCb sera construit autour des faisceaux de protons circulant en sens opposé dans
le collisionneur LHC. Sa mise en route est prévue pour l'année 2007.
Il doit détecter des particules filles produites par des collisions entre particules mères (protons
pour cette expérience) afin de mesurer leur impulsion, leur énergie et de déterminer leur direction.
Le détecteur est compose de trois types de matériels:
- Les capteurs (détecteurs) physiques proprement dits qui interagissent directement avec les
particules.
- Le système d'acquisition des données (électronique et informatique).
- Le système de contrôle et de ressources (alimentations, refroidissement, régulation du faisceau
de particules, etc...).
9
Fig. 1- Détecteur LHCb et ses sous détecteurs
Le détecteur est enterré. Il s'inscrit dans un parallélépipède de 10 x 10 x 20 mètres cubes. Les
systèmes électroniques sont, dans la mesure du possible, protégés des radiations par un mur en béton
dans une partie distincte de la caverne.
Les éléments du détecteur LHCb:
- La détection d'empilement qui permet d'éliminer les événements contenant plusieurs
interactions proton-proton grâce à un détecteur de point d'interaction (vertex detector)
fournissant des informations sur le nombre de collisions et de désintégrations.
- Le système de suivi de trace (tracker) qui permet de reconstruire les traces des particules
chargées et de mesurer précisément leur impulsion.
- Les détecteurs RICH qui permettent notemment la séparation des pions et des kaons.
- Les calorimètres électromagnétiques et hadroniques qui ont pour but d'identifier les électrons
et les hadrons ainsi que de mesurer leurs énergies et positions. Ils seront décrits par la suite.
- Le détecteur de muons qui fournit une identification des muons. Il est constitue de cinq
chambre à pad (feuilles de cuivre déposées en alternance avec des structures en nid d'abeille
remplies de gaz: dioxyde de carbone (CO2), Argon (Ar), Fréon (CF4) ).
Les calorimètres sont les sous-détecteurs essentiels pour le choix des événements à conserver.
Ils couvrent une couronne autour de l'axe du faisceau de 30 à 300 mrad et comprennent trois parties:
10
- Le détecteur de pied de gerbe (PS) qui permet d'identifier les électrons et les photons. Il possède
la même segmentation en cellules que le calorimètre électromagnétique.
- Le calorimètre hadronique qui comporte quatre fois moins de cellules que les deux autres
parties.
Si l'on regarde la disposition des cellules du calorimètre électromagnétique dans le plan
orthogonal au faisceau, on peut voir le trou central pour le passage du faisceau de protons ainsi que les
trois zones de densités différentes (16, 4 ou 1 cellules par rectangles selon les zones). Pour identifier
une particule, on met en correspondance les cellules de la première chambre à pad, du détecteur de pied
de gerbe et des calorimètres.
1.3 L'électronique
Le traitement des informations, les contrôles externes ainsi que de nombreuses autres tâches
dans les détecteurs de particules sont réalisées grâce à l'électronique.
Les technologies employées pour la réalisation des dispositifs doivent satisfaire à un compromis
coût-performance. Cependant les résultats de physique que l'on veut obtenir nécessitent des études de
plus en plus fines et des observations d'autant plus fréquentes et rapides. L'électronique proche des
capteurs est donc très sollicité en fréquence, en temps de calcul ainsi qu'en résistance aux radiations.
Les concepteurs sont parfois amenés à se baser sur des évolutions technologiques promises par les
fabricants mais encore indisponibles.
1.4 La chaîne d'acquisition du détecteur de pied de gerbe
La collision entre deux protons produit diverses particules dont des électrons et des
photons. Certaines de ces particules vont aussi se désintégrer peu après en emmetant aussi des
électrons et des photons. Tout ces électrons et photons passent dans un scintillateur. Celui-ci va
émettre des photons lors des interactions avec ces particules. Ces photons vont être transformés
en signaux électriques par des photomultiplicateurs (PM). Ensuite ces signaux vont être intégrés
pendant 25ns (en effet les collisions proton proton ont lieu en moyenne à 40MHz soit toutes les
25ns) dans la carte Very Front End (VFE). Les signaux intégrés vont être numérisée dans la carte
Front End (FE). Enfin les valeurs numériques sont transmises à l'ordinateur via un bus VME
pour être affi chées et stockées.
11
1.4.1 Les photo-multiplicateurs
Le détecteur de pied de gerbe est constitué
de cellules (scintillateurs) qui ont la propriété
d'emettre des photons d'une longueur d'onde bien
définie lors du passage d'une particule ionisante.
Des photomultiplicateurs multianodes seront reliés
par fibres optiques à ces cellules. Ils seront au
nombre de 93 (soit 5952 voies du détecteur de
pied de gerbe) et sont regroupés dans des boîtiers
cubiques d'environs 3 cm2 de base.
Le rôle d'un PM est de convertir la lumière
en électrons puis d'amplifier ce signal. Ils
comprennent une photocathode en entrée qui n'est
autre qu'un matériau duquel sont arrachés
quelques électrons lors du passage d'un photon,
par effet photo-électrique. Afin de rendre le signal
mesurable, il est amplifié (d'un facteur 106) grâce
à un système multi-anodes alimenté sous hautetension (de l'ordre du kiloVolt).
Fig. 2- Un photomultiplicateur
1.4.2 Les circuits Very Front-End
Les cartes Very Front End (conçues au LPC) effectuent l'intégration sur 25 ns de l'impulsion
ainsi produite en sortie du PM. Elles sont positionnés au plus proche des PM, au coeur même du
détecteur, afin de limiter les pertes de signal en sortie des PM. Le rôle de l'intégration est d'obtenir une
valeur significative de l'interraction proton-proton. En effet l'accélérateur est cadencé à 40MHz, on a
donc une interraction toutes les 25ns. Le circuit fournit ainsi un signal utilisable pour la suite de la
chaîne d'acquisition.
1.4.3 Les cartes Front-End
Elles seront au nombre de 93 (une par PM) et regrouperont chacune 64 voies.Le protoype actuel
ne traite que 16 voies. L'électronique Front-End doit numériser le signal issu des circuits Very FrontEnd. Une correction numérique des erreurs dues à la chaîne d'acquisition (PM + VFE) est effectuée. La
carte sauvegarde les échantillons validés par un système externe de déclanchement puis joue le rôle
d'interface vers un système logiciel extérieur [6].
12
1.5 Vu générale du logiciel d'acquisition et d'affichage
Le logiciel et bibliothèque graphique et d'analyse de données 'ROOT' est très utilisée en
physique des particules. Il a été choisi car il est programmé en C++ et il est considéré comme un
standart.
Des campagnes de test des prototypes sont réalisées au CERN, les deux dernières ont été
réalisées en juin et aout 2002. Pendant les campagnes le logiciel doit récupérer les séries de
données voie par voie á l'aide d'une carte, puis doit ensuite afficher les histogrammes de contrôle
à l'écran.
Simultanément, il doit pouvoir dialoguer avec la carte pour qu'il puisse arrêter une
acquisition en cours en cas de problème, et il doit aussi être capable d'interagir avec le logiciel
pendant une acquisition. Dans ce but la routine de l'interface graphique et celle de l'acquisition
sont placées dans deux 'threads' différents.
1.6 La bibliothèque NIVXI
La carte Front-End est montée sur un chassis VME. La communication entre l'ordinateur
et cette carte se d éroule par l'intermédiaire d u bus VME.
Pour cette communication il faut utiliser le driver du bus avec les fonctions qui lui sont
associées, fourni par National Instrument . Cependant il faut remarquer que National Instrument
a arrêté le développement de ces drivers sous Linux, ils ne sont donc pas compatible avec les
systèmes récents (par exemple on ne peut pas utiliser un noyau Linux de
version supérieure à
2.2).
Seule les fonctions d'écriture et de lecture sur le bus ainsi que celle de lecture en raffale
nous intéressent [1]. En effet nous n'utilisons pas les fonctions d'interruption ni celles de gestion
de plusieurs cartes.
13
2 Etude des besoins et des contraintes du logiciel
2.1 Possibilité de changement de support pour la carte
La carte actuellement utilisée est un prototype pour un détecteur qui ne commencera ses prises
de données qu'en 2007. Pour des raisons de commodité et de matériel, elle a été construite pour un bus
VME. Cependant la réalisation finale devra pouvoir acquérir à des vitesses bien supérieures à celles
qu'un bus VME peut supporter.
Un prototype futur devra donc être construit sur un type de bus ou un système de
communication différent. Ce changement matériel devrait idéalement nécessiter le moins possible de
modifications du code source du programme. A cet effet une classe C++ BusInterface est implémentée.
En effet, actuellement seule une classe BusVME en est dérivée. Dans le cas ou l'on voudrait
implémenter un prototype du même fonctionnement sur un autre bus, il suffirait de créer une classe du
nouveau bus dérivant de BusInterface. Cette classe redéfinirait les fonctions actuelles pour qu'elles
soient compatibles avec le nouveau bus. Ensuite il suffirait de remplacer dans le code les créations de
classe BusVME par celles du nouveau bus.
Grace à cette méthode on minimise donc la modification du code en cas de changement de
support pour la carte.
Fig. 3- Chassis VME
14
2.2 Nécessité d'une gestion du hardware
2.2.1 Gestion et installation du driver VME
La gestion du driver NIVXI de contrôle du bus VME développé par National Instrument
demande des privilèges administrateur et un système particulier. En premier lieu National Instrument a
arrêté l'évolution de ce driver, il n'est donc plus supporté par des noyaux Linux de version supérieure à
la 6.2 . Deux possibilités sont alors envisageables. La première serait d'installer une distribution plus
récente puis rajouter un second noyau de version inférieure avec un choix de version au démarrage du
système. La seconde, la plus simple et le plus sûre pour éviter des incompatibilités serait d'installer un
ancien linux avec le noyau adéquat. Pour éviter tout problème la seconde possibilité a été choisie.
L'installation en elle même requiert en premier lieu une recompilation des sources sur le
système. Ceci est automatisé par un script d'installation fourni avec les sources. Ensuite il faut lancer
sous un utilisateur privilégié l'utilitaire load_vxi à chaque démarrage de l'ordinateur puis unload_vxi à
l'arrêt. On peut aussi les faire lancer directement par le système au départ de celui-ci. Mais il faut pour
cela rajouter manuellement un script dans un dossier système à l'installation du driver.
Tout ajout de carte doit être signalé au gestionnaire du bus via la fonction vxitedit. Celle-ci
permet en effet de définir les propriétés de la carte, et notamment son adresse et le nombre de bits
d'adressage et de données qu'elle utilise.
2.2.2 Installation de bibliothèque supplémentaire
Pour tester le programme on peut en premier lieu réaliser des simulations sans être réellement
connecté au bus VME et à la carte. On peut ensuite mettre la carte et réaliser des acquisitions avec toute
la chaîne de mesures qui précède ainsi qu'un vrai faisceau de particules.
Cependant le logiciel ne peut être validé que lorsque les données auront pu être vérifiées et
déclarées cohérentes par les chercheurs physiciens. Pour cela ils possèdent leurs propres programmes
de test qui nécessitent des bibliothèques d'analyse de données spécifiques comme la CERNLIB, ROOT
[3] ou PAW++. Ces bibliothèques doivent donc pouvoir être mises en place directement sur le terrain.
2.2.3 La sauvegarde des données
Les mesures en physique corpusculaire nécessitent des faisceaux de particules à des énergies
considérables. Ceci implique que ces faisceaux sont très chers à créer et à entretenir . Les temps
d'utilisation possibles sont donc courts et comptés. Il est donc important de sauvegarder les données
prises. A cet effet un graveur nous a été alloué.
Cependant l'utilisation d'un graveur récent sous un système ancien est complexe. Il serait
néanmoins possible d'essayer d'implémenter le driver sous cette version sans être certain de réussir. Il
serait aussi possible d'utiliser deux machines et un transfert réseau pour cette sauvegarde. La dernière
possibilité consiste à installer un double système sur la machine avec un disque partagé. Un système
15
windows étant déjà installé sur la machine avec la gestion du graveur, c'est cette solution que j'ai
choisie.
2.3 Choix du langage de programmation
Pour la réalisation de se programme il fallait un langage permettant de gérer à la fois des
bibliothèques graphiques et d'analyse de données, et des fonctions de lecture et d'écriture sur Bus VME.
Hors ces fonctions pour bus VME étaient directement disponible en language C [5]. De plus il fallait
utiliser une bibliothèque graphique et d'analyse de données du CERN, soit ROOT, qui utilise le C++.
Les avantages de cette bibliothèque sont de nous servir de double emploi, à la fois pour l'affichage et
pour l'analyse des données. Ceci rend la configuration plus simple et évite les problèmes de format et
de convertion. Enfin le fait que cette bibliothèque trés utilisé au CERN, à l'endroit ou à terme le
détecteur sera construit et où le logiciel sera utilisé, cette bibliothèque nous permet donc de respecter
dès à présent les standards de la physique des particules.
Avec ces paramètres j'ai donc choisi d'utiliser le langage C++ pour la réalisation de ce
programme [4].
2.4 Interface graphique interactive durant l'acquisition
Une des demandes au niveau de ce programme est la possibilité de pouvoir continuer à utiliser
l'interface graphique pendant l'acquisition, autrement dit que l'interface ne soit pas bloquée et reste
interactive. Il arrive, pour différentes contraintes techniques, que le faisceau de particules s'arrête pour
des durées assez longues, il faut donc pouvoir arrêter l'acquisition si les données n'arrivent plus, et il
faut aussi pouvoir enregistrer celles qui ont déjà été récupérées.
Pour ce parallélisme, il existe deux possibilités principales.
La première possibilité implique l'utilisation de deux processus qui communiquent entre eux.
Cette méthode est, par exemple, utilisée pour gérer les connections par réseau ou internet. L'avantage
de cette méthode est que l'on peut dupliquer le programme pour le nombre d'utilisateurs voulus,
l'inconveniant est qu'il faut réaliser la communication entre des processus ayant un espace mémoire
séparé. Pour la gestion de la carte un seul programme peut être utilisé à la fois, et il n'y a aucun moyen
de connaître l'état actuel de la carte dans certains modes. Le programme suppose donc qu'elle est dans
la dernière configuration qu'il a demandée et si un autre programme a changé la configuration de la
carte, les ordres envoyés ne sont plus pertinents et les données recupérées aberrantes.
16
Fig. 4- Threads et Processus
La seconde possibilité consiste à utiliser des threads. Ce sont des parties de code exécutées
concurrentiellement à l'intérieur du même processus et donc avec une zone mémoire commune.
Ils peuvent donc avoir des variables communes et se transmettre des données par ce biais.
Cependant, un thread ne sait pas ce que font ces autres comparses. Il est donc impossible
pour lui de savoir si une variable est en cours de modification par un autre thread et donc si elle
est valide. Si la communication est unilatérale le problème est simple, on utilise la technique de la
boîte à messages. Le thread envoyeur dépose la donnée dans une variable puis passe une variable
booléenne à vrai pour dire que la donnée est prête. Le thread récupérateur attend que la variable
donnée prête soit à vrai. Il lit la donnée puis remet la valeur booléenne à faux pour signifier que la
place est libre. Cependant, cette méthode n'est pas utilisable pour des données que plusieurs
threads doivent modifier souvent. Pour cela il existe les mutex.
Les mutex sont des verrous pour des parties de code. Il faut en premier lieu localiser les
zones de code des différents threads qui utilisent des variables communes. Ensuite il suffit de
poser ces mutex pour que ces portions de code ne puissent
être exécutées simultannement.
On peut cependant remarquer la
difficulté de réaliser des boîtes à messages dans des
classes C++; en effet, le double accès à un attribut de classe semble pouvoir causer une erreur de
segmentation.
Ce sont les threads qui sont utilisés dans le programme, malgré leur complexité, car ils
sont beaucoup plus fiables dans ce cas de figure [2].
2.5 Gestion de la mémoire de la carte
La carte attend de recevoir un trigger pour sauvegarder des échantillons de données. Ces
échantillons sont alors mis dans des mémoires sur la carte. Pour pouvoir les récupérer il faut changer le
mode de fonctionnement de la carte. On interompt par ce fait l'acquisition. Pour que cela soit minimisé
on attend donc que la mémoire soit pleine avant de les transférer de la carte vers l'ordinateur.
De plus la carte possède un nombre de FPGA équivalent à son nombre de voies modulo 4 (un
FPGA s'occupe de quatre voies). On ne peut donc recupérer sur la carte les données que de 4 voies par
4 voies. Ces données comportent un nombre variable d'événements qui eux même comportent un
17
nombre variable d'échantillons. Une fois téléchargées sur l'ordinateur il faut donc reclasser ces données
par rapport aux voies demandées. De plus on peut récupérer les données sous différents formats, 8 ou
10 bits, suivant le code implanté sur les FPGAs. Mais le bus VME comportant 32 bits de données, ces
deux modes de lecture ne sont pas compatibles. Pour cela, il faut prévoir des variations dans
l'algorithme de récupération des données.
2.6 Gestion de plusieurs cartes et des FPGAs en simultané
Le but de la mesure, est à terme, de faire l'acquisition en provenance d'un
photomultiplicateur de 64 voies. Le prototype le plus complet ne possèdant actuellement que 16
voies, nous avons pensé utiliser plusieurs cartes simultanément pour acqu érir sur un plus grand
nombre de voies. Cependant un p roblème de synchronisation se pose, non seulement entre
plusieurs cartes mais aussi entre les FPGAs d'une seule carte. En effet le passage au mode
acquisition se fait FPGA par FPGA. Si un trigger arrive pendant ces ordres de début
d'acquisition, les FPGAs déja initialisés vont acquérir une première série de données que les
autres n'auront pas.
Une solution simple a été trouvée pour la syncronisation des FPGAs d'une seule carte. Il
s'agit de pouvoir envoyer un ordre en broadcast à tous les FPGAs de la carte, celui de passer en
mode acquisition. Cette possibilité ne demandant que quelques modifications sur le code VHDL
des fpga elle va donc être implément ée. La même solution pourrait être utilisée pour synchroniser
les cartes. Elle consisterait à un ordre broadcast pour toutes les cartes PSFEE sur le bus VME.
Malheureusement, étant plus complexe à mettre en oeuvre et necessitant des modifications
harware importantes de la carte, cette modification n'est pas à l'ordre du jour.
En attendant, j'ai utilis é une solution imparfaite mais qui tente de limiter au mieux le
problème. Elle consiste à envoyer successivement, et dans un temps le plus court possible, une
remise à zéro du pointeur d'adresse aux FPGAs après les avoir mis en mode acquisition. De cette
mani ère le risque d'avoir un décalage des données est ainsi réduit.
2.7 Vitesse de lecture écriture sur Bus VME
Sur le capteur final qui sera construit au CERN, à Genève, seuls les événements
intéressants seront choisis pour être sauvegardés. Il sera donc important de perdre le moins
possible de ces événements. De plus ,avant la construction du capteur, la durée d'allocation du
local permettant d'effectuer des tests sur faisceau étant très limitée, il sera important de ne pas
perdre d'échantillons. Hors pendant le laps de temps du téléchargement des données des
mémoires de la carte vers l'ordinateur, l'acquisition ne se fait plus. Il est donc important de
diminuer ce temps de téléchargement.
En premier lieu, la lecture d'un bloc de données se faisait en deux temps. D'abord on
écrivait l'adresse que l'on voulait lire, puis on allait lire un registre. La première amélioration a donc été
une auto-incrémentation de l'adresse mémoire. Il suffit de remettre une première fois l'adresse à zéro
puis de lire le registre autant de fois que le nombre de blocs mémoires que l'on veut lire. De cette
manière on est passé d'une écriture suivie d'une lecture à une lecture seule, d'où un gain de temps
théorique de facteur deux. En réalité, le gain de temps est supérieur car les cycles écriture-lecture
18
semblent plus lents que les cycles lecture-lecture, respectivement 90ms pour 30ms environ.
Ensuite, le but a été une amélioration du code pour éviter les pertes de temps, par exemple,
remplacer les divisions par des puissances de deux, par des décalages de bits sur la droite qui sont
beaucoup plus rapides.
Enfin une autre solution est envisagée pour plus tard; elle consiste à utiliser un mode spécial du
bus VME, le mode burst qui permet d'envoyer une suite d'informations très rapidemment. Seulement il
faut pour cela créer le code VHDL qui supporte ce mode, et modifier la carte en conséquence.
2.8 Gestion des exceptions
Le développement du projet, du point de vue électronique et informatique, est en cours. Il est
pour cette raison important que le programme soit résistant aux problèmes et aux changements. Il est de
plus important pour la correction des erreurs qu'il puisse donner des informations sur celles-ci ainsi que
sur l'état de la carte à ce moment précis, ce qui augmente de manière considérable les chances
d'identifier la cause exacte du mauvais fonctionnement.
Un système de gestion des exceptions a donc été mis en place. Celui-ci doit d'abord vérifier la
possibilité de corriger directement l'erreur. Par exemple, réécrire dans un registre si la valeur n'a pas été
enregistrée, avant de signaler une exception et donc d'arrêter l'acquisition ou le test en cour.
Dans le cas d'un problème plus complexe, le but est d'arrêter proprement le programme en
sauvegardant de préférence les données valides s'il y en a. Et de renvoyer, comme souligné
précédemment, les données relatives à l'etat de la carte.
Liste des exceptions gérées
Erreur d'initialisation du bus VME
Erreur d'écriture sur le bus
Erreur de lecture sur le bus
Erreur d'initialisation de la carte
Blockage d'un FPGA
Double lancement d'acquisition
Trop de cartes demandées à l'acquisition
Manipulation de carte durant une acquisition
Fig. 5Liste des exceptions principales
19
3 Réalisations
3.1 Classes utilisées
Class Acquistion
−Le nombre d’instance d’Acquisition
−Une acquisition est en court
−Nombre de voies utilisées sur l’acquisition
−Tableaux des cartes
−Thread et attribut de thread
−Matrice des échantillons recuperes sur les cartes
−Le Nombre d’échantillons
−La taille de la mémoire
−Le nombre de bit auquel l’acquisitionest realisée
+ Initialiser()
+ recuperer()
+ Lancer()
+ Stop()
+ AjouterCarte()
+ RetirerCarte()
1
Class BusCarte
− l’adresse physique de la carte
− Le nombre de voies utilisées sur la carte
1..Nombre de Cartes− Matrice des dernières données de la carte
Gestion de
− Si des données sont prètes
l’acquisition
− Le nombre de données en attante
− Tableau du numéro des voies utilisées
− Files des données en attente
− Pointeur sur une interface bus
− Le nombre d’echantillon par évènement
− La taille de la mémoire
−Le nombre de bit auquel l’acquisition est réalisée
+ Carte()
+ recuperer()
+ acquerir()
+ lancerAcquisition
# clean()
− stoquer()
− defiler()
− Acquisition()
− Routine()
1
1
1
Class BusInterface
# Le nombre d’instance
# Un pointeur sur lui−même
+ Connecter()
+ configurer()
+ configurerTous()
+ lireParamètre()
# BusInterface()
− init()
1..Nombre de Cartes
Class BusVME
−/ Le nombre d’instance
+ Connecter()
+ configurer()
+ configurerTous()
+ lireParamètre()
# BusVME(()
− init()
Fig. 6- Diagramme UML simplifié des classes utilisées
3.1.1 Classes BusInterface et BusVME
Ces classes servent pour la communication vers les cartes physiques à travers un Bus (
actuellement un bus externe). Elles contiennent les entrées sorties entre le software et le hardware.
La classe BusInterface est une classe virtuelle. Aucun objet de cette classe ne peut donc être
instancié. Cependant elle définie les méthodes nécessaires pour communiquer avec la carte. Il suffit
donc d'utiliser une classe fille non virtuelle qui redéfinit ces méthodes. De plus cette classe sert
d'interface. Les parties du programmes qui communiquent avec le bus peuvent se servir d'un pointeur
20
sur une classe BusInterface alors qu'elle pointe en réalité sur une de ses classes filles. On peut aussi
remarquer que l'entité physique du bus est unique. Il est prévu de n'utiliser qu'un seul bus. Par là même,
il faut pour plus d'homogénéité et de logique que la classe bus soit unique. Cette classe et ces classes
filles doivent donc ne pouvoir être créées qu'une seule fois. Il faut pour cela utiliser la méthode
Connecter qui renvoie un pointeur sur le bus. Le constructeur est déclaré en protected pour que la
classe fille puisse l'utiliser.
La classe BusVME contient le code des procédures d'écriture et de lecture de la carte. Elles ne
permettent que la communication à travers le Bus VME.
3.1.2 Classe Carte
Cette classe sert à la gestion de la carte. Elle permet à la fois de l'initialiser et de la configurer
ainsi que de récupérer les données. Les données sont téléchargées à partir de la mémoire de la carte
physique. Cependant on doit prendre les données quatre par quatre. Cette classe vérifie donc si une voie
est demandée pour chaque série de 4 voies. Si c'est le cas, les 4 voies seront mises dans la mémoire de
l'ordinateur, sinon, les valeurs correspondantes resteront à zéro.
3.1.3 Classe Acquisition
Cette classe gère l'acquisition, le thread et la transmission des données vers le programme
graphique et de traitement des données. On peut la séparer en deux parties distinctes, chacune utilisée
par un thread différent. Les points d'interraction sont la transmission des valeurs d'une part, et, d'autre
part, le compte du nombre d'événements déjá mis en mémoire par les deux threads.
L'autre rôle important de cette classe est la communication entre l'acquisition et le programme
principal. Ce sont les méthodes de cette classe qui seront utilisées pour la gestion des cartes, de
l'acquisition et de la récupération des données. Les autres classes Carte et Bus n'ont pas à être connues
et encore moins à être utilisées dans un fonctionnement normal.
3.2 Algorithmes de lecture sur la carte
3.2.1 Récupération sur chaque carte
Le bus VME possède une partie pour le transfert des données de 32 bits, or les données
envoyées par la carte sont soit sur 8 bits soit sur 10.
Le premier cas est le plus simple. Il suffit de configurer correctement le FPGA qui gère les
quatre voies qui nous intéressent. Ensuite, pour chaque échantillon à récupérer il suffit d'aller lire un
registre de 32 bits, et cela autant de fois qu'il y a d'échantillons à récupérer et pour chaque FPGA. Les
valeurs sur 8 bits sont placées à la suite dans cet échantillon. Il suffit donc d'utiliser un opérateur et
21
binaire avec le masque correct pour n'avoir plus que les 8 bits qui nous intéressent, puis de faire un
décalage de bits ou une division par la puissance de 2 correspondante.
Dans le second cas, la totalité des valeurs (soit 40 bits) ne peut passer directement sur le bus de
32 bits. Il est donc nécessaire de lire deux registres différents à chaque fois (on peut remarquer la perte
de 24 bits). Puis on réalise comme précédemment le masque avec le et logique ainsi que le décalage de
bits.
Ces données sont ensuite mises dans une file STL. Lors de chaque transfert vers l'autre thread,
la série d'échantillons d'un événement est défilée pour être mise dans une boîte à messages. L'autre
thread n'a donc plus qu'à lire cette boîte via la fonction Acquisition::recuperer().
Les fonctions des méthodes principales :
-Carte::lancerAcquisition()
Il faut l'exécuter au lancement de l'acquisition pour chaque carte. C'est donc la méthode
Acquisition::Lancer() de la classe Acquisition qui doit le faire. Elle permet d'initialiser la carte
et de lui passer les paramètres nécessaires à sa configuration.
-Carte::acquerir()
C'est la méthode qui s'occupe de récupérer les valeurs qui sont sur la carte en nombre et
au moment voulu. Il faut donc modifier cette classe si la façon de lire la carte change. On peut
remarquer que cette méthode contient aussi la portion de code qui permet de réaliser des
exécutions du programme sans bus VME et sans carte.
-Carte::stoquer
Cette méthode permet de mettre une série de données dans la file de stockage. Elle ne
devrait donc servir que dans la méthode précédente soit Carte::acquerir().
-Carte::defiler()
Cette méthode sert juste à placer, s'il existe, le premier événement de la file dans la boîte
à messages, si elle est vide. Il faut donc la lancer avant de tenter une récupération des données
(gérée par les autres méthodes de la classe).
-Carte::recuperer()
Renvoie les échantillons de l'événement contenu dans la boîte à messages si elle est
pleine, en cas contraire la fonction renvoie NULL.
3.2.2 Tri et gestion des données demandées
C'est la classe Acquisition qui possède ces fonctionnalitées. Il s'agit de prendre une matrice
(voies, échantillons) d'un événement de chaque carte quand ils sont prés et de les trier. En effet il ne
faut renvoyer qu'une matrice contenant les voies des cartes demandées par l'utilisateur.
Dans ce but le programme regarde si des données sont prètes sur les cartes où elles n'ont pas
encore été récupérées. Cela fait, il suffit de prendre les parties de la matrice qui correspondent aux
numéros contenus dans la liste STL des voies passées en paramètre à l'ajout d'une carte à l'acquisition.
Puis il faut copier ces valeurs dans une autre matrice et la renvoyer. Il reste à la charge de
l'utilisateur de détruire cette matrice colonne par colonne, puis la matrice pour éviter les pertes
de mémoire. Il est aussi important de passer en paramètre des variables allouées
22
dynamiquement. En effet à cause des threads des variables peuvent dans le cas contraire être
considérées hors de portée alors qu'elles ne le sont pas.
Les fonctions des méthodes principales :
-Acquisition::AjouterCarte&Acquisition::RetirerCarte
Servent, comme leurs noms l'indiquent à respectivement ajouter ou enlever une carte de
l'acquisition. Attention, il ne faut surtout pas les utiliser pendant une acquisition car elles
n'auront aucun effet.
-Acquisition::Lancer
Doit être lancée par le programme principal pour concrétiser le lancement de
l'acquisition. Cette méthode sert notamment à lancer le thread d'acquisition, mais aussi à
initialiser et configurer les cartes Front-End utilisées dans l'acquisition.
-Acquisition::Stop
Sert à arrêter une acquisition avant son terme normal, par exemple si le faisceau de
particules est coupé ou incorrect et donc que les données sont inexistantes ou invalides. On peut
préciser que le thread sera arrêté plus ou moins brutalement suivant la zone d'exécution où il se
trouve.
-Acquisition::recuperer ou opérateur parenthèse
C'est la méthode qui renvoie la matrice de données si celles-ci sont récupérables et
NULL sinon. Le nombre d'événements renvoyé dépend du paramètre passé à la méthode
Acquisition::lancer().
-Acquisition::Routine
Contient la boucle principale du thread d'acquisition. Elle récupère tour à tour les
événements de chaque carte. Elle s'arrête seule lorsque le nombre d'événements est atteint ou
lors de l'appel de la méthode Acquisition::Stop(). C'est aussi elle qui gère le cheminement des
exceptions entre les deux threads.
3.3.3 Modification des paramètres (nombre de voies et de cartes)
Les constantes du programme sont toutes contenues dans le fichier defcart.hh. En cas de
modification il suffit donc de changer les valeurs contenues dans ce fichier. Attention cependant, dans
certains cas, comme par exemple le changement du nombre de FPGAs, de nouveaux registres (gain,
offset,...) qui servent à les paramétrer doivent être rajoutés dans les méthodes d'initialisation de la carte
et de lecture des registres. Les constantes principales sont :
- NOMBRE_DE_CARTES_MAX : Le nombre maximum de cartes sur lesquelles on peut
réaliser l'acquisition.
- NOMBRE_DE_VOIES : Le nombre de voies de chaque carte qui seront lues.
- NOMBRE_DE_FPGA : Le nombre de FPGAs que contient chaque carte.
De plus ce fichier contient toutes les valeurs nécessaires pour paramétrer la carte, comme par
exemple, les adresses des différents registres. Mais il contient aussi les valeurs qui permettent de
paramétrer la communication à travers le bus VME.
23
On peut aussi modifier le mode de fonctionnement du programme. La valeur __VERBOSE__
correspond au mode de recherche des erreurs avec une sortie texte qui décrit toutes les actions du
programme. Celle-ci est relativement complexe à utiliser à cause du multithread qui peut couper des
messages. La valeur __UNCONNECTED__ a servi pour des simulations d'acquisition sans carte. Elle
ne doit normalement plus être utilisée.
Les bibliothèques utilisées dans la majorité des classes sont aussi inclues dans ce fichier entête.
A son tour ce fichier doit être inclu dans tous les fichiers du driver de la carte pour assurer leur accès
aux constantes.
3.3 Réactions en cas d'erreur
La gestion des erreurs se fait grâce aux exceptions du C++. Un problème particulier se pose
cependant. En effet lorsqu'on lance une exception, on remonte dans la pile des fonctions jusqu'à la
fonction qui la rattrappe. Parfois, les exceptions qui sont lancées dans le thread doivent être gérées par
le thread d'affichage afin que l'utilisateur puisse prendre les décisions concernant leur traitement. Pour
cela les exceptions sont récupérées par la boucle principale du thread d'acquisition et mises dans une
boîte à messages pour l'affichage. Chaque méthode de la classe Acquisition susceptible d'être utilisée
par l'affichage doit donc lire cette boîte à messages et le cas échéant relancer l'exception qu'elle
contient.
Ceci pose plusieurs difficultés. D'abord il faut pouvoir copier les exceptions à partir d'un
pointeur sur leur classe mère. A cet effet une méthode void clone(void) est définie dans chaque classe
d'exception et renvoie un pointeur sur une copie d'elle même. Ce pointeur est transtipé comme pointeur
sur la classe mère. Ensuite il faut pouvoir relancer l'erreur proprement et donc déterminer sa classe pour
pouvoir la copier. Il est préférable de proscrire les gros blocks switch-case ainsi que l'opérateur typeid
puisque les deux sont peu clairs. Il reste cependant une dernière solution, une méthode void
autothrow(void) définie dans les classes exceptions et qui relance une autre exception, copie exacte
d'elle même.
Deux cas de lancement des exceptions sont donc possibles. Dans le premier cas, l'exception a
lieu dans une méthode exécutée par le thread d'affichage. C'est le cas le plus simple, l'exception est
directement rattrapée dans le programme d'affichage. Dans le second cas, l'exception apparait dans le
thread d'acquisition. Dans ce cas, elle est d'abord récupérée dans la boucle principale de ce thread. Elles
est copiée par la suite grâce à la méthode clone() dans une variable globale. Les méthodes lancées par
le thread d'affichage testent cette variable. Si elle est pleine, l'exception se relance elle-même par sa
méthode autothrow(). Il ne reste plus au thread d'affichage que de récupérer cette exception.
3.4 Résultats de la campagne d'essai
3.4.1 Campagne de juin
Cette campagne avait deux buts: vérifier que l'on arrivait bien à récupérer des données et le cas
échéant de réaliser des séries de mesures pour les physiciens.
La première partie a permis de découvrir quelques problèmes de communication avec la carte:
24
départ de valeur d'adresse à zéro au lieu de 1, décalage de début de plage mémoire ainsi que des
problèmes de synchronisation entre l'arrivée des données et celle du trigger sur la carte. Mais ces
problèmes ont pu être rapidement corrigées.
Suite à la résolution des problèmes de communication avec la carte, des séries de mesures
physiques ont pu être réalisées. Elles se sont révellées correctes et nous avons pu conclure au bon
fonctionnement du système d'acquisition. Cependant, il c'est avéré difficile de trouver les origines des
problèmes de communication en mode graphique. Il a été décidé de rajouter des fonctionnalités de tests
et de vérifications (sortie de l'état des cartes).
La chaîne d'acquisition :
Elle est constituée en premier lieu d'un scintillateur situé sur le faisceau. Il est relié par fibres
optiques à un PM. Celui-ci transforme le signal lumineux en signal électrique. Ce sigal électrique est
intégré par la carte Very Front-End. Des câbles éthernet de 22 mètres transmettent ce signal analogique
à la carte Front-End. Un câble éthernet spécifique distribue également un signal d'horloge aux cartes
Front-End et Very Front-End. Le trigger de la carte Front-End est fourni par deux scintillateurs dédiés,
lus par deux PM et mis en coincidence.
Fig. 7 Dispositif pour les tests en faisceau
25
Principales mesures réalisées:
-faisceau de pions:
Il nous a servi pour les mises en temps du détecteur avec le système d'acquisition. Il
a fallu régler le début de l'intégration du signal sur la carte Very Front-End du détecteur, et
la synchronisation de l'arrivée des données et du trigger avec le signal d'horloge.
-faisceau de muons:
Ce faisceau nous a permis de calibrer une voie du PM par rapport à sa tension
d'alimentation. Donc de faire des séries de mesures à des tensions différentes.
Ensuite nous avons pu calibrer l'ensemble des voies du PM à tension fixe soit 640V.
L'ensemble de ces deux mesures permet de voir les effets entre les voies, de mesurer
le signal sur les voies adjacentes à celle qui l'a vraiment reçue pour mesurer la diaphonie et
donc pouvoir la corriger ensuite lors du dépouillement des données.
-faisceau d'électrons:
Ces mesures ont été réalisées à des énergies du faisceau différentes, les électrons
allant de 10GeV à 100GeV. Elles ont permis de mesurer l'influence d'un événement sur les
événements suivant en fonction de l'intensité du signal. A terme cette fonction devra être
assurée automatiquement par l'électronique si la perturbation est significative.
3.4.2 Campagne d'aout
Cette seconde serie de mesure avait deux objectifs. Il fallait acquerir des données pour les
études des physiciens, ce qui permettait en même temps de valider les modifications faites au
programme notemment pour la gestion des exceptions. La mise en place du système ayant été plus
rapide et plus simple qu'en juin, plus de données ont été récupérées.
Mesures realisés:
-faisceau de pions:
D'abord le réglage de la position temporelle (soit t0) du debut de l'intégration par
rapport à l'horloge a été mesurée sur toutes les voies instrumentées (16 sur 64).
Ensuite nous avons réalisé un test d'uniformité des cellules en deplacant le faisceau
par pas de longueur d'un sixième de cellule en hauteur et en largeur pour deux cellules. Un
debordement d'un pas a aussi été fait sur deux cotés de la cellules pour la mesure de la
diaphonie, soit un total de 91 mesures.
Puis nous avons fait varier la tension du PM (550V à 850V par pas de 50) pour
vérifier la linéarite de son gain et ce sur trois voies.
Enfin nous avons refait les mesures du t0, mais avec différentes valeurs de la
tension du PM sur deux voies différentes.
-faisceau d'électrons
En premier lieu nous avons vérifié que le t0 d'intégration pour les signaux
d'électrons coincide avec celui des signaux des muons et des pions.
Aprés nous avons pris de longues séries de mesures avec des faisceaux d'électrons
de différentes énergies (5, 10, 20 et 30 Gev) pour vérifier la linéarite des signaux digitaux
avec l'énergie déposée dans le détecteur de pied de gerbe.
26
Conclusion
La création de cette bibliothèque m'a permis d'appréhender les différentes possibilités et
contraintes de l'utilisation des threads en C++, de la gestion des exceptions et de la communication
avec le matériel à travers un bus VME. Ceci m'a permis de mettre en commun mes connaissances sur le
logiciel et le matériel, notemment grâce à la gestion de la carte et celle du bus. Les mesures sur le
faisceau au CERN m'ont aider a mieux percevoir les difficultées pratiques du problème, installation du
matériel et mise en place de l'acquisition. En effet la chaîne d'acquisition de cette partie du détecteur est
longue.
Sur le terrain j'ai donc pu constater de la difficultée à attribuer à une voie du logiciel sa voie
correspondante sur le PM. Il serait donc pratique de créer un logiciel qui prend en compte les
connections et croisements sur toutes la chaîne d'acquisition, et qui indique la correspondance entre les
voies de manière automatique. Une telle application pourrait être réalisable en php et donc utilisable
directement à partir de l'internet.
27
Bibliographie
[1] National Instruments Corporation. NI-VXI Software Reference Manual for C, October 1994
[2] www.ift.ulaval.ca/~beaulieu/ift21459 LA PROGRAMMATION CONCURRENTE, Janvier 2000
[3] Rene Brun&Fons Rademakers. ROOT Reference Guide, root.cern.ch/root/Reference.html,
19/01/2002
[4] Bruno Garcia. Le C++ pour les pro, ISIMA, 1999
[5] Brian W. Kernigan et Denis M. Ritchie. Le language C Norme ANSI , 1990
[6] Remi Cornat. Carte PSFEE Proto2, Version « release 0 », 22 avril 2002
28
Annexe
A - Aide du logiciel
B - Photos d'écran de l'interface d'acquisition
C - Code source
33
36
38
29
A Aide du Logiciel
Cette aide en HTML est disponible à partir du logiciel et aussi sur l'intranet du laboratoire.
30
dernière modification:
2.09.02
Aide pour acquisition sur la carte PSFEE avec festen
Comment commencer
Comment éteindre
Gestion du driver VME avec nivxi
Normalisation des noms de fichiers
Utilisation de festen
Solutions aux problèmes fréquents
Comment commencer?
allumez l’ordinateur avec sa disquette de boot dans le lecteur (elle ne doit pas en sortir);
connectez-vous avec l’utilisateur testbeam et ouvrez un terminal;
tapez la commande: "mount /home/microelec/data";
vérifiez que le bus VME est allumé, sinon allumez-le;
initialisez le bus VME avec la commande: "/usr/local/nivxi/bin/resman";
préparez le répertoire où seront sauvegardées les données et y allez:
allez sur le disque oú sont sauvegardées toutes les données: "cd /home/microelec/data";
placez-vous dans le répertoire du jour ou créez en s’il n’a pas été encore crée;
créez un répertoire pour le type d’acquisition (par exemple réglage t0, mesure d’énergie
de particule x dans condition alfa);
se placer dans ce répertoire.
lancez la commande " festen";
lancez une acquisition. Des explications sur l’utilisation de festen sont disponibles ici et en
cliquant sur le bouton "Help", situé à droite dans le menu du programme.
Comment aller se coucher?
si personne ne prend la relève: arretez festen;
lancez la commande: "umount /home/microelec/data";
se déloguer et éteindre l’écran.
Gestion du driver VME avec nivxi
avant de lancer une acquisition et après chaque arrêt ou manipulation sur le bus VME ou la
carte, lancez: "/usr/local/nivxi/bin/resman";
en cas d’arrêt brutal du logiciel d’acquisition le relancer en exécutant au préalable :
"/usr/local/nivxi/bin/vxiclean".
Normalisation des noms de fichiers
tb-juin2002-(numéro de l’acquisition).evt dans le bon répertoire;
remplissez le petit calepin à coté.
Utilisation de festen
créer un répertoire pour y sauvegarder vos données;
31
lancer la commande festen à partir de ce répertoire; vous pouvez également la lancer ailleurs,
mais il vous faudra remonter à ce répertoire pour définir le fichier où les données seront
sauvegardées.
Une boite de dialogue apparait.
Avant de lancer une acquisition, il faut définir quelques paramètres (ou vérifier qu’ils sont bien
définis!) :
le nom du fichier oú les données seront sauvegardées -> dans le menu FILE
les paramètres du RUN -> dans le menu CONFIGURE -> Configure Run
les paramètres de la carte PSFEE -> dans le menu CONFIGURE -> Configure Card
les voies de la carte PSFEE que vous désirez lire et celles à monitorer en temps réel -> dans
le menu SELECT FE CHANNELS (en dessous du menu)
Pour lancer, arrêter, sauvegarder un run -> le menu RUN :
Stop Run pour arrêter un run bloqué
Save Run pour sauvegarder un run stoppé, sinon en cas de run réussi la sauvegarde est
automatique.
Monitoring en temps réel des données -> le menu RUN MONITOR :
appuyer sur Refresh Hists si les histogrammes ne s’affichent pas
appuyer sur Normalise pour afficher la moyenne sur tous les échantillons
Print Hists
Save Hists
Info Hists
Solutions aux problèmes fréquents
La carte est bloquée:
Arrêter festen
Eteindre le bus puis le rallumer
Ensuite lancez successivement:
"/usr/local/nivxi/bin/vxiclean"
"/usr/local/nivxi/bin/resman"
Relancer festen dans le bon répertoire(Ne pas oublier de rentrer les bons paramètres)
La carte ne reçoit plus de trigger:
Soit il n’y a pas de beam alors patientez, soit vous avez touché un fil qu’il ne fallait pas, soit
c’est plus grave
En cas de coupure du chassis
toujours éteindre le logiciel d’acquisition puis lancer les 2 commandes
"/usr/local/nivxi/bin/vxiclean"
"/usr/local/nivxi/bin/resman"
32
Resman ou vxiclean donnent des messages d’erreurs
Arrêter puis relancer le système
Ne pas oublier la commande umount de préférence
Des messages d’erreurs s’écrivent sur le terminal
Break ou segfault => arreter puis relancer festen
Error to write on bus => Idem carte bloquée
33
B Photos d'écran de l'interface d'acquisition
Interface : Feuillet de choix des voies d'acquisition
34
Interface : Feuillet des histogrammes
35
C Code source
BusInterface :
Contient les méthodes qui doivent être redéfinies dans une sous classe Bus (Bus VME)
Dans le cas où l'on souhaite définir un autre bus il faut d'abord redéfinir ces méthodes dans une
classe qui en dérive. Ensuite il faut déclarer le fichier qui contient cette nouvelle classe dans
Acquisition.hh et Carte.hh (soit #include "nouveaubus.hh"). Ensuite il suffit de remplacer les appels à
BusVME::Connecter() dans le constructeur de la classe Acquisition et celui de la classe Carte par
nouveaubus::Connecter(). Ceci fait le programme devrait marcher avec le nouveau bus.
BusVME :
Les paramètres nécessaires à ces méthodes ne sont dépendant que de la carte. En cas de
modification, il ne devrait pas y avoir de changement à faire si ce n'est pour l'adresse physique de la
carte. En effet celle-ci peut ne plus exister ou avoir besoin d'un format différent (!!! Attention car dans
ce cas la modification du programme sera plus longue mais restera simple).
Connecter() : Renvoie un pointeur sur la classe Bus. Lors de la première création il lance la
méthode init().
Configurer() : Pour écrire à un FPGA de la carte. Lorsqu'une erreur d'écriture est détectée il
tente de reécrire la valeur avant de lancer un exception si l'erreur provient de NIVXI ou de continuer
avec un Warning en cas de relecture demandée par l'utilisateur.
ConfigurerTous() : Pour écrire à tous les FPGAs (impossible actuellement au niveau de la
carte)
lireParametre() : Pour lire un registre sur un des FPGAs (voie ou FPGA VME). Lorsqu'une
erreur de transfert sur le bus VME est détectée (retour d'erreur de la library NIVXI) il tente de relire la
valeur avant de lancer un exception.
init() : Initialise le driver NIVXI grâce à la fonction InitVXIlibrary() de la bibliothèque
<nivxi.h> .
Carte :
acquerir() : Cette méthode commence par une partie de simulation d'acquisition qui fonctionne
en mode __UNCONNECTED_ (constante dans defcart.hh) . Ensuite le début de l'acquisition réelle
consiste à regarder le nombre d'échantillons présent dans la mémoire de la carte. Quand la mémoire est
pleine, on lit le nombre d'échantillons dans les autres FPGAs afin de détecter tout bloquage. Ensuite on
paramètre la carte pour la récupération des données soit en mode download. Puis, suivant la
configuration 8 ou 10 bits avec ou sans autoincrémentation, on utilise l'algorithme qui correspond.
De manière générale on vérifie si une des 4 voies est demandée sur chaque FPGA. Si oui on
récupère le nombre d'échantillons correspondant au nombre d'événements mémorisable dans la
mémoire de la carte. Ces échantillons sont mis dans des listes. Le passage de la valeur prise sur le bus
aux données est réalisée grâce à un 'ET' logique avec un masque puis un décalage de bit. Ensuite on
demande à la carte de vider sa mémoire (vme_daq_rstramadd_ofst).
36
On classe ensuite les échantillons récupérés 4 voies par 4 voies pour avoir chaque échantillon
sur l'ensemble des voies Enfin on envoie les échantillons à la méthode stoquer() pour les passer à la
suite du traitement.
lancerAcquisition() : Initialise tous les paramètres de la carte pour commencer l'acquisition.
- La lecture autoincrémentée ou non, vme_mode_ofst
- Mise en mode LA (N échantillon par trigger), vme_daq_mode_ofst
- La longueur du pipeline, vme_daq_plen
- Le délais sur le trigger, vme_daq_trigdly_ofst
- Le nombre d'échantillons stocké avec un trigger en mode LA, vme_daq_law_ofst
- Le nombre d'événements maximum stockable sur la carte, vme_daq_nevtmax_ofst
- La correction de l'empilement, vme_alpha_ofst
- Valeur du seuil pour le bit de trigger, vme_threshold_ofst
- La correction des piedestaux, vme_pedestal_ofst
- Les offsets, vme_offset0_ofst et vme_offset1_ofst
- Les gains, vme_gain0_ofst et vme_gain1_ofst
- La configuration du traitement des données, vme_processcfg_ofst
Pour finir on initialise les registres d'adresse.
stoquer() : Sert à mettre les échantillons dans les files d'attente (de type deque<int> de la STL).
Un vérou est nécessaire pour éviter un enfilage et un défilage simultanné. Pour explication, la partie de
code qui est compris entre les deux fonctions pthread_mutex_lock(zone_dangeureuse) et
pthread_mutex_unlock(zone_dangeureuse) ne sera pas exécuté en même temps qu'une partie de code
entre les mêmes balises d'un autre thread. La fonction pthread_mutex_trylock() permet d'exécuter le
code si il n'ait pas vérouillé et de passer à la suite sinon.
defiler() : Met un événement de la file d'attente (soit un nombre d'échantillons par événement
paramétré) dans le buffer pour l'acquisition. Cette méthode possède un vérou.
clean() : Permet de remettre les paramètres dans leurs états initiaux, ainsi que de vider les
buffers de donnée (file et boîte à messages).
Acquisition :
Initialiser() : Permet de créer une instance de la classe Acquisition. Tout appel postérieur à
cette méthode renverra un pointeur sur la première instance, en effet on ne peut pas lancer deux
acquisitions au même moment. Cette méthode crée aussi l'instance de Bus. Elle configure aussi la
gestion des threads. Pour éviter des problèmes de données passant hors de porté il vaut mieu créer les
emplacements mémoire des variables qui lui sont passées en paramètre par pointeur ou référence avec
des new.
recuperer() : Cette méthode lit les boites à message de chaque carte, trie les voies demandées
par l'utilisateur et concatène les données de toutes les cartes lorsqu'elles sont prètes. Pour cela, chaque
carte est défilée (utilisation de Carte::defiler() pour mettre un événement dans la variable lu par la
méthode recuperer() ). Ensuite on tente de récupérer les données de chaque carte qui n'a pas encore
renvoyée cet événement.
Si toutes les données ne sont pas récupées, la méthode renvoie NULL pour que l'interface
puisse continuer son exécution, sinon elle renvoie l'événement (et libère sa variable pour l'événement
suivant).
La place mémoire pris par les donnée doit être libéré pour éviter les fuites de mémoires. D'abord
37
avec une libération de chaque voie puis celle de la donnée elle-même. Les données sont renvoyées par
un pointeur de type int** contenant une matrice[nombre de voies][nombre d'échantillons].
Lancer() : Cette méthode lance le thread d'acquisition pour un nombre d'événements
paramétrable. Si ce nombre est à -1 la durée de l'acquisition est indéterminée. C'est donc cette méthode
qui va lancer réellement le programme d'acquisition en parallèle en appelant pthread_create().
Stop() : Demande au thread d'acquisition de s'arreter proprement. Aprés deux secondes la
méthode considère que le thread est bloquée et le détruit brutalement grâce à la fonction
pthread_cancel().
AjouterCarte() : Teste si la carte n'est pas déja présente puis si le nombre de cartes maximum
n'est pas atteint. Ensuite elle ajoute la carte à la liste des cartes de l'acquisition
RetirerCarte() : Retire une carte de l'acquisition si elle y est présente et si aucune acquisition
est en cour.
TestException() : Lancée par toutes les méthodes de l'acquisition utilisées par l'interface
graphique. Elle relance une exception émise dans le thread d'acquisition. Elle déclare de plus que cette
exception a été relancé en vidant le pointeur qui la contient
Routine() : A son lancement elle fait débuter l'acquisition sur chaque carte avec la méthode
Carte::lancerAcquisition(). Ensuite elle rentre dans sa boucle principale est lance la méthode
Carte::Acquerir() jusqu'à ce que le nombre d'événements requis soit acqueri, ou que la fin de
l'acquisition soit demandée. Cette routine doit aussi gérer les passages d'exception d'un thread à l'autre.
D'où l'utilité des blocks try et catch de cette routine, sans eux le programme s'arreterait à chaque
exception.
Exception :
Les exceptions sont directement différenciées par le nom de leur classe qui explicite le
problème sur lequel elles sont lancées.
ErrGen : Classe d'exception générale de tout le programme
CarteErreur : Classe générale des exceptions sur la classe Carte
CarteErreurInitialisation : Erreur d'initialisation de la carte physique (toujours lancé apré
avoir tenté d'initialiser le reste de la carte malgrés tout)
CarteErreurFPGA : Au moins un des FPGA est désynchroniser fortement des autres
BusErreur : Classe générale d'exception sur un Bus
BusVMEInitialisationError : Erreur d'allocation du bus VME soit de InitVXILibrary()
BusVMeReadError : Erreur de lecture sur le bus VME VXIin (En cas d'erreur de transfert une
double tentative est effectuée)
BusVMeWriteError : Erreur d'écriture sur le bus VME VXIout (En cas d'erreur de transfert
une double tentative est effectuée)
AcquisitionErreur : Classe générale des exceptions sur la classe Acquisition
AcquisitionErreurUtilisation : Classe générale des exceptions d'utilisation illogique de la
classe
AcquisitionErreuDoubleLancement : Lancement demandé lors d'une acquisition en cour
AcquisitionTropDeCarte : Acquisition demandée sur trop de carte voir typedef.hh
AcquisitionErreurManipulationCarte: Carte manipulée durant l'acquisition (ajout ou retrait)
38
Clone() : Renvoie un pointeur sur une copie de la classe (ce pointeur est casté sur un type erreur
générale pour être traité génériquement).
autothrow() : Lance une exception copie exacte de la classe.
Les constantes : La déclaration en static const permet de définir des constantes avec une vérification
de la compatibilité des types lors de la compilation au contraire des déclarations en #define simples
macros recopiées dans le code.
39
Imprimé par Maxime Fia
08 aoû 02 14:28
BusInterface.hh
Page 1/1
//Fichier ./BusVME/BusInterface.hh
//Classe interface pour la comunication a travers un bus
// !!! Cette classe est virtuelle il faut la deriver !!!
// Pour utiliser un autre bus il faut creer une classe fille et
//redefinir chacune des methodes
// De plus il faut modifier les BusAncien::connecter par
//
BusNouveau::conecter
//[email protected]
#ifndef __BUSINTERFACE_HH__
#define __BUSINTERFACE_HH__
#include "defcart.hh"
class BusInterface
{
public:
//fonction pour renvoyer un pointeur sur une classe fille Bus???
static BusInterface* Connecter()
{
return NULL;
}
//Pour configurer un chip specifique sur une carte
virtual int configurer(UINT32 adresseCart, UINT32 chip, UINT32 ins, UINT32 of
fst, UINT32 data, int relecture=−1)=0;
//Pour configurer tous les chips de la meme maniere
virtual int configurerTous(UINT32 adresseCart, UINT32 ins, UINT32 offst, UINT
32 data, int relecture=−1)=0;
//Pour lire un parametre d’un chip
virtual UINT32 lireParametre(UINT32 adresseCart, UINT32 chip, UINT32 ins, UIN
T32 offst, UINT32 *data)=0;
virtual ~BusInterface()
{
}
protected:
BusInterface()
{
#ifdef __VERBOSE__
cout << " Creation Interface " << endl;
#endif
}
static int NombreInstance_;//Nombre d’instance de bus
static BusInterface *Interface_;//Pointeur sur l’interface
private:
//Pour initialiser le bus
virtual void init()=0;//Pour initialiser le bus
};
#endif
lundi 09 septembre 2002
BusVME/BusInterface.hh
Imprimé par Maxime Fia
02 sep 02 11:43
BusInterface.cc
Page 1/1
//Fichier ./BusVME/BusInterface.cc
//Methodes externes de BusInterface et declaration des static
#include "BusInterface.hh"
int BusInterface::NombreInstance_=0;
BusInterface* BusInterface::Interface_=NULL;
lundi 09 septembre 2002
BusVME/BusInterface.cc
Imprimé par Maxime Fia
08 aoû 02 14:29
BusVME.hh
Page 1/2
//Fichier BusVME.hh
//Classe pour la comunication a travers un bus VME
//
//[email protected]
08 aoû 02 14:29
Page
//Constructeur du BusVME
BusVME() throw (BusVMEInitialisationError)
{
try
{
BusInterface();//Appel constructeur classe mere
#ifdef __VERBOSE__
cout << "Creation du Bus VME" << endl;
#endif
this−>init();//On initialise le bus et la bibliotheque de communicat
}
catch(...)
{
NombreInstance_=0;
Interface_=NULL;
throw;
}
}
//!Attention on ne peut utiliser que des pointeurs sur cette classe
//On le recupere par BusInterface* BusVME::Connecter(void)
#ifndef __BUSVME_HH__
#define __BUSVME_HH__
#include "BusInterface.hh"
class BusVME : virtual public BusInterface
{
public:
//Permet de connecter une BusInterface a un BusVME
//Un patern singleton permet de ne recuperer qu’un seul pointeur
//sur BusVME (car il n’y a au’un seul Bus)
static BusInterface* Connecter() throw (BusVMEInitialisationError)
{
#ifdef __VERBOSE__
cout << "Connection a l’interface" << endl;
#endif
if (!NombreInstance_)//Creer pour le premiere fois
{
++NombreInstance_;//On incemente le nombre d’instance
Interface_ = dynamic_cast<BusInterface*>(new BusVME);//On cree l
’instance
private:
//Pour initialiser le BUSVME et sa bibliotheque
virtual void init() throw (BusVMEInitialisationError);
//static int NombreInstance_;
//static BusVME *Interface_;
};
#endif
}
return Interface_;//Renvoyer un pointeur sur une interface deja cree
}
//Pour configurer un chip de la carte adresseCar
virtual int configurer(UINT32 adresseCart, UINT32 chip, UINT32 ins, UINT32 o
ffst, UINT32 data, int relecture=−1) throw (BusVMEWriteError,BusVMEReadError);
//Pour configurer tous les chips d’une carte
virtual int configurerTous(UINT32 adresseCart, UINT32 ins, UINT32 offst, UINT
32 data, int relecture=−1) throw (BusVMEWriteError,BusVMEReadError);
//Pour lire un parametre ou une donnee
virtual UINT32 lireParametre(UINT32 adresseCart, UINT32 chip, UINT32 ins, UIN
T32 offst, UINT32 *data) throw (BusVMEReadError);
virtual ~BusVME()//Destructeur de bus VME
{
#ifdef __VERBOSE__
cout << "Liberation du Bus VME" << endl;
#endif
−−NombreInstance_;
Interface_=NULL;
CloseVXIlibrary();//Liberation de la memoire dynamique alloue pour la gesti
on du bus
}
protected:
lundi 09 septembre 2002
BusVME.hh
BusVME/BusVME.hh
Imprimé par Maxime Fia
02 sep 02 11:44
BusVME.cc
Page 1/3
//Fichier ./BusVME/BusVME.cc
//methodes externes de BusVME
02 sep 02 11:44
#include "BusVME.hh"
//int BusVME::NombreInstance_=0;
//BusVME* BusVME::Interface_=NULL;
int BusVME::configurer(UINT32 adresseCart,UINT32 chip,UINT32 ins,UINT32 offst,UI
NT32 data, int relecture=−1)
throw (BusVMEWriteError,BusVMEReadError)
{
#ifndef __UNCONNECTED__
int ret;
#endif
UINT32 adresse=0;//initialisation de l’adresse d’ecriture
//adresse = @2base , nfpga*2^16, instruction*2^9, offset*4
adresse = adresseCart|(chip*8192)|(ins*512)|(offst*4);//Calcule de l’adresse
#ifdef __VERBOSE__
cout<<"ecriture VME: "<<std::hex<<adresse<<std::dec<<" data: "<<data<< endl;
#endif
#ifndef __UNCONNECTED__
if ((ret=VXIout(VME_A32,adresse,VME_D32,data))!=0)//ecriture sur le bus
{
//cout << "WARNING!!!: Error to write on VME bus"<<endl;
if (ret==−1)//Si erreur de transfert
{
cerr << "WARNING!!!: Transfert Error on VME bus (write)"<<endl;
if ((ret=VXIout(VME_A32,adresse,VME_D32,data))!=0)//On retente
{
cerr << "WARNING!!!: Error to write on VME bus"<<endl;
throw BusVMEWriteError(ret);//Transfert a echoue 2fois
}
else return 1;//second transfert succesfull
}
else throw BusVMEWriteError(ret);//Erreur problematique
Page
//Broadcast => bit n15 a 1 donc 2^15=32768
adresse = adresseCart|(32768)|(ins*512)|(offst*4);
#ifdef __VERBOSE__
cout << "Ecriture tous les chips"<<std::hex<< adresse <<std::dec << endl;
#endif
#ifndef __UNCONNECTED__
if ((ret=VXIout(VME_A32,adresse,VME_D32,data))!=0)//ecriture sur le bus
{
cerr << "WARNING!!!: Error to write on VME bus (broadcast mode)"<<endl;
return 0;
}
#endif
return 1;
}
//−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
UINT32 BusVME::lireParametre(UINT32 adresseCart, UINT32 chip, UINT32 ins, UI
offst, UINT32 *data)
throw (BusVMEReadError)
{
#ifndef __UNCONNECTED__
int ret;
#endif
UINT32 adresse=0;//initialisation de l’adresse
//Calcul de l’adresse de recuperation de la donnee sur la carte
adresse=(adresseCart)|(chip*8192)|(ins*512)|(offst*4);
#ifdef __VERBOSE__
cout << "lecture d’un registre "<< std::hex << adresse << std::dec;
#endif
#ifndef __UNCONNECTED__
return 0;//Retour erreur normalement impossible
}
//Lecture sur le bus
if ((ret=VXIin(VME_A32,adresse,VME_D32,data))==0)//lecture sur le bus
{
#ifdef __VERBOSE__
cout << " lut: "<< std::hex <<*data<< std::dec << endl;
#endif
}
else
{
#ifdef __VERBOSE__
//erreur
cout <<"WARNING!!!"<<endl;
cout<< "Error to read adress "<<adresse<<":"<<data<<endl;
cout<< "Error number: "<<ret<<endl;
#endif
if (ret==−1)//Si erreur de transfert
{
cerr << "WARNING!!!: Transfert Error on VME bus (read)"<<endl;
if ((ret=VXIin(VME_A32,adresse,VME_D32,data))==0)//relecture sur
if (relecture!=−1)//si demande on reli
{
UINT32 relu=0;
lireParametre(adresseCart,chip,ins,offst, &relu);//relecture
if (data!=relu)//on compare
{//aie different
cerr<< "Warning!!!: Retry to write on board memory"<<endl;
if (relecture)
configurer(adresseCart,chip,ins,offst,data, (−−relecture));//on reec
ri
else return 0;
}
}
#endif
return 1;//OK
}
int BusVME::configurerTous(UINT32 adresseCart, UINT32 ins, UINT32 offst, UINT32
data, int relecture=−1)
throw (BusVMEWriteError,BusVMEReadError)
lundi 09 septembre 2002
BusVME.cc
{
#ifndef __UNCONNECTED__
int ret;
#endif
UINT32 adresse=0;//initialisation de l’adresse
us
BusVME/BusVME.cc
{
return 1;//C bon
Imprimé par Maxime Fia
02 sep 02 11:44
BusVME.cc
Page 3/3
}
}
throw BusVMEReadError(ret);//Erreur
}
//return 0;
#endif
return 1;
}
//−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
void BusVME::init()
throw (BusVMEInitialisationError)
{
#ifdef __VERBOSE__
cout << "Initialisation de la librairie VXI" <<endl;
#endif
#ifndef __UNCONNECTED__
int ret;
if ((ret = InitVXIlibrary()) < 0)//Initialisation de la librairie VXI pour l
e bus VME
{
throw BusVMEInitialisationError(ret);//Erreur de retour
}
#endif
}
lundi 09 septembre 2002
BusVME/BusVME.cc
Imprimé par Maxime Fia
02 sep 02 11:39
Carte.hh
Page 1/4
//Fichier ./CartePSFEE/Carte.hh
//Classe pour la gestion d’une carte PSFEE
//
//[email protected]
#ifndef __CARTE_HH__
#define __CARTE_HH__
#include <deque>
#include <set>
#include "defcart.hh"
#include "Acquisition.hh"
#include "BusVME.hh"
class Carte
{
Page
#ifdef __WITH_MUTEX__
pthread_mutex_init(&mutex_carte_,NULL);//initialisation du verrou de t
d pour la carte
#endif
}
public:
//Ami avec la routine pour pouvoir stoquer les donnees
friend class Acquisition;
//Constructeur de Carte avec son adresse en parametre
//ainsi qule la liste des voies
explicit Carte(UINT32 monadresse, const set<int> *voies, int nombreEchantillo
n,int tailleMemoire, int nombreDeBit,
UINT32 daq_trigdly, UINT32 alpha,
UINT32 offset0[NOMBRE_DE_FPGA],UINT32 offset1[NOMBRE_DE_FPGA],
UINT32 gain0[NOMBRE_DE_FPGA],UINT32 gain1[NOMBRE_DE_FPGA],
UINT32 threshold,UINT32 daq_plen,UINT32 processcfg, UINT32 pedestal)
throw (BusVMEInitialisationError):
monadresse_(monadresse), nombreEchantillon_(nombreEchantillon),
tailleMemoire_(tailleMemoire), nombreDeBit_(nombreDeBit),
daq_trigdly_(daq_trigdly),alpha_(alpha),threshold_(threshold),
daq_plen_(daq_plen),processcfg_(processcfg),pedestal_(pedestal)
{
#ifdef __VERBOSE__
cout <<"Creation de la carte d’adresse: "<<std::hex<< monadresse_<<endl;
#endif
lundi 09 septembre 2002
Carte.hh
*voiesaff_=*voies;
donneeready_=false;//Pas encore de donnee
dernieredonnnee_= NULL;//pas de derniere donnee stocke
nombreDeVoies_=voies_−>size();//D’apres la taille du set
nbdonneenattente_=0;//Pas de donnee en attente
switch(nombreDeBit_)//si l’on veu en 8 ou 10 bits
{
case 108://Lecture 8 bit incremente manuellement
case 8:
nbEchParAcq_=static_cast<int>( tailleMemoire_− nombreEchantillon
/En octet donc un ech/8bit
break;
case 10://10bit 1ech/2octet
nbEchParAcq_=(int)(tailleMemoire_/2−nombreEchantillon_);//nombre
ntillon_;
break;
}
//Pour recuperer les donnees
//int** Carte::recuperer(); ou le int** represente un tableau de taille
// de NOMBRE_DE_VOIES de tableau de taille nombre d’echantillon
// !!! Attention throw BusVMEInitialisationErroe !!!
//try
//{
bus_=BusVME::Connecter();//Connection au bus
//}
//catch(){//Re−initialiser les statics}
// !!! !!! !!! !!! !!! !!! !!! !!!
for (int i=0;i<NOMBRE_DE_FPGA;++i)
{
offset0_[i]=offset0[i];
offset1_[i]=offset1[i];
gain0_[i]=gain0[i];
gain1_[i]=gain1[i];
}
voies_=voies;
voiesaff_= new set<int>;
02 sep 02 11:39
//Destructeur avec liberation du pointeur
~Carte()
{
#ifdef __VERBOSE__
cout << "Destruction de la carte d’adresse: " << monadresse_ << endl;
#endif
if (dernieredonnnee_)
delete[] dernieredonnnee_;
}
//Permet de recuperer un pointeur sur les plus anciennes donnes stoque
//ATTENTION: Renvoie NULL si pas de donnees presentes
int** recuperer();//Recupere tous le tableau
//Renvoi l’adresse de la carte
UINT32 adresse()
{
return monadresse_;
}
//Renvoie le nombre de voies
int nombreDeVoies()
{
return nombreDeVoies_;
}
//Renvoie le nombre d evenement en stock
int nbEventWaiting()
{
#ifdef __WITH_MUTEX__
pthread_mutex_lock(&mutex_carte_);//Debut de code verouille
#endif
int val=((int)(nbdonneenattente_/nombreEchantillon_)+((donneeready_)?1
;
#ifdef __WITH_MUTEX__
pthread_mutex_unlock(&mutex_carte_);//Fin de code verouille
CartePSFEE/Carte.hh
Imprimé par Maxime Fia
02 sep 02 11:39
Carte.hh
Page 3/4
#endif
02 sep 02 11:39
return val;
}
//Renvoie la liste des voies
const set<int>* listevoie()
{
return voiesaff_;
}
#endif
//Fonction pour acquerir les donnees
void acquerir() throw (BusVMEWriteError, BusVMEReadError, CarteErreurFPGA);
//stopperAcquisition()
void lancerAcquisition(int evenement) throw (BusVMEWriteError, BusVMEReadErro
r, CarteErreurInitialisation);
//Renvoie les parametres de la carte si possible
ostream & Carte::Etat(ostream &o);
protected:
//vider les buffers, reinitialiser les variables et sorties
void clean();
private:
//Pour stoquer des donnees sur la carte
//Prend les donnees en parametre
void stoquer(int tab[NOMBRE_DE_VOIES]);
//Met le premier element de la file(si elle n’est pas vide)
//dans le buffer si il n’est pas vide non plus
void defiler();
UINT32 monadresse_;//Adresse de la carte
int nombreDeVoies_;//Valeur directe du nombre de voies utilisees sur la carte
int **dernieredonnnee_;//Buffer des donnees a transferer
bool donneeready_;//Des donnees sont pretes
int nbdonneenattente_;//Nombre de donnees en attentes
const set<int> *voies_;//Tableau de la liste des voies pour thread acquisition
set<int> *voiesaff_;//Tableau de la liste des voies pour thread affichage
deque<int> donneenattente_[NOMBRE_DE_VOIES];//Files des donnees en attente
BusInterface *bus_;//La classe bus sur lequel est la carte
int echantillonRestantALire_;
int nombreEchantillon_;//nombre d’echantillon par trigger
int nbEchParAcq_;//nombre d’echantillon par acquisition
int tailleMemoire_;//taille de la memoire de la carte
int nombreDeBit_;//Acquisition en 8 ou 10 bit
UINT32 daq_trigdly_,alpha_;
UINT32 offset0_[NOMBRE_DE_FPGA],offset1_[NOMBRE_DE_FPGA];
UINT32 gain0_[NOMBRE_DE_FPGA],gain1_[NOMBRE_DE_FPGA];
UINT32 threshold_,daq_plen_;
UINT32 processcfg_,pedestal_;
#ifdef __WITH_MUTEX__
pthread_mutex_t mutex_carte_,mutex_data_ready_;//verrou de thread
#endif
};
lundi 09 septembre 2002
Carte.hh
//sortie des parameres sur la carte physique
ostream &operator<< (ostream &o, const Carte &card);
CartePSFEE/Carte.hh
Page
Imprimé par Maxime Fia
02 sep 02 11:41
Carte.cc
Page 1/14
//Fichier ./CartePSFEE/Carte.cc
//Classe pour la gestion d’une carte PSFEE
02 sep 02 11:41
Carte.cc
#include "Carte.hh"
#include <pthread.h>
//On verifie si on veu acquerir moins de donnees que la capacite de la carte
if ((echantillonRestantALire_!=−1)&&(echantillonRestantALire_<nbEchParAcq_))
nbEchParAcq_=echantillonRestantALire_;//Si oui on ne recupere que le nomb
oulu
#ifdef __UNCONNECTED__
#include <unistd.h>
#endif
while(nbEchALire<nbEchParAcq_)//test nombre d’echantillon sur la carte
{
bus_−>lireParametre(monadresse_, 0,vme_daqreg,vme_daq_nevtcurrent_ofst,&d
;
int nbit_s=0;//Pour la simulation d’acquisition non connecte
#ifndef __UNCONNECTED__ //deb temp1
UINT32 olddata=0;
#endif
//fin temp1
void Carte::acquerir() throw (BusVMEWriteError,BusVMEReadError,CarteErreurFPGA)
{
#ifdef __VERBOSE__
cout << "On acquiert sur: " << std::hex << monadresse_ <<std::dec<< endl;
#endif
//calcul provisoire du au non reset de la variable, taille memoire=512
nbEchALire=(unsigned)(data*nombreEchantillon_);//(olddata>data)?(512−oldd
data):(data−olddata);
//#ifdef __VERBOSE__
//cerr<<"data= "<< data<<endl;
//#endif
//−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−debug
//UINT32 test;
//bus_−>lireParametre(monadresse_, 3,vme_daqreg,vme_daq_nevtcurrent_ofst,&te
//cerr<<"data4= "<< test<<endl;
#ifdef __UNCONNECTED__//Simulation
int echantillon_s[NOMBRE_DE_VOIES];
for (int i_s=0; i_s < NOMBRE_DE_VOIES;++i_s)
{
echantillon_s[i_s]=0;//Mise a zero (inutile mais...)
}
{//Teste si un fpga est bloque
UINT32 tab[NOMBRE_DE_FPGA];//pour ranger les valeurs nbevent de chaque fp
int i=0;//Pour les fpga
int mul=1,add=0;
for (i=0;i<NOMBRE_DE_FPGA;++i)
{
bus_−>lireParametre(monadresse_,i,vme_daqreg,vme_daq_nevtcurrent_ofst,
[i]);//chaque fpga
mul*=tab[i];//A zero si 1FPGA a 0
add+=tab[i];//La somme
}
//Si au moins 1 a zero et la moyenne des autres >3
if ((mul==0)&&(add>10))//(int)(nbEchParAcq_/NOMBRE_DE_FPGA)
{//Liste des fpga avec un probleme
char chain[NOMBRE_DE_FPGA*2]="
";//Chaine vide (espace)
for (i=0;i<NOMBRE_DE_FPGA;++i)
if (!tab[i])//Si erreur
chain[2*i]=’0’+i;//numero du FPGA
cout << "WARNING!: Simulation of acquisition ";
cout << " __UNCONNECTED__ is defined" << endl;
for (set<int>::iterator it_s=voies_−>begin();it_s!=voies_−>end();++it_s)
{//Pour chaque voie ou se fait l’acquisition
echantillon_s[(*it_s)]=(int)( (*it_s)+100*nbit_s );
#ifdef __VERBOSE__
cout << "ech" << (*it_s) << "="<< echantillon_s[(*it_s)] << " ";
#endif
}
//usleep( ((unsigned long)(025000)) );
nbit_s++;//iteration suivante, !!! JAMAIS remis a zero
for (int i_s=0;i_s<nombreEchantillon_;++i_s)
stoquer(echantillon_s);//Stock des echantillons produits
chain[NOMBRE_DE_FPGA*2−1]=’\0’;//Fin de chaine par securite
throw CarteErreurFPGA(chain);//Exception fpga bloque
}
#endif
//−−−−−−−−−−−−−−−−−−−−−−−−−−−−− CONNECTED −−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
}
//alouer la matrice voie nb echantillon
int *echantillon[NOMBRE_DE_VOIES];//creaton du tableau des voies
int echantillonrenvoye[NOMBRE_DE_VOIES];
UINT32 data;
data=0; //Initialisation avant premiere lecture
int nbEchALire=0;
//−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−debug
}
#ifndef __UNCONNECTED__
//Lire le nombre d’echantillon lu
#endif
//Si superieur ou egal continuer
#ifdef __VERBOSE__
cout << "nb event OK" << endl;
#endif
lundi 09 septembre 2002
Page
//bus_−>lireParametre(monadresse_, 0,vme_daqreg,vme_daq_nevtcurrent_ofst,&ol
a);
//nbEchParAcq_=0;
nbEchALire=nbEchParAcq_;//Nombre d’echantillon par acquisition
//cerr<<"Ech "<<nbEchALire<<endl;
//sinon wait et restart avec defiler ;o)
CartePSFEE/Carte.cc
Imprimé par Maxime Fia
02 sep 02 11:41
Carte.cc
Page 3/14
Page
if (echantillon[4*i+2])//si lecture voie2 du fpga i=>voie4
echantillon[4*i+2][j]=(( static_cast<int>((data>>16))&0
000FF));//(( static_cast<unsigned int>(data&0x00FF0000))/65536);
if (echantillon[4*i+3])//si lecture voie3 du fpga i=>voie4
echantillon[4*i+3][j]=(( static_cast<int>((data>>24))&0
000FF));//(( static_cast<unsigned int>(data&0xFF000000))/16777216);
}
}
#ifdef __VERBOSE__
cout << "fin recup data" << endl;
#endif
break;
case 8://Lecture 8 bit incremente automatiqument
for (int i=0;i < NOMBRE_DE_VOIES;++i)//Initialisation du tableau
echantillon[i]=NULL;
#ifdef __VERBOSE__
cout << "initialisation acq" << endl;
#endif
//allocation des voies sur lesquelles se fait l’acquisition
for (set<int>::iterator it=voies_−>begin();it!=voies_−>end();++it)
{
echantillon[(*it)]=new int[nbEchALire];//Par echantillon a lire
}
//Initialiation de la lecture
#ifdef __VERBOSE__
cout << "initialisation lecture" << flush<<endl;
#endif
for (int i=0;i<NOMBRE_DE_FPGA;++i)//Pour chaque fpga
{
#ifndef __UNCONNECTED__
//mode de la carte =2 <=> Mode Download
bus_−>configurer(monadresse_, i, vme_daqreg, vme_daq_mode_ofst, vme_mode_DOWN
LOAD);
//reset de l’adresse
bus_−>configurer(monadresse_, i, vme_daqspecial, vme_daq_rstramadd_ofst, 0);
#endif
}
#ifdef __VERBOSE__
cout << "lancement recup data" << flush<< endl;
#endif
switch(nombreDeBit_)//si l’on veu en 8 ou 10 bits
{
case 108://Lecture 8 bit incremente manuellement
for (int i=0;i<NOMBRE_DE_FPGA;++i)//Pour chaque fpga !!! a la suite !!!
if (echantillon[4*i+0]||echantillon[4*i+1]
||echantillon[4*i+2]||echantillon[4*i+3])
{//si une voie a lire sur le fpga
#ifndef __UNCONNECTED__
//ordre transfert mem fpga voi ver mem fpga vme
bus_−>configurer(monadresse_, i,vme_dld4ram,vme_null_ofst,0);
//vme_4ramdownload_ofst,0);
#endif
for (int j=0;j<nbEchALire;++j)//Pour chaque echantillon
{
#ifndef __UNCONNECTED__
//lcture
bus_−>configurer(monadresse_,i,vme_vmereg,vme_ramradd_ofst,j);
bus_−>lireParametre(monadresse_,i,vme_vmeram,
vme_ram1_ofst,&data);
#endif
#ifdef __UNCONNECTED__
data=0x08080808;
#endif
if (echantillon[4*i+0])//si lecture voie0 du fpga i=>voie4*i+0
echantillon[4*i+0][j]=( static_cast<int>(data&0x000000FF));
if (echantillon[4*i+1])//si lecture voie1 du fpga i=>voie4*i+1
echantillon[4*i+1][j]=( static_cast<int>((data>>8)&0x000000F
F));//(((int)(data&0x0000FF00))/256);
//static_cast<int>(data&0x0000FF00>>8)
lundi 09 septembre 2002
Carte.cc
02 sep 02 11:41
for (int i=0;i<NOMBRE_DE_FPGA;++i)//Pour chaque fpga !!! a la suite !!
if (echantillon[4*i+0]||echantillon[4*i+1]
||echantillon[4*i+2]||echantillon[4*i+3])
{//si une voie a lire sur le fpga
#ifndef __UNCONNECTED__
//ordre transfert mem fpga voi ver mem fpga vme
bus_−>configurer(monadresse_, i,vme_dld4ram,vme_null_ofst,0);
bus_−>configurer(monadresse_,i,vme_special,vme_ramraddauto_ofst,
#endif
for (int j=0;j<nbEchALire;++j)//Pour chaque echantillon
{
#ifndef __UNCONNECTED__
//lecture
bus_−>lireParametre(monadresse_,i,vme_vmeram,
vme_ramraddauto_ofst,&data);
#endif
#ifdef __UNCONNECTED__
data=0x08080808;
#endif
if (echantillon[4*i+0])//si lecture voie0 du fpga i=>voie4
echantillon[4*i+0][j]=( (int)(data&0x000000FF));
if (echantillon[4*i+1])//si lecture voie1 du fpga i=>voie4
echantillon[4*i+1][j]=(((int)(data&0x0000FF00))/256);
if (echantillon[4*i+2])//si lecture voie2 du fpga i=>voie4
echantillon[4*i+2][j]=(((int)(data&0x00FF0000))/65536);
if (echantillon[4*i+3])//si lecture voie3 du fpga i=>voie4
echantillon[4*i+3][j]=(((unsigned int)(data&0xFF000000)
777216);
}
}
#ifdef __VERBOSE__
cout << "fin recup data" << endl;
#endif
break;
case 10:
for (int i=0;i<NOMBRE_DE_FPGA;++i)//Pour chaque fpga !!! a la suite !!
if (echantillon[4*i+0]||echantillon[4*i+1]
||echantillon[4*i+2]||echantillon[4*i+3])
{//si une voie a lire sur le fpga
#ifndef __UNCONNECTED__
//ordre transfert mem fpga voi ver mem fpga vme
bus_−>configurer(monadresse_, i,vme_dld4ram,vme_null_ofst,0);
CartePSFEE/Carte.cc
Imprimé par Maxime Fia
02 sep 02 11:41
Carte.cc
Page 5/14
//vme_4ramdownload_ofst,0);
bus_−>configurer(monadresse_,i,vme_special,vme_ramraddauto_ofst,0);
bus_−>lireParametre(monadresse_,i,vme_vmeram,
vme_ramraddauto_ofst,&data);
bus_−>lireParametre(monadresse_,i,vme_vmeram,
vme_ramraddauto_ofst,&data);
#endif
for (int j=0;j<nbEchALire;++j)//Pour chaque echantillon
{
#ifndef __UNCONNECTED__
//lecture
bus_−>lireParametre(monadresse_,i,vme_vmeram,
vme_ram3_ofst,&data);
#endif
#ifdef __UNCONNECTED__
data=0x08080808;
#endif
if (echantillon[4*i+3])
echantillon[4*i+3][j]=(((unsigned int)(data&0x00FFC000))/16
384);
#ifndef __UNCONNECTED__
//lecture
bus_−>lireParametre(monadresse_,i,vme_vmeram,
vme_ramraddauto_ofst,&data);
#endif
#ifdef __UNCONNECTED__
data=0x08080808;
#endif
if (echantillon[4*i+0])
echantillon[4*i+0][j]=( (unsigned int)(data&0x000003FF));
if (echantillon[4*i+1])
echantillon[4*i+1][j]=(((unsigned int)(data&0x000FFC00))/10
24);
if (echantillon[4*i+2])
echantillon[4*i+2][j]=(((unsigned int)(data&0x3FF00000))/10
48576);
}
}
#ifdef __VERBOSE__
cout << "fin recup data" << endl;
#endif
02 sep 02 11:41
Carte.cc
#ifdef __VERBOSE__
cout << "preparation et renvoi" << endl;
#endif
for (int i=0;i<nbEchALire;++i)//Pour chaque echantillon
{
for (int j=0;j<NOMBRE_DE_VOIES;++j)//pour chaque voie
if (echantillon[j])//si on lit
echantillonrenvoye[j]=echantillon[j][i];//renvoi l’echantillon
else
echantillonrenvoye[j]=0;//sinon 0 (quelquonque non utilise apres)
#ifndef __UNCONNECTED__
stoquer(echantillonrenvoye);//Echantillon renvoye
#endif
}
#ifdef __VERBOSE__
cout << "echantillon renvoye" << endl;
#endif
for (set<int>::iterator it=voies_−>begin();it!=voies_−>end();++it)
delete[] echantillon[(*it)];//Liberation des ressources
#ifdef __VERBOSE__
cout << "ressources liberes" << endl;
#endif
}
//−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
void Carte::stoquer(int tab[NOMBRE_DE_VOIES])
{
#ifdef __VERBOSE__
cout << "Stoquage des donnees sur la carte: "<<std::hex<< monadresse_ << std::dec;
#endif
#ifndef __WITH_MUTEX__
defiler();//On defile le cas echeant
#endif
break;
default:
break;
}
for (int i=0;i<NOMBRE_DE_FPGA;++i)//Pour chaque fpga
{
#ifndef __UNCONNECTED__
//reset adresse et mode normal
bus_−>configurer(monadresse_, i, vme_daqspecial, vme_daq_rstramadd_ofst, 0);
bus_−>configurer(monadresse_,i,vme_daqreg,vme_daq_mode_ofst,vme_mode_LAW);
#endif
}
lundi 09 septembre 2002
Page
for (int i=0;i<NOMBRE_DE_FPGA;++i)//Pour chaque fpga
{
#ifndef __UNCONNECTED__
//reset adresse et mode normal
bus_−>configurer(monadresse_, i, vme_daqspecial, vme_daq_rstramadd_ofst,
#endif
}
#ifdef __WITH_MUTEX__
pthread_mutex_lock(&mutex_carte_);//Debut de code verouille
#endif
#ifdef __VERBOSE__
cout << "deb";
#endif
for (int i=0;i<NOMBRE_DE_VOIES;++i)
{
//alors on met dans les files d’attentes
donneenattente_[i].push_back(tab[i]);
#ifdef __VERBOSE__
cout <<std::dec<< tab[i] << " ";
#endif
}
++nbdonneenattente_;
CartePSFEE/Carte.cc
Imprimé par Maxime Fia
02 sep 02 11:41
Carte.cc
Page 7/14
#ifdef __VERBOSE__
cout << " fin OK" <<endl;
#endif
#ifdef __WITH_MUTEX__
pthread_mutex_unlock(&mutex_carte_);//Fin de code verouille
#endif
#ifdef __VERBOSE__
cout<<std::hex<< monadresse_ << endl;
#endif
if (echantillonRestantALire_>0)
−−echantillonRestantALire_;//un echantillon en moins a lire
#ifndef __WITH_MUTEX__
defiler();//On defile le cas echeant
#endif
#ifdef __VERBOSE__
cout << "fin de stockage sur: "<<std::hex<< monadresse_ << std::dec;
#endif
}
//−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
int** Carte::recuperer()
{
int **stock;//Variable de stoquage
#ifdef __VERBOSE__
cout<<"Recuperation des donnees de la carte: "<<std::hex<<monadresse_<< endl;
#endif
if (donneeready_)//si donnees pretent
{
#ifdef __VERBOSE__
cout << "data ready pour recuperation" << endl;
#endif
stock=dernieredonnnee_;//on les sauve
dernieredonnnee_=NULL;//on vide le buffer
donneeready_=false;//plus de donnees pretent
02 sep 02 11:41
Carte.cc
Page
#endif
if (!donneeready_)//si pas de donnees bufferises
{
if (nbdonneenattente_>=nombreEchantillon_)//si des donnes dans les files
{
#ifdef __WITH_MUTEX__
if (!pthread_mutex_trylock(&mutex_carte_))//Debut de code verouille
{
#ifdef __VERBOSE__
cout <<"Verou MUTEX"<<endl;
#endif
return;//Code bloque retour au prog principal
}
#endif
//Creation du buffer
dernieredonnnee_= new int*[NOMBRE_DE_VOIES];
for (int i=0;i<NOMBRE_DE_VOIES;++i)
{
dernieredonnnee_[i]= new int[nombreEchantillon_];
//On defile dans le buffer
for (int j=0;j<nombreEchantillon_;++j)
{
dernieredonnnee_[i][j]=donneenattente_[i].front();
donneenattente_[i].pop_front();
}
}
nbdonneenattente_−=nombreEchantillon_;
donneeready_=true;
#ifdef __VERBOSE__
cout <<"deffilage effectue";
#endif
#ifdef __WITH_MUTEX__
pthread_mutex_unlock(&mutex_carte_);//Fin de code verouille
#endif
}
return stock;//on envoie les donnees
}
else
{
#ifdef __VERBOSE__
cout << "pas de data" << endl;
#endif
}
#ifdef __VERBOSE__
cout <<"Donnee en place"<<endl;
#endif
}
return NULL;//Rien en stock
}
#ifdef __VERBOSE__
cout<<"fin Recuperation des donnees carte: "<<std::hex<<monadresse_<< endl;
#endif
}
void Carte::lancerAcquisition(int evenement)
throw (BusVMEWriteError,BusVMEReadError, CarteErreurInitialisation)
{
int relire=((NOMBRE_DE_RELECTURE!=−1)?NOMBRE_DE_RELECTURE:0);//au moins une
cture
char *retour,num;//liste des parametres a problemes
bool echec=false;//echec d’une ecriture
//−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
//−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
void Carte::defiler()
{
#ifdef __VERBOSE__
cout << "Tentative de defilage de la carte: "<<std::hex<< monadresse_<< std::dec;
lundi 09 septembre 2002
if (evenement!=−1)//Nombre d’echantillon defini
echantillonRestantALire_=evenement*nombreEchantillon_;
else
echantillonRestantALire_=−1;
CartePSFEE/Carte.cc
Imprimé par Maxime Fia
02 sep 02 11:41
Carte.cc
Page 9/14
retour = new char[612];
retour[0]=’\0’;
this−>clean();
switch(nombreDeBit_)//si l’on veu en 8 ou 10 bits
{
case 108://Lecture 8 bit incremente manuellement
bus_−>configurer(monadresse_,0,vme_vmereg,vme_mode_ofst,0x0);
break;
case 8:
case 10:
bus_−>configurer(monadresse_,0,vme_vmereg,vme_mode_ofst,0x1);
break;
}
for (int i=0;i<NOMBRE_DE_FPGA;++i)//Pour chaque fpga
{
num=static_cast<char>(’0’+i);
strcat(retour,"\nfpga ");strcat(retour,&num);strcat(retour,": ");
#ifndef __UNCONNECTED__
if (!bus_−>configurer(monadresse_, i, vme_daqreg, vme_daq_mode_ofst, vme_mode
_LAW,relire))
{strcat(retour,"le mode "); echec=true; }
//reset adresse et mode normal
if (!bus_−>configurer(monadresse_, i, vme_daqreg, vme_daq_plen_ofst,daq_plen_
,relire)) //0x17 ,relire ))
{strcat(retour,"daq_plen "); echec=true; }
if (!bus_−>configurer(monadresse_, i, vme_daqreg, vme_daq_trigdly_ofst, daq_t
rigdly_, relire )) //0x02 ,relire))
{strcat(retour,"daq_trigdly "); echec=true; }
if (!bus_−>configurer(monadresse_, i, vme_daqreg, vme_daq_law_ofst, (nombreEc
hantillon_−1) ,relire))
{strcat(retour,"daq_law "); echec=true;}
switch(nombreDeBit_)//si l’on veu en 8 ou 10 bits
{
case 10:
if (!bus_−>configurer(monadresse_, i, vme_daqreg, vme_daq_nevtmax_ofst,
(UINT32)(tailleMemoire_/nombreEchantillo
n_/2−1) ,relire))
{strcat(retour,"daq_nevtmax "); echec=true;}
break;
case 108://Lecture 8 bit incremente manuellement
case 8:
if (!bus_−>configurer(monadresse_, i, vme_daqreg, vme_daq_nevtmax_ofst,
(UINT32)(tailleMemoire_/nombreEchantillo
n_−1) ,relire))
{strcat(retour,"daq_nevtmax "); echec=true;}
break;
}
if (!bus_−>configurer(monadresse_, i, vme_daqreg, vme_alpha_ofst, alpha_, rel
ire )) //0x0 ,relire))
{strcat(retour,"alpha "); echec=true;}
if (!bus_−>configurer(monadresse_, i, vme_daqreg, vme_threshold_ofst, thresho
ld_ ,relire)) //0x9 ,relire))
{strcat(retour,"threshold "); echec=true; }
if (!bus_−>configurer(monadresse_, i, vme_daqreg, vme_pedestal_ofst, pedestal
_, relire)) //0x0 ,relire))//0x1);
{strcat(retour,"pedestal "); echec=true;}
//vme_mode_ofst 0
lundi 09 septembre 2002
02 sep 02 11:41
Carte.cc
//vme_alpha_ofst
if (!bus_−>configurer(monadresse_, i, vme_daqreg,
i],relire)) //0x0,relire))
{strcat(retour,"offset0 "); echec=true;}
if (!bus_−>configurer(monadresse_, i, vme_daqreg,
i], relire)) //0x0,relire))
{strcat(retour,"offset1 "); echec=true;}
if (!bus_−>configurer(monadresse_, i, vme_daqreg,
relire)) //0x0,relire))
{strcat(retour,"gain0 "); echec=true;}
if (!bus_−>configurer(monadresse_, i, vme_daqreg,
relire)) //0x0,relire))
{strcat(retour,"gain1 ");echec=true;}
if (!bus_−>configurer(monadresse_, i, vme_daqreg,
lire))
{strcat(retour,"processcfg "); echec=true;}
#endif
}
Page 1
vme_offset0_ofst, offse
vme_offset1_ofst, offse
vme_gain0_ofst, gain0_[
vme_gain1_ofst, gain1_[
vme_processcfg_ofst, 0x
for (int i=0;i<NOMBRE_DE_FPGA;++i)//Pour chaque fpga
{
#ifndef __UNCONNECTED__
bus_−>configurer(monadresse_, i, vme_daqspecial, vme_daq_rstramadd_ofst,
#endif
}
if (echec)
{
throw CarteErreurInitialisation(retour);
}
else delete[] retour;
return;
}
//−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
void Carte::clean()
{
donneeready_=false;//Pas encore de donnee
if (dernieredonnnee_)//Si buffer plein
{
for (int i=0;i<NOMBRE_DE_VOIES;++i)//Pour chaque voie
if (dernieredonnnee_[i])//si utilisee
delete[] dernieredonnnee_[i];//detruire
delete[] dernieredonnnee_;//Detruire la matrice
dernieredonnnee_= NULL;//pas de derniere donnee stocke
}
nbdonneenattente_=0;//Pas de donnee en attente
for (int i=0;i<NOMBRE_DE_VOIES;++i)//Si des donnees stoquees
while(donneenattente_[i].size())//si en attente
donneenattente_[i].pop_back();//les enlever
}
//−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
ostream &operator<< (ostream &o,Carte &card)
throw (BusVMEReadError)
{
//recuperation des data par acces vme
CartePSFEE/Carte.cc
Imprimé par Maxime Fia
02 sep 02 11:41
Carte.cc
Page 11/14
Carte.cc
Page 1
}
o<<endl;
return card.Etat(o);
}
o<<"daq_plen
: ";
for (i=0;i<NOMBRE_DE_FPGA;++i)
{
bus_−>lireParametre(monadresse_, i, vme_daqreg, vme_daq_plen_ofst ,&data[
o<<std::hex<<setw(3)<<data[i]<<","<<std::dec<<setw(3)<<data[i]<<" |";
}
o<<endl;
ostream & Carte::Etat(ostream &o)
{
UINT32 data[NOMBRE_DE_FPGA];
int i=0;
/*
if (Acquisition::Initialiser()−>AcquisitionEnCour())
{//Une acquisition est en cour
o<<"daq_nevtmax : ";
for (i=0;i<NOMBRE_DE_FPGA;++i)
{
bus_−>lireParametre(monadresse_, i, vme_daqreg, vme_daq_nevtmax_ofst ,&da
]);
o<<std::hex<<setw(3)<<data[i]<<","<<std::dec<<setw(3)<<data[i]<<" |";
}
o<<endl;
}
else
{//Pas d’acquisition en cour forcer mode normal
}
*/
o<< "Liste des parametres de la carte d’adresse: " << std::hex << monadresse_ << std::dec << en
dl;
o<< "Le parametre " << " FPGA0 |" << " FPGA1 |" << " FPGA2 |" << " FPGA3 |" <<endl;
o<<"(base 16 puis 10) "<<endl;
o<<"Le mode
: ";
for (i=0;i<NOMBRE_DE_FPGA;++i)
{
bus_−>lireParametre(monadresse_, i, vme_daqreg, vme_daq_mode_ofst,&data[i]);
if (data[i]==2)
{
o<< "Lecture impossible fpga "<< i << " en mode 2 ";
//return o;
}
else
{
o<< setw(5) <<data[i]<<" |";
}
}
o<<endl;
o<<"alfa
: ";
for (i=0;i<NOMBRE_DE_FPGA;++i)
{
bus_−>lireParametre(monadresse_, i, vme_daqreg, vme_alpha_ofst ,&data[i]);
o<<std::hex<< setw(3) <<data[i]<<","<<std::dec<< setw(3) <<data[i]<<" |";
}
o<<endl;
o<<"threshold
: ";
for (i=0;i<NOMBRE_DE_FPGA;++i)
{
bus_−>lireParametre(monadresse_, i, vme_daqreg, vme_threshold_ofst ,&data[i])
;
o<<std::hex<<setw(3)<<data[i]<<","<<std::dec<<setw(3)<<data[i]<<" |";
}
o<<endl;
o<<"daq_law
: ";
for (i=0;i<NOMBRE_DE_FPGA;++i)
{
bus_−>lireParametre(monadresse_, i, vme_daqreg, vme_daq_law_ofst ,&data[i]);
o<<std::hex<<setw(3)<<data[i]<<","<<std::dec<<setw(3)<<data[i]<<" |";
lundi 09 septembre 2002
02 sep 02 11:41
o<<"daq_nevtcurrent : ";
for (i=0;i<NOMBRE_DE_FPGA;++i)
{
bus_−>lireParametre(monadresse_, i, vme_daqreg, vme_daq_nevtcurrent_ofst
ta[i]);
o<<std::hex<<setw(3)<<data[i]<<","<<std::dec<<setw(3)<<data[i]<<" |";
}
o<<endl;
o<<"trigdly
: ";
for (i=0;i<NOMBRE_DE_FPGA;++i)
{
bus_−>lireParametre(monadresse_, i, vme_daqreg, vme_daq_trigdly_ofst ,&da
]);
o<<std::hex<<setw(3)<<data[i]<<","<<std::dec<<setw(3)<<data[i]<<" |";
}
o<<endl;
o<<"flags1
: ";
for (i=0;i<NOMBRE_DE_FPGA;++i)
{
bus_−>lireParametre(monadresse_, i, vme_daqreg, vme_flags1_ofst ,&data[i]
o<<std::hex<<setw(3)<<data[i]<<","<<std::dec<<setw(3)<<data[i]<<" |";
}
o<<endl;
o<<"config1
: ";
for (i=0;i<NOMBRE_DE_FPGA;++i)
{
bus_−>lireParametre(monadresse_, i, vme_daqreg, vme_config1_ofst ,&data[i
o<<std::hex<<setw(3)<<data[i]<<","<<std::dec<<setw(3)<<data[i]<<" |";
}
o<<endl;
o<<"daq_status
: ";
for (i=0;i<NOMBRE_DE_FPGA;++i)
{
bus_−>lireParametre(monadresse_, i, vme_daqreg, vme_daq_status_ofst ,&dat
);
o<<std::hex<<setw(3)<<data[i]<<","<<std::dec<<setw(3)<<data[i]<<" |";
}
o<<endl;
CartePSFEE/Carte.cc
Imprimé par Maxime Fia
02 sep 02 11:41
Carte.cc
Page 13/14
02 sep 02 11:41
o<<"processcfg
: ";
for (i=0;i<NOMBRE_DE_FPGA;++i)
{
bus_−>lireParametre(monadresse_, i, vme_daqreg, vme_processcfg_ofst ,&data[i]
);
o<<std::hex<<setw(3)<<data[i]<<","<<std::dec<<setw(3)<<data[i]<<" |";
}
o<<endl;
o<<"offset0
: ";
for (i=0;i<4;++i)
{
bus_−>lireParametre(monadresse_, i, vme_daqreg, vme_offset0_ofst ,&data[i]);
o<< std::hex<<setw(3)<<data[i]<<std::dec<<","<<setw(3)<<data[i]<<" |";
}
o<<endl;
o<<"offset1
: ";
for (i=0;i<4;++i)
{
bus_−>lireParametre(monadresse_, i, vme_daqreg, vme_offset1_ofst ,&data[i]);
o<< std::hex<<setw(3)<<data[i]<<std::dec<<","<<setw(3)<<data[i]<<" |";
}
o<<endl;
o<<"gain0
: ";
for (i=0;i<4;++i)
{
bus_−>lireParametre(monadresse_, i, vme_daqreg, vme_gain0_ofst ,&data[i]);
o<< std::hex<<setw(3)<<data[i]<<std::dec<<","<<setw(3)<<data[i]<<" |";
}
o<<endl;
o<<"gain1
: ";
for (i=0;i<4;++i)
{
bus_−>lireParametre(monadresse_, i, vme_daqreg, vme_gain1_ofst ,&data[i]);
o<< std::hex<<setw(3)<<data[i]<<std::dec<<","<<setw(3)<<data[i]<<" |";
}
o<<endl<<endl;
o<<" −−−−−− "<<endl<<endl;
o<<"Registre fpga vme"<<endl;
bus_−>lireParametre(monadresse_, 0, vme_vmereg, vme_vmeflags1_ofst ,&data[0]);
o<<std::hex<<"flags1 :"<<data[0]<<" , "<<std::dec<<data[0]<<endl;
bus_−>lireParametre(monadresse_, 0, vme_vmereg, vme_status1_ofst ,&data[0]);
o<<std::hex<<"status1 :"<<data[0]<<" , "<<std::dec<<data[0]<<endl;
bus_−>lireParametre(monadresse_, 0, vme_vmereg, vme_mode_ofst ,&data[0]);
o<<std::hex<<"mode :"<<data[0]<<" , "<<std::dec<<data[0]<<endl;
bus_−>lireParametre(monadresse_, 0, vme_vmereg, vme_ramwadd_ofst ,&data[0]);
o<<std::hex<<"ramwadd :"<<data[0]<<" , "<<std::dec<<data[0]<<endl;
return o;
}
lundi 09 septembre 2002
CartePSFEE/Carte.cc
Carte.cc
Page 1
Imprimé par Maxime Fia
08 aoû 02 14:26
Acquisition.hh
Page 1/5
//Fichier ./Acquisition/Acquisition.hh
//Classe
//
//[email protected]
//!Attention on ne peut utiliser que des pointeurs sur cette classe
//On le recupere par static Acquisition* Acquisition::Initialiser(void)
08 aoû 02 14:26
Acquisition.hh
sscfg,pedestal);//On cree l’instance
}
return Interface_;
}
//Pour recuperer les donnees
int** recuperer();
//Classe servant a realiser une acquisition sur une ou plusieur carte
//Methode:
//
//static Acquisition* Initialiser(int nombreEchantillon=16,int tailleMemoire=512
, int nombreDeBit=8)
//−Recupere un pointeur sur la classe
//int* recuperer() − Pour recuperer des donnes en cour et apres acquisition
//void Lancer(int nbevent=−1) − Pour lancer l’acquisition
//void Stop() − Pour arreter l’acquisition
//void AjouterCarte(UINT32 sonAdresse,const set<int> *voies) − pour ajouter une
carte
//void RetirerCarte(UINT32 sonAdresse) − Pour retirer une carte
//
#ifndef __ACQUISITION_HH__
#define __ACQUISITION_HH__
//Pour pouvoir se servir de acquisition en temps que fonction
int** operator()(void)
{
return recuperer();
}
//Permet de lancer une acquisition sur nbevent echantillon par voie
//Parametre: nombre d’echantillon par voie avant l’arret
void Lancer(int nbevent=−1);
//Stoppe l’acqusition brutalement, fin de transmition des donnees
void Stop();
//Permet de rajouter une carte a l’acquisition
//Parametre: Adresse Physique de la carte sur le bus VME
void AjouterCarte(UINT32 sonAdresse,const set<int> *voies);
#include <pthread.h>
#include <set>
//Permet de retirer une carte de l’acquisiton
//Attention pas de tri implante donc faire dans le sans
//inverse de l’ajout
//Parametre: Adresse Physique de la carte sur le bus VME
void RetirerCarte(UINT32 sonAdresse);
#include "BusVME.hh"
#include "defcart.hh"
#include "Carte.hh"
class Carte;
static const UINT32 tabnull[NOMBRE_DE_FPGA]={0};
//Renvoie si l’acquisition est en cour
bool AcquisitionEnCour()
{
return AcquisitionEnCour_;
}
class Acquisition
{
public:
//Fonction pour creer une instance de Acquisition
//Initialise les variables et le thread
static Acquisition* Initialiser(int nombreEchantillon=16,int tailleMemoire=51
2, int nombreDeBit=8,
UINT32 daq_trigdly=2, UINT32 alpha=0,
const UINT32 offset0[NOMBRE_DE_FPGA]=tabnull, const UINT32 offset1[NOMBRE_DE_
FPGA]=tabnull,
const UINT32 gain0[NOMBRE_DE_FPGA]=tabnull, const UINT32 gain1[NOMBRE_DE_FPGA
]=tabnull,
UINT32 threshold=9, UINT32 daq_plen=23, UINT32 processcfg=0, UINT32 pedestal=
0)
{
#ifdef __VERBOSE__
cout << "Connection a l’interface" << endl;
#endif
//Renvoie un stream de l’etat des cartes
ostream & Etat(ostream &o);
//Destructeur de acquisition
//Arrete brutalement le thread d’acquisition si il est en cour
~Acquisition()
{
#ifdef __VERBOSE__
cout << "Destruction de acquisition" << endl;
#endif
this−>Stop();
//Stopper le thread si acquisition en cour
//pthread_kill_other_threads_np();
BusVME::Connecter();
if (!NombreInstance_)//Creer pour le premiere fois
{
//Creation de la classe Acquisition
Interface_ = new Acquisition(nombreEchantillon, tailleMemoire, nombreD
//pour la liberation du bus une unique fois
if ( BusInterface *bus=BusVME::Connecter() )
{
delete bus;
}
eBit,
daq_trigdly,alpha,offset0,offset1,gain0,gain1,threshold,daq_plen,proce
lundi 09 septembre 2002
//Liberation des ressources
Acquisition/Acquisition.hh
Page
Imprimé par Maxime Fia
08 aoû 02 14:26
Acquisition.hh
Page 3/5
08 aoû 02 14:26
if (monThread_)//Le thread
{
delete[] monThread_;
}
Acquisition.hh
Page
{
offset0_[i]=offset0[i];
offset1_[i]=offset1[i];
gain0_[i]=gain0[i];
gain1_[i]=gain1[i];
}
#ifdef __VERBOSE__
cout << "Initialisation du thread" << endl;
#endif
if (attributDeThread_)//Les attribut de thread
{
delete[] attributDeThread_;
}
if (cartes_)//Les cartes
{
delete[] cartes_;
}
attributDeThread_=new pthread_attr_t;//attribut du thread
monThread_=NULL;//Pas de thread
if (pthread_attr_init(attributDeThread_))//initialisation des attrib
{
cerr << "WARNING!: Erreur to Init pthread" << endl;
cerr << "WARNING!: No Real Time Acquisition" << endl;
delete attributDeThread_;
attributDeThread_=NULL;//Attribut detruit
}
else
{
//Gestion thread temps reel
//Selon la politique d’ordonancement temps reel, round−robin
//const struct sched_param msh={SCHED_RR};
//pthread_attr_setschedparam(attributDeThread_,&msh);
pthread_attr_setdetachstate(attributDeThread_,PTHREAD_CREATE_DETA
Interface_=NULL;//PLus de pointeur sur la classe
//plus de classe
NombreInstance_=0;
#ifdef __VERBOSE__
cout << "Acquisition stop" << endl;
#endif
}
protected:
);
sched_param msh;
pthread_attr_setinheritsched(attributDeThread_, PTHREAD_EXPLICIT_
void TestException();
D);
private:
//Constructeur de Acquisition
//ATTENTION on ne peut que utiler un pointeur sur acquisition
//avec la fonction static Acquisition* Initialiser()
explicit Acquisition(int nombreEchantillon,int tailleMemoire, int nombreDeBit
pthread_attr_setschedpolicy(attributDeThread_, SCHED_OTHER);
msh.sched_priority=sched_get_priority_min(SCHED_OTHER);
pthread_attr_setschedparam(attributDeThread_,&msh);
}
}
,
UINT32 daq_trigdly, UINT32 alpha,
const UINT32 offset0[NOMBRE_DE_FPGA], const UINT32 offset1[NOMBRE_DE_FPGA],
const UINT32 gain0[NOMBRE_DE_FPGA], const UINT32 gain1[NOMBRE_DE_FPGA],
UINT32 threshold, UINT32 daq_plen, UINT32 processcfg, UINT32 pedestal) :
AcquisitionEnCour_(false), nbevent_(−1),
monThread_(NULL), attributDeThread_(NULL),
nombreEchantillon_(nombreEchantillon),tailleMemoire_(tailleMemoire),
nombreDeBit_(nombreDeBit),daq_trigdly_(daq_trigdly),alpha_(alpha),
threshold_(threshold),daq_plen_(daq_plen),processcfg_(processcfg),pedesta
l_(pedestal)
{
++NombreInstance_;//On incemente le nombre d’instance
nbvoie_=0;//Pqs de voies pour acquerie
cartes_ = new Carte*[NOMBRE_DE_CARTES_MAX];
for (int i=0;i<NOMBRE_DE_CARTES_MAX;++i)
{
cartes_[i]=NULL;//Pas de carte
recup_[i]=NULL;//Pas de donnees a renvoyer
}
#ifdef __VERBOSE__
cout << "Configuration de l’acquisition" << endl;
#endif
AcquisitionEnCour_=false;//Pas d’acquisition en cour
for (int i=0;i<NOMBRE_DE_FPGA;i++)
lundi 09 septembre 2002
//Routine utilise par le thread d’acquisition
static void *Routine(void *cartes);
static int NombreInstance_;//Nombre d’instance d’acquisition(normalement 0 o
static Acquisition *Interface_;//Pointeur sur la classe d’acquisition(unique
bool AcquisitionEnCour_;//True si une acquisition est en cour
int nbvoie_;//Nombre de voies totales de l’acquisition(!inferieur a nbvoiema
Carte **cartes_;//Adresse des cartes(adresse physique sur le bus)
int nbevent_;//nombre d’evenement a renvoyer (infini si −1)
pthread_t *monThread_;//Pointeur sur le pthread
pthread_attr_t *attributDeThread_;//Pointeur sur l’attribut de configuration
//thread
int **recup_[NOMBRE_DE_CARTES_MAX];//Pour recuperer les matrices de chaque c
//Parametre pour l’acquisition
int nombreEchantillon_;//nombre d’echantillon par trigger
int tailleMemoire_;//taille de la memoire de la carte
int nombreDeBit_;//Acquisition en 8 ou 10 bit
UINT32 daq_trigdly_,alpha_;
UINT32 offset0_[NOMBRE_DE_FPGA],offset1_[NOMBRE_DE_FPGA];
UINT32 gain0_[NOMBRE_DE_FPGA],gain1_[NOMBRE_DE_FPGA];
UINT32 threshold_,daq_plen_;
UINT32 processcfg_,pedestal_;
Acquisition/Acquisition.hh
Imprimé par Maxime Fia
08 aoû 02 14:26
Acquisition.hh
Page 5/5
};
ostream &operator<< (ostream &o, Acquisition &acq);
#endif
lundi 09 septembre 2002
Acquisition/Acquisition.hh
Imprimé par Maxime Fia
02 sep 02 11:41
Acquisition.cc
Page 1/7
//Fichier ./Acquisition/Acquisition.cc
//Classe pour la gestion de l’acquisition
02 sep 02 11:41
Acquisition.cc
Page
{
ret = new int*[nbvoie_];
for (int i=0;i<nbvoie_;++i)
ret[i]= new int[nombreEchantillon_];
#include "Acquisition.hh"
#include <time.h>
#include <signal.h>
//initialisation des attributs static
int Acquisition::NombreInstance_=0;
Acquisition *Acquisition::Interface_=0;
//
!!! ATTENTION !!! LOCAL !!! ATTENTION !!!
//−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
//Variable utile uniqument pour le controle du thread
volatile int ControleDuThread_ct=0;
int nbevent_ct=−1;
int nbeventsend_ct;//nombre d’evenement deja renvoye au programme principal
bool *etat_acq;
//−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
//Variable pour le lancement d’exception inter−thread
ErrGen *exception_ct=NULL;
ErrGen *localexception_ct=NULL;
//−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
int** Acquisition::recuperer()
{
#ifdef __VERBOSE__
cout << "Recuperation des donnees sur la carte" << endl;
#endif
int **ret;//tableau des donnees recuperees
int count=0;//Ou se situe t’on ds le tableau de retour
const set<int> *voies;//liste des voies de chaque carte
bool ToutRecuperer=true;//on a recupere les donnees de toutes les cartes
for (int i=0;i<NOMBRE_DE_CARTES_MAX;++i)//Pour chaque carte
if ( cartes_[i] )//Si elle est selectionne
{
voies=cartes_[i]−>listevoie();//d’apres les numero des voies
for (set<int>::iterator it=voies−>begin();//
it!=voies−>end();++it,++count)
{
for (int j=0;j<nombreEchantillon_;++j)
ret[count][j] = recup_[i][*it][j];//Recupere la donnee
}
for (int k=0;k<NOMBRE_DE_VOIES;++k)
delete[] recup_[i][k];
delete[] recup_[i];
recup_[i]=NULL;
}
++nbeventsend_ct;
#ifdef __VERBOSE__
cout << "fin de Recuperation totale" << endl;
#endif
return ret;//retour de la matrice de valeur
}
else
{
#ifdef __VERBOSE__
cout << "fin de Recuperation partielle" << endl;
#endif
return NULL;
}
}
//−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
TestException();//Teste le passage d’exception interthread
for (int i=0;i<NOMBRE_DE_CARTES_MAX;++i)//Pour chaque carte
if ( cartes_[i] && !recup_[i])//si elle existe et des donnees a recuperer
{
#ifndef __WITH_MUTEX__
if (!AcquisitionEnCour_)//Tres important
{
//Le thread et la carte ne doivent pas defiler en meme temp
cartes_[i]−>defiler();
}
#endif
#ifdef __WITH_MUTEX__
cartes_[i]−>defiler();//defiler pour mettre une donnee dans la boite a
message
#endif
recup_[i]=cartes_[i]−>recuperer();//On recupere la matrice de donne
if (!recup_[i])//si =NULL on a pas recupere les donnees
ToutRecuperer=false;
}
if (ToutRecuperer)//Il ne manque pas les donnees d’une carte
lundi 09 septembre 2002
void Acquisition::Lancer(int nbevent)
{
#ifdef __VERBOSE__
cout << "Lancement de l’acquisition" << endl;
#endif
if (AcquisitionEnCour_) //Une acquistion est deja lance
{
#ifdef __VERBOSE__
cout <<"Exception lancement de deux acquisitions simultannees"<< endl;
#endif
throw AcquisitionErreurDoubleLancement();
}
nbevent_ct=−1;
ControleDuThread_ct=0;
exception_ct=NULL;
localexception_ct=NULL;
nbeventsend_ct=0;//Pas d evenement encore envoye
AcquisitionEnCour_=true;//Elle est en cour
etat_acq=&AcquisitionEnCour_;
//Defintion des controle du thread
nbevent_ct=nbevent;//nombre d’evenement a faire(infini si −1)
ControleDuThread_ct=0;//Mode normal
Acquisition/Acquisition.cc
Imprimé par Maxime Fia
02 sep 02 11:41
Acquisition.cc
Page 3/7
//Lancer le thread d’acquisition
monThread_= new pthread_t;
if (pthread_create(monThread_,attributDeThread_,Routine,cartes_))
{
cout<< "thread error" << endl;
//throw ErreurDeThread();
}
#ifdef __VERBOSE__
cout << "Fin de lancement acquisition et thread" << endl;
#endif
}
02 sep 02 11:41
Page
ion
throw AcquisitionErreurManipulationCarte();
//On verifie que le set n’est pas vide
if ( !voies−>size() )
{
cout << "WARNING!: No channel to acquisition card number: ";
cout << std::hex<<sonAdresse<<std::dec;
cout << endl;
cout << "WARNING!: Acquisition aborded on this card";
cout << endl;
return;
}
//−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
void Acquisition::Stop()
{
time_t duree,now;//Pour l’ecoulement du temps
//On compte le nombre de carte
for (int i=0;i<NOMBRE_DE_CARTES_MAX;++i)
if (cartes_[i]!=NULL)
{
++nbcart;
if (cartes_[i]−>adresse()==sonAdresse)
{
cout << "WARNING!: 2 times the same card at acquisition";
cout << endl;
cout << "WARNING!: The second is not used";
cout << endl;
return;
}
}
#ifdef __VERBOSE__
cout << "\tNOMBRE de cartes: " << nbcart << endl;
#endif
#ifdef __VERBOSE__
cout << "Stop de l’acquisition" << endl;
#endif
if (!AcquisitionEnCour_) //Pas d’acquisition en cour
{
#ifdef __VERBOSE__
cout <<"Erreur stop sans lancement"<< endl;
#endif
return;//Sortie directe gestion d’erreur
//suite inutile
//Pas d’exeption car possible cause thread
//throw ErreurArretSansLancement();
}
//Arret du thread d’acquisition
ControleDuThread_ct=1;//pour provoquer la mort du thread
if (nbcart==(NOMBRE_DE_CARTES_MAX))//test trop de carte
throw AcquisitionErreurTropDeCarte();//Propagation de l’erreur
duree=time(NULL);//Prise de l’heure (en seconde)
while (ControleDuThread_ct)//Si le thread est en vie
{
now=time(NULL)−TEMP_D_ATTENTE_MAX_DE_LA_CARTE;//Temps ecoule
if ( duree <= now )//Si temps max ecoule
{
cout<<"WARNING!!! Acquisition was blocked"<<endl;
pthread_cancel(*monThread_);//Mort brutale tu pthread
ControleDuThread_ct=0;//Officialisation de la mort du thread
}
}
nbcart=0;
while(cartes_[nbcart]!=NULL)//Recherche de l’emplacement
++nbcart;
set<int> *voiesrenvoye = new set<int>;
*voiesrenvoye=*voies;
cartes_[nbcart]= new Carte(sonAdresse, voiesrenvoye,nombreEchantillon_,ta
Memoire_,nombreDeBit_,
daq_trigdly_,alpha_,offset0_,offset1_,gain0_,gain1_,
threshold_,daq_plen_,processcfg_,pedestal_);//Creati
e la classe
nbvoie_+=cartes_[nbcart]−>nombreDeVoies();//Creation de l’emplacement buf
donnee
}
//Plus d’acquisition
AcquisitionEnCour_=false;
#ifdef __VERBOSE__
cout << "fin du thread" << endl;
#endif
}
//−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
//−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
void Acquisition::AjouterCarte(UINT32 sonAdresse, const set<int> *voies)
{
int nbcart=0;
#ifdef __VERBOSE__
cout << "Ajout d’une carte a l’acquisition" << endl;
#endif
lundi 09 septembre 2002
Acquisition.cc
if (AcquisitionEnCour_)//Impossible de manipuler les cartes durant l’acqu
void Acquisition::RetirerCarte(UINT32 sonAdresse)
{
#ifdef __VERBOSE__
cout << "Retirer la carte d’adresse" <<std::hex<< sonAdresse << endl;
#endif
if (AcquisitionEnCour_)//Impossible de manipuler les cartes durant l’acqu
ion
throw AcquisitionErreurManipulationCarte();
Acquisition/Acquisition.cc
Imprimé par Maxime Fia
02 sep 02 11:41
Acquisition.cc
Page 5/7
for (int i=0;i<NOMBRE_DE_CARTES_MAX;++i)
if (cartes_[i]&&(cartes_[i]−>adresse()==sonAdresse))
{
nbvoie_+=cartes_[i]−>nombreDeVoies();
delete cartes_[i];
cartes_[i]=NULL;
}
}
Acquisition.cc
Page
}
catch(exception &e){e.what();}
}
//cout<<"avant ou apres?"<<endl;
while(1)//Boucle principale du pthread
{
//−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
void Acquisition::TestException()//Teste si il faut passer une exception a l’aff
ichage
{
if (exception_ct)//si oui
{
localexception_ct=exception_ct;//recopi en local
exception_ct=NULL;//A ete geree
// cout<<localexception_ct−>what()<<endl;//laquelle (d’exception)
localexception_ct−>autothrow();//Elle s’auto lance
//throw CarteErreur();
}
}
//−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
void *Acquisition::Routine(void *cartes)
{
Carte **cards=(Carte **)(cartes);//passage en parametre du tableau des pointe
urs sur cartes
int nbIt=0;//nombre d’iteration de la routine
bool toutenvoye=false;//Tous les evenement demandes ont ete renvoye?
#ifdef __VERBOSE__
cout << "debut d’execution de la routine thread" << endl;
#endif
for (int i=0;i<NOMBRE_DE_CARTES_MAX;++i)
if (cards[i])//Si carte a l’acquisition
{
try
{//block de code protege
cards[i]−>lancerAcquisition(nbevent_ct);//Configure les cartes pour l
ancer
//l’acquisition
}
catch(ErrGen &e)
{
#ifdef __VERBOSE__
cerr<<"catch carte::lanceracquisition "<< e.what();//Faire passage autre thread
#endif
if (!exception_ct)//Si pas d’exception en cour
{
exception_ct=e.clone();//Passement de l’exception au thread princip
al
//ControleDuThread_ct=1;//Suicide du thread (lancement echoué)
}
else
{//On repart, une exception est deja en cour de traitement
//A rajouter au cas de choix d’enfilement des exceptions
//ControleDuThread_ct=1;//Suicide du thread (lancement echoué)
}
lundi 09 septembre 2002
02 sep 02 11:41
if (toutenvoye)//(nbIt==nbevent_ct)//Test du nombre d’iteration
ControleDuThread_ct=1;//Le thread se suicide
else
toutenvoye=true;//Suppose vrai au debut
//Different cas
switch(ControleDuThread_ct)//Suivant le cas
{
case 1:
ControleDuThread_ct=0;
*etat_acq=false;//<=>acquisitionencour_=false;//Fin de l’acquisi
#ifdef __VERBOSE__
cout << "Le thread a fini, iteration :"<<std::dec<<nbIt<< endl;
#endif
pthread_exit(NULL);//mort du thread
case 0:
//Acquerir sur les cartes
for (int i=0;i<NOMBRE_DE_CARTES_MAX;++i)
if ((cards[i])&&((nbevent_ct==−1)||
((nbeventsend_ct+cards[i]−>nbEventWaiting())<nbevent_ct)))
{
toutenvoye=false;
try
{//reblock protege
cards[i]−>acquerir();//Acquisition par carte
}
catch(ErrGen &e)
{
#ifdef __VERBOSE__
cout<<"catch carte::acquerir "<< e.what();//Faire passage autre
ad
#endif
if (!exception_ct)
exception_ct=e.clone();//Passement de l’exception au t
d principal
}
catch(exception &e){e.what();}
//sched_yield();pour retourner la main au prog principal
}
break;
default:
cout<<"WARNING:UNDEFINED COMMAND ON ACQUISITION THREAD − Iteration
bIt<<endl;
break;
}
++nbIt;//Iteration suivante
sched_yield();//lieu de preference de renvoi au prog principal
}
}
//−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
Acquisition/Acquisition.cc
Imprimé par Maxime Fia
02 sep 02 11:41
Acquisition.cc
Page 7/7
ostream &operator<< (ostream &o, Acquisition &acq)
{
acq.Etat(o);//Recupere l’etat de la carte
return o;//On renvoie
}
ostream & Acquisition::Etat(ostream &o)
{//ostream sur reference d’acquisition (pas par pointeur)
for (int i=0;i<NOMBRE_DE_CARTES_MAX;++i)//Pour chaque carte possible
{
if (cartes_[i])//Si la carte
{
(*cartes_[i]).Etat(o);//on recupere
}
}
return o;//on renvoie
}
lundi 09 septembre 2002
Acquisition/Acquisition.cc
Imprimé par Maxime Fia
06 aoû 02 16:16
Erreur.hh
Page 1/9
//Fichier Erreur.hh
//Definition des exceptions
//
// 2 methodes specifiques definies pour chaque exception
// ErrGen* Clone: Renvoie un pointeur sur la classe fille downcaster sur ErrGen
// void autothrow: relance l’exception (dans l’autre thread)
//[email protected]
#ifndef __ERREUR_HH__
#define __ERREUR_HH__
06 aoû 02 16:16
Page
//−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
//Classe mere d’erreur generale sur une carte
class CarteErreur : virtual public ErrGen
{
public:
CarteErreur():ErrGen()
{
#include "defcart.hh"
}
#ifdef __WITH_MUTEX__
#include <pthread.h>
#endif
virtual ErrGen* clone(void)
{
CarteErreur* classe=new CarteErreur;
*classe = (CarteErreur)(*this);
return dynamic_cast<ErrGen*>(classe);
}
#include <stdexcept>
//Classe mere d’erreur generale sur une carte
//typedef void (*PointeurFonctionVoid)(void);
#ifdef __WITH_MUTEX__
//Pour empecher le lancement de 2 exceptions simultannées sous 2threads differen
ts
extern pthread_mutex_t mutex_exception;
#endif
//Classe virtuelle d’exception generale
//contient les prtototypes de clone() et autothrow()
class ErrGen : public std::exception
{
public:
Erreur.hh
virtual const char * what(void) const throw ()
{
return "Generic error on Carte";
}
virtual void autothrow(void)
{
throw CarteErreur();
}
virtual ~CarteErreur()
{
}
ErrGen() : std::exception()
{
};
}
virtual ErrGen* clone(void)=0;
/*{
ErrGen* classe=new ErrGen;
*classe = (ErrGen)(*this);
return classe;
}*/
virtual const char * what(void) const throw ()
{
return "Generic error on Program";
}
virtual void autothrow(void)
{
throw ErrGen();
}
virtual ~ErrGen()
{
}
};
lundi 09 septembre 2002
//Erreur d’initialisation de la carte
class CarteErreurInitialisation : public CarteErreur
{
public:
explicit CarteErreurInitialisation(char *param) :CarteErreur()
{
param_=param;
}
virtual ErrGen* clone(void)
{
CarteErreurInitialisation* classe=new CarteErreurInitialisation(param_
return dynamic_cast<ErrGen*>(classe);
}
virtual const char * what(void) const throw ()
{
char* ret= new char[128];
ret [0]=’\0’;
strcat(ret,"Impossible de configurer sur la carte le parametre : ");
return strncat(ret,param_,64);
Erreur/Erreur.hh
Imprimé par Maxime Fia
06 aoû 02 16:16
Erreur.hh
Page 3/9
06 aoû 02 16:16
Erreur.hh
Page
}
//Classe mere d’erreur generale sur un bus
class BusErreur : virtual public ErrGen
{
public:
virtual void autothrow(void) throw (CarteErreurInitialisation)
{
throw CarteErreurInitialisation(param_);
}
/*CarteErreurInitialisation & operator=(const CarteErreurInitialisation &cla
sse)
{
cout<< "ptet recop" <<endl;
param_[0]=’\0’;
for (int i=0;i<NOMBRE_DE_FPGA*2;param_[i]=classe.param_[i],++i);
return *this;
}*/
virtual ~CarteErreurInitialisation()
{
}
private:
char *param_;
};
BusErreur():ErrGen()
{
}
virtual ErrGen* clone(void)
{
BusErreur* classe = new BusErreur();
return dynamic_cast<ErrGen*>(classe);
}
virtual const char * what(void) const throw ()
{
return "Generic error on BusInterface";
}
virtual void autothrow(void)
{
throw BusErreur();
}
};
//Erreur sur fpga
class CarteErreurFPGA : public CarteErreur
{
public:
explicit CarteErreurFPGA(char *param) :CarteErreur(), param_(param)
{
}
virtual ErrGen* clone(void)
{
CarteErreurFPGA* classe=new CarteErreurFPGA(param_);
return dynamic_cast<ErrGen*>(classe);
}
virtual const char * what(void) const throw ()
{
char* ret= new char[128];
ret[0]=’\0’;
strcat(ret,"Error fpga bloqued number: ");
return strncat(ret,param_,32);
}
virtual void autothrow(void) throw (CarteErreurFPGA)
{
throw CarteErreurFPGA(param_);
}
private:
char *param_;
};
//−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
lundi 09 septembre 2002
//−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
//Erreur d’initialisation du busVME
class BusVMEInitialisationError : public BusErreur
{
public:
explicit BusVMEInitialisationError(int ret):BusErreur(),ret_(ret)
{
}
virtual ErrGen* clone(void)
{
BusVMEInitialisationError* classe = new BusVMEInitialisationError(ret_)
return dynamic_cast<ErrGen*>(classe);
}
virtual const char * what(void) const throw ()
{
return "Erreur d’initialisation\nEchec de l’’initialisation librairie NIVXI\n\n\tLe chasis est t il sous tens
n\tVerifier la connection du cable\n\tVerifier la configuration du driver avec vxitedit\n\tL’’horloge est elle conne
la carte ?\n\tResman a t il ete lance ?\n\n";
}
virtual void autothrow(void) throw (BusVMEInitialisationError)
{
throw BusVMEInitialisationError(ret_);
}
private:
int ret_;
};
Erreur/Erreur.hh
Imprimé par Maxime Fia
06 aoû 02 16:16
Erreur.hh
//Erreur de lecture sur busVME
class BusVMEReadError : public BusErreur
{
public:
explicit BusVMEReadError(int ret):ret_(ret)
{
}
virtual ErrGen* clone(void)
{
BusVMEReadError* classe = new BusVMEReadError(ret_);
return dynamic_cast<ErrGen*>(classe);
}
virtual const char * what(void) const throw ()
{
switch(ret_)
{
case −1:
return "Read VME bus Error: Bus error occurred during transfer";
break;
case −2:
return "Read VME bus Error: Invalid parms";
break;
case −3:
return "Read VME bus Error: Invalid address";
break;
case −4:
return "Read VME bus Error: Invalid width";
break;
case −5:
return "Read VME bus Error: Byte order not supported";
break;
case −6:
return "Read VME bus Error: address not accessible with this hardware";
break;
case −7:
return "Read VME bus Error: Privilege not supported";
break;
case −9:
return "Read VME bus Error: width not supported";
break;
default:
return "Unknow read VME bus Error";
};
}
virtual void autothrow(void) throw (BusVMEReadError)
{
throw BusVMEReadError(ret_);
}
private:
int ret_;
};
//Erreur d’ecriture sur busVME
class BusVMEWriteError : public BusErreur
{
public:
lundi 09 septembre 2002
Page 5/9
06 aoû 02 16:16
Erreur.hh
explicit BusVMEWriteError(int ret):ret_(ret)
{
}
virtual ErrGen* clone(void)
{
BusVMEWriteError* classe = new BusVMEWriteError(ret_);
return dynamic_cast<ErrGen*>(classe);
}
virtual const char * what(void) const throw ()
{
switch(ret_)
{
case −1:
return "Write VME bus Error: Bus error occurred during transfer";
break;
case −2:
return "Write VME bus Error: Invalid parms";
break;
case −3:
return "Write VME bus Error: Invalid address";
break;
case −4:
return "Write VME bus Error: Invalid width";
break;
case −5:
return "Write VME bus Error: Byte order not supported";
break;
case −6:
return "Write VME bus Error: address not accessible with this hardware";
break;
case −7:
return "Write VME bus Error: Privilege not supported";
break;
case −9:
return "Write VME bus Error: width not supported";
break;
default:
return "Unknow Write VME bus Error";
};
}
virtual void autothrow(void) throw (BusVMEWriteError)
{
throw BusVMEWriteError(ret_);
}
private:
int ret_;
};
//−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
//Classe mere d’erreur generale sur une acquisition
class AcquisitionErreur : virtual public ErrGen
{
public:
virtual ErrGen* clone(void)
{
AcquisitionErreur* classe = new AcquisitionErreur();
Erreur/Erreur.hh
Page
Imprimé par Maxime Fia
06 aoû 02 16:16
Erreur.hh
Page 7/9
return dynamic_cast<ErrGen*>(classe);
}
virtual const char * what(void) const throw ()
{
return "Generic error on acquisition";
}
//Classe mere d’erreur d’utilisation sur une acquisition
class AcquisitionErreurUtilisation : public AcquisitionErreur
{
public:
virtual ErrGen* clone(void)
{
AcquisitionErreurUtilisation* classe = new AcquisitionErreurUtilisation();
return dynamic_cast<ErrGen*>(classe);
virtual const char * what(void) const throw ()
{
return "Generic Error of utilisation of acqusition";
}
};
virtual ErrGen* clone(void)
{
AcquisitionErreurTropDeCarte* classe = new AcquisitionErreurTropDeCarte
virtual void autothrow(void)
{
throw AcquisitionErreurUtilisation();
}
return dynamic_cast<ErrGen*>(classe);
}
};
//Classe Erreur double lancement d’acquisition
class AcquisitionErreurDoubleLancement : public AcquisitionErreurUtilisation
{
public:
virtual ErrGen* clone(void)
{
AcquisitionErreurDoubleLancement* classe = new AcquisitionErreurDoubleLance
ment();
return dynamic_cast<ErrGen*>(classe);
}
lundi 09 septembre 2002
virtual void autothrow(void) throw (AcquisitionErreurArretSansLancement)
{
throw AcquisitionErreurArretSansLancement();
}
//Classe Erreur nombre de carte acquisition
class AcquisitionErreurTropDeCarte : public AcquisitionErreurUtilisation
{
public:
}
};
Page
virtual const char * what(void) const throw ()
{
return "Stop acquisition but not started before";
}
};
virtual void autothrow(void) throw (AcquisitionErreurDoubleLancement)
{
throw AcquisitionErreurDoubleLancement();
}
Erreur.hh
virtual ErrGen* clone(void)
{
AcquisitionErreurArretSansLancement* classe = new AcquisitionErreurArre
sLancement();
return dynamic_cast<ErrGen*>(classe);
}
virtual void autothrow(void)
{
throw AcquisitionErreur();
}
virtual const char * what(void) const throw ()
{
return "Impossible to start two acquisition at the same time";
}
06 aoû 02 16:16
//Classe Erreur Arret d’acquisition invalide
class AcquisitionErreurArretSansLancement : public AcquisitionErreurUtilisat
{
public:
virtual const char * what(void) const throw ()
{
return "Too much cart on acquisition";
}
virtual void autothrow(void) throw (AcquisitionErreurTropDeCarte)
{
throw AcquisitionErreurTropDeCarte();
}
};
//Classe Erreur manipulation de classe carte durant acquisition
class AcquisitionErreurManipulationCarte : public AcquisitionErreurUtilisati
{
public:
virtual ErrGen* clone(void)
{
AcquisitionErreurManipulationCarte* classe = new AcquisitionErreurManip
ionCarte();
return dynamic_cast<ErrGen*>(classe);
}
virtual const char * what(void) const throw ()
{
Erreur/Erreur.hh
Imprimé par Maxime Fia
06 aoû 02 16:16
Erreur.hh
Page 9/9
return "Forbidden manipulation of class card during acquisition";
}
virtual void autothrow(void) throw (AcquisitionErreurManipulationCarte)
{
throw AcquisitionErreurManipulationCarte();
}
};
#endif
lundi 09 septembre 2002
Erreur/Erreur.hh
Imprimé par Maxime Fia
01 aoû 02 10:34
Erreur.cc
Page 1/1
#include "Erreur.hh"
//void (*ErrGen::throwex)(void)=&ErrGen::throwErrGen;
#ifdef __WITH_MUTEX__
pthread_mutex_t mutex_exception;
#endif
lundi 09 septembre 2002
Erreur/Erreur.cc
Imprimé par Maxime Fia
02 sep 02 14:34
#include
#include
#include
#include
#include
testgen.cc
Page 1/2
02 sep 02 14:34
"defcart.hh"
"Acquisition.hh"
"BusInterface.hh"
"BusVME.hh"
"Carte.hh"
int main(int,char**)
{
int **rec;
set <int>ml,sl;
sl.insert(0);
sl.insert(1);
sl.insert(2);
sl.insert(3);
sl.insert(4);
sl.insert(5);
sl.insert(6);
sl.insert(7);
sl.insert(8);
sl.insert(9);
sl.insert(10);
sl.insert(11);
sl.insert(12);
sl.insert(13);
sl.insert(14);
sl.insert(15);
int nbvoi=16;
int nbech=16;
//int calc[16]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
//for (set<int>::iterator it=ml.begin();it!=ml.end();it++)
//
cout<< "voie: "<< *it << endl;
Acquisition *monAcquisition;
monAcquisition=Acquisition::Initialiser(nbech,1024,10);
try
{
monAcquisition−>AjouterCarte(0xDDDD0000,&sl);
//monAcquisition−>AjouterCarte(0x22220001,&sl);
//monAcquisition−>AjouterCarte(0x22220005,&ml);
//monAcquisition−>AjouterCarte(0x22220002,&ml);
monAcquisition−>Lancer(5);
for (int i=1; i<=5; i++)
{
while(! (rec = (*monAcquisition)()) )
{
//cout <<"travail interface"<<endl;
}
cout << "*monAcquisition1(" << std::dec <<i<<")"<<endl;
for (int k=0;k<nbvoi;k++)
{
cout << "voie :" << setw(2) << k << endl;
for(int j=0;j<nbech;j++)
{
cout << setw(4) << rec[k][j];
//calc[j]+=rec[k][j];
}
delete [] rec[k];
cout<< " " << endl;
lundi 09 septembre 2002
testgen.cc
Page
}
cout<< " " << endl;
delete [] rec;
rec=NULL;
//cout<< *monAcquisition <<endl;
}
}
catch(CarteErreurInitialisation &e)
{
cerr << "Carte Init!!!: " << e.what() << endl;
}
catch(CarteErreur &e)
{
cerr << "Erreur!: " << e.what() << endl;
}
catch(ErrGen &e)
{
cerr << "Errgen: " << e.what() << endl;
}
catch(std::exception &e)
{
cerr << "general catch " << e.what() << endl;
}
catch(...)
{
cerr << "exception not handle" << endl;
}
//cout << endl;
//cout<<"moyenne:" << endl;
//for (int i=0;i<16;i++)
//
{
//
cout << calc[i]/32 << " ";
//
}
/*cerr << "Fin du main−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−" << e
delete monAcquisition;
monAcquisition = Acquisition::Initialiser(nbech ,1024, 10);
monAcquisition−>AjouterCarte(0xDDDD0000, &sl);
monAcquisition−>Lancer(5);
for (int i=1;i<5;++i)
{
while(!(rec= ((*monAcquisition)()) ) );
for (int k=0;k<nbvoi;++k)
{cout<<"voie "<<k<<" ";
for (int j=0;j<nbech;++j)
{
cout << rec[k][j]<<" ";
}
cout<<endl;
delete[] rec[k];
}
delete[] rec;
}
delete monAcquisition;
return 0;*/
}
testgen.cc
Imprimé par Maxime Fia
defcart.hh
12 aoû 02 12:14
Page 1/3
//Fichier defcart.hh
//Definition des constantes, enum et struct
//pour la gestion de la carte PSFEE
//ainsi que pour la gestion du bus PCI
//[email protected]
// @bus REGISTRES POUR L’ACQUISITION
#undef __VERBOSE__
#undef __UNCONNECTED__
#define __WITH_MUTEX__
static
static
static
static
static
metre
<iostream>
<nivxi.h>
<stdexcept>
<iomanip.h>
const
const
const
const
const
unsigned
unsigned
unsigned
unsigned
unsigned
short
short
short
short
short
defcart.hh
// instructions au fpga "vme"
static const UINT32 vme_reset_ofst=0x7F;
static const UINT32 vme_dld4ram_ofst=0x0F;
#ifndef __DEFCART_HH__
#define __DEFCART_HH__
#include
#include
#include
#include
12 aoû 02 12:14
int
int
int
int
int
NOMBRE_DE_CARTES_MAX=4;
NOMBRE_DE_VOIES=16;
NOMBRE_DE_FPGA=4;
TEMP_D_ATTENTE_MAX_DE_LA_CARTE=2;
NOMBRE_DE_RELECTURE=0;//apres ecriture d’un para
// offset valeur du compteur d’adresse : RAMADDRESS
static const UINT32 vme_daq_addcnt_ofst=0x14;
//
// offset valeur du nombre d’echantillon par trigger LA_W
static const UINT32 vme_daq_law_ofst=0x12;
//
// offset valeur de la longueur du pipe line : PIPELENGTH
static const UINT32 vme_daq_plen_ofst=0x11;
//
// offset nombre max d’echantillons NEVT_MAX
static const UINT32 vme_daq_nevtmax_ofst=0x13;
//
// offset nombre max d’echantillons NEVT_CURRENT
static const UINT32 vme_daq_nevtcurrent_ofst=0x15;
//
// offset retard trigger TRIG_DLY
static const UINT32 vme_daq_trigdly_ofst=0x16;
#include "Erreur.hh"
static
static
static
static
//
//
//
//
//
//
//
//
//
const
const
const
const
UINT16
UINT16
UINT16
UINT16
VME_A24=2;
VME_A32=3;
VME_D16=2;
VME_D32=4;
@vme INSTRUCTIONS CARTE
on dispose de 16b d’@ vme −2 = 14
les fpga ont 7b d’espace interne
bit 15 : destinataire 1=fpga vme 0=fpga traitement
bit 14−13 : adresse fpga traitement / instruction si b15=1
bit 12−9 : instruction
bit 8−2 : adresse interne fpga de traitement
bit 1 : toujours 0
bit 0 : n’existe pas
static
static
static
static
static
static
static
const
const
const
const
const
const
const
// registres
static const
static const
static const
static const
static const
static const
static const
static const
static const
static const
static const
UINT32
UINT32
UINT32
UINT32
UINT32
UINT32
UINT32
vme_null=0x0;
vme_vmereg=0x1;
vme_vmeram=0x7;
vme_daqreg=0x9;
vme_dld4ram=0xD;
vme_daqspecial=0xE;
vme_special=0xF;
internes fpga "vme"
UINT32 vme_vmeflags1_ofst=0x21;
UINT32 vme_status1_ofst=0x23;
UINT32 vme_mode_ofst=0x25;
UINT32 vme_clstatus1_ofst=0x61;
UINT32 vme_ram1_ofst=0x0D;
UINT32 vme_ram2_ofst=0x0E;
UINT32 vme_ram3_ofst=0x0F;
UINT32 vme_ramradd_ofst=0x1C;
UINT32 vme_ramwadd_ofst=0x1D;
UINT32 vme_ramraddauto_ofst=0x1E;
UINT32 vme_null_ofst=0x00;
lundi 09 septembre 2002
// @bus REGISTRES POUR LE TRAITEMENT
//
// offset ALPHA
static const UINT32 vme_alpha_ofst=0x02;
//
// offset OFFSET0
static const UINT32 vme_offset0_ofst=0x08;
//
// offset OFFSET1
static const UINT32 vme_offset1_ofst=0x09;
//
// offset GAIN0
static const UINT32 vme_gain0_ofst=0x0C;
//
// offset GAIN1
static const UINT32 vme_gain1_ofst=0x0D;
//
// offset THRESHOLD
static const UINT32 vme_threshold_ofst=0x03;
static const UINT32 vme_daq_threshold_ofst=0x03;
//
// offset PEDESTAL
static const UINT32 vme_pedestal_ofst=0x05;
//
// offset configuration du process
static const UINT32 vme_processcfg_ofst=0x06;
// @bus REGISTRES D’ETAT/DE CONFIGURATION DU FPGA
//
// offset registre de FLAGS1
static const UINT32 vme_flags1_ofst=0x1C;
//
// offset registre de CONFIG1
static const UINT32 vme_config1_ofst=0x1E;
defcart.hh
Page
Imprimé par Maxime Fia
12 aoû 02 12:14
defcart.hh
Page 3/3
//
// offset STATUS
static const UINT32 vme_daq_status_ofst=0x1D;
//
// offset MODE
static const UINT32 vme_daq_mode_ofst=0x3C;
// @bus INSTRUCTIONS DU FPGA
//
// Lecture des 4 memoires a l’adresse courante (incrementee par le strobe)
static const UINT32 vme_4ramdownload_ofst=0x44;
//
// Reset de l’adresse courante
static const UINT32 vme_daq_rstramadd_ofst=0x70;
//
// Reset des flags
static const UINT32 vme_daq_rstflags_ofst=0x71;
// MODES :
// "00" & 2 bits daq_ctrl pour version 1_21
// registre pour version 1_22
static const UINT32 vme_mode_w=4;
static const UINT32 vme_mode_NORMAL=0x0;
static const UINT32 vme_mode_LAW=0x1;
static const UINT32 vme_mode_DOWNLOAD=0x2;
#endif
lundi 09 septembre 2002
defcart.hh

Documents pareils