Compare commits

4 Commits

Author SHA1 Message Date
awe
47be2a137d Fix for web 2025-11-25 15:46:52 +03:00
awe
620bef8c88 initial commit 2025-11-24 15:57:57 +03:00
awe
c8b6aed434 remove junk from repo 2025-11-24 15:57:35 +03:00
awe
d3e39ec3b1 gitignore upd 2025-11-24 15:56:36 +03:00
13 changed files with 187 additions and 814 deletions

4
.gitignore vendored Normal file
View File

@ -0,0 +1,4 @@
*.venv
*.pyc
__pycache__/
.env

Binary file not shown.

View File

@ -3,7 +3,6 @@ import json
import math import math
import socket import socket
import subprocess import subprocess
import time
import device_interaction as dev import device_interaction as dev
@ -24,17 +23,6 @@ INITIAL_TEMPERATURE_2 = 28.9 # Set initial temperature for Laser 2 in Celsius: f
INITIAL_CURRENT_1 = 33 # 64.0879 max # Set initial current for Laser 1, in mA INITIAL_CURRENT_1 = 33 # 64.0879 max # Set initial current for Laser 1, in mA
INITIAL_CURRENT_2 = 35 # 64.0879 max # Set initial current for Laser 2, in mA INITIAL_CURRENT_2 = 35 # 64.0879 max # Set initial current for Laser 2, in mA
AD9833_FREQ_DEFAULT_KHZ = 125.0
AD9833_MCLK_DEFAULT_MHZ = 20.0
DS1809_MAX_STEP = 63
DS1809_DEFAULT_STEP = 3
DS1809_INIT_HOME_PULSES = 64
DS1809_INIT_PULSE_MS = 2
DS1809_INIT_STARTUP_DELAY_S = 0.35
STM32_DAC_VREF = 2.5
STM32_DAC_MAX_CODE = 4095
PA4_DAC_DEFAULT_VOLT = 0.0
#### ---- Functions #### ---- Functions
def start_task(prt): def start_task(prt):
@ -56,77 +44,10 @@ def get_float(values, strId):
window['-StartCycle-'].update(disabled = True) window['-StartCycle-'].update(disabled = True)
return value return value
def parse_optional_int(value):
if value is None:
return None
s = str(value).strip()
if s == "":
return None
try:
return int(s, 0)
except Exception:
print(f"Invalid integer value: {s}")
return None
def parse_optional_float(value):
if value is None:
return None
s = str(value).strip()
if s == "":
return None
s = s.replace(",", ".")
try:
return float(s)
except Exception:
print(f"Invalid float value: {s}")
return None
def shorten(i): def shorten(i):
return "{:.2f}".format(round(i, 2)) return "{:.2f}".format(round(i, 2))
def clamp_int(value, min_value, max_value):
if value < min_value:
return min_value
if value > max_value:
return max_value
return value
def format_ds1809_status(step):
return f"{step}/{DS1809_MAX_STEP} шагов"
def voltage_to_dac_code(voltage_v):
if voltage_v is None:
return 0
if voltage_v < 0.0:
voltage_v = 0.0
if voltage_v > STM32_DAC_VREF:
voltage_v = STM32_DAC_VREF
return int(round((voltage_v / STM32_DAC_VREF) * STM32_DAC_MAX_CODE))
def initialize_ds1809_position(prt, default_step):
default_step = clamp_int(int(default_step), 0, DS1809_MAX_STEP)
# Give the STM32 side a short startup margin before DS1809 pulse traffic.
time.sleep(DS1809_INIT_STARTUP_DELAY_S)
dev.send_ds1809_pulse(prt, uc=False, dc=True,
count=DS1809_INIT_HOME_PULSES,
pulse_ms=DS1809_INIT_PULSE_MS)
current_step = 0
if default_step > 0:
dev.send_ds1809_pulse(prt, uc=True, dc=False,
count=default_step,
pulse_ms=DS1809_INIT_PULSE_MS)
current_step = default_step
return current_step
def set_initial_params(): def set_initial_params():
params = {} params = {}
params['Temp_1'] = INITIAL_TEMPERATURE_1 # Initial temperature for Laser 1 params['Temp_1'] = INITIAL_TEMPERATURE_1 # Initial temperature for Laser 1
@ -152,23 +73,6 @@ def set_initial_params():
params['Delta_Current_2'] = 0.05 params['Delta_Current_2'] = 0.05
params['Delta_Time'] = 50 params['Delta_Time'] = 50
params['Tau'] = 10 params['Tau'] = 10
params['RampFreq'] = ''
params['RampDuty'] = ''
params['RampSawStep'] = ''
params['RampPatPeriod'] = ''
params['RampPatBase'] = 2
params['RampDacClk'] = ''
params['RampTriangle'] = True
params['RampSramMode'] = False
params['RampSramSamples'] = ''
params['RampSramAmp'] = ''
params['Ad9833Freq'] = str(AD9833_FREQ_DEFAULT_KHZ)
params['Ad9833Mclk'] = str(AD9833_MCLK_DEFAULT_MHZ)
params['Ad9833Triangle'] = True
params['DS1809Step'] = DS1809_DEFAULT_STEP
params['DS1809Status'] = format_ds1809_status(DS1809_DEFAULT_STEP)
params['PA4DacVolt'] = str(PA4_DAC_DEFAULT_VOLT)
params['PA4DacStatus'] = f"0 / {STM32_DAC_MAX_CODE}"
return params return params
def update_data_lists(): def update_data_lists():
@ -197,29 +101,12 @@ if __name__ == "__main__":
# dev.request_state(prt) # dev.request_state(prt)
dev.send_control_parameters(prt, params) dev.send_control_parameters(prt, params)
saved_data.append(dev.request_data(prt))
draw_data.append(saved_data[0])
window = gui.setup_gui(params) window = gui.setup_gui(params)
axes_signs = gui.sign_axes(window) axes_signs = gui.sign_axes(window)
ds1809_step = initialize_ds1809_position(prt, params['DS1809Step'])
params['DS1809Step'] = ds1809_step
params['DS1809Status'] = format_ds1809_status(ds1809_step)
window['-DS1809Status-'].update(params['DS1809Status'])
initial_data = None
for _ in range(20):
initial_data = dev.request_data(prt)
if isinstance(initial_data, dict):
break
time.sleep(0.05)
if not isinstance(initial_data, dict):
print('Error: initial DATA packet not received. Closing program...')
exit(1)
saved_data.append(initial_data)
draw_data.append(initial_data)
current_and_temperature_settings_available = True current_and_temperature_settings_available = True
disableStartButton = False disableStartButton = False
@ -536,85 +423,19 @@ if __name__ == "__main__":
params['Iset_2'] = float(values['-InputI2-']) params['Iset_2'] = float(values['-InputI2-'])
dev.send_control_parameters(prt, params) dev.send_control_parameters(prt, params)
#print(sending_param) #print(sending_param)
elif event == '-StartRamp-':
freq_hz = parse_optional_float(values.get('-RampFreq-'))
duty = parse_optional_float(values.get('-RampDuty-'))
if duty is not None:
if duty > 1.0:
duty = duty / 100.0
if duty <= 0:
duty = None
saw_step = parse_optional_int(values.get('-RampSawStep-'))
pat_period = parse_optional_int(values.get('-RampPatPeriod-'))
pat_period_base = parse_optional_int(values.get('-RampPatBase-'))
dac_clk_mhz = parse_optional_float(values.get('-RampDacClk-'))
dac_clk_hz = dac_clk_mhz * 1e6 if dac_clk_mhz is not None else None
triangle = values.get('-RampTriangle-', True)
sram_mode = values.get('-RampSramMode-', False)
sram_samples = parse_optional_int(values.get('-RampSramSamples-'))
sram_amp_val = parse_optional_float(values.get('-RampSramAmp-'))
sram_amplitude = None
if sram_amp_val is not None:
if sram_amp_val <= 1.0:
sram_amplitude = int(round(sram_amp_val * 8191.0))
elif sram_amp_val <= 100.0:
sram_amplitude = int(round((sram_amp_val / 100.0) * 8191.0))
else:
sram_amplitude = int(round(sram_amp_val))
dev.start_ramp_max(prt, freq_hz=freq_hz, duty=duty, saw_step=saw_step,
pat_period=pat_period, pat_period_base=pat_period_base,
dac_clk_hz=dac_clk_hz, triangle=triangle,
sram_mode=sram_mode, sram_samples=sram_samples,
sram_amplitude=sram_amplitude)
elif event == '-StartRamp9833-':
freq_khz = parse_optional_float(values.get('-AD9833Freq-'))
freq_hz = int(round(freq_khz * 1000.0)) if freq_khz is not None else None
mclk_mhz = parse_optional_float(values.get('-AD9833Mclk-'))
mclk_hz = mclk_mhz * 1e6 if mclk_mhz is not None else None
triangle = values.get('-AD9833Triangle-', True)
dev.start_ad9833_ramp(prt, freq_hz=freq_hz, mclk_hz=mclk_hz, triangle=triangle, enable=True)
elif event == '-DS1809UC-':
dev.send_ds1809_pulse(prt, uc=True, dc=False, count=1, pulse_ms=DS1809_INIT_PULSE_MS)
ds1809_step = clamp_int(ds1809_step + 1, 0, DS1809_MAX_STEP)
params['DS1809Step'] = ds1809_step
params['DS1809Status'] = format_ds1809_status(ds1809_step)
window['-DS1809Status-'].update(params['DS1809Status'])
elif event == '-DS1809DC-':
dev.send_ds1809_pulse(prt, uc=False, dc=True, count=1, pulse_ms=DS1809_INIT_PULSE_MS)
ds1809_step = clamp_int(ds1809_step - 1, 0, DS1809_MAX_STEP)
params['DS1809Step'] = ds1809_step
params['DS1809Status'] = format_ds1809_status(ds1809_step)
window['-DS1809Status-'].update(params['DS1809Status'])
elif event == '-SetPA4Dac-':
voltage_v = parse_optional_float(values.get('-PA4DacVolt-'))
if voltage_v is None:
print('Invalid PA4 DAC voltage value.')
else:
if voltage_v < 0.0:
voltage_v = 0.0
if voltage_v > STM32_DAC_VREF:
voltage_v = STM32_DAC_VREF
dac_code = voltage_to_dac_code(voltage_v)
dev.set_stm32_dac(prt, dac_code=dac_code, enable=True)
params['PA4DacVolt'] = f"{voltage_v:.3f}"
params['PA4DacStatus'] = f"{dac_code} / {STM32_DAC_MAX_CODE}"
window['-PA4DacVolt-'].update(params['PA4DacVolt'])
window['-PA4DacStatus-'].update(params['PA4DacStatus'])
elif event == '-StopCycle-': elif event == '-StopCycle-':
window['-StopCycle-'].update(disabled = True) window['-StopCycle-'].update(disabled = True)
current_and_temperature_settings_available = True current_and_temperature_settings_available = True
stop_task(prt) stop_task(prt)
elif event == TIMEOUT_KEY: elif event == TIMEOUT_KEY:
data = dev.request_data(prt) data = dev.request_data(prt)
if not isinstance(data, dict):
continue
update_data_lists() update_data_lists()
window['-TOUT_1-'].update(gui.READ_TEMPERATURE_TEXT+' 1: '+shorten(data['Temp_1'])+' C') window['-TOUT_1-'].update(gui.READ_TEMPERATURE_TEXT+' 1: '+shorten(data['Temp_1'])+' C')
window['-TOUT_2-'].update(gui.READ_TEMPERATURE_TEXT+' 2: '+shorten(data['Temp_2'])+' C') window['-TOUT_2-'].update(gui.READ_TEMPERATURE_TEXT+' 2: '+shorten(data['Temp_2'])+' C')
window['-IOUT_1-'].update(gui.READ_CURRENT_TEXT+' 1: '+shorten(data['I1'])+' мА (raw '+str(data.get('I1_raw', ''))+')') window['-IOUT_1-'].update(gui.READ_CURRENT_TEXT+' 1: '+shorten(data['I1'])+' мА')
window['-IOUT_2-'].update(gui.READ_CURRENT_TEXT+' 2: '+shorten(data['I2'])+' мА (raw '+str(data.get('I2_raw', ''))+')') window['-IOUT_2-'].update(gui.READ_CURRENT_TEXT+' 2: '+shorten(data['I2'])+' мА')
window['-DateTime-'].update(data['datetime'].strftime('%d-%m-%Y %H:%M:%S:%f')[:-3]) window['-DateTime-'].update(data['datetime'].strftime('%d-%m-%Y %H:%M:%S:%f')[:-3])
window['-TTerm1-'].update('T терм 1: '+shorten(data['Temp_Ext_1'])+' C') window['-TTerm1-'].update('T терм 1: '+shorten(data['Temp_Ext_1'])+' C')
window['-TTerm2-'].update('T терм 2: '+shorten(data['Temp_Ext_2'])+' C') window['-TTerm2-'].update('T терм 2: '+shorten(data['Temp_Ext_2'])+' C')
@ -644,3 +465,5 @@ if __name__ == "__main__":
window.close() window.close()
dev.close_connection(prt) dev.close_connection(prt)

View File

@ -1,7 +1,7 @@
from enum import IntEnum from enum import IntEnum
from serial import Serial from serial import Serial
from serial.tools import list_ports from serial.tools import list_ports
import device_conversion as cnv from . import device_conversion as cnv
from datetime import datetime from datetime import datetime
#### ---- Constants #### ---- Constants
@ -10,33 +10,6 @@ GET_DATA_TOTAL_LENGTH = 30 # Total number of bytes when getting DATA
SEND_PARAMS_TOTAL_LENGTH = 30 # Total number of bytes when sending parameters SEND_PARAMS_TOTAL_LENGTH = 30 # Total number of bytes when sending parameters
TASK_ENABLE_COMMAND_LENGTH = 32 # Total number of bytes when sending TASK_ENABLE command TASK_ENABLE_COMMAND_LENGTH = 32 # Total number of bytes when sending TASK_ENABLE command
AD9102_CMD_TOTAL_LENGTH = 10 # Total bytes when sending AD9102 saw command
AD9102_CMD_HEADER = "8888"
AD9833_CMD_TOTAL_LENGTH = 10 # Total bytes when sending AD9833 command
AD9833_CMD_HEADER = "9999"
DS1809_CMD_TOTAL_LENGTH = 10 # Total bytes when sending DS1809 UC/DC pulse command
DS1809_CMD_HEADER = "AAAA"
STM32_DAC_CMD_TOTAL_LENGTH = 10 # Total bytes when sending STM32 DAC command
STM32_DAC_CMD_HEADER = "BBBB"
AD9102_SAW_STEP_DEFAULT = 1
AD9102_PAT_PERIOD_DEFAULT = 0xFFFF
AD9102_PAT_PERIOD_BASE_DEFAULT = 0x02
AD9102_DAC_CLK_HZ = None # set to actual DAC clock if you want freq->SAW_STEP conversion
AD9102_FLAG_SRAM = 0x0004
AD9102_FLAG_SRAM_FMT = 0x0008
AD9102_SRAM_SAMPLES_DEFAULT = 16
AD9102_SRAM_HOLD_DEFAULT = 1
AD9102_SRAM_AMP_DEFAULT = 8191
AD9833_FLAG_ENABLE = 0x0001
AD9833_FLAG_TRIANGLE = 0x0002
AD9833_MCLK_HZ_DEFAULT = 20_000_000
DS1809_FLAG_UC = 0x0001
DS1809_FLAG_DC = 0x0002
DS1809_PULSE_MS_DEFAULT = 2
STM32_DAC_FLAG_ENABLE = 0x0001
STM32_DAC_CODE_MAX = 4095
STM32_DAC_VREF_DEFAULT = 3.3
class TaskType(IntEnum): class TaskType(IntEnum):
Manual = 0x00 Manual = 0x00
ChangeCurrentLD1 = 0x01 ChangeCurrentLD1 = 0x01
@ -175,62 +148,26 @@ def send_STATE(prt):
pass pass
def send_AD9102(prt, bytestring):
''' Start/stop AD9102 output with saw/triangle (0x8888 + ...).
Expected device answer: STATE.
'''
if len(bytestring) != AD9102_CMD_TOTAL_LENGTH:
print("Error. Wrong parameter string for AD9102 command.")
return None
prt.write(bytestring)
print("Sent: AD9102 ramp command.")
def send_AD9833(prt, bytestring):
''' Start/stop AD9833 output with triangle (0x9999 + ...).
Expected device answer: STATE.
'''
if len(bytestring) != AD9833_CMD_TOTAL_LENGTH:
print("Error. Wrong parameter string for AD9833 command.")
return None
prt.write(bytestring)
print("Sent: AD9833 ramp command.")
def send_DS1809(prt, bytestring):
''' Pulse DS1809 UC/DC control lines (0xAAAA + ...).
Expected device answer: STATE.
'''
if len(bytestring) != DS1809_CMD_TOTAL_LENGTH:
print("Error. Wrong parameter string for DS1809 command.")
return None
prt.write(bytestring)
print("Sent: DS1809 pulse command.")
def send_STM32_DAC(prt, bytestring):
''' Set STM32 internal DAC output on PA4 (0xBBBB + ...).
Expected device answer: STATE.
'''
if len(bytestring) != STM32_DAC_CMD_TOTAL_LENGTH:
print("Error. Wrong parameter string for STM32 DAC command.")
return None
prt.write(bytestring)
print("Sent: STM32 DAC command.")
# ---- Getting data # ---- Getting data
def get_STATE(prt): def get_STATE(prt):
''' Get decoded state of the device in byte format (2 bytes). ''' Get decoded state of the device in byte format (2 bytes).
''' '''
import time
print("Received "+str(prt.inWaiting())+" bytes.") # Wait a bit more if data hasn't arrived yet
if prt.inWaiting()!=2: waiting_bytes = prt.inWaiting()
print("Error. Couldn't get STATE data. prt.inWaiting():", prt.inWaiting()) if waiting_bytes != 2:
print("Flushing input data:", prt.read(prt.inWaiting())) # Give device a bit more time to respond
# print("Flushing input data:", prt.read(2), prt.read(2)) time.sleep(0.05)
waiting_bytes = prt.inWaiting()
print("Received "+str(waiting_bytes)+" bytes.")
if waiting_bytes != 2:
print("Error. Couldn't get STATE data. prt.inWaiting():", waiting_bytes)
if waiting_bytes > 0:
print("Flushing input data:", prt.read(waiting_bytes))
return None return None
out_bytes = prt.read(2) out_bytes = prt.read(2)
@ -238,15 +175,13 @@ def get_STATE(prt):
def get_DATA(prt): def get_DATA(prt):
''' Get decoded state of the device in byte format (30 bytes). ''' Get decoded state of the device in byte format (426 bytes).
''' '''
print("Received "+str(prt.inWaiting())+" bytes.\n") print("Received "+str(prt.inWaiting())+" bytes.\n")
if prt.inWaiting()!=GET_DATA_TOTAL_LENGTH: if prt.inWaiting()!=GET_DATA_TOTAL_LENGTH:
print("Error. Couldn't get DATA data.") print("Error. Couldn't get DATA data.")
print("receiven data len:", prt.inWaiting()) print("receiven data len:", prt.inWaiting())
if prt.inWaiting() > 0:
print("Flushing input data:", prt.read(prt.inWaiting()))
return None return None
out_bytes = prt.read(GET_DATA_TOTAL_LENGTH) out_bytes = prt.read(GET_DATA_TOTAL_LENGTH)
@ -335,205 +270,6 @@ def create_TaskEnableCommand(sending_param):
return bytearray.fromhex(data) return bytearray.fromhex(data)
def calc_saw_step_for_freq(freq_hz: float, dac_clk_hz: float, triangle: bool):
if freq_hz <= 0 or dac_clk_hz is None or dac_clk_hz <= 0:
return AD9102_SAW_STEP_DEFAULT
n = 2 if triangle else 1
step = int(round(dac_clk_hz / (freq_hz * n * 16384.0)))
if step < 1:
step = 1
if step > 63:
step = 63
return step
def calc_pat_period_for_duty(saw_step: int, duty: float, pat_period_base: int, triangle: bool):
if duty is None or duty <= 0 or duty > 1.0:
return AD9102_PAT_PERIOD_DEFAULT
n = 2 if triangle else 1
base_cycles = 16 if pat_period_base == 0 else pat_period_base
ramp_cycles = n * 16384 * max(1, min(63, saw_step))
pat_period = int(round(ramp_cycles / (duty * base_cycles)))
if pat_period < 1:
pat_period = 1
if pat_period > 0xFFFF:
pat_period = 0xFFFF
return pat_period
def calc_sram_samples_for_freq(freq_hz: float, dac_clk_hz: float, hold: int = None):
if hold is None or hold <= 0:
hold = AD9102_SRAM_HOLD_DEFAULT
if freq_hz is None or freq_hz <= 0 or dac_clk_hz is None or dac_clk_hz <= 0:
return AD9102_SRAM_SAMPLES_DEFAULT
samples = int(round(dac_clk_hz / (freq_hz * hold)))
if samples < 2:
samples = 2
if samples > 4096:
samples = 4096
return samples
def create_AD9102_ramp_command(saw_step: int = None,
pat_period: int = None,
pat_period_base: int = None,
enable: bool = True,
triangle: bool = True,
sram_mode: bool = False,
sram_samples: int = None,
sram_hold: int = None,
sram_amplitude: int = None):
flags = 0
if enable:
flags |= 0x0001
if triangle:
flags |= 0x0002
if sram_mode:
flags |= AD9102_FLAG_SRAM
if sram_mode:
flags |= AD9102_FLAG_SRAM_FMT
if sram_samples is None:
sram_samples = AD9102_SRAM_SAMPLES_DEFAULT
if sram_samples < 2:
sram_samples = 2
if sram_samples > 4096:
sram_samples = 4096
if sram_amplitude is None:
sram_amplitude = AD9102_SRAM_AMP_DEFAULT
if sram_amplitude < 0:
sram_amplitude = 0
if sram_amplitude > AD9102_SRAM_AMP_DEFAULT:
sram_amplitude = AD9102_SRAM_AMP_DEFAULT
param0 = int(sram_amplitude) & 0xFFFF
param1 = int(sram_samples) & 0xFFFF
else:
if saw_step is None:
saw_step = AD9102_SAW_STEP_DEFAULT
if pat_period is None:
pat_period = AD9102_PAT_PERIOD_DEFAULT
if pat_period_base is None:
pat_period_base = AD9102_PAT_PERIOD_BASE_DEFAULT
if saw_step < 1:
saw_step = 1
if saw_step > 63:
saw_step = 63
if pat_period < 0:
pat_period = 0
if pat_period > 0xFFFF:
pat_period = 0xFFFF
if pat_period_base < 0:
pat_period_base = 0
if pat_period_base > 0x0F:
pat_period_base = 0x0F
param0 = ((pat_period_base & 0x0F) << 8) | (saw_step & 0xFF)
param1 = pat_period
crc_word = flags ^ param0 ^ param1
data = flipfour(AD9102_CMD_HEADER) # Word 0 (header)
data += flipfour(int_to_hex(flags))
data += flipfour(int_to_hex(param0))
data += flipfour(int_to_hex(param1))
data += flipfour(int_to_hex(crc_word))
return bytearray.fromhex(data)
def create_AD9833_ramp_command(freq_hz: float,
mclk_hz: float = None,
enable: bool = True,
triangle: bool = True):
if mclk_hz is None or mclk_hz <= 0:
mclk_hz = AD9833_MCLK_HZ_DEFAULT
if mclk_hz is None or mclk_hz <= 0 or freq_hz is None or freq_hz < 0:
freq_word = 0
else:
freq_word = int(round((freq_hz * (1 << 28)) / float(mclk_hz)))
if freq_word < 0:
freq_word = 0
if freq_word > 0x0FFFFFFF:
freq_word = 0x0FFFFFFF
lsw = freq_word & 0x3FFF
msw = (freq_word >> 14) & 0x3FFF
flags = 0
if enable:
flags |= AD9833_FLAG_ENABLE
if triangle:
flags |= AD9833_FLAG_TRIANGLE
crc_word = flags ^ lsw ^ msw
data = flipfour(AD9833_CMD_HEADER) # Word 0 (header)
data += flipfour(int_to_hex(flags))
data += flipfour(int_to_hex(lsw))
data += flipfour(int_to_hex(msw))
data += flipfour(int_to_hex(crc_word))
return bytearray.fromhex(data)
def create_DS1809_pulse_command(uc: bool = False,
dc: bool = False,
count: int = 1,
pulse_ms: int = None):
flags = 0
if uc:
flags |= DS1809_FLAG_UC
if dc:
flags |= DS1809_FLAG_DC
if count is None or count <= 0:
count = 1
if count > 64:
count = 64
if pulse_ms is None:
pulse_ms = DS1809_PULSE_MS_DEFAULT
if pulse_ms < 1:
pulse_ms = 1
if pulse_ms > 500:
pulse_ms = 500
param0 = int(count) & 0xFFFF
param1 = int(pulse_ms) & 0xFFFF
crc_word = flags ^ param0 ^ param1
data = flipfour(DS1809_CMD_HEADER) # Word 0 (header)
data += flipfour(int_to_hex(flags))
data += flipfour(int_to_hex(param0))
data += flipfour(int_to_hex(param1))
data += flipfour(int_to_hex(crc_word))
return bytearray.fromhex(data)
def create_STM32_DAC_command(dac_code: int, enable: bool = True):
if dac_code is None:
dac_code = 0
if dac_code < 0:
dac_code = 0
if dac_code > STM32_DAC_CODE_MAX:
dac_code = STM32_DAC_CODE_MAX
flags = STM32_DAC_FLAG_ENABLE if enable else 0
param0 = int(dac_code) & 0x0FFF
param1 = 0
crc_word = flags ^ param0 ^ param1
data = flipfour(STM32_DAC_CMD_HEADER) # Word 0 (header)
data += flipfour(int_to_hex(flags))
data += flipfour(int_to_hex(param0))
data += flipfour(int_to_hex(param1))
data += flipfour(int_to_hex(crc_word))
return bytearray.fromhex(data)
def encode_Input(params): def encode_Input(params):
if params is None: if params is None:
@ -567,38 +303,24 @@ def encode_Input(params):
def decode_STATE(state): def decode_STATE(state):
st = flipfour(state) st = flipfour(state)
if st is None or len(st) != 4: if st == '0000':
return "Error: invalid STATE length."
hi = int(st[0:2], 16)
lo = int(st[2:4], 16)
errors = []
if lo & 0x01:
errors.append("SD Card reading/writing error (SD_ERR)")
if lo & 0x02:
errors.append("Command error (UART_ERR)")
if lo & 0x04:
errors.append("Wrong parameter value error (UART_DECODE_ERR)")
if lo & 0x08:
errors.append("Laser 1: TEC driver overheat (TEC1_ERR)")
if lo & 0x10:
errors.append("Laser 2: TEC driver overheat (TEC2_ERR)")
if lo & 0x20:
errors.append("Resetting system error (DEFAULT_ERR)")
if lo & 0x40:
errors.append("File deletion error (REMOVE_ERR)")
if lo & 0x80:
errors.append("AD9102 status check failed (AD9102_ERR)")
if not errors:
status = "All ok." status = "All ok."
elif st == '0001':
status = "SD Card reading/writing error (SD_ERR)."
elif st == '0002':
status = "Command error (UART_ERR)."
elif st == '0004':
status = "Wrong parameter value error (UART_DECODE_ERR)."
elif st == '0008':
status = "Laser 1: TEC driver overheat (TEC1_ERR)."
elif st == '0010':
status = "Laser 2: TEC driver overheat (TEC2_ERR)."
elif st == '0020':
status = "Resetting system error (DEFAULT_ERR)."
elif st == '0040':
status = "File deletion error (REMOVE_ERR)."
else: else:
status = "; ".join(errors) status = "Unknown or reserved error."
if hi != 0:
status += f" | AD9102_PAT_STATUS=0x{hi:02X}"
return status return status
@ -611,12 +333,8 @@ def decode_DATA(dh):
data = {} data = {}
data['datetime'] = datetime.now() data['datetime'] = datetime.now()
data['Header'] = get_word(dh, 0) data['Header'] = get_word(dh, 0)
i1_raw = get_int_word(dh, 1) data['I1'] = cnv.conv_I_N_to_mA(get_int_word(dh, 1)) #LD1_param.POWER
i2_raw = get_int_word(dh, 2) data['I2'] = cnv.conv_I_N_to_mA(get_int_word(dh, 2)) #LD2_param.POWER
data['I1_raw'] = i1_raw
data['I2_raw'] = i2_raw
data['I1'] = cnv.conv_I_N_to_mA(i1_raw) #LD1_param.POWER
data['I2'] = cnv.conv_I_N_to_mA(i2_raw) #LD2_param.POWER
data['TO_LSB'] = get_int_word(dh, 3) #TO6_counter_LSB data['TO_LSB'] = get_int_word(dh, 3) #TO6_counter_LSB
data['TO_MSB'] = get_int_word(dh, 4) #TO6_counter_MSB data['TO_MSB'] = get_int_word(dh, 4) #TO6_counter_MSB
data['Temp_1'] = cnv.conv_T_N_to_C(get_int_word(dh, 5)) #LD1_param.LD_CURR_TEMP data['Temp_1'] = cnv.conv_T_N_to_C(get_int_word(dh, 5)) #LD1_param.LD_CURR_TEMP
@ -631,3 +349,7 @@ def decode_DATA(dh):
data['CRC'] = get_word(dh, 14) data['CRC'] = get_word(dh, 14)
return data return data

View File

@ -13,7 +13,7 @@ R4 = 30000 # Ohm
R5 = 27000 # Ohm R5 = 27000 # Ohm
R6 = 56000 # Ohm R6 = 56000 # Ohm
RREF = 30 # Ohm (current-setting resistor) @1550 nm - 28.7 Ohm; @840 nm - 10 Ohm RREF = 10 # Ohm (current-setting resistor) @1550 nm - 28.7 Ohm; @840 nm - 10 Ohm
R7 = 22000 # Ohm R7 = 22000 # Ohm
R8 = 22000 # Ohm R8 = 22000 # Ohm

View File

@ -1,239 +1,168 @@
import time
from datetime import datetime
import device_commands as cmd
import time
from datetime import datetime
from . import device_commands as cmd
#### ---- Constants #### ---- Constants
WAIT_AFTER_SEND = 0.15 # Wait after sending command before requesting input (s). WAIT_AFTER_SEND = 0.15 # Wait after sending command, before requesting input (in seconds).
#### ---- High-level port commands #### ---- High-level port commands
'''
def create_port_connection():
prt = None
for port, _, _ in sorted(cmd.list_ports.comports()):
try:
prt = cmd.setup_port_connection(port=port, baudrate=115200, timeout_sec=1)
cmd.open_port(prt)
reset_port_settings(prt)
except:
prt.close()
continue
break
return prt
'''
def create_port_connection(): def create_port_connection():
prt = None prt = None
print() print()
ports = []
for port, _,_ in sorted(cmd.list_ports.comports()):
ports.append(port)
ports = [port for port, _, _ in sorted(cmd.list_ports.comports())] #ONLY FOR LINUX!!!
have_ttyUSB = False
USB_ports = []
for port in ports:
if "USB" in port:
USB_ports.append(port)
if len(USB_ports):
ports = USB_ports
# print("ports:", ports)
# Linux-only preference: use USB UART ports first.
usb_ports = [port for port in ports if "USB" in port]
if usb_ports:
ports = usb_ports
# for port, _, _ in sorted(cmd.list_ports.comports()):
for port in ports: for port in ports:
try: try:
print("PORT:", port) print("PORT:", port)
prt = cmd.setup_port_connection(port=port, baudrate=115200, timeout_sec=1) prt = cmd.setup_port_connection(port=port, baudrate=115200, timeout_sec=1)
cmd.open_port(prt) cmd.open_port(prt)
reset_port_settings(prt) reset_port_settings(prt)
return prt except:
except Exception: prt.close()
if prt is not None:
try:
prt.close()
except Exception:
pass
continue continue
break
return None return prt
def _print_state_reply(state_bytes):
if state_bytes is None:
return False
status = state_bytes.hex()
print("Received: STATE. State status:", cmd.decode_STATE(status), "(" + cmd.flipfour(status) + ")") # def setup_connection():
print("") # prt = cmd.setup_port_connection()
return True # cmd.open_port(prt)
# return prt
def reset_port_settings(prt): def reset_port_settings(prt):
# Reset port settings and check status
# First, flush any pending data in the input buffer
if prt.inWaiting() > 0:
flushed = prt.read(prt.inWaiting())
print(f"Flushed {len(flushed)} bytes before reset: {flushed.hex()}")
cmd.send_DEFAULT_ENABLE(prt) cmd.send_DEFAULT_ENABLE(prt)
time.sleep(WAIT_AFTER_SEND)
return _print_state_reply(cmd.get_STATE(prt)) # Try multiple times with increasing delays to get response
max_attempts = 3
for attempt in range(max_attempts):
wait_time = WAIT_AFTER_SEND * (attempt + 1) # Increase wait time with each attempt
time.sleep(wait_time)
status_bytes = cmd.get_STATE(prt)
if status_bytes is not None:
status = status_bytes.hex()
print("Received: STATE. State status:", cmd.decode_STATE(status), "("+cmd.flipfour(status)+")")
print("")
return # Success
if attempt < max_attempts - 1:
print(f"Attempt {attempt + 1} failed, retrying with longer delay...")
# If all attempts failed, print warning but don't raise exception
print("Warning: Could not get STATE response after reset, but device may still be reset.")
print("")
def request_state(prt): def request_state(prt):
# Request data
cmd.send_STATE(prt) cmd.send_STATE(prt)
time.sleep(WAIT_AFTER_SEND) time.sleep(WAIT_AFTER_SEND)
return _print_state_reply(cmd.get_STATE(prt)) status_bytes = cmd.get_STATE(prt)
if status_bytes is not None:
status = status_bytes.hex()
print("Received: STATE. State status:", cmd.decode_STATE(status), "("+cmd.flipfour(status)+")")
print("")
def send_control_parameters(prt, params): def send_control_parameters(prt, params):
# Send control parameters
hexstring = cmd.encode_Input(params) hexstring = cmd.encode_Input(params)
cmd.send_DECODE_ENABLE(prt, hexstring) cmd.send_DECODE_ENABLE(prt,hexstring)
time.sleep(WAIT_AFTER_SEND) time.sleep(WAIT_AFTER_SEND)
return _print_state_reply(cmd.get_STATE(prt)) status_bytes = cmd.get_STATE(prt)
if status_bytes is not None:
status = status_bytes.hex()
print("Received: STATE. State status:", cmd.decode_STATE(status), "("+cmd.flipfour(status)+")")
print("")
else:
print("")
def send_task_command(prt, sending_param): def send_task_command(prt, sending_param):
# Send task command (TASK_ENABLE state in firmware) # Send task command (TASK_ENABLE state in firmware)
hexstring = cmd.create_TaskEnableCommand(sending_param) hexstring = cmd.create_TaskEnableCommand(sending_param)
cmd.send_TASK_ENABLE(prt, hexstring) cmd.send_TASK_ENABLE(prt,hexstring)
time.sleep(WAIT_AFTER_SEND) time.sleep(WAIT_AFTER_SEND)
return _print_state_reply(cmd.get_STATE(prt)) status_bytes = cmd.get_STATE(prt)
if status_bytes is not None:
status = status_bytes.hex()
def start_ramp_max( print("Received: STATE. State status:", cmd.decode_STATE(status), "("+cmd.flipfour(status)+")")
prt, print("")
freq_hz=None,
duty=None,
saw_step=None,
pat_period=None,
pat_period_base=None,
dac_clk_hz=None,
triangle=True,
sram_mode=False,
sram_samples=None,
sram_hold=None,
sram_amplitude=None,
):
# Start AD9102 sawtooth with configurable frequency/duty or SRAM ramp mode
if sram_mode:
if sram_hold is None:
sram_hold = cmd.AD9102_SRAM_HOLD_DEFAULT
if sram_samples is None and freq_hz is not None:
if dac_clk_hz is None:
dac_clk_hz = cmd.AD9102_DAC_CLK_HZ
sram_samples = cmd.calc_sram_samples_for_freq(freq_hz, dac_clk_hz, sram_hold)
hexstring = cmd.create_AD9102_ramp_command(
enable=True,
triangle=triangle,
sram_mode=True,
sram_samples=sram_samples,
sram_hold=sram_hold,
sram_amplitude=sram_amplitude,
)
else: else:
if pat_period_base is None: print("")
pat_period_base = cmd.AD9102_PAT_PERIOD_BASE_DEFAULT
if saw_step is None and freq_hz is not None:
if dac_clk_hz is None:
dac_clk_hz = cmd.AD9102_DAC_CLK_HZ
saw_step = cmd.calc_saw_step_for_freq(freq_hz, dac_clk_hz, triangle)
if saw_step is None:
saw_step = cmd.AD9102_SAW_STEP_DEFAULT
if pat_period is None and duty is not None:
pat_period = cmd.calc_pat_period_for_duty(saw_step, duty, pat_period_base, triangle)
if pat_period is None:
pat_period = cmd.AD9102_PAT_PERIOD_DEFAULT
hexstring = cmd.create_AD9102_ramp_command(
saw_step,
pat_period,
pat_period_base,
enable=True,
triangle=triangle,
)
cmd.send_AD9102(prt, hexstring)
time.sleep(WAIT_AFTER_SEND)
return _print_state_reply(cmd.get_STATE(prt))
def start_ad9833_ramp(prt, freq_hz=None, mclk_hz=None, triangle=True, enable=True):
if freq_hz is None:
freq_hz = 0.0
hexstring = cmd.create_AD9833_ramp_command(
freq_hz=freq_hz,
mclk_hz=mclk_hz,
enable=enable,
triangle=triangle,
)
cmd.send_AD9833(prt, hexstring)
time.sleep(WAIT_AFTER_SEND)
return _print_state_reply(cmd.get_STATE(prt))
def set_stm32_dac(prt, dac_code, enable=True):
hexstring = cmd.create_STM32_DAC_command(dac_code=dac_code, enable=enable)
cmd.send_STM32_DAC(prt, hexstring)
time.sleep(WAIT_AFTER_SEND)
return _print_state_reply(cmd.get_STATE(prt))
def _wait_for_min_bytes(prt, expected_len, timeout_s, poll_s=0.01):
deadline = time.time() + timeout_s
while time.time() < deadline:
waiting = prt.inWaiting()
if waiting >= expected_len:
return True
time.sleep(poll_s)
return prt.inWaiting() >= expected_len
def send_ds1809_pulse(prt, uc=False, dc=False, count=1, pulse_ms=None):
if count is None or count <= 0:
count = 1
if pulse_ms is None or pulse_ms <= 0:
pulse_ms = cmd.DS1809_PULSE_MS_DEFAULT
hexstring = cmd.create_DS1809_pulse_command(uc=uc, dc=dc, count=count, pulse_ms=pulse_ms)
cmd.send_DS1809(prt, hexstring)
# Firmware blocks while pulsing DS1809 lines: wait pulse train + safe margin.
pulse_train_time = (2.0 * float(count) * float(pulse_ms)) / 1000.0
time.sleep(max(WAIT_AFTER_SEND, pulse_train_time + 0.35))
# Then poll shortly for STATE bytes; this avoids early read (0 bytes) on startup.
_wait_for_min_bytes(prt, expected_len=2, timeout_s=0.8)
return _print_state_reply(cmd.get_STATE(prt))
def request_data(prt): def request_data(prt):
# Request data
cmd.send_TRANS_ENABLE(prt) cmd.send_TRANS_ENABLE(prt)
time.sleep(WAIT_AFTER_SEND) time.sleep(WAIT_AFTER_SEND)
data_bytes = cmd.get_DATA(prt) data_bytes = cmd.get_DATA(prt)
if data_bytes is None: data_dict = []
return None if data_bytes is not None:
data = data_bytes.hex()
return cmd.decode_DATA(data_bytes.hex()) data_dict = cmd.decode_DATA(data)
return data_dict
def print_data(data): def print_data(data):
def shorten(i): def shorten(i):
return str(round(i, 2)) return str(round(i, 2))
print("Data from device (time: " + datetime.now().strftime("%H:%M:%S:%f") + "):") print("Data from device (time: "+datetime.now().strftime("%H:%M:%S:%f")+"):")
print("Message Header:", data["Header"], " Message ID:", data["Message_ID"]) print("Message Header:", data['Header'], " Message ID:", data['Message_ID'])
print( print("Photodiode Current 1 ("+str(len(data['I1']))+" values):", \
"Photodiode Current 1 (" + str(len(data["I1"])) + " values):", shorten(data['I1']), shorten(data['I1'][1]), "...", \
shorten(data["I1"]), shorten(data['I1']), shorten(data['I1'][-1]), "mA")
shorten(data["I1"][1]), print("Photodiode Current 2 ("+str(len(data['I2']))+" values):", \
"...", shorten(data['I2']), shorten(data['I2'][1]), "...", \
shorten(data["I1"]), shorten(data['I2']), shorten(data['I2'][-1]), "mA")
shorten(data["I1"][-1]), print("Laser Temperature 1:", shorten(data['Temp_1']), "C")
"mA", print("Laser Temperature 2:", shorten(data['Temp_2']), "C")
) print("Temperature of external thermistor 1:", shorten(data['Temp_Ext_1']), "C")
print( print("Temperature of external thermistor 2:", shorten(data['Temp_Ext_2']), "C")
"Photodiode Current 2 (" + str(len(data["I2"])) + " values):", print("Voltages 3V3: "+shorten(data['MON_3V3'])+"V 5V1: "+shorten(data['MON_5V1'])+ \
shorten(data["I2"]), "V 5V2: "+shorten(data['MON_5V2'])+"V 7V0: "+shorten(data['MON_7V0'])+"V.")
shorten(data["I2"][1]),
"...",
shorten(data["I2"]),
shorten(data["I2"][-1]),
"mA",
)
print("Laser Temperature 1:", shorten(data["Temp_1"]), "C")
print("Laser Temperature 2:", shorten(data["Temp_2"]), "C")
print("Temperature of external thermistor 1:", shorten(data["Temp_Ext_1"]), "C")
print("Temperature of external thermistor 2:", shorten(data["Temp_Ext_2"]), "C")
print(
"Voltages 3V3: "
+ shorten(data["MON_3V3"])
+ "V 5V1: "
+ shorten(data["MON_5V1"])
+ "V 5V2: "
+ shorten(data["MON_5V2"])
+ "V 7V0: "
+ shorten(data["MON_7V0"])
+ "V."
)
def close_connection(prt): def close_connection(prt):
cmd.close_port(prt) cmd.close_port(prt)

142
gui.py
View File

@ -38,32 +38,6 @@ SET_TEXT_WIDTH_NEW = 40
SET_START_BUTTON_TEXT = 'Пуск' SET_START_BUTTON_TEXT = 'Пуск'
SET_STOP_BUTTON_TEXT = 'Стоп' SET_STOP_BUTTON_TEXT = 'Стоп'
SET_RAMP_BUTTON_TEXT = 'Пила'
SET_RAMP_SECTION_TEXT = 'Настройка пилы (AD9102)'
SET_RAMP_FREQ_TEXT = 'Частота (Гц):'
SET_RAMP_DUTY_TEXT = 'Скважность (%):'
SET_RAMP_SAWSTEP_TEXT = 'SAW_STEP (1-63):'
SET_RAMP_PATPERIOD_TEXT = 'PAT_PERIOD (1-65535):'
SET_RAMP_PATBASE_TEXT = 'PAT_PERIOD_BASE (0-15):'
SET_RAMP_DACCLK_TEXT = 'DAC clk (МГц):'
SET_RAMP_TRI_TEXT = 'Треугольник'
SET_RAMP_SRAM_MODE_TEXT = 'SRAM режим'
SET_RAMP_SRAM_SAMPLES_TEXT = 'SRAM точки (samples):'
SET_RAMP_SRAM_AMP_TEXT = 'SRAM амплитуда (%):'
SET_AD9833_SECTION_TEXT = 'Настройка пилы (AD9833)'
SET_AD9833_FREQ_TEXT = 'Частота AD9833 (кГц):'
SET_AD9833_MCLK_TEXT = 'MCLK AD9833 (МГц):'
SET_AD9833_TRI_TEXT = 'Треугольник AD9833'
SET_AD9833_BUTTON_TEXT = 'Пила AD9833'
SET_DS1809_SECTION_TEXT = 'DS1809 (UC/DC)'
SET_DS1809_UC_BUTTON_TEXT = 'UC импульс'
SET_DS1809_DC_BUTTON_TEXT = 'DC импульс'
SET_DS1809_STATUS_TEXT = 'Позиция DS1809:'
SET_STM32_DAC_SECTION_TEXT = 'STM32 DAC (PA4)'
SET_STM32_DAC_VOLT_TEXT = 'Напряжение DAC PA4 (В, 0..2.5):'
SET_STM32_DAC_BUTTON_TEXT = 'Установить DAC'
SET_STM32_DAC_STATUS_TEXT = 'Код DAC PA4:'
GRAPH_POINTS_NUMBER = 100 # Number of most recent data points shown on charts GRAPH_POINTS_NUMBER = 100 # Number of most recent data points shown on charts
GRAPH_CANVAS_SIZE = (0, 0) GRAPH_CANVAS_SIZE = (0, 0)
@ -84,12 +58,6 @@ H_SEPARATOR_PAD = (1, 20)
OUTPUT_TEXT_PAD = (5, (20, 5)) OUTPUT_TEXT_PAD = (5, (20, 5))
WINDOW_MARGIN = (60, 90) WINDOW_MARGIN = (60, 90)
MIN_WINDOW_SIZE = (880, 660) MIN_WINDOW_SIZE = (880, 660)
SETTINGS_PANEL_MIN_HEIGHT = 320
SETTINGS_PANEL_HEIGHT_MARGIN = 230
SETTINGS_PANEL_MIN_WIDTH = 320
SETTINGS_PANEL_WIDTH_COMPACT = 420
SETTINGS_PANEL_WIDTH_WIDE = 480
SETTINGS_PANEL_WIDTH_MARGIN = 60
#### ---- Setting GUI #### ---- Setting GUI
@ -102,56 +70,40 @@ def get_screen_size():
screen_width, screen_height = window.get_screen_size() screen_width, screen_height = window.get_screen_size()
window.close() window.close()
COMPACT_LAYOUT = screen_width <= 1280 or screen_height <= 800 COMPACT_LAYOUT = True
margin_w, margin_h = WINDOW_MARGIN margin_w, margin_h = WINDOW_MARGIN
min_w, min_h = MIN_WINDOW_SIZE min_w, min_h = MIN_WINDOW_SIZE
window_width = min(screen_width, max(min_w, screen_width - margin_w)) window_width = min(screen_width, max(min_w, screen_width - margin_w))
window_height = min(screen_height, max(min_h, screen_height - margin_h)) window_height = min(screen_height, max(min_h, screen_height - margin_h))//2
WINDOW_SIZE = (window_width, window_height) WINDOW_SIZE = (window_width, window_height)
if COMPACT_LAYOUT: if COMPACT_LAYOUT:
SET_TEXT_WIDTH = 30 SET_TEXT_WIDTH = 30
SET_TEXT_WIDTH_NEW = 34 SET_TEXT_WIDTH_NEW = 34
graph_width = min(int(screen_width / 3.6), int(window_width / 3.1)) graph_width = min(int(screen_width / 7.2), int(window_width / 5.6))
graph_height = max(110, int(screen_height / 6.5)) graph_height = max(90, int(screen_height / 16))
H_SEPARATOR_PAD = (1, 12) H_SEPARATOR_PAD = (1, 8)
OUTPUT_TEXT_PAD = (5, (12, 5)) OUTPUT_TEXT_PAD = (5, (8, 3))
else: else:
SET_TEXT_WIDTH = 34 SET_TEXT_WIDTH = 34
SET_TEXT_WIDTH_NEW = 40 SET_TEXT_WIDTH_NEW = 40
graph_width = int(screen_width / 3.5) graph_width = int(screen_width / 4)
graph_height = int(screen_width / (3 * 2.75)) graph_height = int(screen_width / (3 * 3.5))
H_SEPARATOR_PAD = (1, 20) H_SEPARATOR_PAD = (1, 15)
OUTPUT_TEXT_PAD = (5, (20, 5)) OUTPUT_TEXT_PAD = (5, (15, 5))
graph_width = max(220, graph_width) graph_width = max(180, graph_width)
GRAPH_CANVAS_SIZE = (graph_width, graph_height) GRAPH_CANVAS_SIZE = (graph_width, graph_height)
return WINDOW_SIZE return WINDOW_SIZE
def get_settings_panel_size(window_size):
window_width, window_height = window_size
desired_width = SETTINGS_PANEL_WIDTH_COMPACT if COMPACT_LAYOUT else SETTINGS_PANEL_WIDTH_WIDE
available_width = window_width - (GRAPH_CANVAS_SIZE[0] * 2) - SETTINGS_PANEL_WIDTH_MARGIN
if available_width > 0:
width = min(desired_width, available_width)
if available_width >= SETTINGS_PANEL_MIN_WIDTH:
width = max(width, SETTINGS_PANEL_MIN_WIDTH)
else:
width = desired_width
height = max(SETTINGS_PANEL_MIN_HEIGHT, window_height - SETTINGS_PANEL_HEIGHT_MARGIN)
return (int(width), int(height))
def setup_gui(params): def setup_gui(params):
sg.theme("DarkBlue12") sg.theme("DarkBlue12")
window_size = get_screen_size() window_size = get_screen_size()
settings_panel_size = get_settings_panel_size(window_size)
layout_input_col1 = [[sg.Text(SET_TEMPERATURE_TEXT_1, size=(SET_TEXT_WIDTH, 1)), sg.Push(), layout_input_col1 = [[sg.Text(SET_TEMPERATURE_TEXT_1, size=(SET_TEXT_WIDTH, 1)), sg.Push(),
sg.Input(params['Temp_1'], disabled_readonly_background_color="Gray", size=(SET_INPUT_WIDTH,1), key='-InputT1-', disabled = True)], sg.Input(params['Temp_1'], disabled_readonly_background_color="Gray", size=(SET_INPUT_WIDTH,1), key='-InputT1-', disabled = True)],
@ -243,80 +195,12 @@ def setup_gui(params):
[sg.Text(SET_TAU_T_TEXT, size=(SET_TEXT_WIDTH_NEW,1)), [sg.Text(SET_TAU_T_TEXT, size=(SET_TEXT_WIDTH_NEW,1)),
sg.Input(params['Tau'], size=(SET_INPUT_WIDTH,1), key='-InputTau-', disabled=True, disabled_readonly_background_color="Gray")], sg.Input(params['Tau'], size=(SET_INPUT_WIDTH,1), key='-InputTau-', disabled=True, disabled_readonly_background_color="Gray")],
[sg.Text(SET_RAMP_SECTION_TEXT, size=(SET_TEXT_WIDTH_NEW,1))],
[sg.Text(SET_RAMP_FREQ_TEXT, size=(SET_TEXT_WIDTH_NEW,1)),
sg.Input(params.get('RampFreq', ''), size=(SET_INPUT_WIDTH,1), key='-RampFreq-')],
[sg.Text(SET_RAMP_DUTY_TEXT, size=(SET_TEXT_WIDTH_NEW,1)),
sg.Input(params.get('RampDuty', ''), size=(SET_INPUT_WIDTH,1), key='-RampDuty-')],
[sg.Text(SET_RAMP_SAWSTEP_TEXT, size=(SET_TEXT_WIDTH_NEW,1)),
sg.Input(params.get('RampSawStep', ''), size=(SET_INPUT_WIDTH,1), key='-RampSawStep-')],
[sg.Text(SET_RAMP_PATPERIOD_TEXT, size=(SET_TEXT_WIDTH_NEW,1)),
sg.Input(params.get('RampPatPeriod', ''), size=(SET_INPUT_WIDTH,1), key='-RampPatPeriod-')],
[sg.Text(SET_RAMP_PATBASE_TEXT, size=(SET_TEXT_WIDTH_NEW,1)),
sg.Input(params.get('RampPatBase', ''), size=(SET_INPUT_WIDTH,1), key='-RampPatBase-')],
[sg.Text(SET_RAMP_DACCLK_TEXT, size=(SET_TEXT_WIDTH_NEW,1)),
sg.Input(params.get('RampDacClk', ''), size=(SET_INPUT_WIDTH,1), key='-RampDacClk-')],
[sg.Text(SET_RAMP_TRI_TEXT, size=(SET_TEXT_WIDTH_NEW,1)),
sg.Checkbox('', default=bool(params.get('RampTriangle', True)), key='-RampTriangle-')],
[sg.Text(SET_RAMP_SRAM_MODE_TEXT, size=(SET_TEXT_WIDTH_NEW,1)),
sg.Checkbox('', default=bool(params.get('RampSramMode', False)), key='-RampSramMode-')],
[sg.Text(SET_RAMP_SRAM_SAMPLES_TEXT, size=(SET_TEXT_WIDTH_NEW,1)),
sg.Input(params.get('RampSramSamples', ''), size=(SET_INPUT_WIDTH,1), key='-RampSramSamples-')],
[sg.Text(SET_RAMP_SRAM_AMP_TEXT, size=(SET_TEXT_WIDTH_NEW,1)),
sg.Input(params.get('RampSramAmp', ''), size=(SET_INPUT_WIDTH,1), key='-RampSramAmp-')],
[sg.HSeparator(pad=H_SEPARATOR_PAD)],
[sg.Text(SET_AD9833_SECTION_TEXT, size=(SET_TEXT_WIDTH_NEW,1))],
[sg.Text(SET_AD9833_FREQ_TEXT, size=(SET_TEXT_WIDTH_NEW,1)),
sg.Input(params.get('Ad9833Freq', ''), size=(SET_INPUT_WIDTH,1), key='-AD9833Freq-')],
[sg.Text(SET_AD9833_MCLK_TEXT, size=(SET_TEXT_WIDTH_NEW,1)),
sg.Input(params.get('Ad9833Mclk', ''), size=(SET_INPUT_WIDTH,1), key='-AD9833Mclk-')],
[sg.Text(SET_AD9833_TRI_TEXT, size=(SET_TEXT_WIDTH_NEW,1)),
sg.Checkbox('', default=bool(params.get('Ad9833Triangle', True)), key='-AD9833Triangle-')],
[sg.HSeparator(pad=H_SEPARATOR_PAD)],
[sg.Text(SET_DS1809_SECTION_TEXT, size=(SET_TEXT_WIDTH_NEW,1))],
[sg.Button(SET_DS1809_UC_BUTTON_TEXT, key='-DS1809UC-', disabled_button_color=("Gray22", "Blue")),
sg.Button(SET_DS1809_DC_BUTTON_TEXT, key='-DS1809DC-', disabled_button_color=("Gray22", "Blue"))],
[sg.Text(SET_DS1809_STATUS_TEXT, size=(SET_TEXT_WIDTH_NEW,1)),
sg.Text(params.get('DS1809Status', '--'), key='-DS1809Status-', size=(20,1))],
[sg.HSeparator(pad=H_SEPARATOR_PAD)],
[sg.Text(SET_STM32_DAC_SECTION_TEXT, size=(SET_TEXT_WIDTH_NEW,1))],
[sg.Text(SET_STM32_DAC_VOLT_TEXT, size=(SET_TEXT_WIDTH_NEW,1)),
sg.Input(params.get('PA4DacVolt', '0.0'), size=(SET_INPUT_WIDTH,1), key='-PA4DacVolt-')],
[sg.Button(SET_STM32_DAC_BUTTON_TEXT, key='-SetPA4Dac-', disabled_button_color=("Gray22", "Blue"))],
[sg.Text(SET_STM32_DAC_STATUS_TEXT, size=(SET_TEXT_WIDTH_NEW,1)),
sg.Text(params.get('PA4DacStatus', '0 / 4095'), key='-PA4DacStatus-', size=(20,1))],
[sg.HSeparator(pad=H_SEPARATOR_PAD)], [sg.HSeparator(pad=H_SEPARATOR_PAD)],
[sg.Button(SET_START_BUTTON_TEXT, key='-StartCycle-', disabled_button_color=("Gray22", "Blue"), disabled=True), sg.Button(SET_STOP_BUTTON_TEXT, disabled_button_color=("Gray22", "Blue"), key='-StopCycle-', disabled=True), sg.Button(SET_RAMP_BUTTON_TEXT, key='-StartRamp-', disabled_button_color=("Gray22", "Blue")), sg.Button(SET_AD9833_BUTTON_TEXT, key='-StartRamp9833-', disabled_button_color=("Gray22", "Blue"))]] [sg.Button(SET_START_BUTTON_TEXT, key='-StartCycle-', disabled_button_color=("Gray22", "Blue"), disabled=True), sg.Button(SET_STOP_BUTTON_TEXT, disabled_button_color=("Gray22", "Blue"), key='-StopCycle-', disabled=True)]]
layout = [[sg.Column(layout_input_col1, pad=(0,0)), sg.VSeparator(pad=(4,0)), sg.Column(layout_input_col2, pad=(0,0)), sg.VSeparator(pad=(4,0)), layout = [[sg.Column(layout_input_col1, pad=(0,0)), sg.VSeparator(pad=(4,0)), sg.Column(layout_input_col2, pad=(0,0)), sg.VSeparator(pad=(4,0)), sg.Column(layout_input_col3, pad=(0,0))],
sg.Column(layout_input_col3, pad=(0,0), scrollable=True, vertical_scroll_only=True, size=settings_panel_size, key='-SettingsPanel-', expand_y=True)],
[sg.HSeparator(pad=(25,10))], [sg.HSeparator(pad=(25,10))],

11
init_params.json Normal file
View File

@ -0,0 +1,11 @@
{
{INITIAL_TEMPERATURE_1 = 28 # Set initial temperature for Laser 1 in Celsius: from -1 to 45 C ??
INITIAL_TEMPERATURE_2 = 28.9 # Set initial temperature for Laser 2 in Celsius: from -1 to 45 C ??
INITIAL_CURRENT_1 = 33 # 64.0879 max # Set initial current for Laser 1, in mA
INITIAL_CURRENT_2 = 35 # 64.0879 max # Set initial current for Laser 2, in mA
GUI_TIMEOUT_INTERVAL = 5#505 - dev.WAIT_AFTER_SEND*1000 # GUI refresh time in milliseconds
SAVE_POINTS_NUMBER = 1000 # Number of most recent data points kept in memory
}

4
run
View File

@ -1,7 +1,7 @@
#!/usr/bin/bash #!/usr/bin/bash
#reset generator PCB #reset generator PCB
#pinctrl set 26 op dl # drive PCB NRST LOW -> reset stm32 # pinctrl set 26 op dl # drive PCB NRST LOW -> reset stm32
#pinctrl set 26 op dh # turn stm32 back ON # pinctrl set 26 op dh # turn stm32 back ON
source .venv/bin/activate source .venv/bin/activate
python3 _device_main.py python3 _device_main.py