Skip to content

Commit

Permalink
added backend for combinational circuits
Browse files Browse the repository at this point in the history
  • Loading branch information
stc19007 committed Nov 18, 2024
1 parent e401d42 commit 9a14e39
Show file tree
Hide file tree
Showing 3 changed files with 329 additions and 0 deletions.
130 changes: 130 additions & 0 deletions SDPPython/prototype5/chip.py
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
32 changes: 32 additions & 0 deletions SDPPython/prototype5/circuits/test.txt
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
167 changes: 167 additions & 0 deletions SDPPython/prototype5/prototype5.py
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()

0 comments on commit 9a14e39

Please sign in to comment.