#Importation des bibliothèques
from random import randrange, choices, randint
import tkinter as tk
from tkinter import ttk
import serial
import serial.tools.list_ports as prtlst
import time
#On définit les variables pour le portUSB, le type de traitement et pour l'actualisation
portUSB = 'Simulateur'
strTypeTraitement = 'Maximum'
boolConnecte = False
intTempsActualisation = 400
intTempsActualisation_temp = 400
boolPlay = False
#Création de la fenêtre du programme
fenetre=tk.Tk()
#-------------------------#
#Les générateurs de trame
#-------------------------#
#Version 1 - Lucas, Elouen, Antoine V., Tom
def generateur_trames()->str:
"""
Génerateur de trames aléatoires, le problème avec ce dernier est qu'il génère quasiment à chaque fois
un octet avec un 7 donc les trames sont presques à chaque fois à l'état maximum.
"""
strTrame = ""
for i in range(50):
strBitAB = hex(randrange(256))[2:] #On choisit un nombre aléatoire entre 0 et 256 et on le convertit en héxadecimal
strBitCD = "0" + hex(choices((0,1,3,7))[0])[2:] #On choisit un état aléatoire pour les LEDs et on le convertit en hexadécimal
if len(strBitAB) < 2:
strBitAB = "0" + strBitAB
strTrame += 'ab' + strBitAB + 'cd' + strBitCD #On associe les bits et on ajoute les identifiants pour créer une trame valide
return strTrame
#Version du prof.
def generateur_niveau(intNiveau:int)->str:
# Fonction permettant de RETOURNER une série de 400 octets de manière aléatoire
# Sous le même format que les données envoyées par la carte STM32
# Un paramètre : intNIveau qui est un entier symbolisant le niveau accoustique simulé :
# 0 = Aucune led allumé.
# 1 = Led verte allumée.
# 3 = leds verte et orange allumées.
# 7 : leds verte, orange et rouge allumées.
byteDonneeEnvoyee = b''
for i in range(100):
intAlea=randint(0,intNiveau)
if intAlea == 3:
intAlea = 7
elif intAlea == 2:
intAlea = 3
byteDonneeEnvoyee += (10*16**7+11*16**6+16**5+7*16**4+12*16**3+13*16**2+intAlea).to_bytes(4, byteorder='big')
return byteDonneeEnvoyee
def generateur_donnees()->str:
# Fonction permettant de RETOURNER une série de 400 octets de manière aléatoire
# sous le même format que les données envoyées par la carte STM32
# après avoir simulé un nievau donné par le choix d'une nombre aléatoire.
# Aucun paramètre.
intNiveau = randint(0,4)
return generateur_niveau(intNiveau).hex()
#------------------------------------------------#
#Connexion à la carte et récupération des données
#------------------------------------------------#
def recherche_port_STM32()->str:
"""
Cette fonction recherche dans les périphériques connectés ceux correspondant
à des cartes STM32, et renvoie la chaîne de caractère correspondant au port
où est connectée cette dernière.
"""
listeDesPorts = prtlst.comports() #On liste tout les ports
Recherche = ['STM32', 'STLink' , 'USB']
for i in range(len(Recherche)):
for pt in listeDesPorts:
if Recherche[i] in pt[1]: # On recherche 'STM32' 'STLink' ou 'USB' dans la description du port
return pt[0] #Si il y est, on retourne le port
break
def connexion_stm32()->None:
"""
Cette procédure se connecte au port de la carte STM32 avec un baudrate de 9600bps
et une taille de bits de 8 bits.
"""
global portSerie
if recherche_port_STM32() != None:
portUSB = recherche_port_STM32()
portSerie = serial.Serial(port=portUSB, #On se connecte au port trouvé précedemment
baudrate=921600,
bytesize=serial.EIGHTBITS)
if portUSB != 'Simulateur':
boolConnecte = True
labelPort.config(text="Carte STM 32 sur le port : " + portUSB) #On configure le texte pour afficher le port où la carte est connecté
def recuperation_trames()->str:
"""
Cette fonction renvoie une trame de 400 caractères prélevée
sur le port où la carte est connectée.
"""
global portSerie
donneeRecue = portSerie.read(size=400) #On récupère une trame de 400 caractères
return donneeRecue.hex()
#Fonction réalisée à l'aide du prof
def releve_niveau():
"""
Cette fonction retourne la valeur maximale de l'état des LEDs sur 100 mesures reçues
"""
valMax = 0
try:
#Je lis 400 octets , ce qui me donne 100 séries de 4 octets en hexa pour y prendre la plus grande valeur :
if boolConnecte and boolPlay:
donneeRecue = portSerie.read(size=400).hex()
elif boolConnecte == False and boolPlay:
donneeRecue = generateur_donnees()
else:
donneeRecue = 'ab00cd00ab00cd00ab00cd00ab00cd00'
if strTypeTraitement == 'Maximum':
#Je récupère la valeur après 'CD0' :
indexCD = donneeRecue.find('cd')
while indexCD >0:
valMax = max(valMax,int(donneeRecue[indexCD+3:indexCD+4]))
donneeRecue=donneeRecue[indexCD+2:len(donneeRecue)]
indexCD = donneeRecue.find('cd')
if valMax ==3:
valMax = 2
elif valMax == 7:
valMax = 3
elif strTypeTraitement == 'Moyenne':
return traitement_trames(donneeRecue)
except:
portSerie.close()
time.sleep(0.1)
portSerie.open()
time.sleep(float(10/100))
return valMax
#-------------------------#
#Traitement des données
#-------------------------#
def traitement_trames(trame:str)->int:
"""
Cette fonction traite les trames reçues à l'aide des fonctions précedentes
"""
strTypeTraitement = comboboxChoixTraitement.get() #Une combobox est une liste de choix déroulant
try:
if strTypeTraitement == 'Maximum': #Pour le type de traitement maximum on utilise la valeurs maximale sur une trame
listBitAB = []
listBitCD = []
#Pour avoir une trame fonctionelle même si elle commence par autre chose que 'ab'
while trame[0:2] != 'ab':
trame = trame[0:1]
trame = trame[0:392]
for i in range(len(trame)-8):
#On analyse la trame, si elle commence par 'ab' on regarde les élements d'après et si il y'a bien le cd et les bits ensuite
if trame[i:i+2] == 'ab':
print(trame[i:i+2], trame[i+2:i+4], trame[i+4:i+6], trame[i+6:i+8] )
if trame[i+4:i+6] == 'cd':
if trame[i+6:i+8] in ['00', '01', '03', '07']: #Si le bit correspond à un état de LEDs, on le mets dans la liste des bits CD
listBitCD.append(trame[i+6:i+8])
global intMaxEtatLed
intMaxEtatLed = int(max(listBitCD)) #On prends le max de cette liste
return intMaxEtatLed
elif strTypeTraitement == 'Moyenne':
listQuantiteEtatLed = [0, 0, 0, 0, 0, 0, 0, 0]
global intMoyVumetre
intMoyVumetre = round(sum(listBitAB)/len(listBitAB), 0)
listBitCD = [trame[i:i+2] for i in range(6, len(trame), 8)]
for intBitsCD in listBitCD:
#Pour tout les bits CD, on compte chacun d'entre eux et on prends celui le plus présent, et on le renvoie
if intBitsCD == '00':
listQuantiteEtatLed[0] += 1
elif intBitsCD == '01':
listQuantiteEtatLed[1] += 1
elif intBitsCD == '03':
listQuantiteEtatLed[3] += 1
elif intBitsCD == '07':
listQuantiteEtatLed[7] += 1
intMoyEtatLed = listQuantiteEtatLed.index(max(listQuantiteEtatLed))
return intMoyEtatLed
except:
portSerie.close()
time.sleep(0.1)
portSerie.open()
time.sleep(0.1)
#----------------#
#Partie graphique
#----------------#
def dessin_Led()->None:
"""
Procédure pour dessiner la forme principale des LEDs dans le canva
"""
global LEDverte
global LEDorange
global LEDrouge
#On dessine les LEDs dans un état vide
LEDverte = canvasDessinLeds.create_oval(50,100,100,150,
fill= 'white'
,width=4
,outline = 'green')
LEDorange = canvasDessinLeds.create_oval(200,100,250,150,
fill= 'white'
,width=4
,outline = 'Orange')
LEDrouge = canvasDessinLeds.create_oval(350,100,400,150,
fill= 'white'
,width=4
,outline = 'red')
contour = canvasDessinLeds.create_rectangle(25,75,425,175,
fill=''
,width=4
,outline='Black'
,activefill='')
#On appelle la fonction pour définir le nouvel état des LEDs
changement_etat_led(releve_niveau())
intTempsActualisation = entryTempsTrame.get()
#On allume le timer pour actualiser la fenêtre
fenetre.after(intTempsActualisation, dessin_Led)
def changement_etat_led(intEtatVuMetre:int)->None:
"""
Cette procédure définit le nouvel état des LEDs selon l'état des LEDs
entré en paramètre.
"""
#Selon l'état des LEDs, on allume ou pas les LEDs virtuelles
if intEtatVuMetre == 0:
canvasDessinLeds.itemconfig(LEDverte, fill='white')
canvasDessinLeds.itemconfig(LEDorange, fill='white')
canvasDessinLeds.itemconfig(LEDrouge, fill='white')
elif intEtatVuMetre == 1:
canvasDessinLeds.itemconfig(LEDverte, fill='green')
canvasDessinLeds.itemconfig(LEDorange, fill='white')
canvasDessinLeds.itemconfig(LEDrouge, fill='white')
elif intEtatVuMetre == 3:
canvasDessinLeds.itemconfig(LEDverte, fill='green')
canvasDessinLeds.itemconfig(LEDorange, fill='orange')
canvasDessinLeds.itemconfig(LEDrouge, fill='white')
elif intEtatVuMetre == 7:
canvasDessinLeds.itemconfig(LEDverte, fill='green')
canvasDessinLeds.itemconfig(LEDorange, fill='orange')
canvasDessinLeds.itemconfig(LEDrouge, fill='red')
def reini()->None:
"""
Cette procédure sert à réinitialiser l'état des LEDs.
"""
global LEDverte
global LEDorange
global LEDrouge
#On supprime les LEDs virtuelles et on les redesinnes
canvasDessinLeds.delete(LEDverte)
canvasDessinLeds.delete(LEDorange)
canvasDessinLeds.delete(LEDrouge)
dessin_Led()
def play_pause()->None:
global boolPlay
"""
Cette procédure sert à déclencher ou non le traitement des données.
"""
if boolPlay == True:
boolPlay = False
else:
boolPlay = True
#Création du texte du titre et du canvas contenant LEDs
labelTitre = tk.Label(fenetre, text="Sonomètre", fg='black', bg='white')
labelTitre.pack(padx=5, pady=5)
labelPort = tk.Label(fenetre, text="Carte STM 32 sur le port : " + portUSB, fg='black', bg='white')
labelPort.pack(padx=5, pady=5)
canvasDessinLeds = tk.Canvas(fenetre,
width=450,#Dimension largeur
height=200,#Dimension longeur
background='ivory') #Zone de dessin avec fond ivoire
#On range tout ça
canvasDessinLeds.pack(padx=5,pady=5)
#On crée les labels et bouton et widgets nécessaires à la fenêtre et on les ranges
buttonQuitter = tk.Button(fenetre, text="Marche/Arrêt", width=15, fg='black', bg='white',command = lambda :play_pause() )#tk.Button crée un bouton
buttonQuitter.pack(padx=5,pady=5)
buttonReset = tk.Button(fenetre, text="Réinitialiser état LEDs", width=15, fg='black', bg='white',command = lambda :reini() )#tk.Button crée un bouton
buttonReset.pack(padx=5,pady=5)
buttonConnexion = tk.Button(fenetre, text="Connexion au STM32", width=15, fg='black', bg='white',command = lambda :connexion_stm32() )#tk.Button crée un bouton
buttonConnexion.pack(padx=5,pady=5)
labelTraitementDonnee = tk.Label(fenetre, text="Type de traitement des donées :", fg='black', bg='white')
labelTraitementDonnee.pack(padx=5, pady=5)
listChoixTraitement = ['Maximum', 'Moyenne']
comboboxChoixTraitement = ttk.Combobox(fenetre, values=listChoixTraitement)
comboboxChoixTraitement.current(0)
comboboxChoixTraitement.pack(padx=5, pady=5)
labelTempsActualisation = tk.Label(fenetre, text="Temps d'actualisation des trames (en mS) :", fg='black', bg='white')
labelTempsActualisation.pack(padx=5, pady=5)
entryTempsTrame = tk.Entry(fenetre)
entryTempsTrame.insert(0, '6')
entryTempsTrame.pack(padx=5, pady=5)
dessin_Led()
fenetre.mainloop()