Salae Logic AnalyzerDans mon billet précédent, je décrivais comment manipuler avec Python les données extraites d’un analyseur logique Saleae afin de visualiser la latence entre deux signaux numériques et en déduire la gigue temporelle de l’un d’entre eux. En conclusion, j’émettais l’hypothèse que le SDK de Saleae pourrait nous permettre de récupérer des informations sur les signaux en temps réel et non plus par l’intermédiaire d’un fichier CSV exporté. Mais au final, c’est un logiciel libre plus générique qui nous a fourni la meilleure solution.

La solution de Saleae et son SDK

Saleae propose aux développeurs deux solutions :

  • une API (en bêta à l’heure actuelle) qui permet uniquement de contrôler leur logiciel de visualisation depuis une socket.
  • un SDK qui permet d’étendre leur logiciel et écrire son propre analyseur de protocole.

Nous aurions pu a priori nous intéresser au SDK et écrire un analyseur qui exporte à la volée la latence entre deux signaux définis, mais cette solution est dépendante du logiciel de Saleae et de son évolution, ce qui nous garantit une très faible pérennité. De plus, le logiciel de visualisation de Saleae n’a pas pour vocation d’être utilisé avec un autre analyseur logique que ceux qu’ils produisent. Nous cherchions donc une solution plus générique et permanente.

Sigrok: une suite logicielle open-source pour les analyseurs logiques

C’est lors d’une discussion entre collègues qu’Emeric Vigier m’a mit sur la piste d’un logiciel nommé Sigrok. Ayant pour objectif de fournir une solution libre et générique pour les analyseurs logiques, Sigrok est une suite logicielle permettant d’extraire les données collectées par divers types d’analyseurs et de les afficher, voire de les traiter, à l’aide de décodeurs de protocole.

Cette suite se compose de plusieurs sous-projets :

  • libsigrok : une librairie écrite en C qui standardise l’accès aux pilotes des différents analyseurs.
  • libsigrokdecode : une librairie écrite en C qui fournit une API pour le décodage de protocole. Les décodeurs sont écrits en Python (>= 3).
  • Sigrok-cli : une interface en ligne de commande pour manipuler Sigrok.
  • PulseView : une interface graphique en Qt pour manipuler Sigrok.
  • Fx2lafw : Sigrok fournit également une implémentation open source du firmware des puces Cypress FX2 qui est la puce utilisé entre autre par Saleae dans toutes les déclinaisons de ses analyseurs logiques hormis le Logic Pro 16. Ce firmware permet de programmer le FPGA pour qu’il fonctionne comme un simple analyseur logique matériel.

Sigrok : exemple d’utilisation

Un exemple de cette suite mise bout à bout sera plus parlant qu’un long discours. Nous allons donc utiliser PulseView pour capturer et visualiser les signaux d’un analyseur logique.

À l’ouverture PulseView dans sa version 0.2.0 ressemble à ceci :
[cliquez sur les images pour les agrandir]

pulseview01

Nous allons commencer une capture en laissant le périphérique de démonstration générer des signaux aléatoires :

pulseview02

Nous allons ensuite ajouter un décodeur assez simple qui calcule le rapport cyclique d’un signal numérique :

pulseview03

Chaque décodeur dispose de ses options. Dans notre cas nous allons simplement définir le canal sur lequel nous voulons appliquer le décodeur :

pulseview04

Le calcul du rapport cyclique est appliqué sur le canal et reporté directement dans l’interface de PulseView :

pulseview05

Sigrok : écriture d’un décodeur pour le calcul de la latence entre deux signaux numériques

Ce qui suit est basé sur la libsigrok et la libsigrokdecode dans leurs version 0.3.0.
Chaque décodeur de protocole est un module Python qui possède son propre sous-répertoire dans le répertoire de décodeurs libsigrokdecode.

Un décodeur se compose de deux fichiers :

  • __init__.py : Ce fichier est requis pour l’initialisation du décodeur et contient une simple description du protocole.
  • pd.py : Ce fichier contient des métadonnées sur le décodeur, et son code, la plupart du temps implémenté dans la méthode decode()

Nous allons nous intéresser au fichier pd.py contenant le code de notre décodeur. L’API de la libsigrokdecode nous fournit toutes les informations sur les signaux capturés.

Rappelons nous que pour calculer la latence entre deux signaux numériques, notre logique est de considérer l’un des signaux comme une horloge de référence, et l’autre comme une résultante de ce premier. Les deux étant liés, à chaque transition d’état du signal d’horloge, le signal résultant changera aussi d’état avec une latence plus ou moins variable. Nous parlerons de la fluctuation de cette latence plus loin.

Les options du décodeur

La première chose à faire est donc de permettre à notre décodeur de définir quel canal correspond au signal d’horloge et quel canal correspond au signal résultant. La classe du décodeur permet justement de définir quelques attributs précisant ses options, notamment celle permettant à l’utilisateur de choisir les canaux :

class Decoder(srd.Decoder):
   # ...
   channels = (
      {'id': 'clk', 'name': 'Clock', 'desc': 'Clock reference channel'},
      {'id': 'sig', 'name': 'Resulting signal', 'desc': 'Resulting signal controlled by the clock'},
   )
   ...

La méthode decode()

La seconde étape va être d’implémenter le contenu de la méthode decode(). Cette méthode est appelé par la libsigrokdecode chaque fois qu’un nouveau bloc de données à traiter est disponible.

Chaque bloc est en fait un échantillon dépendant de la fréquence d’échantillonnage de nos signaux. Par exemple pour une valeur d’échantillonnage de 100 Hz, nous obtiendrons 100 blocs de données par seconde. Ces blocs de données contiennent le numéro de l’échantillon actuel, ainsi que l’état des différents signaux à cet instant.

À partir de ces informations, il est ainsi très facile d’implémenter une machine à état qui va noter à quel échantillon à eu lieu la transition du signal d’horloge et celle du signal résultant. Le nombre d’échantillons écoulés entre les deux, multiplié par la valeur de la fréquence d’échantillonnage, va nous donner la latence exprimée en secondes.

Dans sa version simplifiée, notre machine à état ressemble à cela :

def decode(self, ss, es, data):

    self.oldpin, (clk, sig) = pins, pins

    # State machine:
    # For each sample we can move 2 steps forward in the state machine.
    while True:
        # Clock state has the lead.
        if self.state == 'CLK':
            if self.clk_start == self.samplenum:
                # Clock transition already treated.
                # We have done everything we can with this sample.
                break
            else:
                if self.clk_edge(self.oldclk, clk) is True:
                    # Clock edge found.
                    # We note the sample and move to the next state.
                    self.clk_start = self.samplenum
                    self.state = 'SIG'

        if self.state == 'SIG':
            if self.sig_start == self.samplenum:
                # Signal transition already treated.
                # We have done everything we can with this sample.
                break
            else:
                if self.sig_edge(self.oldsig, sig) is True:
                    # Signal edge found.
                    # We note the sample, calculate the latency
                    # and move to the next state.
                    self.sig_start = self.samplenum
                    self.state = 'CLK'
                    # Calculate and report the latency.
                    self.putx((self.sig_start - self.clk_start) / self.samplerate)

    # Save current CLK/SIG values for the next round.
    self.oldclk, self.oldsig = clk, sig

Les sorties de notre décodeur

La libsigrokdecode propose différentes façons de remonter les informations de notre décodeur. Une méthode register() permet d’enregistrer les sorties que notre décodeur génère. Chaque sortie a un type défini; par exemple, le type OUTPUT_ANN est utilisé pour définir une sortie de type annotation qui sera représentée dans PulseView par les boîtes graphiques que nous avons vues précédemment avec le décodeur de rapport cyclique.

Pour notre décodeur, nous voulons principalement deux types de sorties:

  • une sortie de type annotation (OUTPUT_ANN) pour visualiser la latence mise en forme dans PulseView,
  • et une sortie de type binaire (OUTPUT_BINARY) pour sortir les valeurs de latence brute sans mise en forme afin d’être analysé.

La version finale de notre décodeur inclut également une sortie de type métadonnée (OUTPUT_META) rapportant des statistiques sur les signaux manqués, mais ce n’est pas important ici.

Nos deux sorties donc sont définies dans notre décodeur comme suit :

self.out_ann = self.register(srd.OUTPUT_ANN)
self.out_bin = self.register(srd.OUTPUT_BINARY)

Pour reporter des informations sur ces sorties nous utilisons la méthode put() qui a pour prototype :

put(debut_echantillon, fin_echantillon, type_de_sortie, donnees)

type_de_sortie est une de nos deux méthodes enregistrées au préalable (out_ann, out_bin).

Pour reporter la latence entre deux signaux en utilisant le type annotation nous pourrons par exemple écrire :

put(clk_start, sig_start, out_ann, [0, [ma_latence]])

Les résultats obtenus avec notre décodeur de latence

Voici un exemple des résultats obtenus avec notre décodeur dans PulseView :
pulseview06

Et les résultats obtenus avec sigrok-cli dans sa version 0.5.0 et la sortie binaire pour avoir les valeurs de latence brute :
sigrok-cli

Visualisation des données en temps réel pour en déduire la gigue temporelle

Comme nous venons de le voir, sigrok-cli nous permet de sortir les valeurs de latence brute sur la console en temps réel. Nous allons maintenant nous intéresser aux variations de cette latence. En effet, rien ne nous garantit que la latence entre ces deux signaux sera constante.

Considérant que le signal d’horloge est périodique et sans fluctuation, en théorie, le signal résultant devrait l’être aussi et la latence entre ces deux signaux devraient être constante. Si ce n’est pas le cas, c’est qu’il y a une fluctuation de cette latence que nous avions décrite dans le précédent article comme la gigue temporelle d’un signal, et c’est ce que nous voulons visualiser maintenant.

Nous pouvons donc imaginer récupérer ces valeurs à la volée et les mettre en forme dans un graphique. Pour cela, nous allons encore une fois écrire un script en Python.

Je me suis intéressé à la librairie matplotlib et son module d’animation, qui propose une méthode FuncAnimation() permettant de définir une fonction à appeler pour mettre à jour le graphique à chaque fois que de nouvelles données sont disponibles. Cette fonction prend en paramètre la figure sur laquelle nous travaillons, la fonction d’animation à appeler et l’ensemble de données à traiter.

anim = animation.FuncAnimation(fig, animate, frames=data_gen)

Ces données peuvent être de la forme d’un générateur Python qui va très bien de paire avec la lecture d’un flux de données (merci à Guillaume Roguez pour m’avoir présenté ce type d’objet).

Ainsi à chaque fois qu’une nouvelle latence sera écrite dans le flux, notre générateur récupérera une nouvelle donnée et la fonction d’animation sera appelée.

Voici à quoi ressemble le code du générateur :

# The data generator take its
# input from file or stdin
def data_gen():
    while True:
        line = fd.readline().strip()
        if line:
            yield line

Notre fonction d’animation va, si besoin est, mettre à jour l’abscisse pour visualiser toutes les latences, et ajouter la nouvelle valeur fournie par le générateur.

# The update graph function
def animate(data):
    global x_max, x_min, x, y

    try:
        # we must recalculate the abscissa range
        x_new = float(data)
        if x_max is None or x_new > x_max:
            x_max = x_new
        if x_min is None or x_new < x_min:
            x_min = x_new
        ax.set_xlim(x_min, x_max)

        # add the new plot coordinate
        x.append(x_new)
        y.append(0)
        line.set_data(x, y)

        return line,

    except KeyboardInterrupt:
        print("leaving...")

Finalement, il nous reste plus qu’à éxécuter sigrok-cli avec notre décodeur de latence et à récupérer ces valeurs dans notre script de visualisation.

sigrok-cli -d fx2lafw --config samplerate=24MHz --samples 2M -C 1,2 -P jitter:clk=1:sig=2 -B jitter | rt-draw.py

Ce qui nous donne le résultat final suivant et qui nous permet de visualiser la gigue temporelle du signal résultant :

rt_draw

Notes

  • Le script complet de visualisation est disponible sur Github. Il se veut simpliste afin de donner un exemple de rendu visuel et peut sans aucun doute être optimisé.
  • Le décodeur de latence pour sigrok a été soumis aux développeurs du projet et une première version est upstream ici (la version avec la sortie binaire donnant les valeurs de latence brute n’est pas encore disponible)
  • Le firmware des puces Cypress FX2 a parfois du mal avec des fréquences d’échantillonnage haute et se bloque.

Thibault Cohen et Sébastien CoavouxTrois mois après le lancement du projet 24/7, l’équipe Supervision de Savoir-faire Linux fait encore parler d’elle et s’ouvre un peu plus à la communauté. Elle vient de sortir son premier bulletin de nouvelles et de prendre l’initiative de créer un nouveau Meetup montréalais consacré à la supervision. La première rencontre aura lieu à nos bureaux, le 3 décembre prochain.

Sébastien Coavoux est consultant chez Savoir-faire Linux et membre de l’équipe de développement de Shinken, la célèbre plate-forme de supervision libre écrite en Python. « Avec le bulletin, dit-il, nous souhaitons rester en contact et partager avec nos clients mais aussi, plus largement, avec tous ceux que les services de supervision de Savoir-faire Linux intéressent ». Thibault Cohen, notre meneur de pratique Supervision, lui-même membre de l’équipe de maintenance des paquets de Debian depuis l’an dernier, précise : « nous y annoncerons régulièrement nos contributions, nos réalisations et toute autre information connexe, comme par exemple l’inclusion de Shinken 2.0 dans la prochaine distribution stable de Debian, alias Jessy. »

Pour l’instant, ce premier bulletin a été mis en ligne sur Github et simplement diffusé par les médias sociaux. Début 2015, il sera possible de s’y abonner de différentes façons.

Plus important, l’équipe invite les professionnels de la supervision du Grand Montréal à participer au premier Meetup consacré à ce domaine. Dans une économie de plus en plus numérique, automatisée, en réseau, et soucieuse d’optimiser les coûts de production, en effet, la supervision des systèmes en évolution constante est elle-même un domaine d’ingénierie informatique très riche en innovations qu’il est important de connaître et partager.

« Dans un premier temps, nous allons évaluer quelles technologies les professionnels utilisent à Montréal — en open-source (Shinken, Nagios, Zabbix…) mais pas seulement, explique Thibault. Par la suite, nous souhaitons échanger des ateliers sur des cas pratiques comme, par exemple, la supervision d’une génératrice de courant. »

« Ces échanges nous permettront de démystifier les problèmes que nous savons résoudre et de trouver de l’aide pour ceux pour lesquels nous cherchons encore de meilleures solutions, résume Sébastien. Nous allons donc partager nos propres connaissances avec la communauté et apprendre d’elle, notamment à propos des outils connexes de présentation de rapports (reporting) sur lesquels notre expertise est un peu plus limitée. »

Lavender Albino Python


     Photo© by courtesy of MyBallPython

L’industrie du divertissement numérique, comme Christian Beauchesne l’appelle judicieusement, a des besoins bien spécifiques découlant de ses modèles d’affaires. Soumise à une intense compétition rythmée par les saisons commerciales et les bilans annuels, elle doit produire des films, jeux vidéo et autres livrables à un train d’enfer, dans un grand roulement de tambour personnel. Pour réussir ce tour de force, elle dispose heureusement d’une épée magique : Python.

Générant un chiffre d’affaires galactique de l’ordre des 100 milliards de dollars US en 2014 (1), l’industrie du jeu vidéo est la première industrie culturelle dans le monde et une importante locomotive de l’économie numérique, du Japon aux USA en passant par la France et le Québec (2). Mais le secteur de l’infographie (Computer graphics, en anglais) ne s’arrête pas à la porte des studios de jeux comme Gameloft ou Ubisoft. Il franchit celle des studios d’effets spéciaux, comme Hybride Technologies ou Industrial Light & Magic (auteur des effets spéciaux de Star Wars et Transformers) et pénètre aussi dans les studios d’animation comme Digital District Montreal ou Pixar.

Un langage qui se glisse partout

Or, Python est un langage de programmation ouvert comptant un très grand nombre de modules et bibliothèques logicielles (libraries) qui lui donnent le pouvoir magique de s’adapter à de nombreuses situations. On le retrouve abondamment sur le Web, notamment avec le framework Django et derrière des sites tentaculaires comme Youtube et Google. Dropbox a basé son système sur Python et la NASA elle-même l’utilise, comme le montre l’une des success story du site de la Python Software Foundation.

Python is fast enough for our site and allows us to produce maintainable features in record times, with a minimum of developers” — Cuong Do, Software Architect, YouTube

Les studios d’infographie font partie de ces entreprises friandes de Python. Elles ont besoin d’être réactives à cause des échéances fluctuantes et de délais de plus en plus courts. Python permet justement de produire rapidement du code facile à maintenir. C’est donc un langage de choix pour développer ce que l’on appelle le « pipeline », le flux de données du studio. Ce pipeline va principalement gérer de très gros fichiers et y associer des attributs (ou tags) dans une base de données.

Python est certes plus lent que ses grands frères, C ou Java, mais ce n’est pas un problème, ici. Le principal goulot d’étranglement, c’est le chargement des fichiers et non la lenteur d’exécution du code. C’est pourquoi Python est présent dans toutes les grandes technologies: Maya, Nuke, Shotgun, Houdini, 3ds Max, Arnold, etc. Cette omniprésence fait en sorte que les pipelines peuvent dialoguer avec leurs composantes grâce à un seul et même langage. Cela réduit considérablement la complexité.

Enfin, il y a la philosophie de Python, résumée par ce célèbre aphorisme de Tim Peters :

There should be one– and preferably only one –obvious way to do it.” — Tim Peters (The Zen of Python)

Photo: affiche japonaise "Zen of Python"En d’autres termes, Python permet de sauter rapidement dans le code et de le comprendre. C’est ce que cherchent les studios qui doivent recruter très fréquemment de nouveaux développeurs.

Le choix de Python est d’autant plus logique que, sans être nécessairement le plus répandu, c’est l’un des langages de programmation les plus populaires au monde(3). Du fait de sa grande lisibilité, toutes les universités l’enseignent dans les cours de sciences informatiques et un grand nombre d’autodidactes le maîtrisent parfaitement. À Montréal, le cours DEV401 – Programmer en Python est l’un des plus populaires du centre de formation de Savoir-faire Linux et l’association Montréal Python n’est jamais en manque de présentateurs pour ses soirées-conférences mensuelles.

 
Voilà pourquoi, finalement, lorsque l’École Nad nous a contacté pour nous parler d’un Meetup Python spécifiquement dédié à cette communauté, il nous a semblé tout à fait naturel de nous y associer.


Notes :

(1) Source: Gartner cité par l’Agence française pour le jeu vidéo, 15 janvier 2014

(2) Source: Alliance Numérique, 6 juin 2014. L’industrie du jeu vidéo génère au Québec 9000 emplois direct dans quelque 130 studios et des retombées annuelles estimées à 741 millions $.

(3) Source: CodeEval, Most Popular Programming Languages of 2014. Voir aussi le TIOBE Index.

À l’été 2012, le réalisateur Sébastien Landry réalisait son premier long métrage, Un parallèle plus tard, qui est sorti en salle cet automne et dont l’action principale se déroule à Havre-Saint-Pierre, sur la Côte-Nord du Québec. L’une des premières scènes se passe dans une entreprise de sécurité informatique montréalaise. Le jeune cinéaste cherchait donc un bureau moderne, chaleureux, avec une belle lumière, un grand espace ouvert et des bureaux largement vitrés.

La vidéo est sous-titrée en français cc 

Le partage et l’entraide sont des valeurs communes à la culture de l’open-source et des jeunes créateurs qui, comme Sébastien, ont recours au pouvoir des communautés afin de réaliser leurs rêves. Malgré le dérangement que cela pouvait susciter en pleine semaine, nous avons donc accueilli l’équipe du film à bras « ouverts ».

À la fin de la journée de tournage, j’ai demandé à Sébastien de me parler de son expérience de socio-financement et des raisons pour lesquelles il avait choisi notre bureau comme décor naturel. Visionnez ci-dessus et partagez la vidéo sur Youtube ou bien lisez la transcription de l’entrevue.

Pour en savoir plus

Montréal est l’une des grandes capitales de l’industrie du divertissement numérique et les principaux cadriciels de développement de cette industrie reposent, aujourd’hui, sur le langage Python. C’est à partir de ce constat que l’École des arts numériques, de l’animation et du design (NAD), en partenariat avec Savoir-faire Linux, a conçu Meetup Python. Ce nouvel événement vise à réunir les développeurs de l’industrie dans une communauté de pratique Python spécifique à leurs problématiques.

Vendredi dernier, quelques heures avant que les rues de Montréal ne soient livrées aux sorcières, vampires et morts-vivants, j’ai rencontré Christian Beauchesne, directeur du service aux entreprises et des projets spéciaux du NAD, qui m’en a présenté les grandes lignes, résumées cette vidéo :

Lors du premier Meetup qui aura lieu le 17 novembre 2014 à partir de 18h, dans les locaux de l’école, Éric Thivierge (Hybride Technologies) et Dave Lajoie (Digital District) présenteront leurs techniques et méthodes de travail dans ces domaines, tandis que Jordì Rìera (Savoir-faire Linux) donnera un aperçu des dernières nouveautés en matière d’utilisation de Python dans l’industrie du divertissement numérique.

RSVP: http://sflx.ca/meetpy