Skip to content

Commit 804bce6

Browse files
committed
Update functions.py
1 parent d69d398 commit 804bce6

File tree

1 file changed

+181
-71
lines changed

1 file changed

+181
-71
lines changed

code/functions.py

Lines changed: 181 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424
import numpy as np
2525

2626
from pulsecatcher import pulsecatcher
27-
from dash import dash_table
27+
from dash import dash_table, html
2828
from scipy.signal import find_peaks, peak_widths
2929
from collections import defaultdict
3030
from datetime import datetime
@@ -62,33 +62,6 @@ def normalise_pulse(average):
6262
normalised = [int(n - mean) for n in average]
6363
return normalised
6464

65-
def get_serial_device_information():
66-
try:
67-
with shproto.dispatcher.command_lock:
68-
shproto.dispatcher.command = "-inf"
69-
time.sleep(0.2)
70-
device_info = shproto.dispatcher.inf_str
71-
time.sleep(0.2)
72-
shproto.dispatcher.inf_str = ""
73-
time.sleep(0.2)
74-
return device_info if device_info else "No response from device"
75-
except Exception as e:
76-
logger.error(f"Error retrieving device information: {e}")
77-
return "Error retrieving device information"
78-
79-
def parse_device_info(info_string):
80-
components = info_string.split()
81-
settings = {}
82-
for i in range(0, len(components) - 1, 2):
83-
key = components[i]
84-
value = components[i + 1]
85-
if value.replace('.', '', 1).isdigit() and value.count('.') < 2:
86-
converted_value = float(value) if '.' in value else int(value)
87-
else:
88-
converted_value = value
89-
settings[key] = converted_value
90-
return settings
91-
9265
# Normalized pulse samples less normalized shape samples squared summed and rooted
9366
def distortion(normalised, shape):
9467
product = [(x - y) ** 2 for x, y in zip(shape, normalised)]
@@ -765,57 +738,173 @@ def fetch_json(file_id):
765738
logger.error(f"Error fetching JSON: {e}\n")
766739
return None
767740

768-
def execute_serial_command(input_cmd):
769-
with shproto.dispatcher.command_lock:
770-
shproto.dispatcher.command = input_cmd
771-
logger.info(f"Sending command {input_cmd} to device\n")
741+
def get_serial_device_information():
742+
try:
743+
with shproto.dispatcher.command_lock:
744+
shproto.dispatcher.command = "-inf"
745+
746+
time.sleep(0.4)
747+
748+
dev_info = shproto.dispatcher.inf_str
749+
shproto.dispatcher.inf_str = ""
750+
751+
return dev_info if dev_info else "No response from device"
752+
753+
except Exception as e:
754+
logger.error(f"Error retrieving device information: {e}")
755+
return "Error retrieving device information"
756+
757+
758+
759+
760+
def parse_device_info(info_string):
761+
762+
tokens = info_string.split()
763+
settings = {}
764+
i = 0
765+
n = len(tokens)
766+
767+
while i < n:
768+
# 1) key is always one token
769+
key = tokens[i]
770+
i += 1
771+
if i >= n:
772+
break
773+
774+
# 2) if the next token starts a bracketed list, consume until the closing bracket
775+
if tokens[i].startswith("["):
776+
start = i
777+
j = i
778+
while j < n and not tokens[j].endswith("]"):
779+
j += 1
780+
781+
# join all pieces of the list, strip brackets, split into parts
782+
raw_list = " ".join(tokens[start : j + 1])
783+
inner = raw_list.strip("[]").strip()
784+
parts = re.split(r"[,\s]+", inner)
785+
786+
# convert each part to int/float if possible
787+
lst = []
788+
for part in parts:
789+
if part.lstrip("-").replace(".", "", 1).isdigit() and part.count(".") < 2:
790+
lst.append(int(part) if "." not in part else float(part))
791+
else:
792+
lst.append(part)
793+
794+
settings[key] = lst
795+
i = j + 1 # advance past the entire bracketed list
796+
797+
else:
798+
# 3) single-token value case
799+
val_token = tokens[i]
800+
i += 1
801+
802+
# convert to int/float if it looks like a number
803+
if val_token.lstrip("-").replace(".", "", 1).isdigit() and val_token.count(".") < 2:
804+
converted = int(val_token) if "." not in val_token else float(val_token)
805+
else:
806+
converted = val_token
807+
808+
settings[key] = converted
809+
810+
return settings
772811

773812
def generate_device_settings_table():
774-
shproto.dispatcher.spec_stopflag = 0
775-
dispatcher = threading.Thread(target=shproto.dispatcher.start)
776-
dispatcher.start()
777-
dev_info = get_serial_device_information()
778-
time.sleep(0.3)
779-
info_dict = parse_device_info(dev_info)
780-
time.sleep(0.3)
813+
# 1) Fetch serial number
814+
process_03('-cal')
815+
time.sleep(0.1)
781816
serial_number = shproto.dispatcher.serial_number
817+
time.sleep(0.1)
818+
819+
# 2) Fetch settings info
820+
dev_info = get_serial_device_information()
821+
time.sleep(0.1)
822+
info = parse_device_info(dev_info)
823+
time.sleep(0.1)
824+
825+
# 3) Build only the main settings DataTable
782826
table = dash_table.DataTable(
783827
columns=[
784-
{"id": "Setting", "name": "Firmware settings"},
785-
{"id": "cmd", "name": "Command"},
786-
{"id": "Value", "name": "Value"}
828+
{"id": "Setting", "name": "Firmware setting"},
829+
{"id": "cmd", "name": "Cmd"},
830+
{"id": "Value", "name": "Value"},
787831
],
788832
data=[
789-
{"Setting": "Version", "cmd": "-", "Value": info_dict.get('VERSION')},
790-
{"Setting": "Serial number", "cmd": "status", "Value": serial_number},
791-
{"Setting": "Samples for X (pulse rise)", "cmd": "-ris", "Value": info_dict.get('RISE')},
792-
{"Setting": "Samples for Y (pulse fall)", "cmd": "-fall", "Value": info_dict.get('FALL')},
793-
{"Setting": "Lower Limit Discriminator LLD", "cmd": "-nos", "Value": info_dict.get('NOISE')},
794-
{"Setting": "ADC Sample Frequency", "cmd": "-frq", "Value": info_dict.get('F')},
795-
{"Setting": "Max integral value", "cmd": "-max", "Value": info_dict.get('MAX')},
796-
{"Setting": "Hysteresis value", "cmd": "-hyst", "Value": info_dict.get('HYST')},
797-
{"Setting": "Working Mode [0, 1, 2]", "cmd": "-mode", "Value": info_dict.get('MODE')},
798-
{"Setting": "Discriminator step (>1)", "cmd": "-step", "Value": info_dict.get('STEP')},
799-
{"Setting": "High Voltage (0-255)", "cmd": "-U", "Value": info_dict.get('POT')},
800-
{"Setting": "Baseline trim (0-255)", "cmd": "-V", "Value": info_dict.get('POT2')},
801-
{"Setting": "Temperature sensor 1", "cmd": "status", "Value": f"{info_dict.get('T1')} C˚"},
802-
{"Setting": "Energy Window (-win X1 X2)", "cmd": "-win", "Value": info_dict.get('OUT')},
803-
{"Setting": "Temp. compensation status", "cmd": "status", "Value": info_dict.get('TCpot')},
804-
{"Setting": "Temp. compensation table", "cmd": "status", "Value": info_dict.get('Tco')}
833+
{"Setting": "Version", "cmd": "-ver", "Value": info.get("VERSION")},
834+
{"Setting": "Serial number", "cmd": "-cal", "Value": serial_number},
835+
{"Setting": "Rise samples", "cmd": "-ris", "Value": info.get("RISE")},
836+
{"Setting": "Fall samples", "cmd": "-fall", "Value": info.get("FALL")},
837+
{"Setting": "Noise LLD", "cmd": "-nos", "Value": info.get("NOISE")},
838+
{"Setting": "ADC freq (Hz)", "cmd": "-frq", "Value": info.get("F")},
839+
{"Setting": "Max integral", "cmd": "-max", "Value": info.get("MAX")},
840+
{"Setting": "Hysteresis", "cmd": "-hyst", "Value": info.get("HYST")},
841+
{"Setting": "Mode [0–2]", "cmd": "-mode", "Value": info.get("MODE")},
842+
{"Setting": "Discriminator step","cmd": "-step", "Value": info.get("STEP")},
843+
{"Setting": "High voltage", "cmd": "-U", "Value": info.get("POT")},
844+
{"Setting": "Baseline trim", "cmd": "-V", "Value": info.get("POT2")},
845+
{"Setting": "Temp sensor 1 (°C)","cmd": "status","Value": info.get("T1")},
846+
{"Setting": "Energy window", "cmd": "-win", "Value": info.get("OUT")},
847+
{"Setting": "Temp-comp enabled", "cmd": "-tc", "Value": info.get("TC")},
805848
],
806849
style_cell={
807-
'textAlign': 'left',
808-
'padding': '4px',
809-
'fontSize': '12px',
810-
'fontFamily': 'Arial'
850+
'textAlign': 'left',
851+
'padding': '4px',
852+
'fontSize': '12px',
853+
'fontFamily': 'Arial',
854+
'whiteSpace': 'normal',
855+
'height': 'auto'
811856
},
812857
style_cell_conditional=[
813-
{'if': {'column_id': 'Setting'}, 'width': '60%'},
814-
{'if': {'column_id': 'cmd'}, 'width': '10%'},
815-
{'if': {'column_id': 'Value'}, 'width': '30%'}
816-
]
858+
{'if': {'column_id':'Setting'}, 'width':'60%'},
859+
{'if': {'column_id':'cmd' }, 'width':'10%'},
860+
{'if': {'column_id':'Value' }, 'width':'30%'},
861+
],
862+
style_table={
863+
'overflowX': 'auto'
864+
}
865+
)
866+
867+
with global_vars.write_lock:
868+
global_vars.serial_number = serial_number
869+
870+
# 4) Return only that table
871+
return html.Div(table, style={"width": "100%", "overflowX": "auto"})
872+
873+
def generate_temperature_comp_table():
874+
875+
# fetch & parse (you can swap to cached or direct fetch if you like)
876+
raw = get_serial_device_information()
877+
info = parse_device_info(raw)
878+
879+
tco_raw = info.get("Tco", []) # should now be a Python list of numbers
880+
881+
# group into (Temp, MaxIntegral) pairs
882+
pairs = [(tco_raw[i], tco_raw[i+1]) for i in range(0, len(tco_raw)-1, 2)]
883+
884+
# build header
885+
header = html.Tr([
886+
html.Th("Temperature (°C)", style={"padding": "4px", "fontWeight": "bold", "textAlign":"center"}),
887+
html.Th("Max Integral", style={"padding": "4px", "fontWeight": "bold", "textAlign":"center"})
888+
])
889+
890+
# build data rows
891+
rows = []
892+
for temp, integral in pairs:
893+
rows.append(html.Tr([
894+
html.Td(str(temp), style={"padding": "4px", "textAlign":"center"}),
895+
html.Td(str(integral),style={"padding": "4px", "textAlign":"right"})
896+
]))
897+
898+
return html.Table(
899+
[header] + rows,
900+
style={
901+
"borderCollapse": "collapse",
902+
"width": "100%",
903+
"maxHeight": "400px",
904+
"overflowY": "auto",
905+
"display": "block",
906+
}
817907
)
818-
return table
819908

820909
# Check if commands sent to processor is safe
821910
def allowed_command(cmd):
@@ -931,7 +1020,6 @@ def reset_stores():
9311020
'store_load_flag_tab4': False,
9321021
}
9331022

934-
9351023
def save_settings_to_json():
9361024
settings = {key: getattr(global_vars, key) for key in [
9371025
"bin_size",
@@ -988,7 +1076,18 @@ def save_settings_to_json():
9881076
"val_flag",
9891077
"max_pulse_length",
9901078
"max_pulse_height",
991-
"flags_selected"
1079+
"flags_selected",
1080+
"tempcal_table",
1081+
"tempcal_stability_tolerance",
1082+
"tempcal_stability_window_sec",
1083+
"tempcal_poll_interval_sec",
1084+
"tempcal_spectrum_duration_sec",
1085+
"tempcal_smoothing_sigma",
1086+
"tempcal_peak_search_range",
1087+
"tempcal_cancelled",
1088+
"tempcal_base_value",
1089+
"tempcal_num_runs",
1090+
"tempcal_delta"
9921091
]}
9931092

9941093
try:
@@ -1063,7 +1162,18 @@ def load_settings_from_json(path):
10631162
"val_flag": bool,
10641163
"max_pulse_length": int,
10651164
"max_pulse_height": int,
1066-
"flags_selected": str
1165+
"flags_selected": str,
1166+
"tempcal_table": list,
1167+
"tempcal_stability_tolerance": float,
1168+
"tempcal_stability_window_sec": int,
1169+
"tempcal_poll_interval_sec": int,
1170+
"tempcal_spectrum_duration_sec":int,
1171+
"tempcal_smoothing_sigma": float,
1172+
"tempcal_peak_search_range": list,
1173+
"tempcal_cancelled": bool,
1174+
"tempcal_base_value": int,
1175+
"tempcal_num_runs": int,
1176+
"tempcal_delta": int
10671177
}
10681178

10691179
with global_vars.write_lock:
@@ -1296,4 +1406,4 @@ def read_isotopes_data(data_path):
12961406
return data
12971407
except Exception as e:
12981408
print(f"Error reading isotopes data: {e}")
1299-
return []
1409+
return []

0 commit comments

Comments
 (0)