-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
added backend for combinational circuits
- Loading branch information
Showing
3 changed files
with
329 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,130 @@ | ||
import json | ||
import serial | ||
class IC74Series: | ||
def __init__(self, chip_number, logic_type,n,TruthTable=[],pin_count=14, description=None, pin_config=None): | ||
""" | ||
Initializes a 74 series IC chip. | ||
:param chip_number: The number associated with the IC (e.g., '7400', '74138'). | ||
:param logic_type: Type of logic gate/function the IC performs (e.g., 'NAND', 'Multiplexer'). | ||
:param pin_count: Number of pins on the chip, defaults to 14 for most 74 series ICs. | ||
:param description: Optional description of the IC's function. | ||
:param pin_config: A dictionary mapping each pin to its type (input, output, VCC, ground). | ||
""" | ||
self.chip_number = chip_number | ||
self.logic_type = logic_type | ||
self.pin_count = pin_count | ||
self.inputn = n | ||
self.TruthTable = TruthTable | ||
self.description = description if description else "No description provided." | ||
self.pin_config = pin_config if pin_config else {} | ||
|
||
def set_pin(self, pin_number, pin_type): | ||
""" | ||
Sets the type of a specific pin (input, output, VCC, or ground). | ||
:param pin_number: The pin number (1-based index). | ||
:param pin_type: The type of the pin ('input', 'output', 'VCC', 'ground'). | ||
""" | ||
if 1 <= pin_number <= self.pin_count: | ||
self.pin_config[pin_number] = pin_type | ||
else: | ||
raise ValueError(f"Invalid pin number. This IC has {self.pin_count} pins.") | ||
|
||
def get_pin(self, pin_number): | ||
""" | ||
Returns the type of a specific pin. | ||
:param pin_number: The pin number (1-based index). | ||
:return: The type of the pin ('input', 'output', 'VCC', or 'ground') or 'not configured'. | ||
""" | ||
return self.pin_config.get(pin_number, "not configured") | ||
|
||
def get_details(self): | ||
""" | ||
Returns the details of the IC as a string. | ||
""" | ||
return f"74{self.chip_number} IC - Logic Type: {self.logic_type}, Pins: {self.pin_count}, Description: {self.description}" | ||
|
||
def pin_configuration(self): | ||
""" | ||
Returns a formatted string with the pin configuration. | ||
""" | ||
config_str = f"Pin Configuration for 74{self.chip_number}:\n" | ||
for pin in range(1, self.pin_count + 1): | ||
pin_type = self.get_pin(pin) | ||
config_str += f"Pin {pin}: {pin_type}\n" | ||
return config_str | ||
|
||
def is_standard_pin_count(self): | ||
""" | ||
Checks if the IC has a standard pin count of 14. | ||
""" | ||
return self.pin_count == 14 | ||
|
||
def __str__(self): | ||
return f"74{self.chip_number} ({self.logic_type})" | ||
|
||
def pin_configuration_json(self): | ||
""" | ||
Returns the pin configuration as a JSON string. | ||
""" | ||
config = { | ||
"chip_number": self.chip_number, | ||
"logic_type": self.logic_type, | ||
"pin_count": self.pin_count, | ||
"description": self.description, | ||
"pins": self.pin_config | ||
} | ||
return json.dumps(config) | ||
|
||
def send_pin_configuration(self, uart_port, baudrate=250000): | ||
""" | ||
Sends the pin configuration as a JSON string over UART. | ||
:param uart_port: The UART port (e.g., 'COM3' on Windows or '/dev/ttyUSB0' on Linux). | ||
:param baudrate: The baudrate for UART communication. | ||
""" | ||
json_data = self.pin_configuration_json() | ||
#print("JSON Data to be sent:", json_data) | ||
#raw_bytes = json_data.encode('utf-8') | ||
#hex_bytes = [f"{byte:02x}" for byte in raw_bytes] # Convert bytes to hex | ||
#print("Raw Bytes (Hex) to be sent:", ' '.join(hex_bytes)) # Print hex bytes as a space-separated string | ||
with serial.Serial(uart_port, baudrate, timeout=10000000) as ser: | ||
ser.write(json_data.encode('utf-8')) | ||
print(f"Sent JSON data over UART: {json_data}") | ||
def set_truth_table(self,outputs): | ||
self.TruthTable=binary_number_list(self.inputn,outputs) | ||
|
||
def print_truth_tale(self): | ||
print(f"Chip: {self.chip_number}") | ||
print(f"Logic type: {self.logic_type}") | ||
print("INPUT BITS|OUTPUT BITS") | ||
for entry in self.TruthTable: | ||
print(f" {entry[0]} {entry[1]}") | ||
|
||
def binary_number_list(bits,outputs): | ||
list = [] | ||
bits = int(bits) | ||
for number in range(0,(2**bits)): | ||
bitslist = separate_bits(number,bits) | ||
list.append([bitslist,outputs[number]]) | ||
return list | ||
|
||
def separate_bits(num, n): | ||
bits = [(num >> i) & 1 for i in range(n)] # Extract each bit | ||
return bits[::-1] # Return in correct order | ||
|
||
def find_input_pins(ic): | ||
n = ic.inputn | ||
|
||
inputpins = [] | ||
temp = [] | ||
for pin in range(1,ic.pin_count+1): | ||
print("PIN NUMBER IS: ", pin, ic.get_pin(pin)) | ||
if(ic.get_pin(pin) == "input"): | ||
temp.append(pin) | ||
if len(temp) == n: | ||
inputpins.append(temp) | ||
temp=[] | ||
return inputpins |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
Chip Number: 00 | ||
Logic Type: NAND | ||
Number of Inputs: 2 | ||
Description: Quad 2-input NAND gate | ||
Pin Count: 14 | ||
1: INPUT | ||
2: INPUT | ||
3: OUTPUT | ||
4: INPUT | ||
5: INPUT | ||
6: OUTPUT | ||
7: GND | ||
8: OUTPUT | ||
9: INPUT | ||
10: INPUT | ||
11: OUTPUT | ||
12: INPUT | ||
13: INPUT | ||
14: VCC | ||
Tests | ||
1: 1 | ||
2: 1 | ||
OUTPUT: 3 | ||
1: 0 | ||
2: 1 | ||
OUTPUT: 3 | ||
1: 1 | ||
2: 0 | ||
OUTPUT: 3 | ||
1: 0 | ||
2: 0 | ||
OUTPUT: 3 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,167 @@ | ||
import tkinter as tk | ||
from tkinter import ttk, filedialog | ||
import os | ||
import serial | ||
import chip | ||
import json | ||
|
||
|
||
# folder path, default is None until user selects one | ||
folder_path = None | ||
|
||
def select_folder(): | ||
global folder_path | ||
folder_path = filedialog.askdirectory(initialdir=".", title="Select Circuit Folder") | ||
if folder_path: | ||
print(f"Selected folder: {folder_path}") | ||
display_label.config(text="Folder selected.", fg="green") | ||
update_folder_display() # update listbox with files from the selected folder | ||
|
||
def get_file_names(folder_path): | ||
try: | ||
return [f for f in os.listdir(folder_path) if os.path.isfile(os.path.join(folder_path, f))] | ||
except FileNotFoundError: | ||
print("The specified folder was not found.") | ||
return [] | ||
|
||
def update_folder_display(): | ||
file_names = get_file_names(folder_path) | ||
file_listbox.delete(0, tk.END) # clear existing items in the Listbox | ||
|
||
if not file_names: | ||
display_label.config(text="No files found in the folder.", fg="red") | ||
else: | ||
for file in file_names: | ||
file_listbox.insert(tk.END, file) # insert items from selected folder | ||
dropdown['values'] = file_names | ||
|
||
def on_file_select(event): | ||
# update dropdown_var when a file is selected in the listbox | ||
selected_index = file_listbox.curselection() | ||
if selected_index: | ||
selected_file = file_listbox.get(selected_index[0]) | ||
dropdown_var.set(selected_file) | ||
|
||
def read_chip_configuration(file_path): | ||
circuit_data = {} | ||
with open(file_path, 'r') as file: | ||
for line in file: | ||
# Stop reading when reaching "Tests" | ||
if line.strip() == "Tests": | ||
break | ||
if ":" not in line: | ||
continue | ||
key, value = line.strip().split(":") | ||
circuit_data[key.strip()] = value.strip() | ||
return circuit_data | ||
|
||
def read_tests(file_path): | ||
tests = [] | ||
key_values = {} | ||
with open(file_path, 'r') as file: | ||
# Skip lines until "Tests" is found | ||
in_tests_section = False | ||
for line in file: | ||
if line.strip() == "Tests": | ||
in_tests_section = True | ||
continue | ||
if in_tests_section: | ||
if ":" not in line: | ||
continue | ||
key, value = line.strip().split(":") | ||
key_values[key.strip()] = value.strip() | ||
if key.strip() == "OUTPUT": | ||
tests.append(key_values) | ||
key_values = {} | ||
return tests | ||
|
||
def send_selected_file(): | ||
if folder_path is None: | ||
display_label.config(text="Please select a folder.", fg="red") | ||
return | ||
|
||
selected_file = dropdown_var.get() | ||
if not selected_file: | ||
display_label.config(text="Please select a file.", fg="red") | ||
return | ||
|
||
file_path = os.path.join(folder_path, selected_file) | ||
circuit_data = {} | ||
print(0) | ||
try: | ||
# read the chip configuration | ||
circuit_data = read_chip_configuration(file_path) | ||
print(1) | ||
|
||
# read the tests | ||
tests = read_tests(file_path) | ||
print(2) | ||
ic = chip.IC74Series( | ||
chip_number=circuit_data['Chip Number'], | ||
logic_type=circuit_data['Logic Type'], | ||
n=circuit_data['Number of Inputs'], | ||
) | ||
|
||
print(circuit_data) | ||
print(tests) | ||
|
||
for i in range(1, int(circuit_data['Pin Count']) + 1): | ||
ic.set_pin(i, circuit_data[str(i)]) | ||
|
||
ser = serial.Serial('COM1', 9600) | ||
message = ic.pin_configuration_json() | ||
ser.write((message+"\n").encode('utf-8')) | ||
|
||
response = [] | ||
for test in tests: | ||
ser.write(json.dumps(test).encode('utf-8')) | ||
response.append(ser.readline().decode('utf-8').strip()) | ||
print(response) | ||
display_label.config(text="Circuit test complete. Check console for results.", fg="green") | ||
|
||
except Exception as e: | ||
print(f"An error occurred while reading {selected_file}: {e}") | ||
display_label.config(text="Error testing circuit.", fg="red") | ||
|
||
def print_results(): | ||
print("Results printed to the console or log file.") | ||
|
||
root = tk.Tk() | ||
root.title("Circuit GUI Prototype") | ||
root.geometry("270x350") | ||
|
||
# dropdown for selecting circuit file | ||
dropdown_var = tk.StringVar() | ||
dropdown = ttk.Combobox(root, textvariable=dropdown_var, state="readonly") | ||
dropdown.grid(row=0, column=0, columnspan=3, padx=10, pady=10) | ||
|
||
# label for file list | ||
file_list_label = tk.Label(root, text="Files in Selected Folder:") | ||
file_list_label.grid(row=1, column=0, columnspan=3, padx=10, pady=(5, 0)) | ||
|
||
# frame around Listbox for thicker border | ||
file_listbox_frame = tk.Frame(root, borderwidth=1, relief="solid") | ||
file_listbox_frame.grid(row=2, column=0, columnspan=3, padx=10, pady=(0, 10)) | ||
|
||
# listbox to display files in the selected folder | ||
file_listbox = tk.Listbox(file_listbox_frame, width=40, height=10) | ||
file_listbox.pack() | ||
|
||
# bind the Listbox to an event for selecting a file | ||
file_listbox.bind("<<ListboxSelect>>", on_file_select) | ||
|
||
# buttons in the same row | ||
select_folder_button = tk.Button(root, text="Select Folder", command=select_folder) | ||
select_folder_button.grid(row=3, column=0, padx=5, pady=10) | ||
|
||
send_button = tk.Button(root, text="Test Circuit", command=send_selected_file) | ||
send_button.grid(row=3, column=1, padx=5, pady=10) | ||
|
||
print_results_button = tk.Button(root, text="Print Results", command=print_results) | ||
print_results_button.grid(row=3, column=2, padx=5, pady=10) | ||
|
||
# display label for messages | ||
display_label = tk.Label(root, text="", font=("Arial", 11)) | ||
display_label.grid(row=4, column=0, columnspan=3, padx=10, pady=10) | ||
|
||
root.mainloop() |