#!/usr/bin/python3 # -*- coding: utf-8 -* #B. Vandeportaele 2021 # à lancer avec la commande python wokwi2gtkwave.py dans ~/wokwi/ ou C:\Users\login\wokwi\ #TODO: #arg pour passer les emplacements si autre que ceux par défaut #variables de chemin à régler plutot au début du script #TODO: ajouter téléchargement automatique de gtkwave si besoin debug=False #set to True to activate display of debug messages debug=True import os import sys import math import shutil from sys import platform ######################################## #https://stackoverflow.com/questions/1051254/check-if-python-package-is-installed #install automatically watchdog if not already installed import subprocess import sys reqs = subprocess.check_output([sys.executable, '-m', 'pip', 'freeze']) installed_packages = [r.decode().split('==')[0] for r in reqs.split()] if 'watchdog' in installed_packages: if debug: print('watchdog pip package already installed') else: if debug: print('watchdog pip package missing, lets install it') import pip pip.main(['install','watchdog']) ########################################################## #----téléchargement de fichier, récupéré sur https://www.programcreek.com/python/example/83386/wget.download def download_file(local_path, link, checksum_reference=None): """Checks if a local file is present and downloads it from the specified path otherwise. If checksum_reference is specified, the file's md5 checksum is compared against the expected value. Keyword arguments: local_path -- path of the file whose checksum shall be generated link -- link where the file shall be downloaded from if it is not found locally checksum_reference -- expected MD5 checksum of the file """ if not os.path.exists(local_path): print('Downloading from %s, this may take a while...' % link) wget.download(link, local_path) print() if checksum_reference is not None: checksum = generate_md5_checksum(local_path) if checksum != checksum_reference: raise ValueError( 'The MD5 checksum of local file %s differs from %s, please manually remove \ the file and try again.' % (local_path, checksum_reference)) return local_path ######################################## if platform == "win32": import glob ''' if 'glob' in installed_packages: if debug: print('glob pip package already installed') else: if debug: print('glob pip package missing, lets install it') import pip pip.main(['install','glob']) ''' if 'wget' in installed_packages: if debug: print('wget pip package already installed') else: if debug: print('wget pip package missing, lets install it') import pip pip.main(['install','wget']) #to get gtkwave from the web import wget #to unzip file import shutil path_to_zip_file="gtkwave-3.3.100-bin-win32.zip" #download the zip file only if it does not exist if not os.path.exists(path_to_zip_file): print("downloading gtkwave") download_file(path_to_zip_file,"https://bvdp.inetdoc.net/files/cesi/gtkwave/gtkwave-3.3.100-bin-win32.zip", checksum_reference=None) directory_to_extract_to="./" print("unzipping gtkwave") shutil.unpack_archive(path_to_zip_file, directory_to_extract_to) ######################################## #inspiré de http://sametmax.com/reagir-a-un-changement-sur-un-fichier-avec-watchdog/ #sudo pip3 install watchdog from watchdog.events import FileSystemEventHandler from watchdog.observers import Observer #doc dans : https://pythonhosted.org/watchdog/api.html#watchdog.observers.Observer import time ######################################## #pour s'assurer que le fichier est bien terminé de copier: #https://instructobit.com/tutorial/117/Detecting-files-in-the-process-of-being-copied-or-written-to-in-Python def get_file_size(filepath): # open the file in read only with open(filepath, "r") as file: # move pointer to the end of the file file.seek(0, 2) # retrieve the current position of the pointer # this will be the file's size in bytes size = file.tell() return size # if the function reaches this statement it means an error occurred within the above context handler return False #---------------------------------------------------- def repairVcdFile(filename_in, filename_out): fin = open(filename_in, "r") fout = open(filename_out, "w") previous_time=0 for line in fin.readlines(): #this repair should not be required since 2021/11/24th as Uri has corrected Wokwi lineout = line.replace("(heure d’été d’Europe centrale)", "") lineout = lineout.replace("(heure normale d’Europe centrale)", "") #avec le changement d'heure.... #ne marche pas sous windows... :( du coup je coupe à partir de ( if lineout.startswith('$date'): pos=lineout.find('(') if pos!=-1: #found lineout=lineout[0:pos]+'$end\n' #number doit être croissant; if lineout.startswith('#'): current_time=int(lineout[1:]) #print("current_time="+str(current_time)) if current_timeil faut laisser le temps que le fichier soit terminé de copier final_size = get_file_size(str( event.src_path)) #print("compare "+str(initial_size) +" et " + str(final_size)) #determine si il faut tuer gtkwave currentTime = int(time.time()) if currentTime-self.timeLastPKill>10: #tue les instances anciennes de gtkwave mais pas les récentes qui peuvent etre due à des analyseurs logiques en parallèle self.timeLastPKill=currentTime if platform == "linux" or platform == "linux2": commandLine="pkill gtkwave &" if debug: print("running: "+commandLine) os.system(commandLine) isANewSimulation=True time.sleep(1) filename_in=event.src_path.replace("./","") #nom du fichier avec chemin complet basename_in=os.path.basename(filename_in) if debug: print("filename_in: "+filename_in) #commandLine="mkdir -p " + directoryforgtkwave; print("execution de: "+commandLine); os.system(commandLine) try: os.mkdir(directoryToStore) except OSError: if debug: print ("Creation of the directory %s failed" % directoryToStore) else: if debug: print ("Successfully created the directory %s " % directoryToStore) filename_rc=os.path.join(directoryToStore, basename_rc) createRcFile(filename_rc) #commandLine="mv \""+ filename_in +"\" " + directoryforgtkwave +"/"; print("execution de: "+commandLine); os.system(commandLine) #déplace le fichier en écrasant la cible si elle existe déjà (il faut indiquer dossier+nom en destination) #shutil.move(filename_in, os.path.join(directoryforgtkwave, basename_in)) #filename_in=directoryforgtkwave+"/"+filename_in #filename_out=event.src_path.replace(".vcd","-out.vcd") #basename_out=basename_in.replace(".vcd",".VCD") #extension VCD pour éviter que la création d'un vcd dans le meme dossier rapelle on_modified.... basename_out=basename_in filename_out=os.path.join(directoryToStore, basename_out) if debug: print("basename_out: "+basename_out) if debug: print("filename_out: "+filename_out) #repairVcdFile(os.path.join(directoryforgtkwave, basename_in),filename_out) repairVcdFile(filename_in, filename_out) basename_gtkw=basename_in.replace(".vcd",".gtkw") filename_gtkw=os.path.join(directoryToStore, basename_gtkw) if debug: print("filename_gtkw:"+filename_gtkw) createGtkwFile(filename_gtkw) #mince sous windows, il n'y a pas de différentiation entre vcd et VCD... #commandLine="rm \"" +directoryforgtkwave+"/"+filename_in+"\""; print("execution de: "+commandLine); os.system(commandLine) try: #os.remove(os.path.join(directoryforgtkwave, basename_in)) os.remove(filename_in) except OSError: print ("Deletion of the file %s failed" % os.remove(filename_in) ) #os.path.join(directoryforgtkwave, basename_in)) if platform == "linux" or platform == "linux2": commandLine="gtkwave --slider-zoom "+"\"" +filename_out+"\" \"" +filename_gtkw+"\" \"" +filename_rc+"\" & " #sleep 1 " #attention les noms de fichiers peuvent contenir des espaces, donc il faut les protéger elif platform == "win32": #commandLine="START \"\" C:\\Users\\travailleur\\Desktop\\gtkwave-3.3.100-bin-win32\\gtkwave\\bin\\gtkwave --slider-zoom "+"\"" +filename_out+"\" \"" +filename_gtkw+"\" \"" +filename_rc+"\" " #sleep 1 " #attention les noms de fichiers peuvent contenir des espaces, donc il faut les protéger commandLine="START \"\" \""+ pathForGtkwaveBin + "\\gtkwave\" --slider-zoom "+"\"" +filename_out+"\" \"" +filename_gtkw+"\" \"" +filename_rc+"\" " #sleep 1 " #attention les noms de fichiers peuvent contenir des espaces, donc il faut les protéger #commandLine="pkill gtkwave & gtkwave "+"\"" +filename_out+"\"" +" "+"\"" +filename_gtkw+"\"" + " & " #attention les noms de fichiers peuvent contenir des espaces, donc il faut les protéger if debug: print("running: "+commandLine) os.system(commandLine) if platform == "linux" or platform == "linux2": basename_script="showtraces.sh" filename_script=os.path.join(directoryToStore, basename_script) fileExists=os.path.isfile(filename_script) if isANewSimulation==True: fout = open(filename_script, "w") #write #if not fileExists: fout.write("#!/bin/bash\n") else: fout = open(filename_script, "a") #append #commandLine="gtkwave --slider-zoom "+"\"" +filename_out+"\"" +" "+"\"" +filename_gtkw+"\" \""+rcFile+"\" & \n" #sleep 1 " #attention les noms de fichiers peuvent contenir des espaces, donc il faut les protéger commandLine="gtkwave --slider-zoom "+"\"" +basename_out+"\" \"" +basename_gtkw+"\" \"" +filename_rc+"\" & " #sleep 1 " #attention les noms de fichiers peuvent contenir des espaces, donc il faut les protéger fout.write(commandLine) fout.close() commandLine="chmod a+x "+filename_script if debug: print("running: "+commandLine) os.system(commandLine) elif platform == "win32": basename_script="showtraces.bat" filename_script=os.path.join(directoryToStore, basename_script) fileExists=os.path.isfile(filename_script) if isANewSimulation==True: fout = open(filename_script, "w") #write else: fout = open(filename_script, "a") #append #commandLine="START \"\" gtkwave --slider-zoom "+"\"" +basename_out+"\" \"" +basename_gtkw+"\" \"" +filename_rc+"\" \n" #sleep 1 " #attention les noms de fichiers peuvent contenir des espaces, donc il faut les protéger commandLine="START \"\" "+ pathForGtkwaveBin + "\\gtkwave --slider-zoom "+"\"" +basename_out+"\" \"" +basename_gtkw+"\" \"" +filename_rc+"\" \n" #sleep 1 " #attention les noms de fichiers peuvent contenir des espaces, donc il faut les protéger fout.write(commandLine) fout.close() #print("execution de: "+commandLine +" terminée") time.sleep(0.1) #il faut laisser un peu de temps entre les 2 appels de gtkwave sinon il ouvre 2 fois le meme fichier ################################################################################ def main(): print("Wokwi2gtkwave V0.1\nB. Vandeportaele IUT GEII 2021\nCan be used with multiple logic analyzers, processing one file for each analyzer\nKeep this window open!\nWaiting for new .vcd files to be downloaded in: "+directoryToScan) #if len(sys.argv)==2: # inf=sys.argv[1] # ouf=sys.argv[2] observer = Observer() # Surveiller récursivement tous les événements du dossier pathToObserve # et appeler les méthodes de MonHandler quand quelque chose se produit observer.schedule(MyEventHandler(), path=directoryToScan, recursive=True) observer.start() # L'observer travaille dans un thread séparé donc on fait une # boucle infinie pour maintenir le thread principal # actif dans cette démo try: while True: time.sleep(1) except KeyboardInterrupt: # Ctrl + C arrête tout observer.stop() # on attend que tous les threads se terminent proprement observer.join() return ################################################################################ main()