Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
__pycache__/
*.pyc
.venv/
2 changes: 0 additions & 2 deletions Roteador.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
# -*- coding: utf-8 -*-
import sys
#from tkinter.tix import Form

################################################################################
## Form generated from reading UI file 'RoteadorjxHyuV.ui'
Expand Down
269 changes: 235 additions & 34 deletions main.py
Original file line number Diff line number Diff line change
@@ -1,24 +1,32 @@
import os
import sys
import util.MPSoCConfig

from PySide6.QtGui import QIcon, QPixmap, Qt, QPalette, QColor, QAction, QKeySequence
from PySide6.QtGui import Qt, QPalette, QColor, QAction, QKeySequence
from PySide6.QtWidgets import (QApplication, QMainWindow, QFileDialog, QMessageBox, QWidget,
QVBoxLayout, QGridLayout, QFrame, QScrollArea, QTableWidgetItem, QTableWidget)
QVBoxLayout, QHBoxLayout, QScrollArea, QTableWidgetItem, QTableWidget, QLabel,
QHeaderView)

from ui_mainwindow import MainWindow
from commsUi import Ui_Form
from taskmap import Ui_TaskMap
from util import MPSoCConfig
from information import MPSoCInformation
from router_matrix import RouterMatrixWidget
from simulation import SimulationController, MAX_REPAINT_SPEED, ticks_to_ms
from slave_matrix import SlaveMatrixWidget
from pe_matrix import PEMatrixWidget


class MinhaJanela(QMainWindow, MainWindow):
filePath = ""
mpconfig = None
mpsoc_information = None
router_matrix_widget = None
frame_scroll_area = None
simulation = None

# Arquivos obrigatórios em um diretório de debug
REQUIRED_FILES = ("platform.cfg", "services.cfg", "traffic_router.txt")

# Variável de controle do tema
is_dark_mode = False
Expand Down Expand Up @@ -52,11 +60,40 @@ def __init__(self):

self.actionExit.triggered.connect(self.close)
self.actionNew_Debugging.triggered.connect(self.open_file)
self.horizontalSlider.valueChanged.connect(self.updadeSlide)
self.horizontalSlider.valueChanged.connect(self.update_slide)
self.label_2.setText(f"{self.horizontalSlider.value()}")
self.actionCommunication_Overview.triggered.connect(self.open_communication)
self.actionTask_Mapping_Overview.triggered.connect(self.open_taskmap)
self.actionTask_List.triggered.connect(self.taskList)
self.actionServices_List.triggered.connect(self.servicesList)

# ---------------------------------------------------------
# CONTROLE DA SIMULAÇÃO
# ---------------------------------------------------------
self.horizontalSlider.setRange(0, 100)
self.horizontalSlider.setValue(MAX_REPAINT_SPEED)

self.pushButton_2.clicked.connect(self.next_packet) # >||
self.pushButton.clicked.connect(self.play_simulation) # >
self.pushButton_3.clicked.connect(self.stop_simulation) # STOP
self.toolButton.setText("Go")
self.toolButton.clicked.connect(self.go_to_time)
self.lineEdit.setPlaceholderText("Time in ticks")
self.lineEdit.returnPressed.connect(self.go_to_time)
self.actionReset_Simulation.triggered.connect(self.reset_simulation)
self.actionRest_Graphical_Path.triggered.connect(self.reset_graphical_path)

# Tabela "Current Packet Information" com uma única linha
self.tableWidget.setRowCount(1)
self.tableWidget.verticalHeader().setVisible(False)
self.tableWidget.horizontalHeader().setSectionResizeMode(QHeaderView.ResizeMode.Stretch)
self.reset_current_packet_table()

# Tempo de simulação exibido na caixa "Speed Control"
self.build_speed_control()
self.update_simulation_time(0)

self.set_simulation_buttons(loaded=False)

# ==========================================
# LÓGICA DE MUDANÇA DE TEMA
Expand Down Expand Up @@ -123,19 +160,35 @@ def open_communication(self):
self.janela_secundaria.show()

def open_taskmap(self):
self.janela_taskmap = taskMap(self.mpconfig)
if self.filePath == "":
QMessageBox.warning(self, "Attention", "Please, load a debugging before")
return
self.janela_taskmap = TaskMapWindow(self.mpconfig)
self.janela_taskmap.show()

def updadeSlide(self, valor):
def update_slide(self, valor):
self.label_2.setText(str(valor))
if self.simulation is not None:
self.simulation.set_speed(valor)

def open_file(self):
self.filePath, _ = QFileDialog.getOpenFileName(
self,
"Open File",
"./",
"Config Files (*.cfg);;All Files (*)"
)
caminho = QFileDialog.getExistingDirectory(self, "Open Debug Directory", "./")
if caminho == "":
return

# Verifica se o diretório possui todos os arquivos necessários
faltando = [arquivo for arquivo in self.REQUIRED_FILES
if not os.path.isfile(os.path.join(caminho, arquivo))]
if faltando:
QMessageBox.critical(
self,
"Diretório invalido",
"O diretório selecionado não é um diretório de debug valido.\n\n"
"Selecione um diretório valido"
)
return

self.filePath = caminho
if self.filePath != "":
self.actionCommunication_Overview.setEnabled(True)
self.actionDeloream.setEnabled(True)
Expand All @@ -145,7 +198,13 @@ def open_file(self):
self.actionTask_List.setEnabled(True)

self.mpconfig = MPSoCConfig.MPSoCConfig(self.filePath)

# Fecha o traffic_router.txt do debug anterior antes de abrir o novo
if self.mpsoc_information is not None:
self.mpsoc_information.close()
self.mpsoc_information = MPSoCInformation(self.mpconfig)
self.build_router_matrix()
self.start_simulation()

def build_router_matrix(self):
"""
Expand All @@ -162,6 +221,7 @@ def build_router_matrix(self):
self.mpconfig.mpsoc_y,
self.mpconfig.cluster_x,
self.mpconfig.cluster_y,
mpsoc_config=self.mpconfig,
)

# Primeira vez: cria um QScrollArea dentro do self.frame para
Expand Down Expand Up @@ -193,44 +253,185 @@ def build_router_matrix(self):
self.router_matrix_widget.adjustSize()
self.frame_scroll_area.setWidget(self.router_matrix_widget)

def taskList(self):
services_hash = self.mpconfig.get_task_name_hash()
# ==========================================
# SIMULAÇÃO DOS ROTEADORES
# ==========================================
def start_simulation(self):
"""Cria o controlador da simulação para o debug carregado (ou recarregado)."""
if self.simulation is not None:
self.simulation.stop()
self.simulation.deleteLater()

self.simulation = SimulationController(self.mpconfig, self.mpsoc_information,
self.router_matrix_widget, self)
self.simulation.set_speed(self.horizontalSlider.value())
self.simulation.time_changed.connect(self.update_simulation_time)
self.simulation.packet_changed.connect(self.update_current_packet_table)
self.simulation.running_changed.connect(self.on_simulation_running_changed)
self.simulation.finished.connect(self.on_simulation_finished)
self.simulation.unknown_service.connect(self.on_unknown_service)

self.update_simulation_time(0)
self.reset_current_packet_table()
self.set_simulation_buttons(loaded=True)

def set_simulation_buttons(self, loaded, running=False):
self.pushButton.setEnabled(loaded and not running)
self.pushButton_2.setEnabled(loaded and not running)
self.pushButton_3.setEnabled(loaded and running)
self.toolButton.setEnabled(loaded and not running)
self.lineEdit.setEnabled(loaded and not running)

def play_simulation(self):
if self.simulation is not None:
self.simulation.play()

def stop_simulation(self):
if self.simulation is not None:
self.simulation.stop()

def next_packet(self):
if self.simulation is not None:
self.simulation.step()

def go_to_time(self):
if self.simulation is None:
return
try:
self.simulation.go_to_time(int(self.lineEdit.text()))
except ValueError:
QMessageBox.warning(self, "Attention", "Enter only numbers and valid times!\n\n"
"It is only possible to go to a time already simulated.")

def reset_simulation(self):
"""Recarrega o debug atual e volta a simulação para o início."""
if self.mpconfig is None:
QMessageBox.warning(self, "Attention", "Please, load a debugging before")
return

self.task_list_frame = QWidget()
self.task_list_frame.setWindowTitle("Current Task List")
self.stop_simulation()
self.mpconfig = MPSoCConfig.MPSoCConfig(self.filePath)
self.mpsoc_information.close()
self.mpsoc_information = MPSoCInformation(self.mpconfig)
self.build_router_matrix()
self.start_simulation()

self.task_list_frame.setAttribute(Qt.WidgetAttribute.WA_DeleteOnClose)
def reset_graphical_path(self):
if self.simulation is None:
QMessageBox.warning(self, "Attention", "Please, load a debugging before")
return
self.simulation.reset_graphical_path()

self.task_list_frame.setGeometry(100, 100, 500, 500)
def on_simulation_running_changed(self, running):
self.set_simulation_buttons(loaded=True, running=running)

table_widget = QTableWidget()
table_widget.setColumnCount(2)
table_widget.setHorizontalHeaderLabels(["Task Name", "ID"])
table_widget.setRowCount(len(services_hash))
def on_simulation_finished(self):
self.statusbar.showMessage("End of traffic_router.txt reached", 5000)

def on_unknown_service(self, packet):
if self.mpconfig.router_addressing == MPSoCConfig.MPSoCConfig.XY:
router = self.mpconfig.ham_address_to_xy_label(packet.router_address)
else:
router = str(packet.router_address)

for row, key in enumerate(sorted(services_hash.keys())):
task_name = services_hash[key]
QMessageBox.critical(self, "Error",
f"ERROR: Service <{packet.service}> packet unidentified.\n"
f"Router: {router} Input port: {packet.get_input_port_string()}")

name_item = QTableWidgetItem(task_name)
id_item = QTableWidgetItem(str(key))
def build_speed_control(self):
"""
Reorganiza a caixa "Speed Control" igual ao debugger original:
velocidade no canto superior direito, slider no meio e, embaixo,
o tempo de simulação em ms (esquerda) e em ticks (direita).
"""
for widget in (self.horizontalSlider, self.label_2, self.label):
self.horizontalLayout_4.removeWidget(widget)

# O antigo rótulo fixo "Ticks" passa a mostrar os ticks da simulação
self.simulation_ticks_label = self.label
self.simulation_time_label = QLabel(self.groupBox_2)

speed_row = QHBoxLayout()
speed_row.addStretch()
speed_row.addWidget(self.label_2)

time_row = QHBoxLayout()
time_row.addWidget(self.simulation_time_label)
time_row.addStretch()
time_row.addWidget(self.simulation_ticks_label)

speed_layout = QVBoxLayout()
speed_layout.setSpacing(0)
speed_layout.addLayout(speed_row)
speed_layout.addWidget(self.horizontalSlider)
speed_layout.addLayout(time_row)
self.horizontalLayout_4.addLayout(speed_layout)

def update_simulation_time(self, ticks):
clock_period = self.mpconfig.clock_period_in_ns if self.mpconfig else 0
self.simulation_time_label.setText(f"{ticks_to_ms(ticks, clock_period):.5f} ms")
self.simulation_ticks_label.setText(f"{ticks} ticks")

def update_current_packet_table(self, packet):
if self.mpconfig.router_addressing == MPSoCConfig.MPSoCConfig.HAMILTONIAN:
source = str(packet.router_address)
target = str(packet.target_router)
else:
source = self.mpconfig.ham_address_to_xy_label(packet.router_address)
target = self.mpconfig.ham_address_to_xy_label(packet.target_router)

table_widget.setItem(row, 0, name_item)
table_widget.setItem(row, 1, id_item)
values = (source, target,
self.mpconfig.get_string_service_name(packet.service),
f"{packet.size} | {packet.bandwidth_cycles}")
for column, value in enumerate(values):
self.tableWidget.setItem(0, column, QTableWidgetItem(value))

def reset_current_packet_table(self):
for column in range(self.tableWidget.columnCount()):
self.tableWidget.setItem(0, column, QTableWidgetItem("-"))

def taskList(self):
task_hash = self.mpconfig.get_task_name_hash()
rows = [(task_hash[key], str(key)) for key in sorted(task_hash.keys())]
self.task_list_frame = self.create_table_window("Current Task List", ["Task Name", "ID"], rows)

def servicesList(self):
services_hash = self.mpconfig.get_services_hash()
rows = [(services_hash[key], str(key)) for key in sorted(services_hash.keys())]
self.services_list_frame = self.create_table_window("Services List", ["Service Name", "ID"], rows)

def create_table_window(self, title, headers, rows):
"""Cria e exibe uma janela com uma tabela de duas colunas (nome e ID)."""
table_frame = QWidget()
table_frame.setWindowTitle(title)

table_frame.setAttribute(Qt.WidgetAttribute.WA_DeleteOnClose)

table_frame.setGeometry(100, 100, 500, 500)

table_widget = QTableWidget()
table_widget.setColumnCount(len(headers))
table_widget.setHorizontalHeaderLabels(headers)
table_widget.setRowCount(len(rows))

for row, values in enumerate(rows):
for column, value in enumerate(values):
table_widget.setItem(row, column, QTableWidgetItem(value))

layout = QVBoxLayout()
layout.addWidget(table_widget)
self.task_list_frame.setLayout(layout)

self.task_list_frame.show()
table_frame.setLayout(layout)

table_frame.show()
return table_frame


class NovaJanela(QWidget, Ui_Form):
def __init__(self, mpconfig=None):
super().__init__()
self.setupUi(self)
self.mpconfig = mpconfig
self.checkBox.checkStateChanged.connect(self.CheckB)
self.checkBox.checkStateChanged.connect(self.on_checkbox_changed)

self.build_slave_matrix()

Expand All @@ -250,7 +451,7 @@ def build_slave_matrix(self):
layout.addWidget(matrix)
self.scrollAreaWidgetContents.setLayout(layout)

def CheckB(self):
def on_checkbox_changed(self):
if (self.checkBox.isChecked()):
self.radioButton.setEnabled(False)
self.radioButton_2.setEnabled(False)
Expand All @@ -263,7 +464,7 @@ def CheckB(self):
self.comboBox.setEnabled(True)


class taskMap(QWidget, Ui_TaskMap):
class TaskMapWindow(QWidget, Ui_TaskMap):
def __init__(self, mpconfig=None):
super().__init__()
self.setupUi(self)
Expand Down
3 changes: 1 addition & 2 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ name = "project-memphis-py"
version = "0.1.0"
requires-python = ">=3.14"
dependencies = [
"pyside6",
"pyside6>=6.7",
"sortedcontainers>=2.4.0",
"SortedDict",
]
Loading
Loading