Skip to content

Commit

Permalink
v2.10
Browse files Browse the repository at this point in the history
  • Loading branch information
Paolo-Beci committed Jul 23, 2024
1 parent ac5648a commit ced931b
Show file tree
Hide file tree
Showing 4 changed files with 95 additions and 34 deletions.
6 changes: 4 additions & 2 deletions CONFIG.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
VALUES=example1,example2,NOPE,example3
VALUES=EX1,EX2,EX3
AUTO_DETECT=False
AUTO_DETECT_FLAG=###
NEWLINE=LF
SEPARATOR=,
BAUDRATE=9600
UDP_PORT=4444
SERIAL_PORT=/dev/tty.usbmodem21301
SERIAL_PORT=/dev/tty.usbmodem11201
20 changes: 17 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ pip install -r requirements.txt
To configure the parameters of the program you have to create a `CONFIG.txt` file with the following parameters:
```txt
VALUES=PARAM1,PARAM2,NULL,PARAM3
AUTO_DETECT=True
AUTO_DETECT_FLAG=###
NEWLINE=;
SEPARATOR=,
BAUDRATE=9600
Expand All @@ -39,10 +41,22 @@ With the configuration shown above you can send the following JSON (assuming CSV
### Command-line run option
It is possible to run the program directly from the command line (for example) with the following command:
```bash
./SerialToUdpTranslator-v2.8.2-Win-x64.exe --config ./CONFIG.txt --nogui
#./NameOfTheExecutable --config ./CONFIG.txt --nogui
./SerialToUdpTranslator-v2.8.2-Win-x64.exe --config ./CONFIG.txt --autodetect <starting flag> --nogui
#./NameOfTheExecutable --config ./CONFIG.txt --autodetect <starting flag> --nogui
```
Where you can specify the path of the configuration file `--config` -> `CONFIG.txt` file (explained above) and the `--nogui` flag to run the program without the GUI.
You can also specify the `--autodetect` flag to start the program with the autodetection of the `<starting flag>` in order to automatically discover the parameters that will be passed to the program as first message (note that if you want to use special characters like ### you have to pass them via CONFIG file above), for example:
```txt
starting flag -> ###
first message -> ###,PARAM1,PARAM2,NULL,PARAM3
second message -> 1,2,3,4
parsing result:
{
"PARAM1": 1,
"PARAM2": 2,
"PARAM3": 4
}
```
Where you can specify the path of the configuration file `--config` -> `CONFIG.txt` file (explained above) and the `--nogui` flag to run the program without the GUI.

## How to pair with Plotjuggler graphing tool
1. Open Plotjuggler
Expand Down
31 changes: 22 additions & 9 deletions backend/functions.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,17 +11,19 @@

udp_socket = None
ser_socket = None
values = []

# Controller
def start_connection_controller(UDP_PORT, SERIAL_PORT, VALUES, NEWLINE, SEPARATOR, BAUDRATE, label_connected, connect_button, disconnect_button):
global udp_socket, ser_socket
def start_connection_controller(UDP_PORT, SERIAL_PORT, VALUES, NEWLINE, SEPARATOR, BAUDRATE, AUTO_DETECT, AUTO_DETECT_FLAG, label_connected, connect_button, disconnect_button):
global udp_socket, ser_socket, values
udp_socket = open_stream_udp(int(UDP_PORT))
ser_socket = open_stream_serial(SERIAL_PORT, BAUDRATE)
values = VALUES
time.sleep(1)

if udp_socket and ser_socket:
print("Connection established")
read_serial_data(ser_socket, udp_socket, VALUES, NEWLINE, SEPARATOR, UDP_PORT)
read_serial_data(ser_socket, udp_socket, NEWLINE, SEPARATOR, UDP_PORT, AUTO_DETECT, AUTO_DETECT_FLAG)
if label_connected:
label_connected.grid(row=18, column=1, columnspan=10)
if connect_button:
Expand Down Expand Up @@ -57,7 +59,7 @@ def open_stream_udp(UDP_PORT):
print(f"Error opening JSON streaming server: {e}")

# Read data from the serial port
def read_serial_data(ser_socket, udp_socket, VALUES, NEWLINE, SEPARATOR, UDP_PORT):
def read_serial_data(ser_socket, udp_socket, NEWLINE, SEPARATOR, UDP_PORT, AUTO_DETECT, AUTO_DETECT_FLAG):
data_buffer = ""

# NEWLINE translation of special characters
Expand Down Expand Up @@ -90,7 +92,7 @@ def read_data_handler(data_buffer):
#print(f"Received line: {line}") #DEBUG

# Process the line (convert to json and send it to the UDP server)
csv_to_json(udp_socket, line, UDP_PORT, VALUES, SEPARATOR)
csv_to_json(udp_socket, line, UDP_PORT, SEPARATOR, AUTO_DETECT, AUTO_DETECT_FLAG)

except serial.SerialException as e:
break
Expand All @@ -103,24 +105,35 @@ def read_data_handler(data_buffer):
read_serial_thread.start()

# Converter Serial CSV stream to JSON converter
def csv_to_json(udp_socket, line_csv, UDP_PORT, VALUES, SEPARATOR):
def csv_to_json(udp_socket, line_csv, UDP_PORT, SEPARATOR, AUTO_DETECT, AUTO_DETECT_FLAG):
global values
try:
# Split the CSV data by comma
csv_parts = line_csv.strip().split(SEPARATOR)

if AUTO_DETECT:
if csv_parts[0] == AUTO_DETECT_FLAG:
values = [csv_parts[i] for i in range(1, len(csv_parts))]
print(f"Auto-detected values: {values}")
return
else:
# Check if VALUES are default and replace them with param1, param2, param3, ...
if not values or values == ['']:
values = [f"param{i+1}" for i in range(len(csv_parts))]

# Initialize a dictionary to hold the JSON data
json_data = {}

# Loop through each value and its corresponding csv part
for value, csv_part in zip(VALUES, csv_parts):
for value, csv_part in zip(values, csv_parts):
# Check if the csv part is not NULL
if value != "NOPE":
# Convert value to int or float if possible
try:
csv_part = int(csv_part) # Try converting to integer
csv_part = int(csv_part)
except ValueError:
try:
csv_part = float(csv_part) # Try converting to float
csv_part = float(csv_part)
except ValueError:
pass # If not convertible, keep the value as string

Expand Down
72 changes: 52 additions & 20 deletions main.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,17 @@
import argparse

class GUI:
def __init__(self, config_path=None, direct_connect=False):
def __init__(self, config_path=None, autodetect=None,direct_connect=False):
# Config parameters
self.PATH_CONFIG_MODEL = "Path"
self.VALUES=['example1,example2,example3']
self.VALUES=''
self.NEWLINE=';'
self.SEPARATOR=','
self.BAUDRATE=9600
self.UDP_PORT=5000
self.SERIAL_PORT='/dev/ttyUSB0'
self.AUTO_DETECT=False
self.AUTO_DETECT_FLAG="###"

global controller_thread
controller_thread = None
Expand All @@ -28,6 +30,10 @@ def __init__(self, config_path=None, direct_connect=False):
self.PATH_CONFIG_MODEL = config_path
self.startup()

if autodetect:
self.AUTO_DETECT = True
self.AUTO_DETECT_FLAG = autodetect

if direct_connect:
self.connect_thread(direct=True)
return
Expand All @@ -42,7 +48,7 @@ def __init__(self, config_path=None, direct_connect=False):
self.screen_width = self.app.winfo_screenwidth()
self.screen_height = self.app.winfo_screenheight()
self.window_width = 500
self.window_height = 600
self.window_height = 650
self.x_coordinate = (self.screen_width - self.window_width) // 2
self.y_coordinate = (self.screen_height - self.window_height) // 2

Expand All @@ -64,55 +70,67 @@ def __init__(self, config_path=None, direct_connect=False):
self.browse_button_config_model = tk.Button(self.frame, text="Browse", command=self.browse_file_config_model)
self.browse_button_config_model.grid(row=3, column=1, columnspan=10, pady=10)

# Autodetect values
self.label_autodetect_values = tk.Label(self.frame, text="Check the box if you want to autodetect the values, \nspecify the special line starter value:")
self.label_autodetect_values.grid(row=4, column=1, columnspan=10)
self.auto_detect_var = tk.BooleanVar()
if self.AUTO_DETECT == True:
self.auto_detect_var.set(True)
self.checkbox_autodetect = tk.Checkbutton(self.frame, text="Autodetect", variable=self.auto_detect_var)
self.checkbox_autodetect.grid(row=5, column=0, columnspan=10)
self.textbox_autodetect_values = tk.Text(self.frame, height=1, width=10)
self.textbox_autodetect_values.insert("1.0", self.AUTO_DETECT_FLAG)
self.textbox_autodetect_values.grid(row=5, column=6, columnspan=10)

# Values
self.label_values = tk.Label(self.frame, text="Insert data label values, separated by spaces:")
self.label_values.grid(row=4, column=1, columnspan=10)
self.label_values = tk.Label(self.frame, text="OR insert data label values, separated by the value you specify below:")
self.label_values.grid(row=6, column=1, columnspan=10)
self.textbox_values = tk.Text(self.frame, height=1, width=50)
self.textbox_values.insert("1.0", self.VALUES)
self.textbox_values.grid(row=5, column=1, columnspan=10)
self.textbox_values.grid(row=7, column=1, columnspan=10)

# Newline
self.label_newline = tk.Label(self.frame, text="Insert newline separator for the upcoming CSV stream. \nInsert LF->'\\n' and CRLF->'\\r\\n':")
self.label_newline.grid(row=6, column=1, columnspan=10)
self.label_newline.grid(row=8, column=1, columnspan=10)
self.textbox_newline = tk.Text(self.frame, height=1, width=30)
self.textbox_newline.insert("1.0", self.NEWLINE)
self.textbox_newline.grid(row=7, column=1, columnspan=10)
self.textbox_newline.grid(row=9, column=1, columnspan=10)

# Separator
self.label_separator = tk.Label(self.frame, text="Insert single data separator for the upcoming CSV stream:")
self.label_separator.grid(row=8, column=1, columnspan=10)
self.label_separator.grid(row=10, column=1, columnspan=10)
self.textbox_separator = tk.Text(self.frame, height=1, width=30)
self.textbox_separator.insert("1.0", self.SEPARATOR)
self.textbox_separator.grid(row=9, column=1, columnspan=10)
self.textbox_separator.grid(row=11, column=1, columnspan=10)

# Baudrate
self.label_baudrate = tk.Label(self.frame, text="Insert baudrate of the serial signal:")
self.label_baudrate.grid(row=10, column=1, columnspan=10)
self.label_baudrate.grid(row=12, column=1, columnspan=10)
self.textbox_baudrate = tk.Text(self.frame, height=1, width=30)
self.textbox_baudrate.insert("1.0", self.BAUDRATE)
self.textbox_baudrate.grid(row=11, column=1, columnspan=10)
self.textbox_baudrate.grid(row=13, column=1, columnspan=10)

# Local UDP Port
self.label_udp_port = tk.Label(self.frame, text="Local UDP port:")
self.label_udp_port.grid(row=12, column=1, columnspan=10)
self.label_udp_port.grid(row=14, column=1, columnspan=10)
self.textbox_udp_port = tk.Text(self.frame, height=1, width=30)
self.textbox_udp_port.insert("1.0", self.UDP_PORT)
self.textbox_udp_port.grid(row=13, column=1, columnspan=10)
self.textbox_udp_port.grid(row=15, column=1, columnspan=10)

# Serial Port
self.label_serial_port = tk.Label(self.frame, text="Serial port:")
self.label_serial_port.grid(row=14, column=1, columnspan=10)
self.label_serial_port.grid(row=16, column=1, columnspan=10)
self.textbox_serial_port = tk.Text(self.frame, height=1, width=30)
self.textbox_serial_port.insert("1.0", self.SERIAL_PORT)
self.textbox_serial_port.grid(row=15, column=1, columnspan=10)
self.textbox_serial_port.grid(row=17, column=1, columnspan=10)

# Connect button
self.connect_button = tk.Button(self.frame, text="Connect", command=self.connect_thread, font=("Arial", 14, "bold"), width=8, height=2)
self.connect_button.grid(row=16, column=0, columnspan=5, pady=15)
self.connect_button.grid(row=18, column=0, columnspan=5, pady=15)

# Disconnect button
self.disconnect_button = tk.Button(self.frame, text="Disconnect", command=self.disconnect, font=("Arial", 14, "bold"), width=8, height=2, state="disabled")
self.disconnect_button.grid(row=16, column=7, columnspan=5, pady=15)
self.disconnect_button.grid(row=18, column=7, columnspan=5, pady=15)

# Connected status
self.label_connected = tk.Label(self.frame, text="CONNECTED!", font=("Arial", 14, "bold"))
Expand Down Expand Up @@ -165,10 +183,15 @@ def connect(self, direct=False):
self.SEPARATOR = self.textbox_separator.get("1.0", "end-1c")
if hasattr(self, 'textbox_baudrate'):
self.BAUDRATE = self.textbox_baudrate.get("1.0", "end-1c")
if hasattr(self, 'auto_detect_var'):
self.AUTO_DETECT = self.auto_detect_var.get()
if hasattr(self, 'textbox_autodetect_values'):
self.AUTO_DETECT_FLAG = self.textbox_autodetect_values.get("1.0", "end-1c")
self.save_to_config_file() # Save the data to the CONFIG file for future reuse

try:
start_connection_controller(self.UDP_PORT, self.SERIAL_PORT, self.VALUES, self.NEWLINE, self.SEPARATOR, self.BAUDRATE, self.label_connected, self.connect_button, self.disconnect_button)
start_connection_controller(self.UDP_PORT, self.SERIAL_PORT, self.VALUES, self.NEWLINE, self.SEPARATOR, self.BAUDRATE,
self.AUTO_DETECT, self.AUTO_DETECT_FLAG, self.label_connected, self.connect_button, self.disconnect_button)
except Exception as e:
print(f"Connection failed: {e}")

Expand Down Expand Up @@ -204,6 +227,10 @@ def startup(self):
self.SERIAL_PORT = value
elif name == 'VALUES':
self.VALUES = value.replace(' ', '_').strip()
elif name == 'AUTO_DETECT':
self.AUTO_DETECT = value
elif name == 'AUTO_DETECT_FLAG':
self.AUTO_DETECT_FLAG = value

def update_interface(self):
self.textbox_path_config_model.delete("1.0", tk.END)
Expand All @@ -220,13 +247,17 @@ def update_interface(self):
self.textbox_separator.insert("1.0", str(self.SEPARATOR))
self.textbox_baudrate.delete("1.0", tk.END)
self.textbox_baudrate.insert("1.0", str(self.BAUDRATE))
self.textbox_autodetect_values.delete("1.0", tk.END)
self.textbox_autodetect_values.insert("1.0", str(self.AUTO_DETECT_FLAG))

def save_to_config_file(self):
values_string = ",".join(self.VALUES)

if self.PATH_CONFIG_MODEL != "Path":
with open(self.PATH_CONFIG_MODEL, 'w') as f:
f.write(f'VALUES={values_string}\n')
f.write(f'AUTO_DETECT={self.AUTO_DETECT}\n')
f.write(f'AUTO_DETECT_FLAG={self.AUTO_DETECT_FLAG}\n')
f.write(f'NEWLINE={self.NEWLINE}\n')
f.write(f'SEPARATOR={self.SEPARATOR}\n')
f.write(f'BAUDRATE={self.BAUDRATE}\n')
Expand All @@ -236,7 +267,8 @@ def save_to_config_file(self):
if __name__ == "__main__":
parser = argparse.ArgumentParser(description="Start the Serial CSV to UDP JSON Translator GUI.")
parser.add_argument('--config', type=str, help='Path to the configuration file')
parser.add_argument('--autodetect', type=str, help='Autodetect values from the serial stream, specify the special line starter value')
parser.add_argument('--nogui', action='store_true', default=False, help='Connect directly without showing the GUI')
args = parser.parse_args()

gui = GUI(config_path=args.config, direct_connect=args.nogui)
gui = GUI(config_path=args.config, autodetect=args.autodetect,direct_connect=args.nogui)

0 comments on commit ced931b

Please sign in to comment.