Rigolinux :
Rigolinux est un logiciel libre (créé par La Boite à Physique !) permettant de piloter les oscilloscopes de la marque Rigol, disposant d'une liaison série RS232. Il fonctionne sous Linux.
Ce logiciel est dédié à l'enseignement : toute l'ergonomie a été orientée dans le but d'une vidéoprojection du logiciel au tableau :
- format 1024x768 (résolution de base d'un grand nombre de vidéoprojecteurs)
- possibilité de modifier les couleurs des courbes et du fond ainsi que l'épaisseur des courbes (en vidéoprojection on choisira une courbe plus épaisse pour la rendre bien visible du fond de la classe)
- possibilité d'afficher ou pas les réglages de sensibilités de l'oscilloscope (Pratique lors de la découverte de l'oscilloscope :
- au bureau connecter le GBF sur l'osilloscope Rigol et projeter Rigolinux.
- relier également le GBF à la ligne sèche de la salle de TP : tous les élèves disposent alors du même signal que le professeur.
- en ayant masqué les réglages, demander au élèves de régler leur oscilloscope pour retrouver un affichage similaire
Ci-dessous Rigolinux (V1_03) en situation réelle : l'oscilloscope sur le bureau est relié au portable, lui même relié au vidéoprojecteur :
Ci-dessous, une vidéo (version 1_3 du logiciel) avec commentaires qui détaille tous les réglages de base.
Cette vidéo est réalisée avec les logiciels suivants :
- capture d'écran : Vokoscreen
- titrages : Inkscape
- montage vidéo : Openshot
- conversion vidéo : Winff
Le logiciel n'est pas terminé, mais suffisamment fonctionnel pour pouvoir être proposé sur ce site.
Les fonctions non disponibles à ce jour (Mars 2018) :
- les fonctions mathématiques (en particulier la FFT)
- le mode Roll
A venir :
- sauvegarde de l'écran au format image
Le matériel nécessaire :
Le port série du PC comme celui du Rigol est de type mâle SUBD9 :
Il faut donc un câble série SUBD9 femelle-femelle.
Le protocole choisi par Rigol impose un câblage dit « droit » (fil à fil entre les deux connecteurs SUBD9)
Mais, on trouve généralement des câbles série :
- femelle-femelle mais avec un câblage croisé
- mâle-femelle avec un câblage droit ….
L'un comme l'autre ne suffisent pas. On achètera :
- un câble série mâle-femelle
- un adaptateur femelle-femelle :
Si on souhaite travailler avec un PC portable (généralement démuni de port série), il faut se procurer un câble adaptateur USB-série (Prolific par exemple)
Pour réaliser la commnication série entre le logiciel et l'oscilloscope :
- s'assurer que l'on appartient au groupe autorisé à utiliser les ports série du PC (voir l'onglet "Port série et Linux" sur la page dédiée à l'alimentation ELC AL991S)
- câbler comme indiqué ci-dessus,
- régler la vitesse de communication de l'oscilloscope sur 38400 bauds (menu Utility -> Param.E/S)
- si l'oscilloscope est correctement détecté, le nom du modèle s'affiche au dessus de l'écran (Cf vidéo de démo ci dessus : ici c'est un DS1062CD qui est utilisé)
(Logiciel libre sous licence GPL. Copyright 2014)
Pour contacter l'auteur : vlemieux@laboiteaphysique.fr
#!/usr/bin/python
#-*- coding: iso-8859-15 -*-
# Copyright 2014 Vincent LE MIEUX
# Contact : vlemieux@laboiteaphysique.fr
# La version la plus récente de ce programme se trouve
# sur le site de l'auteur : www.laboiteaphysique.fr
# Ce programme est un logiciel libre ; vous pouvez le redistribuer ou le modifier suivant
# les termes de la GNU General Public License telle que publiée par la Free Software Foundation ;
# soit la version 3 de la licence, soit (à votre gré) toute version ultérieure.
# Ce programme est distribué dans l'espoir qu'il sera utile, mais SANS AUCUNE GARANTIE ;
# sans même la garantie tacite de QUALITÉ MARCHANDE ou d'ADÉQUATION à UN BUT PARTICULIER.
# Consultez la GNU General Public License pour plus de détails.
# Vous devez avoir reçu une copie de la GNU General Public License en même temps que ce programme ;
# si ce n'est pas le cas, consultez <http://www.gnu.org/licenses>.
from __future__ import division
import gi
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk, Gdk, GObject
import os, sys, re
import serial
import string
import cairo
from time import sleep
import glob
import math
class RIGOLINUX:
def __init__(self):
self.builder = Gtk.Builder()
self.builder.add_from_file("rigolinux.glade")
#recuperation des widgets utilises par le programme :
self.lb_idn = self.builder.get_object("lb_idn")
self.btOuvrir = self.builder.get_object("btOuvrir")
self.btFermer = self.builder.get_object("btFermer")
self.btQuitter = self.builder.get_object("btQuitter")
self.btRafraichir = self.builder.get_object("btRafraichir")
self.comboPort = self.builder.get_object("comboPort")
self.comboBauds = self.builder.get_object("comboBauds")
self.bt_Manuel = self.builder.get_object("bt_Manuel")
self.bt_Auto = self.builder.get_object("bt_Auto")
self.tgb_RunStop = self.builder.get_object("tgb_RunStop")
self.tgb_manuel = self.builder.get_object("tgb_manuel")
self.bt_acq1 = self.builder.get_object("bt_acq1")
self.zone_ecran = self.builder.get_object("zone_ecran")
self.zone_ecran.add_events(Gdk.EventMask.BUTTON_PRESS_MASK)
self.bt_aff_ch1 = self.builder.get_object("bt_aff_ch1")
self.bt_aff_ch2 = self.builder.get_object("bt_aff_ch2")
self.bt_aff_bdt = self.builder.get_object("bt_aff_bdt")
self.lb_CH1 = self.builder.get_object("lb_CH1")
self.sw_ch1 = self.builder.get_object("sw_ch1")
self.bt_plus_ch1 = self.builder.get_object("bt_plus_ch1")
self.bt_moins_ch1 = self.builder.get_object("bt_moins_ch1")
self.scaleCH1 = self.builder.get_object("scaleCH1")
self.combo_couplage1 = self.builder.get_object("combo_couplage1")
self.lb_CH2 = self.builder.get_object("lb_CH2")
self.sw_ch2 = self.builder.get_object("sw_ch2")
self.bt_plus_ch2 = self.builder.get_object("bt_plus_ch2")
self.bt_moins_ch2 = self.builder.get_object("bt_moins_ch2")
self.scaleCH2 = self.builder.get_object("scaleCH2")
self.combo_couplage2 = self.builder.get_object("combo_couplage2")
self.lb_BdT = self.builder.get_object("lb_BdT")
self.bt_plus_BdT = self.builder.get_object("bt_plus_BdT")
self.bt_moins_BdT = self.builder.get_object("bt_moins_BdT")
self.scaleBdT= self.builder.get_object("scaleBdT")
self.lb_decalage_horizontal = self.builder.get_object("lb_decalage_horizontal")
self.sw_math = self.builder.get_object("sw_math")
self.comboBdT = self.builder.get_object("comboBdT")
self.lb_niveau_trigger = self.builder.get_object("lb_niveau_trigger")
self.cb_afficher = self.builder.get_object("cb_afficher")
self.colorbutton_fond = self.builder.get_object("colorbutton_fond")
self.colorbutton1 = self.builder.get_object("colorbutton1")
self.colorbutton2 = self.builder.get_object("colorbutton2")
self.colorbutton_math = self.builder.get_object("colorbutton_math")
self.sb_ligne = self.builder.get_object("sb_ligne")
self.comboTrigSource = self.builder.get_object("comboTrigSource")
self.comboTrigFront = self.builder.get_object("comboTrigFront")
self.comboBalayage = self.builder.get_object("comboBalayage")
self.scaleTrigger = self.builder.get_object("scaleTrigger")
self.combo_math = self.builder.get_object("combo_math")
#Onglet Mesures :
self.switch_aff_curseurY = self.builder.get_object("switch_aff_curseurY")
self.colorbutton_curseurY = self.builder.get_object("colorbutton_curseurY")
self.comboCurseurY = self.builder.get_object("comboCurseurY")
self.scaleCAY = self.builder.get_object("scaleCAY")
self.lb_CAY = self.builder.get_object("lb_CAY")
self.scaleCBY = self.builder.get_object("scaleCBY")
self.lb_CBY = self.builder.get_object("lb_CBY")
self.lb_CdY = self.builder.get_object("lb_CdY")
self.switch_aff_curseurX= self.builder.get_object("switch_aff_curseurX")
self.colorbutton_curseurX = self.builder.get_object("colorbutton_curseurX")
self.scaleCAX = self.builder.get_object("scaleCAX")
self.lb_CAX = self.builder.get_object("lb_CAX")
self.scaleCBX = self.builder.get_object("scaleCBX")
self.lb_CBX = self.builder.get_object("lb_CBX")
self.lb_CdX = self.builder.get_object("lb_CdX")
self.label20 = self.builder.get_object("label20")
self.lb_debug = self.builder.get_object("lb_debug")
self.builder.connect_signals(self)
window = self.builder.get_object('window')
window.show_all()
self.lister_ports()
self.desactiver_widget_reglages()
#initialisations :
self.ouvert = False
self.timer_id = None
self.sortie =""
self.port_serie = " "
self.port_choisi = " "
self.data_format = " "
self.debit = " "
self.parite = ""
self.comboPort.set_active(0) # le premier port decouvert
self.comboBauds.set_active(2) # 38400 bauds
self.lb_idn.set_text("déconnecté")
self.data_ch1 = [0]
self.Affiche_S1 = True
self.Gnd1 = False
self.Affiche_S2 = True
self.Gnd2 = False
self.Affiche_BdT = True
self.Affiche_ValCY = True
self.Affiche_ValCX = True
self.data_ch2 = [0]
self.delai = 1000
self.longueur_data = 1024
# tableau des difféentes valeurs de sensibilité à envoyer :
self.env_cal = \
['0.000000001', '0.000000002', '0.000000005'\
,'0.00000001', '0.00000002', '0.00000005'\
,'0.0000001', '0.0000002', '0.0000005',\
'0.000001', '0.000002', '0.000005',\
'0.00001', '0.00002', '0.00005',\
'0.0001', '0.0002', '0.0005',\
'0.001','0.002', '0.005', \
'0.01', '0.02', '0.05',\
'0.1', '0.2', '0.5',\
'1', '2', '5',\
'10','20', '50']
# tableau des difféentes valeurs de sensibilité recevables :
self.rec_cal = \
['1.000e-09','2.000e-09','5.000e-09', \
'1.000e-08','2.000e-08','5.000e-08',\
'1.000e-07','2.000e-07','5.000e-07',\
'1.000e-06','2.000e-06','5.000e-06',\
'1.000e-05','2.000e-05','5.000e-05',\
'1.000e-04','2.000e-04','5.000e-04',\
'1.000e-03','2.000e-03','5.000e-03',\
'1.000e-02','2.000e-02','5.000e-02',\
'1.000e-01','2.000e-01','5.000e-01',\
'1.000e+00','2.000e+00','5.000e+00',\
'1.000e+01','2.000e+01','5.000e+01']
#DS1062CD : 2 mV à 5V ; 5 ns à 50 s :
self.index_Vmin = 19
self.index_Vmax = 29
self.index_Hmin = 2
self.index_Hmax = 26 #version du logiciel limitée actuellement
#couleurs :
self.couleur_fond = self.colorbutton_fond.get_rgba()
self.couleur_ch1 = self.colorbutton1.get_rgba()
self.couleur_ch2 = self.colorbutton2.get_rgba()
self.couleur_math = self.colorbutton_math.get_rgba()
self.couleur_curseurX = self.colorbutton_curseurX.get_rgba()
self.couleur_curseurY = self.colorbutton_curseurY.get_rgba()
adjLigne = Gtk.Adjustment(0, 1, 5, 1, 1, 0)
self.sb_ligne.configure(adjLigne, 1,1)
self.sb_ligne.set_value(3)
self.epaisseur_ligne = int(self.sb_ligne.get_value())
self.Ch1active = True
self.Ch2active = False
self.ModeYT = True
self.ModeXY = False
self.Mathactive = False
self.FFTactive = False
self.CurseurYactive = False
self.PosCursYA = 110
self.PosCursYB = 210
self.PosCursXA = 210
self.PosCursXB = 410
self.CurseurXactive = False
self.comboCurseurY.set_active(0)
# masque de recherche des valeurs numériques :
# exemple 2.000e+01
self.masque = re.compile('([0-9])\.([0-9]+)e\D([0-9])([0-9])')
#masque de recherche trigger :
self.masque_trigger = re.compile('([A-Z0-9]+)')
self.masque_triggerFront = re.compile('([A-Z]+)')
self.masque_triggerSweep = re.compile('([A-Z]+)')
self.masque_trigger_niveau = re.compile('(\-*[0-9])\.([0-9]+)e\D([0-9])([0-9])')
#masque de recherche couplages :
self.masque_couplage = re.compile('([A-Z]+)')
def lister_ports(self) :
if sys.platform.startswith('linux'): #test du système d'exploitation
# sous Linux
list_port = glob.glob('/dev/ttyUSB*') + glob.glob('/dev/ttyS*')
# puis affichage des ports dans le combo :
i = 0
while i < len(list_port):
self.comboPort.append_text(list_port[i].strip('/dev/'))
i=i+1
def desactiver_widget_reglages(self):
self.btFermer.set_sensitive(False)
self.bt_Manuel.set_sensitive(False)
self.bt_Auto.set_sensitive(False)
self.tgb_RunStop.set_sensitive(False)
self.scaleCH1.set_sensitive(False)
self.bt_plus_ch1.set_sensitive(False)
self.sw_ch1.set_sensitive(False)
self.bt_moins_ch1.set_sensitive(False)
self.scaleCH2.set_sensitive(False)
self.sw_ch2.set_sensitive(False)
self.bt_plus_ch2.set_sensitive(False)
self.bt_moins_ch2.set_sensitive(False)
self.sw_math.set_sensitive(False)
self.combo_math.set_sensitive(False)
#self.comboBdT.set_sensitive(False)
self.bt_plus_BdT.set_sensitive(False)
self.bt_moins_BdT.set_sensitive(False)
self.scaleBdT.set_sensitive(False)
self.scaleCH1.set_sensitive(False)
self.bt_plus_ch1.set_sensitive(False)
self.comboTrigSource.set_sensitive(False)
self.comboTrigFront.set_sensitive(False)
self.scaleTrigger.set_sensitive(False)
def activer_widget_reglages(self):
self.btFermer.set_sensitive(True)
self.bt_Manuel.set_sensitive(True)
self.bt_Auto.set_sensitive(True)
self.tgb_RunStop.set_sensitive(True)
self.scaleCH1.set_sensitive(True)
self.bt_plus_ch1.set_sensitive(True)
self.sw_ch1.set_sensitive(True)
self.bt_moins_ch1.set_sensitive(True)
self.scaleCH2.set_sensitive(True)
self.sw_ch2.set_sensitive(True)
self.bt_plus_ch2.set_sensitive(True)
self.bt_moins_ch2.set_sensitive(True)
#self.sw_math.set_sensitive(True)
#self.combo_math.set_sensitive(True)
self.comboBdT.set_sensitive(True)
self.scaleBdT.set_sensitive(True)
self.bt_plus_BdT.set_sensitive(True)
self.bt_moins_BdT.set_sensitive(True)
self.scaleCH1.set_sensitive(True)
self.bt_plus_ch1.set_sensitive(True)
self.comboTrigSource.set_sensitive(True)
self.comboTrigFront.set_sensitive(True)
self.scaleTrigger.set_sensitive(True)
def lire_reglages_sensibilites(self):
try:
#récupérer la sensibilité CH1 :
self.port_serie.write(':CHAN1:SCAL?' + '\n')
sleep(0.01)
self.sensib1 = self.masque.search(self.port_serie.readline()).group(0)
if self.Affiche_S1 == True :
if float(self.sensib1) < 1 :
self.lb_CH1.set_text(str(int(1000*float(self.sensib1))) + " mV/div")
else:
self.lb_CH1.set_text(str(int(float(self.sensib1))) + " V/div")
else:
self.lb_CH1.set_text("")
#recuperation de l'indice (dans le tableau) du calibre de la voie 1
self.index1 = self.rec_cal.index(self.sensib1)
#récupérer la sensibilité CH2 :
self.port_serie.write(':CHAN2:SCAL?' + '\n')
sleep(0.01)
self.sensib2 = self.masque.search(self.port_serie.readline()).group(0)
if self.Affiche_S2 == True :
if float(self.sensib2) < 1 :
self.lb_CH2.set_text(str(int(1000*float(self.sensib2))) + " mV/div")
else:
self.lb_CH2.set_text(str(int(float(self.sensib2))) + " V/div")
else:
self.lb_CH2.set_text("")
self.index2 = self.rec_cal.index(self.sensib2)
#récupérer la sensibilité horizontale :
self.port_serie.write(':TIM:SCAL?' + '\n')
sleep(0.01)
self.BdT = self.masque.search(self.port_serie.readline()).group(0)
if self.Affiche_BdT == True :
if float(self.BdT) < 1E-6 :
self.lb_BdT.set_text(str(int(1E9*float(self.BdT))) + " ns/div")
elif float(self.BdT) < 1E-3 :
self.lb_BdT.set_text(str(int(1E6*float(self.BdT))) + " " + u"\u03BC" + "s/div")
elif float(self.BdT) < 1 :
self.lb_BdT.set_text(str(int(1E3*float(self.BdT))) + " ms/div")
else:
self.lb_BdT.set_text(str(int(float(self.BdT))) + " s/div")
else:
self.lb_BdT.set_text("")
self.indexH = self.rec_cal.index(self.BdT)
self.lb_debug.set_text('')
except :
self.lb_debug.set_text('erreur de lecture')
def lire_couplages(self):
#récupérer le mode de couplage sur chacune des voies :
try:
self.port_serie.write(':CHANnel1:COUPling?' + '\n')
sleep(0.01)
self.Couplage1_Oscillo = self.masque_couplage.search(self.port_serie.readline()).group(0)
if self.Couplage1_Oscillo == 'DC' :
self.combo_couplage1.set_active(0)
elif self.Couplage1_Oscillo == 'AC' :
self.combo_couplage1.set_active(1)
elif self.Couplage1_Oscillo == 'GND' :
self.combo_couplage1.set_active(2)
self.Gnd1 = True
else :
self.combo_couplage1.set_active(0)
self.port_serie.write(':CHANnel1:COUPling DC' + '\n' )
self.port_serie.write(':CHANnel2:COUPling?' + '\n')
sleep(0.01)
self.Couplage2_Oscillo = self.masque_couplage.search(self.port_serie.readline()).group(0)
if self.Couplage2_Oscillo == 'DC' :
self.combo_couplage2.set_active(0)
elif self.Couplage2_Oscillo == 'AC' :
self.combo_couplage2.set_active(1)
elif self.Couplage2_Oscillo == 'GND' :
self.combo_couplage2.set_active(2)
self.Gnd2 = True
else :
self.combo_couplage2.set_active(0)
self.port_serie.write(':CHANnel2:COUPling DC' + '\n' )
except :
self.lb_debug.set_text('erreur de lecture')
def lire_reglages_trigger(self):
#récupérer les réglages trigger :
try:
# source du trigger :
self.port_serie.write(':TRIG:EDGE:SOUR?' + '\n')
sleep(0.01)
self.TrigSourceOscillo = self.masque_trigger.search(self.port_serie.readline()).group(0)
if self.TrigSourceOscillo == 'CH1' :
self.comboTrigSource.set_active(0)
elif self.TrigSourceOscillo == 'CH2' :
self.comboTrigSource.set_active(1)
elif self.TrigSourceOscillo == 'EXT' :
self.comboTrigSource.set_active(2)
else :
self.comboTrigSource.set_active(0)
self.port_serie.write(':TRIG:EDGE:SOUR CH1' + '\n' )
# Front du trigger :
self.port_serie.write(':TRIGger:EDGE:SLOPe?' + '\n')
sleep(0.01)
self.TrigFrontOscillo = self.masque_triggerFront.search(self.port_serie.readline()).group(0)
if self.TrigFrontOscillo == 'POSITIVE' :
self.comboTrigFront.set_active(0)
elif self.TrigFrontOscillo == 'NEGATIVE' :
self.comboTrigFront.set_active(1)
else :
self.comboTrigFront.set_active(0)
self.port_serie.write(':TRIG:EDGE:SLOP POS' + '\n' )
# niveau du trigger :
self.port_serie.write(':TRIG:EDGE:LEV?' + '\n')
sleep(0.01)
self.niveau_trigger_oscillo = float(self.masque_trigger_niveau.search(self.port_serie.readline()).group(0) )
self.scaleTrigger.set_value(10*self.niveau_trigger_oscillo)
self.lb_niveau_trigger.set_text(str("{:1.2f}".format(float(self.sensib1)*self.niveau_trigger_oscillo/10) + 'V'))
# balayage :
self.port_serie.write(':TRIGger:EDGE:SWEep?' + '\n')
sleep(0.01)
self.TrigSweep = self.masque_triggerSweep.search(self.port_serie.readline()).group(0)
if self.TrigSweep == 'AUTO' :
self.comboBalayage.set_active(0)
elif self.TrigSweep == 'NORMAL' :
self.comboBalayage.set_active(1)
elif self.TrigSweep == 'SINGLE' :
self.comboBalayage.set_active(2)
else :
self.self.comboBalayage.set_active(1)
self.port_serie.write(':TRIGger:EDGE:SWEep NORMAL' + '\n')
except :
self.lb_debug.set_text('erreur de lecture')
def on_colorbutton_fond_color_set(self, user_data):
self.couleur_fond = self.colorbutton_fond.get_rgba()
self.zone_ecran.queue_draw()
def on_colorbutton_math_color_set(self, user_data):
self.couleur_math = self.colorbutton_math.get_rgba()
self.zone_ecran.queue_draw()
def on_colorbutton1_color_set(self, user_data):
self.couleur_ch1 = self.colorbutton1.get_rgba()
self.zone_ecran.queue_draw()
def on_colorbutton2_color_set(self, user_data):
self.couleur_ch2 = self.colorbutton2.get_rgba()
self.zone_ecran.queue_draw()
def on_sb_ligne_value_changed(self, user_data):
self.epaisseur_ligne = int(self.sb_ligne.get_value())
self.zone_ecran.queue_draw()
def on_bt_aff_ch1_toggled(self,widget):
if widget.get_active():
self.Affiche_S1 = False
self.lb_CH1.set_text("")
else:
self.Affiche_S1 = True
def on_bt_aff_ch2_toggled(self,widget):
if widget.get_active():
self.Affiche_S2 = False
self.lb_CH2.set_text("")
else:
self.Affiche_S2 = True
def on_bt_aff_bdt_toggled(self,widget):
if widget.get_active():
self.Affiche_BdT = False
self.lb_BdT.set_text("")
else:
self.Affiche_BdT = True
def tracer_grille(self,cr):
self.epaisseur_ligne = int(self.sb_ligne.get_value())
#Tracé du tour et des axes centraux :
cr.set_line_width(2)
cr.set_source_rgb(self.couleur_fond.red,self.couleur_fond.green,self.couleur_fond.blue)
cr.rectangle(0, 0, 620, 580)
cr.fill()
cr.set_source_rgb(0,0,0)
cr.move_to(10,10)
cr.rel_line_to(0, 400)
cr.rel_line_to(600,0)
cr.rel_line_to(0,-400)
cr.rel_line_to(-600,0)
cr.move_to(10,210)
cr.rel_line_to(600,0)
cr.move_to(310,10)
cr.rel_line_to(0,400)
for i in range (40):
cr.move_to(305,10*i + 10)
cr.rel_line_to(10,0)
for i in range (120):
cr.move_to(10 * i + 10,205)
cr.rel_line_to(0,10)
cr.stroke()
# tracé de la grille secondaire :
cr.set_line_width(0.5)
for i in range (12):
cr.move_to(50 * i + 10,10)
cr.rel_line_to(0,400)
for i in range (8):
cr.move_to(10,50*i + 10)
cr.rel_line_to(600,0)
cr.stroke()
def tracer_courbes(self,cr):
cr.set_line_width(self.epaisseur_ligne)
if self.ModeYT == True:
if self.Ch1active == True:
#tracé de CH1:
cr.set_source_rgb(self.couleur_ch1.red,self.couleur_ch1.green,self.couleur_ch1.blue)
try:
#tracé du repère 0 de la voie 1
cr.move_to(0 ,210 - 5*self.scaleCH1.get_value())
cr.line_to(10, 210 - 5*self.scaleCH1.get_value())
cr.stroke()
#tracé du repère du trigger :
if self.TrigSource == 0:
cr.move_to(310 - 5*self.scaleBdT.get_value(), 0)
cr.line_to(310 - 5*self.scaleBdT.get_value(), 10)
cr.stroke()
#tracé de la courbe CH1
for i in range (217,816):
if self.Gnd1 == False:
cr.move_to(i-207 ,2*self.data_ch1[i]-40)
cr.line_to(i-206, 2*(self.data_ch1[i+1])-40)
cr.stroke()
else:
cr.move_to(0 ,210 - 5*self.scaleCH1.get_value())
cr.line_to(610, 210 - 5*self.scaleCH1.get_value())
cr.stroke()
except:
self.lb_debug.set_text("")
if self.Ch2active == True:
#tracé de CH2:
cr.set_source_rgb(self.couleur_ch2.red,self.couleur_ch2.green,self.couleur_ch2.blue)
try:
cr.move_to(0 ,210 - 5*self.scaleCH2.get_value())
cr.line_to(10, 210 - 5*self.scaleCH2.get_value())
cr.stroke()
#tracé du repère du trigger :
if self.TrigSource == 1:
cr.move_to(310 - 5*self.scaleBdT.get_value(), 0)
cr.line_to(310 - 5*self.scaleBdT.get_value(), 10)
cr.stroke()
for i in range (217,816):
if self.Gnd2 == False:
cr.move_to(i-207 ,2*self.data_ch2[i]-40)
cr.line_to(i-206, 2*(self.data_ch2[i+1])-40)
cr.stroke()
else:
cr.move_to(0 ,210 - 5*self.scaleCH2.get_value())
cr.line_to(610, 210 - 5*self.scaleCH2.get_value())
cr.stroke()
except:
self.lb_debug.set_text("")
if self.FFTactive == True:
#tracé de la FFT:
cr.set_line_width(self.epaisseur_ligne)
cr.set_source_rgb(self.couleur_math.red,self.couleur_math.green,self.couleur_math.blue)
try:
for i in range (217,816):
cr.move_to(i-207 ,2*self.data_FFT[i]-40)
cr.line_to(i-206, 2*(self.data_FFT[i+1])-40)
cr.stroke()
except:
self.lb_debug.set_text("")
#Mode XY
if self.ModeXY == True:
#tracé de la courbe XY
cr.set_line_width(self.epaisseur_ligne)
cr.set_source_rgb(self.couleur_ch1.red,self.couleur_ch1.green,self.couleur_ch1.blue)
if self.Ch1active == True and self.Ch2active == True:
for i in range (217,816):
if (self.Gnd1 == False) and (self.Gnd2 == False):
cr.move_to(560-2*self.data_ch1[i] , 2*self.data_ch2[i] -40 )
cr.line_to(560-2*self.data_ch1[i+1], 2* self.data_ch2[i+1] -40)
else:
self.lb_debug.set_text('Choisir un couplage <> GND')
cr.stroke()
def on_zone_ecran_draw(self, widget,cr):
self.tracer_grille(cr)
self.tracer_courbes(cr)
self.tracer_curseurs(cr)
def on_zone_ecran_button_press_event(self, widget, event):
print "Mouse clicked... at ", event.x, ", ", event.y
# How to draw a line starting at this point on the drawing area?
return True
def on_sw_ch1_button_press_event(self,widget,event):
self.Ch1active = not self.Ch1active
def on_bt_plus_ch1_clicked(self,widget):
if (self.index1 < self.index_Vmax) :
self.port_serie.write(':CHAN1:SCAL ' + self.env_cal[self.index1 +1] + '\n' )
sleep(0.01)
self.lire_reglages_sensibilites()
def on_bt_moins_ch1_clicked(self,widget):
if (self.index1 > self.index_Vmin) :
self.port_serie.write(':CHAN1:SCAL ' + self.env_cal[self.index1 - 1] + '\n' )
sleep(0.01)
self.lire_reglages_sensibilites()
def on_scaleCH1_value_changed(self,widget):
self.decalage_CH1 = self.scaleCH1.get_value()
self.envoi_decalage_CH1 = str(float(self.sensib1)*self.decalage_CH1/10)
self.port_serie.write(':CHAN1:OFFS ' + (self.envoi_decalage_CH1) + '\n')
sleep(0.01)
def on_scaleCH1_button_press_event(self,widget,event):
self.scaleCH1.set_value(0)
def on_combo_couplage1_changed(self,widget):
#régler couplage CH1 selon choix logiciel :
self.Couplage1 = self.combo_couplage1.get_active()
if self.Couplage1 == 0:
self.Gnd1 = False
self.port_serie.write(':CHANnel1:COUPling DC' + '\n' )
if self.Couplage1 == 1:
self.Gnd1 = False
self.port_serie.write(':CHANnel1:COUPling AC' + '\n' )
if self.Couplage1 == 2:
self.port_serie.write(':CHANnel1:COUPling GND' + '\n' )
self.Gnd1 = True
def on_bt_plus_ch2_clicked(self,widget):
if (self.index2 < self.index_Vmax) :
self.port_serie.write(':CHAN2:SCAL ' + self.env_cal[self.index2 +1] + '\n' )
sleep(0.01)
self.lire_reglages_sensibilites()
def on_bt_moins_ch2_clicked(self,widget):
if (self.index2 > self.index_Vmin) :
self.port_serie.write(':CHAN2:SCAL ' + self.env_cal[self.index2 - 1] + '\n' )
sleep(0.01)
self.lire_reglages_sensibilites()
def on_scaleCH2_value_changed(self,widget):
self.decalage_CH2 = self.scaleCH2.get_value()
self.envoi_decalage_CH2 = str(float(self.sensib2)*self.decalage_CH2/10)
self.port_serie.write(':CHAN2:OFFS ' + (self.envoi_decalage_CH2) + '\n')
sleep(0.01)
def on_scaleCH2_button_press_event(self,widget,event):
self.scaleCH2.set_value(0)
def on_combo_couplage2_changed(self,widget):
#régler couplage CH2 selon choix logiciel :
self.Couplage2 = self.combo_couplage2.get_active()
if self.Couplage2 == 0:
self.Gnd2 = False
self.port_serie.write(':CHANnel2:COUPling DC' + '\n' )
if self.Couplage2 == 1:
self.Gnd2 = False
self.port_serie.write(':CHANnel2:COUPling AC' + '\n' )
if self.Couplage2 == 2:
self.Gnd2=True
self.port_serie.write(':CHANnel2:COUPling GND' + '\n' )
def on_bt_plus_BdT_clicked(self,widget):
if (self.indexH < self.index_Hmax) :
self.port_serie.write(':TIM:SCAL ' + self.env_cal[self.indexH +1] + '\n' )
sleep(0.01)
self.lire_reglages_sensibilites()
def on_bt_moins_BdT_clicked(self,widget):
if (self.indexH > self.index_Hmin) :
self.port_serie.write(':TIM:SCAL ' + self.env_cal[self.indexH - 1] + '\n' )
sleep(0.01)
self.lire_reglages_sensibilites()
def on_scaleBdT_value_changed(self,widget):
self.decalage_Horizontal = self.scaleBdT.get_value()
self.envoi_decalage_Horizontal = str("{:1.8f}".format(float(self.BdT)*self.decalage_Horizontal/10))
self.port_serie.write(':TIM:OFFS ' + (self.envoi_decalage_Horizontal) + '\n')
sleep(0.01)
self.lb_decalage_horizontal.set_text(str("{:1.1f}".format(float(-self.decalage_Horizontal/10)) + ' div'))
def on_scaleBdT_button_press_event(self,widget,event):
self.scaleBdT.set_value(0)
def on_comboBdT_changed(self,widget):
self.lb_CAX.set_text(' ')
self.lb_CAY.set_text(' ')
self.lb_CBX.set_text(' ')
self.lb_CBY.set_text(' ')
self.lb_CdX.set_text(' ')
self.lb_CdY.set_text(' ')
#choisir le mode : YT ou XY
self.FormatBdt = self.comboBdT.get_active()
if self.FormatBdt == 0:
self.comboCurseurY.set_sensitive(True)
self.port_serie.write(':TIM:FORM YT' + '\n' )
self.ModeYT = True
self.ModeXY = False
if self.FormatBdt == 1:
self.comboCurseurY.set_active(1)
self.comboCurseurY.set_sensitive(False)
if self.Ch1active == False :
self.sw_ch1.set_active(True)
self.Ch1active = True
if self.Ch2active == False :
self.sw_ch2.set_active(True)
self.Ch2active = True
#self.port_serie.write(':TIM:FORM XY' + '\n' )
self.ModeYT = False
self.ModeXY = True
def on_sw_ch2_button_press_event(self,widget,event):
self.Ch2active = not self.Ch2active
def on_comboTrigSource_changed(self,widget):
#régler Trigger selon choix logiciel :
self.TrigSource = self.comboTrigSource.get_active()
if self.TrigSource == 0:
self.port_serie.write(':TRIG:EDGE:SOURce CHANnel1' + '\n' )
if self.TrigSource == 1:
self.port_serie.write(':TRIG:EDGE:SOURce CHANnel2' + '\n' )
if self.TrigSource == 2:
self.port_serie.write(':TRIG:EDGE:SOURce EXT' + '\n' )
def on_comboBalayage_changed(self,widget):
# régler le type de balayge selon choix logiciel :
self.TrigSweep = self.comboBalayage.get_active()
if self.TrigSweep == 0 :
self.port_serie.write(':TRIGger:EDGE:SWEep AUTO' + '\n')
if self.TrigSweep == 1 :
self.port_serie.write(':TRIGger:EDGE:SWEep NORMAL' + '\n')
if self.TrigSweep == 2 :
self.port_serie.write(':TRIGger:EDGE:SWEep SINGLE' + '\n')
def on_comboTrigFront_changed(self,widget):
self.TrigFront = self.comboTrigFront.get_active()
if self.TrigFront == 0 :
self.port_serie.write(':TRIGger:EDGE:SLOPe POSitive' + '\n' )
if self.TrigFront == 1 :
self.port_serie.write(':TRIGger:EDGE:SLOPe NEGative' + '\n' )
def on_scaleTrigger_value_changed(self,widget):
self.niveau_trigger = self.scaleTrigger.get_value()
self.TrigSource = self.comboTrigSource.get_active()
if self.TrigSource == 0:
self.envoi_trigger = str(float(self.sensib1)*self.niveau_trigger/10)
self.lb_niveau_trigger.set_text(str("{:1.2f}".format(float(self.sensib1)*self.niveau_trigger/10) + 'V'))
if self.TrigSource == 1:
self.envoi_trigger = str(float(self.sensib2)*self.niveau_trigger/10)
self.lb_niveau_trigger.set_text(str("{:1.2f}".format(float(self.sensib2)*self.niveau_trigger/10) + 'V'))
self.port_serie.write(':TRIG:EDGE:LEV ' + (self.envoi_trigger) + '\n')
sleep(0.01)
def on_scaleTrigger_button_press_event(self,widget,event):
self.scaleTrigger.set_value(0)
def acquisition(self):
if self.timer_id is not None:
self.port_serie.flushInput()
self.lire_reglages_sensibilites()
self.port_serie.write(':WAV:POIN:MODE NOR' + '\n' )
sleep(0.01)
#acquisition voie 1 :
self.port_serie.flushInput()
sleep(0.01)
for i in range (self.longueur_data):
self.data_ch1 = [0]
self.data_ch2 = [0]
self.data_FFT = [0]
if self.Ch1active == True:
self.port_serie.write(':WAVeform:DATA? CHANnel1' + '\n')
sleep(0.3)
lecture1 = self.port_serie.read(self.longueur_data)
try:
for i in range (self.longueur_data):
self.data_ch1.append(ord(lecture1[i]))
except:
self.lb_debug.set_text("")
#acquisition voie 2 :
self.port_serie.flushInput()
sleep(0.01)
if self.Ch2active == True:
self.port_serie.write(':WAVeform:DATA? CHANnel2' + '\n')
sleep(0.1)
lecture2 = self.port_serie.read(self.longueur_data)
try:
for i in range (self.longueur_data):
self.data_ch2.append(ord(lecture2[i]))
except:
self.lb_debug.set_text("")
if self.FFTactive == True:
self.port_serie.write(':WAVeform:DATA? FFT' + '\n')
sleep(0.3)
lectureFFT = self.port_serie.read(self.longueur_data)
try:
for i in range (self.longueur_data):
self.data_FFT.append(ord(lectureFFT[i]))
except:
self.lb_debug.set_text("")
self.zone_ecran.queue_draw()
return True
return False
def on_btRafraichir_clicked(self,widget):
#Rafraichir la liste des ports série disponibles
self.comboPort.remove_all()
self.lister_ports()
def on_btOuvrir_clicked(self,widget):
# recuperation des parametres choisis :
self.port_choisi = '/dev/' + self.comboPort.get_active_text()
debit = self.comboBauds.get_active_text()
data_format = serial.EIGHTBITS
stop = serial.STOPBITS_ONE
parite = serial.PARITY_NONE
try:
# desactivation de widgets (ceux qui ne doivent pas
# etre modifies une fois le port serie ouvert) :
self.comboPort.set_sensitive(False)
self.btRafraichir.set_sensitive(False)
self.btQuitter.set_sensitive(True)
#ouverture du port serie :
self.port_serie = serial.Serial(
port=self.port_choisi,
baudrate = debit,
bytesize = data_format,
parity = parite,
stopbits = stop,
timeout=2
)
#activation/desactivation de widgets :
self.btFermer.set_sensitive(True)
self.btOuvrir.set_sensitive(False)
self.comboBauds.set_sensitive(False)
self.activer_widget_reglages()
#vidage du port et tentative de contact :
self.port_serie.flushInput()
self.port_serie.write('*IDN?' + '\n')
#petit délai avant de lire le retour :
sleep(0.1)
data = []
n_data = 0
n_data = self.port_serie.inWaiting()
sleep(0.1)
if n_data > 0 :
chaine = ""
for i in range (n_data) :
data.append(ord(self.port_serie.read(1)))
chaine += chr(data[i])
identite = chaine.split(',')
self.lb_idn.set_text(identite[1])
self.port_serie.write(':KEY:LOCK ENABLE' + '\n')
sleep(0.01)
self.port_serie.write(':STOP' + '\n')
sleep(0.01)
# ces deux lignes à déplacer par la suite :
self.port_serie.write(':TIM:MODE MAIN' + '\n')
sleep(0.01)
self.lire_reglages_sensibilites()
self.lire_reglages_trigger()
self.lire_couplages()
self.comboBdT.set_active(0)
self.ouvert = True
except :
self.comboPort.set_sensitive(True)
self.btOuvrir.set_sensitive(True)
self.btRafraichir.set_sensitive(True)
self.ouvert = False
#self.bt_fermer.set_sensitive(False)
self.ouvert = False
msg = "Erreur lors de l'ouverture du port série : ce port n'est peut-être pas valide, ou bien vous n'avez pas les droits pour accéder aux ports série"
dialog = Gtk.MessageDialog(None, 0, Gtk.MessageType.WARNING, Gtk.ButtonsType.OK, msg)
# Montre le dialog
dialog.run()
# Destruction du dialog
dialog.destroy()
def fermer_port(self):
try :
if self.ouvert == True:
self.port_serie.write(':STOP' + '\n')
self.port_serie.write(':KEY:LOCK DISABLE' + '\n')
self.port_serie.close()
self.comboPort.set_sensitive(True)
self.comboBauds.set_sensitive(True)
self.btOuvrir.set_sensitive(True)
self.btRafraichir.set_sensitive(True)
self.btFermer.set_sensitive(False)
self.lb_idn.set_text("Etat : déconnecté ")
self.desactiver_widget_reglages()
self.ouvert = False
except :
msgFermer = "Erreur lors de la fermeture du port série !"
dlgFermer = Gtk.MessageDialog(None, 0, Gtk.MessageType.WARNING, Gtk.ButtonsType.OK, msgFermer)
dlgFermer.run()
dlgFermer.destroy()
def on_btFermer_clicked(self,widget):
#fermeture du port série ouvert
self.fermer_port()
def on_bt_Auto_clicked(self,widget):
self.port_serie.write(':AUTO' + '\n')
self.tgb_RunStop.set_active(True)
def on_tgb_RunStop_toggled(self,widget):
if widget.get_active():
self.lire_reglages_sensibilites()
self.lire_couplages()
self.lire_reglages_trigger()
# met les deux entrées en coef 1 :
self.port_serie.write(':CHAN1:PROB 1' + '\n')
sleep(0.01)
self.port_serie.write(':CHAN2:PROB 1' + '\n')
sleep(0.01)
# mode YT :
self.port_serie.write(':TIM:FORM YT' + '\n' )
sleep(0.01)
#mode Run :
self.port_serie.write(':RUN' + '\n')
sleep(0.01)
self.timer_id = GObject.timeout_add(self.delai, self.acquisition)
self.btFermer.set_sensitive(False)
self.btQuitter.set_sensitive(False)
else:
self.timer_id = None
self.port_serie.write(':STOP' + '\n')
self.btFermer.set_sensitive(True)
self.btQuitter.set_sensitive(True)
def on_bt_Manuel_clicked(self,widget):
self.port_serie.write(':KEY:LOCK DISABLE' + '\n')
# Onglet Mesures :
# curseurs horizontaux :
def on_switch_aff_curseurY_button_press_event(self,widget,event):
self.CurseurYactive = not self.CurseurYactive
def on_colorbutton_curseurY_color_set(self, user_data):
self.couleur_curseurY = self.colorbutton_curseurY.get_rgba()
self.zone_ecran.queue_draw()
def on_tgb_Affiche_ValCY_toggled(self,widget):
if widget.get_active():
self.Affiche_ValCY = False
self.lb_CAY.set_text("")
self.lb_CBY.set_text("")
self.lb_CdY.set_text("")
else:
self.Affiche_ValCY = True
def on_scaleCAY_value_changed(self,widget):
self.PosCursYA = self.scaleCAY.get_value()
def on_scaleCBY_value_changed(self,widget):
self.PosCursYB = self.scaleCBY.get_value()
# curseurs verticaux
def on_switch_aff_curseurX_button_press_event(self,widget,event):
self.CurseurXactive = not self.CurseurXactive
def on_colorbutton_curseurX_color_set(self, user_data):
self.couleur_curseurX = self.colorbutton_curseurX.get_rgba()
self.zone_ecran.queue_draw()
def on_tgb_Affiche_ValCX_toggled(self,widget):
if widget.get_active():
self.Affiche_ValCX = False
self.lb_CAX.set_text("")
self.lb_CBX.set_text("")
self.lb_CdX.set_text("")
else:
self.Affiche_ValCX = True
def on_scaleCAX_value_changed(self,widget):
self.PosCursXA = self.scaleCAX.get_value()
def on_scaleCBX_value_changed(self,widget):
self.PosCursXB = self.scaleCBX.get_value()
def tracer_curseurs(self,cr):
if self.CurseurYactive == True:
#tracé des curseurs horizontaux :
cr.set_dash([12,12])
cr.set_source_rgb(self.couleur_curseurY.red,self.couleur_curseurY.green,self.couleur_curseurY.blue)
cr.move_to(10 ,self.PosCursYA)
cr.line_to(610, self.PosCursYA)
cr.move_to(10 ,self.PosCursYB)
cr.line_to(610, self.PosCursYB)
cr.stroke()
#affichage des valeurs des curseurs horizontaux :
if self.Affiche_ValCY == True:
if self.ModeYT == True:
self.ChoixVoie = self.comboCurseurY.get_active()
if self.ChoixVoie == 0:
self.sensib = self.sensib1
if self.ChoixVoie == 1:
self.sensib = self.sensib2
if self.ModeXY == True:
self.sensib = self.sensib2
self.ValCA = float(self.sensib)*((210 - 5*self.scaleCH1.get_value())-self.PosCursYA)
self.ValCB = float(self.sensib)*((210 - 5*self.scaleCH1.get_value())-self.PosCursYB)
if float(self.sensib) < 1 :
self.lb_CAY.set_text(str(int(20*self.ValCA)) + " mV")
self.lb_CBY.set_text(str(int(20*self.ValCB)) + " mV")
self.lb_CdY.set_text(str(int(20*(self.ValCA - self.ValCB))) + " mV")
else:
self.lb_CAY.set_text(str("{:1.2f}".format(0.02*self.ValCA) + " V"))
self.lb_CBY.set_text(str("{:1.2f}".format(0.02*self.ValCB) + " V"))
self.lb_CdY.set_text(str("{:1.2f}".format(0.02*(self.ValCA - self.ValCB))) + " V")
if self.CurseurXactive == True:
#tracé des curseurs verticaux :
cr.set_dash([12,12])
cr.set_source_rgb(self.couleur_curseurX.red,self.couleur_curseurX.green,self.couleur_curseurX.blue)
cr.move_to(self.PosCursXA,10)
cr.line_to(self.PosCursXA,410)
cr.move_to(self.PosCursXB,10)
cr.line_to(self.PosCursXB,410)
cr.stroke()
#affichage des valeurs des curseurs verticaux :
if self.Affiche_ValCX == True:
if self.ModeYT == True:
self.ValCA = float(self.BdT)*(self.PosCursXA - (310 - 5*self.scaleBdT.get_value()))
self.ValCB = float(self.BdT)*(self.PosCursXB - (310 - 5*self.scaleBdT.get_value()))
if float(self.BdT) < 1E-6 :
self.lb_CAX.set_text(str("{:1.2f}".format(2E7*self.ValCA) + " ns"))
self.lb_CBX.set_text(str("{:1.2f}".format(2E7*self.ValCB) + " ns"))
self.lb_CdX.set_text(str("{:1.2f}".format(2E7*(self.ValCB - self.ValCA ))) + " ns")
elif float(self.BdT) < 1E-3 :
self.lb_CAX.set_text(str("{:1.2f}".format(2E4*self.ValCA)) + " " + u"\u03BC" + "s")
self.lb_CBX.set_text(str("{:1.2f}".format(2E4*self.ValCB)) + " " + u"\u03BC" + "s")
self.lb_CdX.set_text(str("{:1.2f}".format(2E4*(self.ValCB - self.ValCA))) + " " + u"\u03BC" + "s")
elif float(self.BdT) < 1 :
self.lb_CAX.set_text(str("{:1.2f}".format(20*self.ValCA) + " ms"))
self.lb_CBX.set_text(str("{:1.2f}".format(20*self.ValCB) + " ms"))
self.lb_CdX.set_text(str("{:1.2f}".format(20*(self.ValCB - self.ValCA))) + " ms")
else:
self.lb_CAX.set_text(str("{:1.2f}".format(0.02*self.ValCA) + " s"))
self.lb_CBX.set_text(str("{:1.2f}".format(0.02*self.ValCB) + " s"))
self.lb_CdX.set_text(str("{:1.2f}".format(0.02*(self.ValCB - self.ValCA))) + " s")
if self.ModeXY == True:
self.sensib = self.sensib1
self.ValCA = float(self.sensib)*(self.PosCursXA - (310 - 5*self.scaleCH1.get_value()))
self.ValCB = float(self.sensib)*(self.PosCursXB - (310 - 5*self.scaleCH1.get_value()))
if float(self.sensib) < 1 :
self.lb_CAX.set_text(str(int(20*self.ValCA)) + " mV")
self.lb_CBX.set_text(str(int(20*self.ValCB)) + " mV")
self.lb_CdX.set_text(str(int(20*(self.ValCA - self.ValCB))) + " mV")
else:
self.lb_CAX.set_text(str("{:1.2f}".format(0.02*self.ValCA) + " V"))
self.lb_CBX.set_text(str("{:1.2f}".format(0.02*self.ValCB) + " V"))
self.lb_CdX.set_text(str("{:1.2f}".format(0.02*(self.ValCB - self.ValCA))) + " V")
self.zone_ecran.queue_draw()
def on_btQuitter_clicked(self,widget):
self.fermer_port()
sleep(0.1)
Gtk.main_quit()
def destroy(window, self):
Gtk.main_quit()
def main():
app = RIGOLINUX()
Gtk.main()
if __name__ == "__main__":
sys.exit(main())