Training software PCIe400

Europe/Paris
Description
    • 09:00 09:10
      Introduction 10m
      Orateur: Renaud Le Gac (CPPM CNRS/IN2P3)
    • 09:10 10:10
      Environnement de développement
      • 09:10
        Git et GitLab 20m
        Orateur: Renaud Le Gac (CPPM CNRS/IN2P3)

        Serveur de développement

        • 10.10.0.6
        • Répertoire par personne / binôme : formation_pcie400/userN ou N=1, ...

        Projet GitLab dédié à cette formation

        https://gitlab.in2p3.fr/legac/p400-model

        Les raccourcis git

        • Recommandons d'utiliser les raccourcis clavier à définir dans le fichier /home/me/.gitconfig

        [user]
            name = Prénom Nom
            email = nom@mylab.in2p3.fr
        [alias]
            co = checkout
            br = branch
            ci = commit
            st = status
            lo = log --oneline --decorate
            rso = remote show origin

        • Ne pas oublier de configurer son nom et son adresse email

        • Ils sont actifs sur le serveur

        git branch → git br
        git checkout → git co
        git log → git lo
        git status → git st
        git remote show origin → git rso

        • Mais aussi :

        $ git pull
        $ git push

        Se connecter sans mot de passe

      • 09:30
        p400-model -- épisode 1 20m
        Orateur: Renaud Le Gac (CPPM CNRS/IN2P3)

        Installer le projet GitLab p400-model

        Comment installer p400-model dans son environnement de développement est détaillé dans la documentation du projet README/install ou p400-model/docs/install_stable

        La suite est adaptée à la configuration du serveur que nous utilisons pour cette formation

        Activer python3.7

        • Dépend de votre distribution
        • Recommandé d'utiliser python 3.7 ou ses successeurs
        • Semble fonctionner aussi avec Centos7 et python 3.6.8
        • Recommandé d'utiliser les instructions de base et de se limiter à celles de Python3.7

        $ conda deactivate
        $ conda activate py37

        Préférer pyenv à conda si la version native de python est trop ancienne.

        Cloner le projet GitLab

        $ cd formation_pcie400/userN
        $ git clone https://gitlab.in2p3.fr/legac/p400-model.git

        Préférer un clonage via SSH (pas possible ici)

        Créer un environnement virtuel et l'activer

        $ python -m venv venv
        $ source venv/bin/activate

        Mettre à jour pip et le configurer pour accéder aux packages du projet PCIe40

        (venv) (py37) $ pip install -U pip

        • Copier le fichier pip.conf dans le répertoire formation_pcie400/userN/venv

        (venv) (py37) $ cp ../../pip.conf venv/

        Installer les packages PyPI requis pour le dévelopement

        (venv) (py37) $ cd p400-model
        (venv) (py37) $ pip install -r requirements-dev.txt

        Tester l'installation

        (venv) (py37) $ pip list | grep p400rw  → 0.3.1
        (venv) (py37) $ pip list | grep pyftdi
          → 0.54.0

        (venv) (py37) $ python
               import p400rw as rw
               print(rw.read)

        Anatomie du projet GitLab p400-model (pdf)

        Le package p400rw

        • Permet d'accéder à un bus I²C à travers un contrôleur FTDI
        • Opération de lecture et d'écriture
        • Documentation du package

        Contrôleur FTDI

        • Des commandes sont disponibles pour lister les contrôleurs FTDI connectées au serveur :

        $ ftdi_urls.py

         

      • 09:50
        Pause Café 20m
    • 10:10 11:30
      Exercice
      • 10:10
        Présentation Module DC/DC 10m
        Orateur: Paul Bibron (Aix Marseille Université, CNRS/IN2P3, CPPM, Marseille, France)
      • 10:20
        Présentation module PLL 10m
        Orateur: Jean-Pierre Cachemiche (Aix Marseille Univ, CNRS/IN2P3, CPPM, Marseille, France)
      • 10:30
        Développement d'une classe pour lire ou écrire les valeurs 1h
    • 11:30 12:30
      Discussion sur le code
    • 12:30 14:00
      Repas 1h 30m
    • 14:00 18:00
      Flux et méthodes de development
      • 14:00
        Flux de dévelopement 20m
        Orateur: Renaud Le Gac (CPPM CNRS/IN2P3)

        Flux de développement

        1. Étudier la fiche technique du composant
        2. Discuter avec les développeurs hardware des méthodes les plus utiles
        3. Préparer un brouillon de la classe python avec uniquement la signature des méthodes et leurs documentations (i.e Ltm46xx)
        4. Itérer avec les développeurs hardware
        5. Développer le code python en appliquant les règles de nommages et les normes de codage
        6. Développer les tests unitaires pour valider le code python
        7. Intégrer le module et ses tests dans le projet p400-model
      • 14:20
        Flux GitLab 20m
        Orateur: Renaud Le Gac (CPPM CNRS/IN2P3)

        Flux GitLab

        Créer une issue dans GitLab

        •  Créer une issue et la documenter (composant, référence à la fiche technique, mécanisme d'héritage, etc) :

        Gitab > Issue > New issue

        • Remplir le Titre et la description.
          Le titre et la description doivent être compréhensibles
           
        • Cliquer sur le bouton Create issue
          Garder en mémoire le numéro de l'issue, i.e 123.
          Il est aussi visible à travers la liste des issues

           

        Créer une branche dans son environnement de développement

        • le nom de la branche commence par le numéro de l'issue, i.e 123-si5394
          Le nom doit être compréhensible, chaque mot séparé par un tiret ou un underscore

        $ cd p400-model
        $ git co master
        $ git pull
        $ git co -b 123-si5394

        $ git push --set-upstream origin 123-si5394

        Créer un module pour le composant et un module pour les tests unitaires

        $ cd p400-model/src/p400model
        $ touch si5394.py

        $ cd p400-model/tests/
        $ touch test_si5394_1000.py

        Développer simultanément la classe et les tests des méthodes

        • Très régulièrement, à chaque étape, commit et push du code dans GitLab

        cd p400-model/src/p400model
        $ git add si5394.py
        $ git ci -m"Update si5394.py to add the method part_number"
        $ git push

        cd p400-model/tests
        $ git add test_si5394_1000.py
        $ git ci -m"Update test_si5394_1000.py to add tests of Si5394.part_number"
        $ git push

        Appliquer les normes de codage

        • Commit et pousser votre code dans GitLab
           
        • Pour obtenir un état des lieux :

        $ cd p400-model
        $ isort --diff src
        $ black --diff --color src
        $ flake8 src

        • Modifier le code automatiquement :

        $ cd p400-model
        $ isort -v src
        $ black -v src

        • Les violations des règles PEP8, identifiées par flake8, doivent être corrigées à la main. Une technique est de configurer l'IDE pour les détecter lors du codage.
           
        • Vérifier une dernière fois le code, pousser le code dans GitLab

        Créer un merge request dans GitLab

        GitLab > Merge requests > New merge request

        • Sélectionner la branche source, 123-si5394 et celle de destination, master
          Cliquez sur Compare branches and continue
        • Compléter la description pour expliquer ce qui a été fait
        • Vérifier que la description se termine parClose #123
        • Vérifier que la case Delete source branch when merge request is accepted  est cochée
        • Cliquer sur le bouton Create merge request
           
        • Quand le merge request est accepté par GitLab, il sera regardé par un membre d'une autre équipe qui aura la charge de l'accepter ou de discuter avec vous d'améliorations à apporter.

        Intégration Continue dans GitLab (pdf)

        • Les scripts d'Intégration Continue démarrent dès qu'un merge request est créé.
           
        • Vérifie que les imports sont classés par groupes et par ordre alphabétique (isort)
        • Vérifie que le code est formaté selon les standards du moment (black)
        • Vérifie que les règles PEP8 sont satisfaites (flake8)
        • Vérifie que l'historique de GitLab est limpide (pdf)
           
        • Si l'un de ces tests échoue, le merge request est rejeté.
          Il reste actif en attente de correction.

           
        • L'état des scripts d'intégration Continue sont visibles dans :

        GitLab > CI/CD > Pipelines
        GitLab > CI/CD > Jobs

        • Corriger le code dans la branche de travail, puis pousser les modifications dans GitLab
          Les scripts d'intégration sont exécutés à nouveau.
           
        • Si le merge request échoue, car l'historique n'est pas limpide, il faut rebaser ma branche de travail par rapport à la branche master

        $ cd p400-model
        $ git co master
        $ git pull
        $ git remote show origin
        $ git co 123-si5394
        $ git rebase master
        $ git push --force

        Cette dernière opération est délicate. Il faut prendre des précautions quand plusieurs développeurs travaillent sur la même branche. Il faut alors les prévenir en leur demandant de mettre à jour leur copie et de régler les confits qui pourraient apparaitre.

        Mettre à jour la branche master

        • Quand le merge request est accepté et fermé :

        $ git co master
        $ git pull
        $ git remote show origin
        $ git br -d 123-si5394

      • 14:40
        Application le flux GitLab sur l'exercice 20m
      • 15:00
        Les nomes de codage 10m
        Orateur: Renaud Le Gac (CPPM CNRS/IN2P3)

        Les normes de codage du code Python (PEP8)

        Références

        https://pep8.org/

        Nom des modules

        Nom court en minuscule
        L'underscore peut être utilisé si il améliore la lisibilité

        Nom des classes

        Utiliser la convention CapWord

        Nom des méthodes et des fonctions

        Nom en minuscule
        L'underscore peut être utilisé si il améliore la lisibilité

        Nom des variables

        En minuscules avec un underscore pour séparer les mots
        Le nom de la variable doit faire sens pour un non-expert

        Nom des constantes

        Défini au niveau du module
        En majuscules avec underscore pour séparer les mots, i.e MAX_OVERFLOW

        Les chaînes de caractères

        Entre double quote, i.e "Hello"

        Mise en forme du code

        • Pris en charge par les outils isort et black
           
        • Longueur de la ligne est limitée à 79 caractères
        • Indentation est de 4 espaces (pas de caractères TAB)
           
        • Deux lignes blanches avant la définition d'une classe ou d'une fonction
        • Une seule ligne banche avant la définition d'une méthode
      • 15:10
        Les docs string 10m

        Les docs string

        • Chaque module, classe, méthode et fonction sont documentés.
        • Le système d'intégration continue de GitLab, génère automatiquement la documentation quand une version est publiée
           
        • Cette documentation est publique. Elle est disponible à l'adresse  https://in2p3-readout400.pages.in2p3.fr/software/p400-xyz/ pour le projet GitLab p400-xyz
           
        • Exemple : le module p400rw.fdti.py
        • Pour chaque projet, voir docs/devguide/docsting.md
           
        • La langue est l'anglais

        Exception

        Pas de doc string quand :

        • l'objet n'est pas exposé
        • la fonction / méthode est très courte ou évidente

        Documenter le module

        """
        * Wrapper around the ``pydfti`` packages.
        * Read and write to device connected to an I²C bus.
          The bus is managed by an FTDI controller.
        
        * Documentation: https://eblot.github.io/pyftdi/
        
        Note:
        
            * The best way to import read / write functions in your python code,
              is the following::
        
                        import p400rw as rw
                        value = rw.read(master, slave, register)
        
            * In the current release, it uses the I²C bus via an FTDI device.
            * In the future, read and write operations can be done via different paths:
              FTDI, Jtag, PCIe, etc.
            * The selection of the path will be performed by the syntactic
              sugar ``import p400rw as rw`` as well as by an environment variable.
            * Signature for ``read`` and ``write`` functions will stay the same and
              don't depend on the path.
        
        """
        

        Documenter une classe et son constructeur

        class ExampleClass(object):
            """The summary line for a class docstring should fit on one line.
        
            The __init__ method may be documented the class level docstring.
        
            Note:
                * Do not include the `self` parameter in the ``Args`` section.
                * Multiple line are supported for the description of parameters
        
            Args:
                param1 (str): Description of `param1`.
                param2 (int, optional): Description of `param2`.
                    Multiple lines are supported.
                param3 (list(str)): Description of `param3`.
        
            """
            def __init__(self, param1, param2, param3):
        

        Documenter une méthode ou une fonction

        def read(
            master_url, devadd, regadd, master=None, readlen=1, relax=True, start=True
        ):
            """Read a register content.
        
            Args:
                master_url (str):
                    URL of the FTDI master: ftdi://:232h:FT0FMF6V/1
        
                devadd (int):
                    address of the slave on the I²C bus
        
                regadd (int):
                    slave register address to read from
        
                master (pyftdi.i2c.I2cController)
                    master controlling slave
        
                readlen (int):
                    count of bytes to read out
        
                relax (bool):
                    whether to relax the bus (emit STOP) or not
        
                start (bool):
                    whether to emit a start sequence (w/ address)
        
            Returns:
                bytes
        
            Raises:
                pyftdi.i2c.I2cIOError
        
            """
        

        Autres exemples

        Utilisation des commentaires dans le code

        • Les commentaires dans le code ne sont pas publiés dans la documentation
        • Ils ont là pour aider le lecteur à comprendre un passage difficile
        • Afin de faciliter la lecture, éviter les commentaires inline :
              x = x + 1                 # Compensate for border
      • 15:20
        Application les normes de codage sur l'exercice 20m
      • 15:40
        Pause café 30m
      • 16:10
        Organisation du software 20m
        Orateur: Renaud Le Gac (CPPM CNRS/IN2P3)

        Organisation du software (pdf)

        Projets GitLab: https://gitlab.in2p3.fr/in2p3-readout400/software

         

      • 16:30
        Discussion p400-rw 40m

        Discussion p400-rw

        Le problème (pdf)

        Approche envisagée

        • Un RPM par chemin d'accès avec les drivers :
        p400-rpm-ftdi
        p400-rpm-pcie-intel
        • Un module python par chemin d'accès avec les fonctions read, write et close
        p400-rw/
            src/p400rw/
                fdti.py
                pcie_intel.py
        • Une variable d'environnement qui définit le chemin, avec une valeur par défaut PCIe:
        $ export P400_RW="FDTI"
        • La logique de sélection des fonctions dans le module __init__.py
        import os

        P400_RW = os.environment["P400_RW"]

        if p400_RW == "FDTI":
            from .fdti import close, read, write

        else:
            from .pcie_intel import close, read, write
        • Signature d'une fonction read :
        def read(controller, device, register, hwarg1=None, kwarg2=True):

        Les keyword arguments dependent du chemin.
        Les valeurs par défaut couvrent l'utilisation usuelle.

      • 17:10
        EDI Pycharm 20m
        Orateur: Renaud Le Gac (CPPM CNRS/IN2P3)

        Environnement Développement Intégré PyCharm

        • Pour développer des codes complexe, il est recommandé d'utiliser un Environnement de Développement Intégré (EDI)  plutôt qu'un simple éditeur de texte et une console.
           
        • Pour projet le p400-model, utiliser les outils avec lesquels vous êtes à l'aise.
           
        • Au CPPM, nous utilisons PyCharm CE qui pourrait vous simplifier la tâche :
           
          • Éditeur de code python
          • Gestion de Git et GitLab
          • Exécution de test unitaire et d'outils externe
          • Débogage
          • Vérification orthographe et grammaire anglaise
          • Rendu des pages écrites en MarkDown
          • etc

        Installer PyCharm

        • Espace utilisateur
        • Installer PyCharm via la ToolBox de JetBrain

        Nombre de caractères maximum par lignes

        File > Settings > Editor > Code Style > Python:  Wrapping sand Braces
        Hard wrap at 79
        Ensure that right margin is not exceed
        File > Settings > General > Editor > Appearance
        Show hard wrap and visual guide

        Indentation 4 espaces

        File > Settings > Editor > Code Style > Python:  Tabs and indents

        Numéro des lignes

        File > Settings > General > Editor > Appearance
        Show line number

        Orthographe et grammaire

         File > Settings > Apparence > Editor > Natural Languages

        Règles PEP 8

        • Actif par défaut
         File > Settings > Apparence > Editor > Inspections: python

        Organisation des projets

        p400/          
            p400-model/
            p400-xyz/  
            venv/      

        Configurer python et son environnent virtuel

        File > Settings > Project: p400 > Python Interpreter → p400/venv/bin/python

        Configurer les outils externes (isort, black, flake8)

        File > Settings > Tools > External Tools
        Program: $ProjectFileDir$/venv/bin/isort
        Arguments: $FilePath$
        Working directory: $ProjectFileDir$
    • 09:00 12:10
      Pytest
      • 09:00
        Introduction Pytest 30m
        Orateur: Renaud Le Gac (CPPM CNRS/IN2P3)

        Tests unitaires avec pytest

        Référence :  https://pytest.org/en/7.1.x/

        Le code pour les tests

        p400-model/
            tests/
        • un module par composant, i.e test_si5394_1000.py
        • une fonction par méthode

        Importer la classe du composant Si5394 dans le module de test

        from p400model.si5394 import Si5394

        Convention de nommage

        • module:
        test_composant_ijkl.py ou ijkl = 1000, 2000, 3000, etc
        • fonction:
        def test_composant_method_iuvw() ou uvw = 001, 002, ..., 999

        Tester une méthode d'un composant

        • module test_si5394_1000.py
        from p400model.si5394 import Si5394

        def test_si5394_part_number_1001():
            pll = Si5394(controler, device)
            value = pll.part_number()
            assert value == "5394"
        • NOTE : il est possible de mettre plusieurs assert par fonction
        • Exécuter le test
        $ cd p400-model
        $ pytest

        Tester deux méthodes d'un composant

        import pytest
        from p400model.si5394 import Si5394


        @pytest.fixture
        def pll():
            return Si5394(controler, device)


        def test_si5394_part_number_1001(pll):
            value = pll.part_number()
            assert value == "5394"


        def test_si5394_is_locked_1002(pll)
            assert pll.is_locked()

        Tester une exception

        import pytest
        from p400model.exception import P400ModelException


        def test_si5394_my_method(pll):
            with pytest.raises(P400ModelException):
                pll.my_method(port=4)

           

        La liste des tests

        $ cd p400-model
        $ pytest --collect-only -q

        Filtrer les tests

        https://docs.pytest.org/en/7.1.x/how-to/usage.html#usage

        $ cd p400-model
        $ pytest -k si5394_part_number
        $ pytest -k 1001

        $ pytest -k test_si5394
        $ ...

        Print pour comprendre ce qui se passe

        import logging

        def test_si5394_part_number_1001(pll):
            value = pll.part_number()
            logging.debug(f"part number: {value}")
            assert value == "5394"

         
        • Pour voir les messages de type debug et au-delà:
        $ cd p400-model
        $ pytest -k 1001 --log-cli-level DEBUG

         
        • Le niveau de logging :
        CRITICAL 50
        ERROR    40
        WARNING  30
        INFO     20 (défaut)
        DEBUG    10
        NOSET     0
        • En cas de problèmes
        $ cd p400-model
        $ pytest -k 1001 --tb auto
      • 09:30
        Exercice 1h
      • 10:30
        p400-model -- épisode 2 10m

        p400-model -- épisode 2

        Guide développement

        • Tous nos packages python ont un Guide de développement
        • Écrit en Markdown, il est accessible à partir de GitLab ou directement dans le code

        via le README
        Access directe : devguide

        $ cd p400-model
        $ more README

        $ cd p400-model/docs/devguide

        • Le Markdown est aussi interprété par PyCharm

        Unité de mesure

        • Unité de base du système international (Ampère, Hertz, Volt, Watt, °C, etc)

        Héritage

        • Des composants de la même famille, mais avec quelques variations, i.e. Ltm4677 et Ltm4681
        • La classe Ltm46xx contient les méthodes communes aux deux composants
        • La classe Ltm4677 hérite de la classe Ltm46xx.Elle contient les méthodes qui lui sont spécifiques
        from .ltm46xx import Ltm46xx

        class Ltm4677(Ltm46xx):

            def my_method(self):
                ...
        • Idem pour la classe Ltm4681

        Fonctions communes à plusieurs composants

        • Essentiellement des fonctions de conversions
        • Concentrées dans le module p400model/tools.py

        Les exceptions

        from .exception import P400ModelException

        class Ltm46xx:


            def part_number(self):
                ...

                                 if error:
                    msg = "bla bla"
                    raise P400ModelException(msg)

        Manipuler les adresses des registres

        • Définit l'adresse dans la méthode, ne pas utiliser de constante
        def part_number(self):
            value = rw.read(0x67)

        Méthodes status et info ?

        • La méthode status est optimisée pour extraire tous les paramètres vitaux ou tous les paramètres en une seule fois
        • Le résultat est retourné sous la forme d'un dictionnaire
        • Exemple de nommage des clés :

        v_in_12v
        v_out_0.9v
        i_out_0.9v_0
        f_240mhz_0
        pn

        • la méthode info print le status (user friendly)
        from pprint import pprint

        ...
        def info(self):
            pprint(self.status())
      • 10:40
        Pause café 20m
      • 11:00
        Les composants à développer 20m
        Orateur: Paul Bibron (Aix Marseille Université, CNRS/IN2P3, CPPM, Marseille, France)

        Trouver les datasheet des composants sur boxIN2P3

        boxIN2P3:/PCIe400/documentation/datasheet

      • 11:20
        Organisation et plans 40m
    • 12:10 13:30
      Repas 1h 20m
    • 13:30 15:00
      Hackathon