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