Skip to content
Open
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
73 changes: 37 additions & 36 deletions concore.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
import time
import logging
import os
from ast import literal_eval
import sys
import re
import zmq # Added for ZeroMQ
import numpy as np # Added for numpy type conversion
import zmq
logging.basicConfig(
level=logging.INFO,
format='%(levelname)s - %(message)s'
) # Added for ZeroMQ

# if windows, create script to kill this process
# because batch files don't provide easy way to know pid of last command
Expand Down Expand Up @@ -37,10 +41,10 @@ def __init__(self, port_type, address, zmq_socket_type):
# Bind or connect
if self.port_type == "bind":
self.socket.bind(address)
print(f"ZMQ Port bound to {address}")
logging.info(f"ZMQ Port bound to {address}")
else:
self.socket.connect(address)
print(f"ZMQ Port connected to {address}")
logging.info(f"ZMQ Port connected to {address}")

def send_json_with_retry(self, message):
"""Send JSON message with retries if timeout occurs."""
Expand All @@ -49,9 +53,9 @@ def send_json_with_retry(self, message):
self.socket.send_json(message)
return
except zmq.Again:
print(f"Send timeout (attempt {attempt + 1}/5)")
logging.warning(f"Send timeout (attempt {attempt + 1}/5)")
time.sleep(0.5)
print("Failed to send after retries.")
logging.error("Failed to send after retries.")
return

def recv_json_with_retry(self):
Expand All @@ -60,9 +64,9 @@ def recv_json_with_retry(self):
try:
return self.socket.recv_json()
except zmq.Again:
print(f"Receive timeout (attempt {attempt + 1}/5)")
logging.warning(f"Receive timeout (attempt {attempt + 1}/5)")
time.sleep(0.5)
print("Failed to receive after retries.")
logging.error("Failed to receive after retries.")
return None

# Global ZeroMQ ports registry
Expand All @@ -77,28 +81,28 @@ def init_zmq_port(port_name, port_type, address, socket_type_str):
socket_type_str (str): String representation of ZMQ socket type (e.g., "REQ", "REP", "PUB", "SUB").
"""
if port_name in zmq_ports:
print(f"ZMQ Port {port_name} already initialized.")
logging.info(f"ZMQ Port {port_name} already initialized.")
return # Avoid reinitialization

try:
# Map socket type string to actual ZMQ constant (e.g., zmq.REQ, zmq.REP)
zmq_socket_type = getattr(zmq, socket_type_str.upper())
zmq_ports[port_name] = ZeroMQPort(port_type, address, zmq_socket_type)
print(f"Initialized ZMQ port: {port_name} ({socket_type_str}) on {address}")
logging.info(f"Initialized ZMQ port: {port_name} ({socket_type_str}) on {address}")
except AttributeError:
print(f"Error: Invalid ZMQ socket type string '{socket_type_str}'.")
logging.error(f"Error: Invalid ZMQ socket type string '{socket_type_str}'.")
except zmq.error.ZMQError as e:
print(f"Error initializing ZMQ port {port_name} on {address}: {e}")
logging.error(f"Error initializing ZMQ port {port_name} on {address}: {e}")
except Exception as e:
print(f"An unexpected error occurred during ZMQ port initialization for {port_name}: {e}")
logging.error(f"An unexpected error occurred during ZMQ port initialization for {port_name}: {e}")

def terminate_zmq():
for port in zmq_ports.values():
try:
port.socket.close()
port.context.term()
except Exception as e:
print(f"Error while terminating ZMQ port {port.address}: {e}")
logging.error(f"Error while terminating ZMQ port {port.address}: {e}")
# --- ZeroMQ Integration End ---


Expand Down Expand Up @@ -163,13 +167,13 @@ def safe_literal_eval(filename, defaultValue):

# Convert key=value;key2=value2 to Python dict format
if sparams != '{' and not (sparams.startswith('{') and sparams.endswith('}')): # Check if it needs conversion
print("converting sparams: "+sparams)
logging.debug("converting sparams: "+sparams)
sparams = "{'"+re.sub(';',",'",re.sub('=',"':",re.sub(' ','',sparams)))+"}"
print("converted sparams: " + sparams)
logging.debug("converted sparams: " + sparams)
try:
params = literal_eval(sparams)
except Exception as e:
print(f"bad params content: {sparams}, error: {e}")
logging.warning(f"bad params content: {sparams}, error: {e}")
params = dict()
else:
params = dict()
Expand Down Expand Up @@ -226,17 +230,17 @@ def read(port_identifier, name, initstr_val):
message = zmq_p.recv_json_with_retry()
return message
except zmq.error.ZMQError as e:
print(f"ZMQ read error on port {port_identifier} (name: {name}): {e}. Returning default.")
logging.error(f"ZMQ read error on port {port_identifier} (name: {name}): {e}. Returning default.")
return default_return_val
except Exception as e:
print(f"Unexpected error during ZMQ read on port {port_identifier} (name: {name}): {e}. Returning default.")
logging.error(f"Unexpected error during ZMQ read on port {port_identifier} (name: {name}): {e}. Returning default.")
return default_return_val

# Case 2: File-based port
try:
file_port_num = int(port_identifier)
except ValueError:
print(f"Error: Invalid port identifier '{port_identifier}' for file operation. Must be integer or ZMQ name.")
logging.error(f"Error: Invalid port identifier '{port_identifier}' for file operation. Must be integer or ZMQ name.")
return default_return_val

time.sleep(delay)
Expand All @@ -250,8 +254,7 @@ def read(port_identifier, name, initstr_val):
ins = str(initstr_val)
s += ins # Update s to break unchanged() loop
except Exception as e:
print(f"Error reading {file_path}: {e}. Using default value.")
s += str(initstr_val) # Update s to break unchanged() loop
logging.error(f"Error reading {file_path}: {e}. Using default value.")
return default_return_val

# Retry logic if file is empty
Expand All @@ -263,13 +266,12 @@ def read(port_identifier, name, initstr_val):
with open(file_path, "r") as infile:
ins = infile.read()
except Exception as e:
print(f"Retry {attempts + 1}: Error reading {file_path} - {e}")
logging.warning(f"Retry {attempts + 1}: Error reading {file_path} - {e}")
attempts += 1
retrycount += 1

if len(ins) == 0:
print(f"Max retries reached for {file_path}, using default value.")
s += str(initstr_val) # Update s to break unchanged() loop
logging.error(f"Max retries reached for {file_path}, using default value.")
return default_return_val

s += ins
Expand All @@ -283,10 +285,10 @@ def read(port_identifier, name, initstr_val):
simtime = max(simtime, current_simtime_from_file)
return inval[1:]
else:
print(f"Warning: Unexpected data format in {file_path}: {ins}. Returning raw content or default.")
logging.warning(f"Warning: Unexpected data format in {file_path}: {ins}. Returning raw content or default.")
return inval
except Exception as e:
print(f"Error parsing content from {file_path} ('{ins}'): {e}. Returning default.")
logging.error(f"Error parsing content from {file_path} ('{ins}'): {e}. Returning default.")
return default_return_val


Expand All @@ -303,24 +305,23 @@ def write(port_identifier, name, val, delta=0):
try:
zmq_p.send_json_with_retry(val)
except zmq.error.ZMQError as e:
print(f"ZMQ write error on port {port_identifier} (name: {name}): {e}")
logging.error(f"ZMQ write error on port {port_identifier} (name: {name}): {e}")
except Exception as e:
print(f"Unexpected error during ZMQ write on port {port_identifier} (name: {name}): {e}")
return
logging.error(f"Unexpected error during ZMQ write on port {port_identifier} (name: {name}): {e}")

# Case 2: File-based port
try:
file_port_num = int(port_identifier)
file_path = os.path.join(outpath + str(file_port_num), name)
except ValueError:
print(f"Error: Invalid port identifier '{port_identifier}' for file operation. Must be integer or ZMQ name.")
logging.error(f"Error: Invalid port identifier '{port_identifier}' for file operation. Must be integer or ZMQ name.")
return

# File writing rules
if isinstance(val, str):
time.sleep(2 * delay) # string writes wait longer
elif not isinstance(val, list):
print(f"File write to {file_path} must have list or str value, got {type(val)}")
logging.error(f"File write to {file_path} must have list or str value, got {type(val)}")
return

try:
Expand All @@ -334,7 +335,7 @@ def write(port_identifier, name, val, delta=0):
else:
outfile.write(val)
except Exception as e:
print(f"Error writing to {file_path}: {e}")
logging.error(f"Error writing to {file_path}: {e}")

def initval(simtime_val_str):
"""
Expand All @@ -350,12 +351,12 @@ def initval(simtime_val_str):
simtime = first_element
return val[1:]
else:
print(f"Error: First element in initval string '{simtime_val_str}' is not a number. Using data part as is or empty.")
logging.error(f"Error: First element in initval string '{simtime_val_str}' is not a number. Using data part as is or empty.")
return val[1:] if len(val) > 1 else []
else:
print(f"Error: initval string '{simtime_val_str}' is not a list or is empty. Returning empty list.")
logging.error(f"Error: initval string '{simtime_val_str}' is not a list or is empty. Returning empty list.")
return []

except Exception as e:
print(f"Error parsing simtime_val_str '{simtime_val_str}': {e}. Returning empty list.")
logging.error(f"Error parsing simtime_val_str '{simtime_val_str}': {e}. Returning empty list.")
return []
48 changes: 24 additions & 24 deletions mkconcore.py
Original file line number Diff line number Diff line change
Expand Up @@ -413,8 +413,8 @@
fsource = open(CONCOREPATH+"/concoredocker.py")
else:
fsource = open(CONCOREPATH+"/concore.py")
except:
logging.error(f"{CONCOREPATH} is not correct path to concore")
except (FileNotFoundError, IOError) as e:
logging.error(f"{CONCOREPATH} is not correct path to concore: {e}")
quit()
with open(outdir+"/src/concore.py","w") as fcopy:
fcopy.write(fsource.read())
Expand All @@ -426,8 +426,8 @@
fsource = open(CONCOREPATH+"/concoredocker.hpp")
else:
fsource = open(CONCOREPATH+"/concore.hpp")
except:
logging.error(f"{CONCOREPATH} is not correct path to concore")
except (FileNotFoundError, IOError) as e:
logging.error(f"{CONCOREPATH} is not correct path to concore: {e}")
quit()
with open(outdir+"/src/concore.hpp","w") as fcopy:
fcopy.write(fsource.read())
Expand All @@ -439,8 +439,8 @@
fsource = open(CONCOREPATH+"/concoredocker.v")
else:
fsource = open(CONCOREPATH+"/concore.v")
except:
logging.error(f"{CONCOREPATH} is not correct path to concore")
except (FileNotFoundError, IOError) as e:
logging.error(f"{CONCOREPATH} is not correct path to concore: {e}")
quit()
with open(outdir+"/src/concore.v","w") as fcopy:
fcopy.write(fsource.read())
Expand All @@ -449,8 +449,8 @@
#copy mkcompile into /src 5/27/21
try:
fsource = open(CONCOREPATH+"/mkcompile")
except:
logging.error(f"{CONCOREPATH} is not correct path to concore")
except (FileNotFoundError, IOError) as e:
logging.error(f"{CONCOREPATH} is not correct path to concore: {e}")
quit()
with open(outdir+"/src/mkcompile","w") as fcopy:
fcopy.write(fsource.read())
Expand All @@ -460,56 +460,56 @@
#copy concore*.m into /src 4/2/21
try: #maxtime in matlab 11/22/21
fsource = open(CONCOREPATH+"/concore_default_maxtime.m")
except:
logging.error(f"{CONCOREPATH} is not correct path to concore")
except (FileNotFoundError, IOError) as e:
logging.error(f"{CONCOREPATH} is not correct path to concore: {e}")
quit()
with open(outdir+"/src/concore_default_maxtime.m","w") as fcopy:
fcopy.write(fsource.read())
fsource.close()
try:
fsource = open(CONCOREPATH+"/concore_unchanged.m")
except:
logging.error(f"{CONCOREPATH} is not correct path to concore")
except (FileNotFoundError, IOError) as e:
logging.error(f"{CONCOREPATH} is not correct path to concore: {e}")
quit()
with open(outdir+"/src/concore_unchanged.m","w") as fcopy:
fcopy.write(fsource.read())
fsource.close()
try:
fsource = open(CONCOREPATH+"/concore_read.m")
except:
logging.error(f"{CONCOREPATH} is not correct path to concore")
except (FileNotFoundError, IOError) as e:
logging.error(f"{CONCOREPATH} is not correct path to concore: {e}")
quit()
with open(outdir+"/src/concore_read.m","w") as fcopy:
fcopy.write(fsource.read())
fsource.close()
try:
fsource = open(CONCOREPATH+"/concore_write.m")
except:
logging.error(f"{CONCOREPATH} is not correct path to concore")
except (FileNotFoundError, IOError) as e:
logging.error(f"{CONCOREPATH} is not correct path to concore: {e}")
quit()
with open(outdir+"/src/concore_write.m","w") as fcopy:
fcopy.write(fsource.read())
fsource.close()
try: #4/9/21
fsource = open(CONCOREPATH+"/concore_initval.m")
except:
logging.error(f"{CONCOREPATH} is not correct path to concore")
except (FileNotFoundError, IOError) as e:
logging.error(f"{CONCOREPATH} is not correct path to concore: {e}")
quit()
with open(outdir+"/src/concore_initval.m","w") as fcopy:
fcopy.write(fsource.read())
fsource.close()
try: #11/19/21
fsource = open(CONCOREPATH+"/concore_iport.m")
except:
logging.error(f"{CONCOREPATH} is not correct path to concore")
except (FileNotFoundError, IOError) as e:
logging.error(f"{CONCOREPATH} is not correct path to concore: {e}")
quit()
with open(outdir+"/src/concore_iport.m","w") as fcopy:
fcopy.write(fsource.read())
fsource.close()
try: #11/19/21
fsource = open(CONCOREPATH+"/concore_oport.m")
except:
logging.error(f"{CONCOREPATH} is not correct path to concore")
except (FileNotFoundError, IOError) as e:
logging.error(f"{CONCOREPATH} is not correct path to concore: {e}")
quit()
with open(outdir+"/src/concore_oport.m","w") as fcopy:
fcopy.write(fsource.read())
Expand All @@ -519,8 +519,8 @@
fsource = open(CONCOREPATH+"/import_concoredocker.m")
else:
fsource = open(CONCOREPATH+"/import_concore.m")
except:
logging.error(f"{CONCOREPATH} is not correct path to concore")
except (FileNotFoundError, IOError) as e:
logging.error(f"{CONCOREPATH} is not correct path to concore: {e}")
quit()
with open(outdir+"/src/import_concore.m","w") as fcopy:
fcopy.write(fsource.read())
Expand Down