# ------------------------------------------------------------------
# python GUI for PyCROS (FERS readout software by Tintori)
# ------------------------------------------------------------------

# from msilib.schema import ComboBox
import sys
import subprocess
import time
import os
import re

from threading import Thread, Lock

from tkinter import *
from tkinter import messagebox
from tkinter import ttk
from tkinter import Widget
from tkinter.filedialog import askdirectory
# from turtle import bgcolor

import shared as sh
import leds as leds
import cfgfile_rw as cfg
import socket2daq as comm
import tooltips as tt
import json

params = sh.params
sections = sh.sections


# *******************************************************************************
# Main Tabs
# *******************************************************************************

# DNIN: create a dictionary with the tabs name {0:"Connect", 1:"RunCtrl" ...}

class TabsPanel():
	def __init__(self):

		# self.defaultFont = font.nametofont("TkDefaultFont")
		# print(self.defaultFont)
		if sys.platform.find('win') < 0:
			sh.ImgPath = '../img/'
		self.img_hvon = PhotoImage(file=sh.ImgPath + "pwon.png").subsample(3, 3)

		self.MaskWinIsOpen = False
		self.Mask = [IntVar() for i in range(64)]

		# This variable is needed to avoid crash during a run if the spinbox value is cancelled
		self.TmpActiveBrd = StringVar()
		self.TmpActiveBrd.set(0)
		self.TmpActiveBrd.trace('w', lambda name, index, mode: self.ValidateActiveBrd())

		self.ActiveBrd = IntVar()
		self.ActiveBrd.set(0)
		self.ActiveBrd.trace('w', lambda name, index, mode: self.SendActiveBrd())   # comm.SendCmd('b ' + str(self.ActiveBrd.get()))) # 

		self.ActiveTDC = IntVar()
		self.ActiveTDC.set(0)
		# self.ActiveTDC.trace('w', lambda name, index, mode: self.ChangeTDC)

		self.FitWinIsOpen = False

		# Default settings
		self.par_def_svar = {}			# String Var 
		self.par_def_entry = {}			# Entry
		self.par_def_checkbox = {}		# check box
		self.par_def_combo = {}			# combo
		self.par_def_spinbox = {}		# spinbox
		self.par_def_label = {}			# label - to change GUImode
		# Board settings
		self.par_brd_svar = {}			# String Var 
		self.par_brd_entry = {}			# Entry
		self.par_brd_checkbox = {}		# check box
		self.par_brd_combo = {}			# combo
		# Channel settings
		self.par_ch_svar = {}			# String Var 
		self.par_ch_entry = {}			# Entry
		self.par_ch_checkbox = {}		# check box
		self.par_ch_combo = {}			# combo
		self.par_ch_label = {}			# labels (monitror)

		# Widget positions
		self.ypos_def = {}				# y pos of the widget
		self.ypos_brd = {}				# y pos of the widget
		self.ypos_ch = {}				# y pos of the widget

		self.button_names = {}			# additional widget on tabs

		self.StopUpdate = False

		self.param_rename = {}
		if os.path.isfile(sh.ParRename):
			cf = open(sh.ParRename, "r")
			for line in cf:
				line = line.split('=')
				if len(line) == 2:
					self.param_rename[line[0].strip()] = line[1].strip()
			cf.close		

		self.status_now = sh.ACQSTATUS_DISCONNECTED
		self.CfgChanged = IntVar()
		self.CfgChanged.set(0)
		self.change_statistics = IntVar()
		self.change_statistics.set(0)
		self.change_statistics.trace('w', lambda name, index, mode:self.ChgStatMode()) #new function that changes the visualization and sends a command to JanusC for change the statistics
		self.change_stat_integral = IntVar()
		self.change_stat_integral.set(0)
		self.change_stat_integral.trace('w', lambda name, index, mode:self.ChgStatIntegr())

		# self.change_statistics.trace('w', lambda name, index, mode: self.all_brd_statistics)

		self.update_stats = True
		self.gui_update = True

		self.AllBrdLabel = [] # for statistic visualization change
		self.AllBrdCounts = {}

		self.AcqMode_Dict = {} # {"AcqMode0": 0, "AcqMode1": 1 ...}, for GUI visualization
		self.MeasMode_Dict = {} # {"MeasMode0": "A", "MeasMode1": "B", ...}, needed for A5203
		self.StopRunMode_Dict = {} # {"JobEnabled": "J", "JobNotEnabled": "K"}

		self.LSB_param = [] # List of params driving the LSB of the picoTDC
		self.timeval = {} # Dictionary for Label of time LSB val
		self.rangeval = {} # Dictionary of Label for the Dynamic Range: 2**NBIN*LSB
		self.tname = ""

		self.AF_dict = {} # Dict for Almost Full obj
		self.AF_dict_allbrd = {}

		self.tdc_num = IntVar()	# For A5203, 64 or 128 channel
		self.tdc_num.set(1)

		self.new_options = {}	# GUI parameter new options 
		self.offline = False

		self.fpga_fwver = ["" for i in sh.Boards]


	# *******************************************************************************************
	# Validate Functions
	# *******************************************************************************************
	def ValidateActiveBrd(self):
		if self.TmpActiveBrd.get().isdigit():
			if int(self.TmpActiveBrd.get()) < sh.MaxBrd and int(self.TmpActiveBrd.get()) >= 0:
				self.ActiveBrd.set(int(self.TmpActiveBrd.get()))
			else: self.TmpActiveBrd.set(str(self.ActiveBrd.get()))
		elif len(self.TmpActiveBrd.get().strip()) == 0: return True
		else: self.TmpActiveBrd.set(str(self.ActiveBrd.get()))
		return True
		
	def validate_ch(self, new_value):
		if new_value.isdigit(): return int(new_value) < sh.MaxCh
		elif not new_value: return True
		else: return False

	def validate_LSB(self, new_value, notused, edges):	#Edges are write in the name, here name = ".!notebook.!frame.MIN-MAX"
		rpoint = edges.rfind('.')
		minmax = [int(edges[rpoint+1:].split("-")[0]), int(edges[rpoint+1:].split("-")[1])]
		if new_value.isdigit(): return int(new_value) in range(minmax[0], minmax[1]+1)
		elif not new_value: return True
		else: return False

	def SendActiveBrd(self):
		try: comm.SendCmd(f"b{str(self.ActiveBrd.get())}")
		except: pass	

	def OpenTabs(self, parent):
		# ***************************************************************************************
		# create Notebook for Main Tabs (tabs are defined in param_defs file)
		# ***************************************************************************************
		self.Mtabs_nb = ttk.Notebook(parent)
		self.Mtabs = {}
		self.Mtabs_shown = {}
		i = 0
		for s in sections:
			self.Mtabs[s] = ttk.Frame(self.Mtabs_nb)  #, width=sh.Win_Tabs_W, height=sh.Win_Tabs_H)
			self.Mtabs_nb.add(self.Mtabs[s], text=' ' + s + ' ')
			i += 1	

		self.Mtabs_nb.place(relx=float(sh.Win_Tabs_X)/sh.Win_W, rely=float(sh.Win_Tabs_Y)/sh.Win_H, relwidth=float(sh.Win_Tabs_W+3)/sh.Win_W, relheight=float(sh.Win_Tabs_H+26)/sh.Win_H)  #    x=sh.Win_Tabs_X, y=sh.Win_Tabs_Y)
	
		# ***************************************************************************************
		# Create controls for the params of the config file (distributed over multiple tabs)
		# ***************************************************************************************
		# Stop the b_apply during start-up
		self.StopUpdate = True

		# fill user tabs with parameters defined in param_defs
		x_def = 140	# x-pos of default entry/combo
		x_brd = 3	# x-pos of board entry/combo
		x_ch = 300	# x-pos of channel entry/combo
		yrow = {s: 20 for s in sections} # initial Y-position for default and channel rows (one variable per section)
		ypos = {}	# save y pos of each parameter
		#create_brdtabs = {s: TRUE for s in sections} # flag indacating that board tabs are not created yet
		#create_chtabs = {s: TRUE for s in sections} # flag indacating that channel tabs are not created yet
		ngr = 8  # num of groups
		nch_gr = 8  # num of channels per group

		vfnc = {} # Validation for Spinbox, 

		# find sections that require board and channel tabs (0=no tabs, 1=board tab only, 2=board and channel tabs)
		self.tabmode = {s : 0 for s in sections}
		for param in params.values():
			if param.distr == 'c': 
				self.tabmode[param.section] = 2
				yrow[param.section] = 40 #68
			if param.distr == 'b' and self.tabmode[param.section] == 0: 
				self.tabmode[param.section] = 1
				yrow[param.section] = 10 #16

		# create TABs for boards and channels
		self.BrdTabs_nb = {}
		self.BrdTabs = {}
		self.ChTabs_nb = {}
		self.ChTabs = {}
		self.GlbTab = {}
		self.GlbFrame_nb = {s:ttk.Notebook(self.Mtabs[s]) for s in sections}
		self.GlbFrame = {s:ttk.Frame(self.GlbFrame_nb[s]) for s in sections}
		self.Level2nd_nb = {s:ttk.Notebook(self.GlbFrame[s]) for s in sections}
		self.Level2nd = {s:ttk.Frame(self.Level2nd_nb[s]) for s in sections} 
		for s in sections:
			if self.tabmode[s] > 0 and s != 'Connect':
				self.GlbFrame_nb[s].place(relx=0, rely=0, relwidth=1, relheight=1)   # to allign with boards 
				self.GlbFrame_nb[s].add(self.GlbFrame[s], text="Global Settings")
				self.GlbTab[s] = self.GlbFrame[s]

				self.BrdTabs_nb[s] = ttk.Notebook(self.Mtabs[s])
				self.aaa= ttk.Notebook(self.Mtabs[s])
				self.aaa.winfo_geometry()
				self.BrdTabs_nb[s].place(relx=256./sh.Win_W, rely=0, relwidth=float(sh.Win_Tabs_W-x_ch+49)/sh.Win_W, relheight=float(sh.Win_Tabs_H-12)/sh.Win_Tabs_H)  #  x=256, y=0)
				self.BrdTabs[s] = [ttk.Frame(self.BrdTabs_nb[s]) for i in sh.Boards] # , width=sh.Win_Tabs_W - x_ch + 40, height=sh.Win_Tabs_H - 40
				for brd in sh.Boards: 
					self.BrdTabs_nb[s].add(self.BrdTabs[s][brd], text=str("B" + str(brd)))
				if self.tabmode[s] == 2:
					self.Level2nd_nb[s].place(relx=0, rely=0, relwidth=1, relheight=1)
					self.Level2nd_nb[s].add(self.Level2nd[s], text="")
					Frame(self.GlbFrame[s]).place(relx=0, rely=0, relwidth=1, relheight=0.1)
					self.GlbTab[s] = self.Level2nd[s]

					self.ChTabs[s] = []
					self.ChTabs_nb[s] = []
					for brd in sh.Boards:
						self.ChTabs_nb[s].append(ttk.Notebook(self.BrdTabs[s][brd]))
						self.ChTabs_nb[s][brd].place(relx=0, rely=0, relwidth=float(sh.Win_Tabs_W)/sh.Win_Tabs_W, relheight=float(sh.Win_Tabs_H+2)/sh.Win_Tabs_H)  #   x=0, y=0)	
						self.ChTabs[s].append([])
						for gr in range(ngr):
							self.ChTabs[s][brd].append(ttk.Frame(self.ChTabs_nb[s][brd]))  #  , width=sh.Win_Tabs_W - x_ch + 10, height=sh.Win_Tabs_H - 40
							self.ChTabs_nb[s][brd].add(self.ChTabs[s][brd][gr], text='   ' + str(gr*nch_gr) + ':' + str((gr+1)*nch_gr-1)+ '   ')
			else:
				self.GlbTab[s] = self.Mtabs[s]

		for param in params.values():
			# ADD *_LSB param to the proper list
			if "LSB" in param.name: self.LSB_param.append(param.name)

			if param.section == 'Connect': # this has a separate management!
				self.conn_path = [StringVar() for i in sh.Boards]
				for brd in sh.Boards:
					self.conn_path[brd].set(param.value[brd])
				continue

			tab = self.GlbTab[param.section]
			yd = yrow[param.section]  	# y position for parameter label and control (default setting)
			yb = yd  #*14.1/13.1 - 24.756  # y position for relative placement (board setting)  yb = yd - 23 # y position for parameter label and control (board setting)
			yc = yd  #*14.1/12.45 - 53.23  # y position for relative placement (channel setting) yd - 45 # y position for parameter label and control (channel setting)
			yrow[param.section] += 25

			m_xdef = x_def 
			lx = 0
			if param.name == "OutputFiles":
				yrow[param.section] = 20
				yd = yrow[param.section]
				yrow[param.section] += 25
				lx = 310
			if param.name == "DataFilePath":
				kk = yd-3
				m_xdef = 420
				lx = 310
			if "OF_" in param.name:
				if 'FileUnit' in param.name: m_xdef = 465
				else: m_xdef = 480
				lx = 310

			if param.type == '-':  # separator or labels
				if param.name.find('_BLANK') < 0:	
					self.par_def_label[param.name] = ttk.Label(tab, text=param.name.ljust(31, ' '), font=("Courier", 10, "bold underline"))
					self.par_def_label[param.name].place(relx=lx, rely=float(yd)/sh.Win_Tabs_H)  # x=0, y=yd) #  
			elif param.type == 'D': continue	# not shown on GUI
			else:
				ypos[param.name] = yd
				if param.name in self.param_rename: parname = self.param_rename[param.name]
				else: parname = param.name
				self.par_def_label[param.name] = ttk.Label(tab, text=parname)
				self.par_def_label[param.name].place(relx=lx, rely=float(yd)/sh.Win_Tabs_H)  #   x=0, y=yd) #
				# ------------------------------------------------------------------------------
				# create variables and controls for Default
				# ------------------------------------------------------------------------------
				if  param.type != 'm':
					self.par_def_svar[param.name] = StringVar()
					self.par_def_svar[param.name].set(param.default)
					self.par_def_svar[param.name].trace('w', lambda name, index, mode, param=param: self.update_def_param(param))
					#if param.distr != 'b':  # board params don't have controls for default value 
					if TRUE:  # board params don't have controls for default value 
						if param.type == 'c':  # Combobox
							self.par_def_combo[param.name] = ttk.Combobox(tab, textvariable=self.par_def_svar[param.name], state='readonly') #, width=15)
							# self.par_def_combo[param.name].append(ttk.Combobox(tab, textvariable=self.par_def_svar[param.name], state='readonly', width=15))
							self.par_def_combo[param.name]['values'] = param.options
							self.par_def_combo[param.name].place(relx=float(m_xdef)/sh.Win_Tabs_W, rely=float(yd)/sh.Win_Tabs_H, relwidth=0.163, relheight=0.037)  #   x=x_def, y=yd)
							tt.Tooltip(self.par_def_combo[param.name], text=param.descr, wraplength=200)
						elif param.type == 'b':	# boolean
							self.par_def_checkbox[param.name] = Checkbutton(tab, variable=self.par_def_svar[param.name])
							self.par_def_checkbox[param.name].place(relx=float(m_xdef)/sh.Win_Tabs_W, rely=float(yd)/sh.Win_Tabs_H)  #   x=x_def, y=yd)
							tt.Tooltip(self.par_def_checkbox[param.name], text=param.descr, wraplength=200)
						elif param.type == 'x': # spinbox
							vfnc[param.name] = (parent.register(self.validate_LSB), '%P', '%S','%W')
							self.par_def_spinbox[param.name] = Spinbox(tab, textvariable=self.par_def_svar[param.name], from_=param.options[0], to=param.options[1], 
																		name='{}-{}'.format(param.options[0], param.options[1]), validate='all', validatecommand=vfnc[param.name])
							self.par_def_spinbox[param.name].place(relx=m_xdef/sh.Win_Tabs_W, rely=yd/sh.Win_Tabs_H, relwidth=0.095, relheight=0.039)
							tt.Tooltip(self.par_def_spinbox[param.name], text=param.descr, wraplength=200)
							if '5203' in sh.Version:
								val = 3.125*2**int(self.par_def_svar[param.name].get())
								unit = 'ns' if val > 0 else 'ps'
								self.timeval[param.name] = Label(tab, text="{} {}".format(val, unit), bg='white', anchor='w', relief=SUNKEN) # Cell next to the LSB spinbox
								self.timeval[param.name].place(relx=(m_xdef/sh.Win_Tabs_W), rely=yd/sh.Win_Tabs_H, relwidth=0.08, relheight=0.039) # +0.065
								tt.Tooltip(self.timeval[param.name], text="{} value = {}".format(param.name, param.descr.split(':')[1].replace("LSB = ", "")), wraplength=200)
								self.tname = param.section				#		3.125ps * 2^N, Max N=10 (Max LSB = ~3.125 ns)
						else:  # entry (string)
							self.par_def_entry[param.name] = Entry(tab, textvariable=self.par_def_svar[param.name]) #, width=18)  
							self.par_def_entry[param.name].place(relx=float(m_xdef)/sh.Win_Tabs_W, rely=float(yd)/sh.Win_Tabs_H, relwidth=0.163, relheight=0.036)  #   x=x_def, y=yd)
							tt.Tooltip(self.par_def_entry[param.name], text=param.descr, wraplength=200)

				# ------------------------------------------------------------------------------
				# create controls for board params
				# ------------------------------------------------------------------------------
				if (param.distr == 'b'): 
					chn = 1	 
					self.par_brd_svar[param.name] = []
					self.par_brd_combo[param.name] = []
					self.par_brd_checkbox[param.name] = []
					self.par_brd_entry[param.name] = []
					self.ypos_brd[param.name] = yb		# y pos of the widget
					# yb = (yb)*(sh.Win_Tabs_H+60)/(sh.Win_Tabs_W-12)
					# height = sh.Win_Tabs_H
					for brd in sh.Boards:
						btab = self.BrdTabs[param.section][brd]
						if self.tabmode[param.section] == 2:
							chn = 8
						self.par_brd_svar[param.name].append(StringVar())
						self.par_brd_svar[param.name][brd].set(param.value[brd])
						self.par_brd_svar[param.name][brd].trace('w', lambda name, index, mode, param=param, brd=brd: self.update_brd_param(param, brd))
						for tch in range(chn):
							if chn == 8:
								btab = self.ChTabs[param.section][brd][tch]

							if param.type == 'c':  # Combobox    # before par_def_....
								if tch == 0: self.par_brd_combo[param.name].append([])
								self.par_brd_combo[param.name][brd].append(ttk.Combobox(btab, textvariable=self.par_brd_svar[param.name][brd], state='readonly')) # , width=15
								self.par_brd_combo[param.name][brd][tch]['values'] = param.options
								self.par_brd_combo[param.name][brd][tch].place(relx=float(x_brd)/sh.Win_Tabs_W, rely=float(yb)/sh.Win_Tabs_H, relwidth=0.2, relheight=0.039) #x=x_brd, y=yb)#)  #   			
							elif param.type == 'b':	# Boolean
								if tch == 0: self.par_brd_checkbox[param.name].append([])
								self.par_brd_checkbox[param.name][brd].append(Checkbutton(btab, variable=self.par_brd_svar[param.name][brd]))
								self.par_brd_checkbox[param.name][brd][tch].place(relx=float(x_brd)/sh.Win_Tabs_W, rely=float(yb)/sh.Win_Tabs_H)  #x=x_brd, y=yb)#
							else:  # entry (string)
								if tch == 0: self.par_brd_entry[param.name].append([])
								self.par_brd_entry[param.name][brd].append(Entry(btab, textvariable=self.par_brd_svar[param.name][brd])) # , width=18
								self.par_brd_entry[param.name][brd][tch].place(relx=float(x_brd)/sh.Win_Tabs_W, rely=float(yb)/sh.Win_Tabs_H, relwidth=0.27, relheight=0.041) #x=x_brd, y=yb)# relx=float(x_brd)/sh.Win_Tabs_W, rely=float(yb)/height)#, relwidth=0.27, relheight=0.037)  #  

				# ------------------------------------------------------------------------------
				# create variables and controls for channel settings
				# ------------------------------------------------------------------------------
				if (param.distr == 'c'): 
					self.par_ch_svar[param.name] = []
					self.par_ch_entry[param.name] = []
					self.par_ch_checkbox[param.name] = []
					self.par_ch_combo[param.name] = []
					self.par_ch_label[param.name] = []
					self.ypos_ch[param.name] = yc			# y pos of the widget
					for brd in sh.Boards: 
						self.par_ch_svar[param.name].append([])
						for gr in range(ngr):
							for i in range(nch_gr):
								ch = gr * nch_gr + i
								# x = 2 + i * 81.5  #50
								x = x_brd + i * 81.5
								ctab = self.ChTabs[param.section][brd][gr]
								if param.type == 'm':
									if ch == 0: self.par_ch_label[param.name].append([])
									self.par_ch_label[param.name][brd].append(Label(ctab, text='', anchor = 'w', relief = 'groove'))#,  width=6
									self.par_ch_label[param.name][brd][ch].place(relx=float(x)/sh.Win_Tabs_W, rely=float(yc)/sh.Win_Tabs_H, relwidth=0.11, relheight=0.041) # x=x, y=yc)#
								else:
									self.par_ch_svar[param.name][brd].append(StringVar())
									self.par_ch_svar[param.name][brd][ch].set(param.value[brd][ch])
									self.par_ch_svar[param.name][brd][ch].trace('w', lambda name, index, mode, param=param, brd=brd, ch=ch: self.update_ch_param(param, brd, ch))
									if param.type == 'c':
										if ch == 0: self.par_ch_combo[param.name].append([])
										self.par_ch_combo[param.name].append(ttk.Combobox(ctab, textvariable=self.par_ch_svar[param.name][brd][ch], state = 'readonly')) #, width=6
										opt = param.options + ['']
										self.par_ch_combo[param.name][brd][ch]['values'] = opt
										self.par_ch_combo[param.name][brd][ch].place(relx=float(x)/sh.Win_Tabs_W, rely=float(yc)/sh.Win_Tabs_H, relwidth=0.11, relheight=0.041)# x=x, y=yc)# 
									elif param.type == 'b':	
										if ch == 0: self.par_ch_checkbox[param.name].append([])
										self.par_ch_checkbox[param.name][brd].append(Checkbutton(ctab, variable=self.par_ch_svar[param.name][brd][ch]))
										self.par_ch_checkbox[param.name][brd][ch].place(relx=float(x)/sh.Win_Tabs_W, rely=float(yc)/sh.Win_Tabs_H) # x=x, y=yc)#
									else:
										if ch == 0: self.par_ch_entry[param.name].append([])
										self.par_ch_entry[param.name][brd].append(Entry(ctab, textvariable=self.par_ch_svar[param.name][brd][ch])) #, width=7
										self.par_ch_entry[param.name][brd][ch].place(relx=float(x)/sh.Win_Tabs_W, rely=float(yc)/sh.Win_Tabs_H, relwidth=0.11, relheight=0.041)#x=x, y=yc)#) # 
								Label(ctab, text='CH ' + str(ch)).place(relx=x/sh.Win_Tabs_W, rely=(5.*14.1/12.45)/sh.Win_Tabs_H) # relx=float(x+5)/sh.Win_Tabs_W, rely=5./sh.Win_Tabs_H) #
			

		for mode in params["AcquisitionMode"].options: # Set dictionary for GUI view
			self.AcqMode_Dict[mode] = str(params["AcquisitionMode"].options.index(mode))
		
		
		try:
			for mode in params["MeasMode"].options:
				self.MeasMode_Dict[mode] = chr(params["MeasMode"].options.index(mode)+97).capitalize()
		except:
			self.MeasMode_Dict[""] = ""  # Default for A5202
		self.ypos_def = ypos

		for k, v in self.Mtabs.items():
			self.Mtabs_shown[k] = v

		# ***************************************************************************************
		# Add extra controls in some tabs
		# ***************************************************************************************
		# ------------------------------------------------------------
		# Connect
		# ------------------------------------------------------------
		self.BrdEnable = [IntVar() for i in sh.Boards]
		self.path_entry = []
		self.info_pid = []
		self.info_fpga_fwrev = []
		self.info_board_model = []
		self.info_uc_fwrev = []
		self.brd_enable_cb = []
		# xl0, xl1, xl2, xl3 = 60, 220, 300, 450
		# xl = [60, 220, 301, 451]
		xl = [60, 220, 285, 354, 486]
		for i in range(len(xl)-1):
			xl[i+1] = xl[i+1] + 50
		xr=[xx/sh.Win_Tabs_W for xx in xl]	# for relative placement
		y0 = 5
		Label(self.Mtabs['Connect'], text='PATH').place(relx=xr[0], rely=y0/sh.Win_Tabs_H) # place(x=xl[0], y=y0)
		Label(self.Mtabs['Connect'], text='PID').place(relx=xr[1], rely=y0/sh.Win_Tabs_H) #   x=xl[1], y=y0)
		Label(self.Mtabs['Connect'], text='Brd Model').place(relx=xr[2], rely=y0/sh.Win_Tabs_H)
		Label(self.Mtabs['Connect'], text='FPGA FW Rev').place(relx=xr[3], rely=y0/sh.Win_Tabs_H) #x=xl[2], y=y0)
		Label(self.Mtabs['Connect'], text='uC FW Rev').place(relx=xr[4], rely=y0/sh.Win_Tabs_H) #x=xl[3], y=y0)

		x0 = 5
		y0 += 25
		ys = 27
		for b in sh.Boards:
			yb = y0 + b*ys
			if (self.conn_path[b].get() == ""):	self.BrdEnable[b].set(0)
			else: self.BrdEnable[b].set(1)
			self.brd_enable_cb.append(Checkbutton(self.Mtabs['Connect'], variable = self.BrdEnable[b], state=NORMAL))
			self.brd_enable_cb[b].place(relx=x0/sh.Win_Tabs_W, rely=(yb-3)/sh.Win_Tabs_H) #  x = x0, y = yb-3)
			Label(self.Mtabs['Connect'], text='%2s' % (str(b))).place(relx=35./sh.Win_Tabs_W, rely=yb/sh.Win_Tabs_H) #  x=35, y=yb)
			self.path_entry.append(Entry(self.Mtabs['Connect'], textvariable=self.conn_path[b]))  # , width=20+10
			self.path_entry[b].place(relx=xr[0], rely=yb/sh.Win_Tabs_H, relwidth=184/sh.Win_Tabs_W, relheight=0.039)  #  x = xl[0], y = yb)
			self.conn_path[b].trace('w', lambda name, index, mode, brd=b: self.update_conn_path(brd))
			self.BrdEnable[b].trace('w', lambda name, index, mode, brd=b: self.enable_conn_path(brd))
			if b > 0 and not self.BrdEnable[b].get(): 
				self.brd_enable_cb[b].config(state=DISABLED)
			
			self.info_pid.append(Label(self.Mtabs['Connect'], text="", anchor="w", relief = 'groove')) # , width = 10
			self.info_pid[b].place(relx=xr[1], rely=yb/sh.Win_Tabs_H, relwidth=60/sh.Win_Tabs_W, relheight=0.039) #  x=xl[1], y=yb)
			self.info_board_model.append(Label(self.Mtabs['Connect'], text="", anchor="w", relief = 'groove'))
			self.info_board_model[b].place(relx=xr[2], rely=yb/sh.Win_Tabs_H, relwidth=65/sh.Win_Tabs_W, relheight=0.039)
			self.info_fpga_fwrev.append(Label(self.Mtabs['Connect'], text="", anchor="w", relief = 'groove')) # , width = 20
			self.info_fpga_fwrev[b].place(relx=xr[3], rely=yb/sh.Win_Tabs_H, relwidth=126/sh.Win_Tabs_W, relheight=0.039) #x=xl[2], y=yb)
			self.info_uc_fwrev.append(Label(self.Mtabs['Connect'], text="", anchor="w", relief = 'groove')) # , width = 20
			self.info_uc_fwrev[b].place(relx=xr[4], rely=yb/sh.Win_Tabs_H, relwidth=136/sh.Win_Tabs_W, relheight=0.039) #)

		# ------------------------------------------------------------
		# Log
		# ------------------------------------------------------------
		x0 = 5
		self.Output = Text(self.Mtabs["Log"]) # , width=83, height=32
		self.Output.tag_configure('error', foreground='#FF0000')
		self.Output.tag_configure('warning', foreground='#FF8800')
		self.Output.tag_configure('normal', foreground='#000000')
		self.Output.tag_configure('empty', foreground='#CCBB00')
		self.Output.tag_configure('verbose', foreground='Violet')
		txt_width=0.975
		self.Output.place(relx=x0/sh.Win_Tabs_W, rely=5/sh.Win_Tabs_H, relwidth=txt_width, relheight=0.975) #  x=x0, y=5)
		scrollb = ttk.Scrollbar(self.Mtabs["Log"], orient='vertical', command=self.Output.yview)
		self.Output['yscrollcommand'] = scrollb.set
		scrollb.place(relx=txt_width, rely=5/sh.Win_Tabs_H, relheight=0.975)
		
		# ------------------------------------------------------------
		# Run Ctrl
		# ------------------------------------------------------------
		browse_button_outdir = Button(self.Mtabs["RunCtrl"], text='Browse', command=self.BrowseOutDir) # , width=14, height=1
		browse_button_outdir.place(relx=595/sh.Win_Tabs_W, rely=(ypos['DataFilePath']-3)/sh.Win_Tabs_H, relwidth=80/sh.Win_Tabs_W, relheight=0.049)  #  x=270, y=ypos['DataFilePath']-3)
		self.button_names["DataFilePath"] = [browse_button_outdir, 595/sh.Win_Tabs_W, (ypos['DataFilePath']-3)/sh.Win_Tabs_H, 80/sh.Win_Tabs_W, 0.049]

		# Reset Jobs
		# last_par_idx = list(params.keys()).index('OutputFiles') - 2
		# last_par_name = list(params.keys())[last_par_idx]
		# last_par_name = "EnableJobs" # DNIN: the button position made with list(paramkeys())[last_par_idx] was in conflict with the Set Coeff button in DataAcquisition.
		# self.reset_job = Button(self.GlbFrame["RunCtrl"], text="Reset Job", command=lambda:comm.SendCmd('j')) # New position is next to EnableJobs spinbox
		# self.reset_job.place(relx=10/sh.Win_Tabs_W, rely=(ypos[last_par_name])/sh.Win_Tabs_H, relwidth=109/sh.Win_Tabs_W, relheight=0.049)
		# self.button_names[last_par_name] = [self.reset_job, 170/sh.Win_Tabs_W, (196)/sh.Win_Tabs_H, 80/sh.Win_Tabs_W, 0.049]
		# Reset Jobs
		#last_col_idx = list(params.keys()).index("OutputFiles") - 2
		last_col_name = 'EnableJobs' #list(params.keys())[last_col_idx]
		reset_job = Button(self.Mtabs["RunCtrl"], text="Reset Job", command=lambda:comm.SendCmd('j'))
		reset_job.place(relx=140/sh.Win_Tabs_W, rely=(ypos[last_col_name]+50)/sh.Win_Tabs_H, relwidth=109/sh.Win_Tabs_W, relheight=0.049)
		self.button_names[last_col_name] = [reset_job, 170/sh.Win_Tabs_W, (ypos[last_col_name]+80)/sh.Win_Tabs_H, 80/sh.Win_Tabs_W, 0.049]
		tt.Tooltip(reset_job, text="Reset the Job. Active when jobs are enabled", wraplength=200)

		# ------------------------------------------------------------
		# Statistics
		# ------------------------------------------------------------
		# if '5202' in sh.Version:
		# 	self.smon_options = ['ChTrg Rate', 'ChTrg Cnt', 'Tstamp Rate', 'Tstamp cnt', 'PHA Rate', 'PHA Cnt']
		# else:
		# 	self.smon_options = ['Tstamp Rate', 'Tstamp cnt']
		# self.smon_type = StringVar()
		# self.smon_type.set(self.smon_options[0])

		maxbb = 0
		for i in range(sh.MaxBrd):
			if params['Open'].value[i] != "": maxbb += 1 
		self.ChCounts = []
		self.ChLabel = []
		y0 = 10
		ts = 85	
		self.StatsTypeLabel = Label(self.Mtabs["Statistics"], text = "", anchor="c", width = 18)
		self.StatsTypeLabel.place(relx=250/sh.Win_Tabs_W, rely=y0/sh.Win_Tabs_H) #  x = 250, y = y0)
		ttk.Checkbutton(self.Mtabs["Statistics"], text="All Boards Statistics", variable=self.change_statistics).place(relx=10/sh.Win_Tabs_W, rely=y0/sh.Win_Tabs_H) # x=10, y=y0)
		ttk.Checkbutton(self.Mtabs["Statistics"], text="Integral", variable=self.change_stat_integral).place(relx=140/sh.Win_Tabs_W, rely=y0/sh.Win_Tabs_H) 
		# Spinbox for TDC selection in the 128 chs version of 5203
		self.sTDClabel = Label(self.Mtabs["Statistics"], text = "TDC", font=("Arial", 12))
		self.sTDCbox = Spinbox(self.Mtabs["Statistics"], textvariable=self.ActiveTDC, command=self.ChangeTDC, from_=0, to=1, font=("Arial", 14), width=3)
		self.PlaceTDCs() # Call when 

		self.slabel = Label(self.Mtabs["Statistics"], text = "Brd", font=("Arial", 12))
		self.slabel.place(relx=(sh.Win_Tabs_W-100)/sh.Win_Tabs_W, rely=y0/sh.Win_Tabs_H)  #  x =  sh.Win_Tabs_W - 100, y = y0)
		self.sbox = Spinbox(self.Mtabs["Statistics"], textvariable=self.TmpActiveBrd, from_=0, to=sh.MaxBrd-1, font=("Arial", 14), width=3)
		self.sbox.place(relx=(sh.Win_Tabs_W-65)/sh.Win_Tabs_W, rely=y0/sh.Win_Tabs_H)  #  x = sh.Win_Tabs_W - 65, y = y0)
		y0 = y0 + 35
		for i in range(128): #sh.MaxCh):
			self.ChCounts.append(Label(self.Mtabs["Statistics"], width = 8, bg = 'White', font=("courier", 9), relief="groove"))
			self.ChLabel.append(Label(self.Mtabs["Statistics"], text=str(i),  font=("courier", 9), width = 2)) #anchor="e",
			if i > 63: continue # 
			self.ChCounts[i].place(relx=(21+ts*(i%8))/sh.Win_Tabs_W, rely=(y0+30*(int)(i/8))/sh.Win_Tabs_H)  #  x = 20 + ts * (i % 8), y = y0 + 30 * (int)(i / 8))
			self.ChLabel[i].place(relx=(ts*(i%8))/sh.Win_Tabs_W, rely=(y0+30*(int)(i/8))/sh.Win_Tabs_H)  #  x = ts * (i % 8), y = y0 + 30 * (int)(i / 8))

		# global statistics (will be dynamically created by the DAQ)
		self.Gstats_y0 = 300  # position
		self.GStatsLabel = []  # label
		self.GStats = []  # value

		# alternative all boards statistics
		new_leg = ["Brd", "TStamp(s)", "Trigger-ID", "TrgRate(KHz)", "LostTrg(%)", "EvtBuild(%)", "DtRate(MB/s)"] #  # DNIN: checking for width
		for i in range(len(new_leg)):
			self.AllBrdLabel.append(Label(self.Mtabs["Statistics"], text=new_leg[i], anchor = "c", justify=CENTER, bg="light gray", font=("courier", 9))) # width=12, 
		for i in sh.Boards:
			self.AllBrdCounts[str(i)] = [] 
			for j in range(len(new_leg)): 
				self.AllBrdCounts[str(i)].append(Label(self.Mtabs["Statistics"], width = 12, bg = 'White', font=("courier", 9), relief="groove"))

		if '5202' not in sh.Version: # Create the led for AF - DNIN: also in single board statistics the af-led should depend on each board
			y0 = sh.Win_StatBar_Y
			x0 = 637
			Label(parent, text="AF_Buff").place(relx=(x0-25)/sh.Win_W, rely=y0/sh.Win_H) #  x=x0, y = y0)
			x0 += 23
			self.afled = leds.Led(parent, 18)
			self.afled.rel_place(x0/sh.Win_W, y0/sh.Win_H)  #   place(x0, y0)
			self.afled.set_color(sh.OffCol)

			# Tooltips for Buffer LEDs
			ttips_descr = {
				"ROB": "TDC Readout Buffers, 1 per each channels group",
				"RPF": "FPGA Readout Port FIFO, 1 per each channels group",
				"TRGB": "TDC Trigger Buffer",
				"TRGF": "FPGA Trigger Fifo",
				"LSOF": "FPGA List Ouput FIFO",
				"HLOSS": "Data Loss to prevent LSOF overrun"
			}

			y0=self.Gstats_y0 + 30
			self.AF_dict['HLOSS'] = {
				'val':sh.OffCol, 
				'led':[leds.Led(self.Mtabs["Statistics"], 18)], 
				'label':Label(self.Mtabs["Statistics"], text="Data Loss", font=("Arial bold", 9), anchor='e'),
				'posled': [(0.87, (y0+15)/sh.Win_Tabs_H)],
				'poslabel': [0.84, (y0-2)/sh.Win_Tabs_H]
			}
			self.AF_dict['HLOSS']['led'][0].rel_place(self.AF_dict['HLOSS']['posled'][0][0], self.AF_dict['HLOSS']['posled'][0][1])
			self.AF_dict['HLOSS']['led'][0].set_color(self.AF_dict['HLOSS']['val'])
			self.AF_dict['HLOSS']['label'].place(relx=self.AF_dict['HLOSS']['poslabel'][0], rely=(y0-10)/sh.Win_Tabs_H)
			tt.Tooltip(self.AF_dict['HLOSS']['label'], text=ttips_descr['HLOSS'], wraplength=200)


			# y0+=40
			self.AF_dict['AFB'] = {
				'label': Label(self.Mtabs['Statistics'], text='Almost Full Buffers', font=("Arial bold", 9)),
				'poslabel': [0.62, 0.2]
			  }
			self.AF_dict['AFB']['label'].place(relx=0.62, rely=(y0-10)/sh.Win_Tabs_H)
			y0 += 15
			# TDC Buff: Ch Buff (directly on channels), ROBuff (4 per each TDC, 1 per ch group), TRGBuff (4, put 'em in OR)
			# FPGA Buff: RPF (4 per each TDC, 1 per ch group), LSOF. TRGF 

			for name in ["LSOF", "TRGF"]: #["TRGB", "LSOF", "TRGF"]:
				self.AF_dict[name]={
					'val':sh.OffCol, 
					'led':[leds.Led(self.Mtabs["Statistics"], 18)], 
					'label':Label(self.Mtabs["Statistics"], text="{}".format(name), anchor='e'),
					'posled': [(0.69, y0/sh.Win_Tabs_H)],
					'poslabel': [0.63, (y0-2)/sh.Win_Tabs_H]}
				self.AF_dict[name]['led'][0].rel_place(0.69, y0/sh.Win_Tabs_H)
				self.AF_dict[name]['led'][0].set_color(self.AF_dict[name]['val'])
				self.AF_dict[name]['label'].place(relx=0.63, rely=(y0-2)/sh.Win_Tabs_H, relwidth=0.05)
				tt.Tooltip(self.AF_dict[name]['label'], text=ttips_descr[name], wraplength=200)
				y0 += 22

			y0 += 44

			self.AF_dict['TDC0'] = {
				'label': Label(self.Mtabs["Statistics"], text="TDC0", font=("Arial Bold", 10)),
				'poslabel': [0.715, (y0-35)/sh.Win_Tabs_H]
			}
			self.AF_dict['TDC1'] = {
				'label': Label(self.Mtabs["Statistics"], text="TDC1", font=("Arial Bold", 10)),
				'poslabel': [0.715+0.12, (y0-35)/sh.Win_Tabs_H]
			}
			self.AF_dict['TDC0']['label'].place(relx=self.AF_dict['TDC0']['poslabel'][0], rely=self.AF_dict['TDC0']['poslabel'][1])
			self.AF_dict['TDC1']['label'].place(relx=self.AF_dict['TDC1']['poslabel'][0], rely=self.AF_dict['TDC1']['poslabel'][1])
			
			for name in ["ROB", "RPF"]:
				if name == "ROB": 
					self.AF_dict['CHGRP'] = {
						'label': Label(self.Mtabs["Statistics"], text="Ch Group:", font=("Arial Bold", 7)), 
						'poslabel': [0.62, (y0-15)/sh.Win_Tabs_H]
					}
					self.AF_dict['CHGRP']['label'].place(relx = 0.62, rely = (y0-15)/sh.Win_Tabs_H)

				self.AF_dict[name]={
					'val':sh.OffCol, 
					'led':[], 
					'label':Label(self.Mtabs["Statistics"], text="{}".format(name), anchor='e'),
					'posled': [],
					'poslabel': [0.63,(y0-2)/sh.Win_Tabs_H]
				}
				for i in range(8):
					if name == "ROB": 
						self.AF_dict[f"GR{i}"] = {
							'label': Label(self.Mtabs["Statistics"], text=f"{i%4}", font=("Bold", 7)),  # Group index
							'poslabel': [0.695+0.03*i+0.01*(int(i/4)), (y0-15)/sh.Win_Tabs_H]
						}
						self.AF_dict[f"GR{i}"]['label'].place(relx = 0.695+0.03*i+0.01*(int(i/4)), rely = (y0-15)/sh.Win_Tabs_H)

					self.AF_dict[name]['led'].append(leds.Led(self.Mtabs["Statistics"], 18))
					self.AF_dict[name]['led'][i].rel_place(0.69+0.03*i+0.01*(int(i/4)), (y0+1)/sh.Win_Tabs_H)
					self.AF_dict[name]['led'][i].set_color(self.AF_dict[name]['val'])
					self.AF_dict[name]['posled'].append((0.69+0.03*i+0.01*(int(i/4)), (y0+1)/sh.Win_Tabs_H))

				self.AF_dict[name]['label'].place(relx=0.63, rely=(y0-2)/sh.Win_Tabs_H, relwidth=0.05)
				tt.Tooltip(self.AF_dict[name]['label'], text=ttips_descr[name], wraplength=200)
				y0 += 22

			# for name in ['led0', 'led1', 'led2']: # In case to show 
			# 	self.AF_dict_allbrd[name] = {'led': leds.Led(self.Mtabs['Statistics'], 10)}	
			# 	self.AF_dict_allbrd[name]['led'].set_color('grey')			
	
		# ttk.Combobox(self.Mtabs["Statistics"], values=self.smon_options, textvariable=self.smon_type, state='readonly').place(relx=0.43, rely=0.02, relwidth=110./sh.Win_W, relheight=26./sh.Win_H)
		# ------------------------------------------------------------
		# AcqMode
		# ------------------------------------------------------------
		self.maskch = {}
		self.maskch[0] = [Button(self.BrdTabs["AcqMode"][i], text='CHANNEL MASK TDC0', command=lambda:self.OpenMask("CHANNEL MASK TDC0", "AcqMode", "ChEnableMask0"), width=14, height=2) for i in range(sh.MaxBrd)]
		#self.maskch[0].place(relx=380/sh.Win_Tabs_W, rely=ypos['ChEnableMask0']/sh.Win_Tabs_H, relwidth=129/sh.Win_Tabs_W, relheight=0.08) # x = 380, y = ypos['ChEnableMask0'])
		self.button_names["ChEnableMask0"] = [self.maskch[0], 210/sh.Win_Tabs_W, ypos['ChEnableMask0']/sh.Win_Tabs_H, 210/sh.Win_Tabs_W, 0.08]

		self.maskch[1] = [Button(self.BrdTabs["AcqMode"][i], text='CHANNEL MASK TDC1', command=lambda:self.OpenMask("CHANNEL MASK TDC1", "AcqMode", "ChEnableMask2"), width=14, height=2) for i in range(sh.MaxBrd)]
		#self.maskch[1].place(relx=380/sh.Win_Tabs_W, rely=ypos['ChEnableMask0']/sh.Win_Tabs_H, relwidth=129/sh.Win_Tabs_W, relheight=0.08) # x = 380, y = ypos['ChEnableMask0'])
		self.button_names["ChEnableMask2"] = [self.maskch[1], 210/sh.Win_Tabs_W, ypos['ChEnableMask2']/sh.Win_Tabs_H, 210/sh.Win_Tabs_W, 0.08]

		# ------------------------------------------------------------
		# Histogram/DataAnalysis
		# ------------------------------------------------------------
		if '5202' not in sh.Version:
			self.button_names["WalkFitCoeff"] = [Button(self.Mtabs[self.tname], text='Set Coeff', command=self.Set_WalkFitCoeff), 140/sh.Win_Tabs_W + 0.175, ypos['WalkFitCoeff']/sh.Win_Tabs_H, 90/sh.Win_Tabs_W, 0.049]
			self.button_names["WalkFitCoeff"][0].place(relx=140/sh.Win_Tabs_W + 0.175, rely=ypos['WalkFitCoeff']/sh.Win_Tabs_H, relwidth=90/sh.Win_Tabs_W, relheight=0.049)


		# Max value depends on LSB, Min and bin# Can be moved up with the param definition?
		if '5202' not in sh.Version:
			self.rangeval["LeadTrailFRange"] = Label(self.Mtabs[self.tname], text="Lead/Trail Full Range")
			self.rangeval["ToTFRange"] = Label(self.Mtabs[self.tname], text="ToT Full Range")
			self.rangeval["LeadTrailGate"] = Label(self.Mtabs[self.tname], text="Lead/Trail Acq Gate Width")
			self.rangeval["ToTGate"] = Label(self.Mtabs[self.tname], text="ToT Acq Gate Width")
			self.rangeval["LeadMax"] = Label(self.Mtabs[self.tname], text="Lead Histo Max")
			self.rangeval["TrailMax"] = Label(self.Mtabs[self.tname], text="Trail Max")
			self.rangeval["ToTMax"] = Label(self.Mtabs[self.tname], text="ToT Histo Max")
			self.rangeval["LeadTrail_LSB"] = Label(self.Mtabs[self.tname], text="", bg='white', anchor='w')
			self.rangeval["ToT_LSB"] = Label(self.Mtabs[self.tname], text="", bg='white', anchor='w')
			self.rangeval["LeadTrailGateVal"] = Label(self.Mtabs[self.tname], text="", bg='white', anchor='w')
			self.rangeval["ToTGateVal"] = Label(self.Mtabs[self.tname], text="", bg='white', anchor='w')
			self.rangeval["LeadMaxVal"] = Label(self.Mtabs[self.tname], text="", bg='white', anchor='w')
			self.rangeval["TrailMaxVal"] = Label(self.Mtabs[self.tname], text="", bg='white', anchor='w')			
			self.rangeval["ToTMaxVal"] = Label(self.Mtabs[self.tname], text="", bg='white', anchor='w')

			self.rangeval["LeadTrailFRange"].place(relx=140/sh.Win_Tabs_W + 0.17, rely=70/sh.Win_Tabs_H)
			self.rangeval["LeadTrail_LSB"].place(relx=140/sh.Win_Tabs_W + 0.175, rely=(95+25*2)/sh.Win_Tabs_H, relwidth=0.12)
			self.rangeval["ToT_LSB"].place(relx=140/sh.Win_Tabs_W + 0.175, rely=(120+25*2)/sh.Win_Tabs_H, relwidth=0.12)

			tt.Tooltip(self.rangeval["LeadTrail_LSB"], text="Dynamic range for ToA", wraplength=200)
			tt.Tooltip(self.rangeval["ToT_LSB"], text="Dynamic range for ToT", wraplength=200)
			self.write_time_val("LeadTrail_LSB")
			self.write_time_val("ToT_LSB")
			self.update_acq_time_val("LeadTrailbin")
			self.update_acq_time_val("LeadMin")
			self.update_acq_time_val("TrailMin")
			self.update_acq_time_val("ToTbin")
			self.update_acq_time_val("ToTMin")

		# ------------------------------------------------------------
		# TDC
		# ------------------------------------------------------------
		if '5202' not in sh.Version:
			self.TDC0Temp = [0 for i in sh.Boards]
			self.TDC1Temp = [0 for i in sh.Boards]
			self.PICTemp  = [0 for i in sh.Boards]
			self.FPGATemp = [0 for i in sh.Boards]
			for brd in sh.Boards:	
				ym = 300
				y0 = ym
				x0 = 15
				xs = 130 # 80
				btab = self.BrdTabs["TDC"][brd]
				Label(btab, text='TDC0 Temp').place(relx=x0/sh.Win_Tabs_W, rely=(y0*14.1/13.1)/sh.Win_Tabs_H)  # x=x0, y=y0)
				self.TDC0Temp[brd] = Label(btab, width = 14, relief='groove')
				self.TDC0Temp[brd].place(relx=(x0+xs)/sh.Win_Tabs_W, rely=(y0*14.1/13.1)/sh.Win_Tabs_H, relwidth=169/sh.Win_Tabs_W, relheight=0.044)
				y0 += 25
				Label(btab, text='TDC1 Temp').place(relx=x0/sh.Win_Tabs_W, rely=(y0*14.1/13.1)/sh.Win_Tabs_H)  # x=x0, y=y0)
				self.TDC1Temp[brd] = Label(btab, width = 14, relief='groove')
				self.TDC1Temp[brd].place(relx=(x0+xs)/sh.Win_Tabs_W, rely=(y0*14.1/13.1)/sh.Win_Tabs_H, relwidth=169/sh.Win_Tabs_W, relheight=0.044)
				y0 += 25
				Label(btab, text='PIC Temp').place(relx=x0/sh.Win_Tabs_W, rely=(y0*14.1/13.1)/sh.Win_Tabs_H)  # x=x0, y=y0)
				self.PICTemp[brd] = Label(btab, width = 14, relief='groove')
				self.PICTemp[brd].place(relx=(x0+xs)/sh.Win_Tabs_W, rely=(y0*14.1/13.1)/sh.Win_Tabs_H, relwidth=169/sh.Win_Tabs_W, relheight=0.044)
				y0 += 25
				Label(btab, text='FPGA Temp').place(relx=x0/sh.Win_Tabs_W, rely=(y0*14.1/13.1)/sh.Win_Tabs_H)  # x=x0, y=y0)
				self.FPGATemp[brd] = Label(btab, width = 14, relief='groove')
				self.FPGATemp[brd].place(relx=(x0+xs)/sh.Win_Tabs_W, rely=(y0*14.1/13.1)/sh.Win_Tabs_H, relwidth=169/sh.Win_Tabs_W, relheight=0.044)


		# ------------------------------------------------------------
		# Adapters
		# ------------------------------------------------------------
		ybutt = list(ypos.values())[-1]+85
		Label(self.GlbTab["Adapters"], text="Calib Brd", font=("Arial", 12)).place(relx=3/sh.Win_Tabs_W, rely=(ybutt)/sh.Win_Tabs_H)
		self.adapter_brd = [Spinbox(self.GlbTab["Adapters"], text="Calib Brd", textvariable=self.TmpActiveBrd, from_=0, to=sh.MaxBrd-1, state='readonly', font=("Arial", 14)), 
					  80/sh.Win_Tabs_W, (ybutt)/sh.Win_Tabs_H, 45/sh.Win_Tabs_W, 0.049]
		self.adapter_calib = [Button(self.GlbTab["Adapters"], text="Calibration", command=lambda:comm.SendCmd("T{}".format(self.TmpActiveBrd.get()))), 
						145/sh.Win_Tabs_W, (ybutt-1)/sh.Win_Tabs_H, 90/sh.Win_Tabs_W, 0.049]
		self.adapter_brd[0].place(relx=self.adapter_brd[1], rely=self.adapter_brd[2], relwidth=self.adapter_brd[3], relheight=self.adapter_brd[4])
		self.adapter_calib[0].place(relx=self.adapter_calib[1], rely=self.adapter_calib[2], relwidth=self.adapter_calib[3], relheight=self.adapter_calib[4])
		tt.Tooltip(self.adapter_calib[0], text="Calibrate A5256 Discriminator Thresholds. Active when an A5256 adapter is selected", wraplength=200)

		# ------------------------------------------------------------
		# Regs
		# ------------------------------------------------------------
		x0 = 10 
		y0 = 20
		self.reg_base = StringVar()
		self.reg_ch   = StringVar()
		self.reg_offs = StringVar()
		self.reg_addr = StringVar()
		self.reg_data = StringVar()
		self.cmd      = StringVar()

		Radiobutton(self.Mtabs["Regs"], text = 'COMM', variable = self.reg_base, value = '01').place(relx=x0/sh.Win_Tabs_W, rely=y0/sh.Win_Tabs_H) #  x = x0, y = y0)
		Radiobutton(self.Mtabs["Regs"], text = 'INDIV', variable = self.reg_base, value = '02').place(relx=(x0+80)/sh.Win_Tabs_W, rely=y0/sh.Win_Tabs_H) # x = x0+80, y = y0)
		Radiobutton(self.Mtabs["Regs"], text = 'BCAST', variable = self.reg_base, value = '03').place(relx=(x0+160)/sh.Win_Tabs_W, rely=y0/sh.Win_Tabs_H) # x = x0+160, y = y0)
		self.reg_base.set('01')
		self.reg_base.trace('w', lambda name, index, mode: self.set_reg_addr())
		self.reg_ch.set(0)
		self.reg_ch.trace('w', lambda name, index, mode: self.set_reg_addr())
		vcmdch = (parent.register(self.validate_ch), '%P')
		Label(self.Mtabs["Regs"], text = "Ch", font=("Arial", 12)).place(relx=(x0+243)/sh.Win_Tabs_W, rely=y0/sh.Win_Tabs_H) #  x =  x0 + 243, y = y0)
		Spinbox(self.Mtabs["Regs"], textvariable=self.reg_ch, from_=0, to=63, font=("Arial", 14), validate='key', validatecommand=vcmdch, width=3).place(relx=(x0+270)/sh.Win_Tabs_W, rely=y0/sh.Win_Tabs_H) # x = x0 + 270, y = y0)
		Label(self.Mtabs["Regs"], text = "Brd", font=("Arial", 12)).place(relx=(x0+349)/sh.Win_Tabs_W, rely=y0/sh.Win_Tabs_H) # x = x0 + 349, y = y0)
		Spinbox(self.Mtabs["Regs"], textvariable=self.ActiveBrd, from_=0, to=sh.MaxBrd-1, font=("Arial", 14), state='readonly', width=3).place(relx=(x0+380)/sh.Win_Tabs_W, rely=y0/sh.Win_Tabs_H) # x = x0 + 380, y = y0)
	
		y0 = y0 + 30
		self.reg_offs.set('0000')
		self.reg_offs.trace('w', lambda name, index, mode: self.set_reg_addr())
		Label(self.Mtabs["Regs"], text="Offset").place(relx=x0/sh.Win_Tabs_W, rely=y0/sh.Win_Tabs_H)  #  x = x0, y = y0), width=12
		Entry(self.Mtabs["Regs"], textvariable=self.reg_offs).place(relx=(x0+60)/sh.Win_Tabs_W, rely=y0/sh.Win_Tabs_H, relwidth=76/sh.Win_Tabs_W, relheight=0.035)  #  x = x0+60, y = y0)
		y0 = y0 + 20
		self.reg_addr.set("01000000")
		Label(self.Mtabs["Regs"], text="Address").place(relx=x0/sh.Win_Tabs_W, rely=y0/sh.Win_Tabs_H)  # x = x0, y = y0)
		Entry(self.Mtabs["Regs"], textvariable=self.reg_addr, width=12).place(relx=(x0+60)/sh.Win_Tabs_W, rely=y0/sh.Win_Tabs_H, relwidth=76/sh.Win_Tabs_W, relheight=0.035)  #  x = x0+60, y = y0)
		y0 = y0 + 20
		self.reg_data.set('00000000')
		Label(self.Mtabs["Regs"], text="Data").place(relx=x0/sh.Win_Tabs_W, rely=y0/sh.Win_Tabs_H)  #   x = x0, y = y0), width=12
		Entry(self.Mtabs["Regs"], textvariable=self.reg_data).place(relx=(x0+60)/sh.Win_Tabs_W, rely=y0/sh.Win_Tabs_H, relwidth=76/sh.Win_Tabs_W, relheight=0.035)  #  x = x0+60, y = y0)
		y0 = y0 + 20
		self.cmd.set('14')
		Label(self.Mtabs["Regs"], text="Cmd").place(relx=x0/sh.Win_Tabs_W, rely=y0/sh.Win_Tabs_H)  #   x = x0, y = y0), width=12
		Entry(self.Mtabs["Regs"], textvariable=self.cmd).place(relx=(x0+60)/sh.Win_Tabs_W, rely=y0/sh.Win_Tabs_H, relwidth=76/sh.Win_Tabs_W, relheight=0.035)  #  x = x0+60, y = y0)
		y0 = y0 + 30
		Button(self.Mtabs["Regs"], text='Read',	command=self.read_reg, width= 12).place(relx=x0/sh.Win_Tabs_W, rely=y0/sh.Win_Tabs_H, relwidth=93/sh.Win_Tabs_W, relheight=0.05)  #   x=x0, y=y0)
		Button(self.Mtabs["Regs"], text='Write',command=self.write_reg, width= 12).place(relx=(x0+100)/sh.Win_Tabs_W, rely=y0/sh.Win_Tabs_H, relwidth=93/sh.Win_Tabs_W, relheight=0.05)  #  x=x0+100, y=y0)
		Button(self.Mtabs["Regs"], text='Send Cmd',command=self.send_cmd, width= 12).place(relx=(x0+200)/sh.Win_Tabs_W, rely=y0/sh.Win_Tabs_H, relwidth=93/sh.Win_Tabs_W, relheight=0.05)  #  x=x0+200, y=y0)

		self.RWregLog = Text(self.Mtabs["Regs"]) # , width=83, height=20
		self.RWregLog.place(relx=5/sh.Win_Tabs_W, rely=190/sh.Win_Tabs_H, relwidth=0.984, relheight=0.61)  #  x=5, y=190)

		# *******************************************************************************************
		# Save Additional Widget button - ypos is not used anymore
		# self.button_names = {"DataFilePath" : [self.browse_button_outdir, 580/sh.Win_Tabs_W, (ypos['DataFilePath']-3)/sh.Win_Tabs_H, 90/sh.Win_Tabs_W, 0.049], 
		# 					"ChEnableMask0" : [self.maskch, 380/sh.Win_Tabs_W, ypos['ChEnableMask0']/sh.Win_Tabs_H, 109/sh.Win_Tabs_W, 0.08], 
		# 					"Q_DiscrMask0" : [self.maskqd, 380/sh.Win_Tabs_W, ypos['Q_DiscrMask0']/sh.Win_Tabs_H, 109/sh.Win_Tabs_W, 0.08], 
		# 					"Tlogic_Mask0" : [self.masktd, 380/sh.Win_Tabs_W, ypos['Tlogic_Mask0']/sh.Win_Tabs_H, 109/sh.Win_Tabs_W, 0.08]}
		# *******************************************************************************************

		# **************************************************************************
		# Load the options for parameters affected by the GUI hide parameters file
		# **************************************************************************
		with open(sh.GUIParamOptions, "r") as f:
			self.new_options = json.load(f)
		# Add param type
		for parname in self.new_options.keys():
			self.new_options[parname]['type'] = params[parname].type

		self.StopUpdate = False


	# ***************************************************************************************
	# Modify the time val
	def write_dynamic_range(self, name):
		"""
		Update the dynamic range of the ToA (Delta T) and Tot
		and update the max value of timing histograms
		"""
		HTrail = self.par_def_svar["En_Head_Trail"].get()  # One word trailer needs 2 bit to decoding
		if HTrail == "ONE_WORD": num = 0
		else: num = 2
		try:
			totbit = 0
			mbit = {}
			if "8" in self.par_def_svar["MeasMode"].get(): 
				mbit = {"LeadTrail_LSB": 17+num, "ToT_LSB": 8}   # totbit = 7
			elif "11" in self.par_def_svar["MeasMode"].get(): # totbit = 10
				mbit = {"LeadTrail_LSB": 14+num, "ToT_LSB": 11}
			elif 'TRAIL' in self.par_def_svar['MeasMode'].get():
				mbit = {"LeadTrail_LSB": 24+num, "ToT_LSB": 16}
			else:
				mbit = {"LeadTrail_LSB": 24+num, "ToT_LSB": 0}
			
			# 3.125* 2**NTOTBIN * 2**LSB_VAL
			# In LEAD ONLY mode, the LSB is always the minimum, 3.125 ps
			if "LEAD_ONLY" not in self.par_def_svar["MeasMode"].get() and "TOT" in str(name).upper(): tmax = 2**mbit[name] * 3.125 * 2**int(self.par_def_svar[name].get()) # 'TOT' in
			elif 'TOT' in self.par_def_svar["MeasMode"].get(): tmax = 2**mbit[name] * 3.125 * 2**int(self.par_def_svar[name].get())
			else: tmax = 2**mbit[name] * 3.125
			# if totbit: tmax = 2**mbit[name] * 3.125 * 2**int(self.par_def_svar[name].get())
			# 	# try: tmax = 3.125 * 2**int(self.par_def_svar[name].get())
			# else: tmax = 2**mbit[name] * 3.125 * 2**int(self.par_def_svar[name].get())
			unit, tmax = sh.get_timeunit(tmax)
			self.rangeval[name]['text'] = "{:.4f} {}".format(tmax, unit)				
		except:
			pass


	def write_time_val(self, name):
		unit = 'ps'
		try:
			if not self.par_def_svar[name].get().isdigit(): 
				self.timeval[name]['text'] = "{} ps".format(3.125)
				self.write_dynamic_range(name)
				return
			val = 3.125 * 2**int(self.par_def_svar[name].get())
			if val > 1000: 
				val /= 1000
				unit = 'ns'
			self.timeval[name]['text'] = "{} {}".format(val, unit)
			self.write_dynamic_range(name)
		except:
			return


		# if not self.par_def_svar['ToT_LSB'].get().isdigit(): return
		# val = 3.125 * 2**int(self.par_def_svar['ToT_LSB'].get())
		# self.timeval['ToT_LSB']['text'] = "{} ps".format(val)

	def write_acq_range(self, name):
		opt = {'256':256, '512':512,'1K':1024, '2K':2048, '4K':4096, '8K':8192, '16K':16384}
		if 'Lead' in name: name = 'LeadTrail'
		else: name = 'ToT'
		rename = {
			'LeadTrail': ['LeadTrailGateVal', 'LeadTrail_LSB', 'LeadTrailHistoNbin', 'LeadTrailRebin'], 
			'ToT': ['ToTGateVal', 'ToT_LSB', 'ToTHistoNbin', 'ToTRebin']
		}
		unit = 'ps'
		try:
			if 'DISABLED' in self.par_def_svar[rename[name][2]].get(): 
				self.rangeval[rename[name][0]]['text'] = '0 ps'
				return
			if self.par_def_svar[rename[name][2]].get() not in opt.keys():
				return
			lsb_in_ps = sh.get_time_from_unit(self.timeval[rename[name][1]]['text'])
			acq_range = opt[self.par_def_svar[rename[name][2]].get()]*lsb_in_ps*int(self.par_def_svar[rename[name][3]].get())  # float(self.timeval[rename[name][1]]['text'].split(' ')[0])
			unit, acq_range = sh.get_timeunit(acq_range)
			self.rangeval[rename[name][0]]['text'] = '{:.4f} {}'.format(acq_range, unit)
		except: 
			return

		# self.rangeval[rename[name][0]].text('{} {}'.format(acq_range, unit))

	def write_time_max(self, name):
		opt = {'1k':1e3, '2K':2e3, '4k':4e3, '8K':8e3, '16K':16e3}
		tmax = 0
		if 'Lead' in name: 
			name = 'Lead'
			self.write_time_max('Trail')
		elif 'ToT' in name: name = 'ToT'
		else: name = 'Trail'
		rename = {
			'Lead': ['LeadMaxVal', 'LeadTrailGateVal', 'LeadHistoMin', 'LeadTrail_LSB'], 
			'Trail': ['TrailMaxVal', 'LeadTrailGateVal', 'TrailHistoMin', 'LeadTrail_LSB'],
			'ToT': ['ToTMaxVal', 'ToTGateVal', 'ToTHistoMin', 'ToT_LSB']}
		unit = 'ps'
		try: 
			acq_gate_in_ps = sh.get_time_from_unit(self.rangeval[rename[name][1]]['text'])
			if acq_gate_in_ps == 0: # Histogram disabled
				self.rangeval[rename[name][0]]['text'] = '-'
				return
			# lsb_in_ps = self.get_time_from_unit(self.timeval[rename[name][3]]['text'])
			try: min_in_ps = sh.get_time_from_unit(self.par_def_svar[rename[name][2]].get())
			except: min_in_ps = float(self.par_def_svar[rename[name][2]].get())*1000	# DNIN: Is this correct?
			tmax = min_in_ps + acq_gate_in_ps  # float(self.par_def_svar[rename[name][2]].get())*lsb_in_ps + acq_gate_in_ps 
		except: return
		unit, tmax = sh.get_timeunit(tmax)
		self.rangeval[rename[name][0]]['text'] = ('{:.4f} {}'.format(tmax, unit))

	def update_acq_time_val(self, name):
		if 'LSB' in name:
			self.write_time_val(name)
			self.write_acq_range(name)
			self.write_time_max(name)
		elif 'bin' in name:
			self.write_acq_range(name)
			self.write_time_max(name)
		elif 'Min' in name:
			self.write_time_max(name)


	# ***************************************************************************************
	# Write log tabs
	# ***************************************************************************************
	def set_output_log(self, text, option='normal'):
		self.Output['state'] = NORMAL
		self.Output.insert(END, text, option)
		self.Output.yview_scroll(100, UNITS)
		self.Output['state'] = DISABLED

	# ***************************************************************************************
	# Update params
	# ***************************************************************************************
	def scale_ped_zs(self, param):	# scale the ZS and pedestal value according to the Ebin used
		shiftfact = {
					'8K': 1,
					'4K': 2,
					'2K': 4,
					'1K': 8,
					'512': 16,
					'256': 32
				}
		rf_HV = re.compile(r"^\d*\.?\d{0,10}$")	# float positive
		val_to_scale = ['Pedestal', 'ZS_Threshold_LG', 'ZS_Threshold_HG']
		# compact the code
		try:	# remove the .0's
			ff = float(shiftfact[param.default]/shiftfact[self.par_def_svar[param.name].get()])
		except:
			ff = 1

		to_scale = [names for names in val_to_scale if rf_HV.search(self.par_def_svar[names].get())]
		tvalt = [str(float(self.par_def_svar[names].get())*ff) for names in to_scale]
		tval = [tv.split('.')[0] if tv.split(".")[1] == '0' else tv for tv in tvalt]
		[self.par_def_svar[to_scale[i]].set(tval[i]) for i in range(len(to_scale))] 
		
		list_not_zero = {}
		for names in val_to_scale[1:]:
			list_not_zero[names] = [(i,j) for i in range(sh.MaxBrd) for j in range(sh.MaxCh) 
					if self.par_ch_svar[names][i][j].get() != "" and rf_HV.search(self.par_ch_svar[names][i][j].get())]
			isfloat = [str(float(self.par_ch_svar[names][a[0]][a[1]].get())*ff) for a in list_not_zero[names]]
			tval = [isf.split('.')[0] if isf.split(".")[1] == '0' else isf for isf in isfloat]
			[self.par_ch_svar[names][list_not_zero[names][i][0]][list_not_zero[names][i][1]].set(tval[i]) for i in range(len(list_not_zero[names]))]

	def isChanged(self, param, myval):
		if myval != param.default:
			return True
		else:
			return False
	
	def exadec_val(self, param):
		r = re.compile("[a-f0-9]", re.IGNORECASE)
		self.par_def_svar[param.name].set("0x" + (''.join(r.findall(self.par_def_svar[param.name].get()[2:10]))).upper())
		# if len(self.par_def_svar[param.name].get()) == 2: self.par_def_svar[param.name].set("0x0")
		return self.isChanged(param, self.par_def_svar[param.name].get())


	def set_units(self, prev_unit, upd_unit):	
		prev_unit = str(prev_unit)
		units = {}
		# if prev_unit == "m":
		# 	return prev_unit

		unit = ["second", "volt", "ampere"]
		units[unit[0]] = ["s", "ms", "us", "ns"]
		units[unit[1]] = ["V", "mV", "uV", "nV"]
		units[unit[2]] = ["A", "mA", "uA", "nA"]
		
		for u in unit:
			if prev_unit in units[u]:
				if len(upd_unit)>2:	# 3 letters: ending with the correct unit
					upd_unit = upd_unit[0] + upd_unit[units[u].index(units[u][0])]
				if upd_unit in units[u]: return upd_unit
				else: return prev_unit
		
		return upd_unit
			
	
	def val_with_unit(self, param):
		if len(self.par_def_svar[param.name].get().split(" ")) > 2:
			self.par_def_svar[param.name].set(param.default)
		if len(self.par_def_svar[param.name].get().split(" ")) > 1 and len(param.type) == 1:
			self.par_def_svar[param.name].set(param.default)

		mynum = self.par_def_svar[param.name].get().split(" ")[0]
		res = self.val_no_unit(param, mynum)	
		if len(param.type) == 2:	# process also the unit
			try:
				myunit = self.par_def_svar[param.name].get().split(" ")[1]	
				prev_unit = param.default.split(" ")[1]
				myunit = self.set_units(prev_unit, myunit)
				valtoset = res + " " + myunit	# param.default.split(" ")[1]
			except:
				valtoset = res + " "
		else: valtoset = res
		self.par_def_svar[param.name].set(valtoset)
		return  self.isChanged(param, valtoset)

	def remove_one_dot(self, param, tmpval, maxval, len_int=5, len_dec=14):
		old_pos = int(param.default.find('.'))	# remove the new dot 
		if tmpval[old_pos] != '.': return self.manage_float_format(param, (tmpval[::-1].replace('.', '', 1))[::-1], maxval, len_int, len_dec)
		else: return self.manage_float_format(param, tmpval.replace('.', '', 1), maxval, len_int, len_dec)

	def manage_float_format(self, param, tmpval, maxval, len_int=5, len_dec=14):	
		# tmp_pos = tmpval.find('.')
		if len(tmpval) < 3: return tmpval 	
		if abs(float(tmpval)) < maxval: return tmpval 	# control that is below the maximum
		else: return param.default.split(" ")[0]
		
	def val_no_unit(self, param, tmp_val):
		len_int = 5
		len_dec = 14
		max_val = 9999999999999999999999999
		# the length of the decimal part is defined here. No further control is applied
		# rd = re.compile("^-?\d{0,6}$")	# int pos/neg
		rf = re.compile(r"^-?\d*\.?\d{0,10}$")	# float pos/neg
		rd_HV = re.compile(r"^\d{0,10}$")	# int positive
		rf_HV = re.compile(r"^\d*\.?\d{0,10}$")	# float positive
		
		if param.name == "HV_Vbias": r1 = rf_HV		# HV and DAC step are defined positive
		elif param.name == "HV_IndivAdj": r1 = rd_HV
		#elif param.type == "d": r1 = rd
		else: r1 = rf

		tmp_val = str(tmp_val)
		if r1.match(tmp_val): return self.manage_float_format(param, tmp_val, max_val, len_int, len_dec)
		elif tmp_val.count('.') > 1: return self.remove_one_dot(param, tmp_val, max_val, len_int, len_dec)
		else: return param.default.split(" ")[0]

	def real_update_param(self, param):
		param.default = self.par_def_svar[param.name].get()
		if '5202' in sh.Version: self.UpdateVnom()
		self.CfgChanged.set(1)

	def update_def_param(self, param):
		if self.StopUpdate: return

		if "En_Head_Trail" in param.name:
			for pname in self.LSB_param:
				self.write_time_val(pname)
			# self.write_time_val("LeadTrail_LSB")
			# self.write_time_val("ToT_LSB")
			self.real_update_param(param)		
		elif 'Lead' in param.name or 'ToT' in param.name or 'Trail' in param.name:
			if param.type[0] != 'c': self.val_with_unit(param) 
			self.update_acq_time_val(param.name)
			self.real_update_param(param)
		elif param.name == "PresetTime": self.real_update_param(param)
		# elif param.name == "EHistoNbin": # DNIN may it is not needed since it is implemented similarly in paramparser.c
		# 	self.scale_ped_zs(param)
		# 	self.real_update_param(param)
		elif param.type[0] == 'd' or param.type[0] == 'f': # or param.type == 'u':
			if self.val_with_unit(param): self.real_update_param(param)
		elif param.type == 'h': 
			if self.exadec_val(param): self.real_update_param(param)
		elif param.type == 'x' and '5202' not in sh.Version: 
			# self.write_time_val(param.name)
			self.update_acq_time_val(param.name)
			self.real_update_param(param)
		elif param.name == "MeasMode" and '5202' not in sh.Version:
			# if 'TRAIL' in self.par_def_svar[param.name].get(): self.par_def_spinbox['ToT_LSB']['to'] = 8
			# else: self.par_def_spinbox['ToT_LSB']['to'] = params['ToT_LSB'].options[1]
			for pname in self.LSB_param:
				self.write_time_val(pname)
			# self.write_time_val("LeadTrail_LSB")
			# self.write_time_val("ToT_LSB")
			self.real_update_param(param)		
		else:
			self.real_update_param(param)

#	def update_def_param(self, param):
#		if self.StopUpdate: return
#		param.default = self.par_def_svar[param.name].get()
#		self.UpdateVnom()
#		self.CfgChanged.set(1)

	######################################################################
	# These controls prevent the GUI to crash
	######################################################################
	def set_Vbias(self, param, brd):	# should be integrated with the regex for default values
		tmpval = self.par_brd_svar[param.name][brd].get()
		rf_HV = re.compile(r"^\d*\.?\d{0,10}$")	# float positive
		if rf_HV.search(tmpval) or param.name != "HV_Vbias": # Trasparent if the format is correct or it is not HV_Vbias
			param.value[brd] = tmpval
			return 1
		elif tmpval.count('.') > 1: 
			old_pos = int(param.value[brd].find('.'))	# remove the new dot 
			if tmpval[old_pos] != '.': param.value[brd] = tmpval[::-1].replace('.', '', 1)[::-1]
			else: param.value[brd] = tmpval.replace('.', '', 1)
			self.par_brd_svar[param.name][brd].set(param.value[brd])
			return 0
		else: 
			self.par_brd_svar[param.name][brd].set(param.value[brd])
			return 0		

	def set_HVIndAdj(self, param, brd, ch):
		tmpval = self.par_ch_svar[param.name][brd][ch].get()
		rd_HV = re.compile(r"^\d{0,10}$")	# int positive
		if rd_HV.search(tmpval) or param.name != "HV_IndivAdj": 
			param.value[brd][ch] = tmpval
			return 1
		else:
			self.par_ch_svar[param.name][brd][ch].set(param.value[brd][ch]) 
			return 0
	#######################################################################
	#######################################################################
	#######################################################################

	def update_brd_param(self, param, brd):	# to DO
		if self.StopUpdate: return
		if (param.distr == 'b'): # Is not obviously?
			# if "5202" not in sh.Version: self.CfgChanged.set(1)
			if(self.set_Vbias(param, brd)):
				# self.UpdateVnom()
				self.CfgChanged.set(1)	

	def update_ch_param(self, param, brd, ch):	# to DO
		if self.StopUpdate: return
		if (param.distr == 'c'): # Is not obviously?
			# if "5202" not in sh.Version: self.CfgChanged.set(1)
			if(self.set_HVIndAdj(param, brd, ch)):
				# self.UpdateVnom()
				self.CfgChanged.set(1)
		# 	param.value[brd][ch] = self.set_HVIndAdj(param, brd, ch)
		# 	# param.value[brd][ch] = self.par_ch_svar[param.name][brd][ch].get()
		# self.UpdateVnom()
		# self.CfgChanged.set(1)

	def enable_brd_cb(self, brd):	
		if brd > sh.MaxBrd-1: pass
		elif brd < 1: 
			self.brd_enable_cb[brd].config(state=NORMAL)
			self.enable_brd_cb(brd+1)
		elif self.conn_path[brd].get() != '' and (self.BrdEnable[brd-1].get() and self.brd_enable_cb[brd-1].cget('state')!=DISABLED):  
			self.brd_enable_cb[brd].config(state=NORMAL)
			self.enable_brd_cb(brd+1)
		else: 
			self.brd_enable_cb[brd].config(state=DISABLED)
			if self.BrdEnable[brd].get() == 1:
				self.BrdEnable[brd].set(0)
			self.enable_brd_cb(brd+1)

	def enable_conn_path(self, brd):
		if self.BrdEnable[brd].get() == 1: 
			params['Open'].value[brd] = self.conn_path[brd].get()
		else: 
			params['Open'].value[brd] = ''
		self.enable_brd_cb(brd)
		self.CfgChanged.set(1)		

	def update_conn_path(self, brd):	# DNIN: Is this reduntant?
		self.enable_brd_cb(brd)
		if self.BrdEnable[brd].get() == 1: 
			params['Open'].value[brd] = self.conn_path[brd].get()
		self.CfgChanged.set(1)

	def update_brd_info(self, infostr):
		bi = infostr.split(';')
		brd = int(bi[0])
		if brd >= 0 and brd < sh.MaxBrd:
			self.info_pid[brd].config(text = bi[1], bg = 'light blue')
			self.info_board_model[brd].config(text = bi[2], bg = 'light blue')
			self.info_fpga_fwrev[brd].config(text = bi[3], bg = 'light blue')
			self.fpga_fwver[brd] = bi[3].split(" ")[0]
			self.info_uc_fwrev[brd].config(text = bi[4], bg = 'light blue')

	def Params2Tabs(self, reloaded):  
		if not reloaded:
			return
		self.StopUpdate = True
		if '5202' in sh.Version: self.UpdateVnom()
		for param in params.values():
			if param.distr == '-' or param.type == 'm': continue
			if param.name == 'Open':
				if self.status_now != sh.ACQSTATUS_DISCONNECTED:
					continue
				for i in range(sh.MaxBrd): #len(param.value)):	
					self.conn_path[i].set(param.value[i])
					# if param.value[i] != '':
					if self.conn_path[i].get() != '' and self.status_now == sh.ACQSTATUS_DISCONNECTED: 
						self.BrdEnable[i].set(1)
					if self.status_now != sh.ACQSTATUS_DISCONNECTED:
						self.brd_enable_cb[i].config(state=DISABLED)
					# else: 
					# 	self.BrdEnable[i].set(0)				
			else:
				self.par_def_svar[param.name].set(param.default)
				if (param.distr == 'b'):
					for brd in sh.Boards:
						self.par_brd_svar[param.name][brd].set(param.value[brd])
				if (param.distr == 'c'):
					for brd in sh.Boards:
						for ch in sh.Channels:
							self.par_ch_svar[param.name][brd][ch].set(param.value[brd][ch])
		self.StopUpdate = False	
		self.CfgChanged.set(1)				

	def TabsUpdateStatus(self, status):	# Not everything is a brd parameter. To be changed
		if '5202' in sh.Version: self.UpdateVnom()
		for brd in sh.Boards:
			if status == sh.ACQSTATUS_DISCONNECTED:  # disconnected (offline)
				if '5202' in sh.Version:
					self.HVcb[brd].config(state=DISABLED)
					self.HVcb_status[brd].set(0)
					self.hvbrdled[brd].set_color(sh.OffCol)
					self.hvled.set_color(sh.OffCol)
					self.Vmon[brd].config(text='')
					self.Imon[brd].config(text='')
					self.DTemp[brd].config(text='')
					self.BTemp[brd].config(text='')
					self.FPGATemp[brd].config(text='')
				else: 
					self.TDC0Temp[brd].config(text='')
					self.TDC1Temp[brd].config(text='')
					self.PICTemp[brd].config(text='')
					self.FPGATemp[brd].config(text='')
					self.afled.set_color(sh.OffCol)
					for key in self.AF_dict.keys():
						if key == "AFB": continue
						try:
							for mled in self.AF_dict[key]['led']:
								mled.set_color(sh.OffCol)  # DNIN: Or white?
						except: 
							pass

				self.info_pid[brd].config(text = "", bg = sh.BgCol)
				self.info_board_model[brd].config(text = "", bg = sh.BgCol)
				self.info_fpga_fwrev[brd].config(text = "", bg = sh.BgCol)
				self.info_uc_fwrev[brd].config(text = "", bg = sh.BgCol)
				self.enable_brd_cb(brd)	# enabling checkbox with some text, if consecutive to another one
				self.path_entry[brd].config(state=NORMAL)
				for i in range(64):
					self.ChCounts[i].config(bg='white')
				for i in range(len(self.AllBrdLabel)):
					self.AllBrdCounts[str(brd)][i].config(bg='white')			
				# enable brd_cb
				# self.brd_enable_cb[brd].config(state=NORMAL)
			elif status == sh.ACQSTATUS_READY: # ready
				#self.HVupd[brd].config(state=NORMAL)
				if '5202' in sh.Version: self.HVcb[brd].config(state=NORMAL)
				# self.enable_brd_cb(brd)
				self.path_entry[brd].config(state=DISABLED)
				self.brd_enable_cb[brd].config(state=DISABLED)
			elif status == sh.ACQSTATUS_RAMPING_HV and '5202' in sh.Version:
				self.HVcb[brd].config(state=NORMAL)
			else: # running
				if '5202' in sh.Version: self.HVcb[brd].config(state=DISABLED)
				self.path_entry[brd].config(state=DISABLED)
				self.brd_enable_cb[brd].config(state=DISABLED)

	def set_reg_addr(self):
		if self.reg_base.get() == '02':
			base = '02'+str(self.reg_ch.get().rjust(2, '0'))
		else:
			base = self.reg_base.get() + '00'
		offs = self.reg_offs.get().rjust(4, '0')
		self.reg_addr.set(base + offs)

	def read_reg(self):
		comm.SendCmd('Rr' + self.reg_addr.get() + '\n')

	def write_reg(self):
		comm.SendCmd('Rw' + self.reg_addr.get() + '\n' + self.reg_data.get() + '\n')
		self.RWregLog.insert(END, "Wr-Reg: A=" + self.reg_addr.get() + " D=" + self.reg_data.get() + '\n')
		self.RWregLog.see(END)

	def send_cmd(self):
		comm.SendCmd('Rw 0x01008000' + self.cmd.get() + '\n')
		self.RWregLog.insert(END, "Send Command " + self.cmd.get() + '\n')
		self.RWregLog.see(END)

	def BrowseOutDir(self):
#		OutDir = filedialog.askdirectory()
		try:
			OutDir = askdirectory()
			OutDir = os.path.relpath(OutDir)
			self.par_def_svar['DataFilePath'].set(OutDir)
		except:
			pass
	
	
	# ***************************************************************************************
	# Service Event (Temperatures updatating) only for 5203, but have to be done in 5202 too
	# ***************************************************************************************
	def UpdateTemp(self, ser_string):	# What about general fail bit?
		temps = ser_string.split()
		for i in range(int(len(temps)/6)):
			brd = int(temps[i*6])
			if float(temps[1+i*6]) > 0 and float(temps[1+i*6]) < 200: self.TDC0Temp[brd].config(text="{} {}".format(temps[1+i*6], " degC"))
			else: self.TDC0Temp[brd].config(text="N.A.")
			if float(temps[2+i*6]) > 0 and float(temps[2+i*6]) < 200:self.TDC1Temp[brd].config(text="{} {}".format(temps[2+i*6], " degC"))
			else: self.TDC1Temp[brd].config(text="N.A.")
			if float(temps[3+i*6]) > 0 and float(temps[3+i*6]) < 200:self.PICTemp[brd].config(text="{} {}".format(temps[3+i*6], " degC"))
			else: self.PICTemp[brd].config(text="N.A.")
			if float(temps[4+i*6]) > 0 and float(temps[4+i*6]) < 200:self.FPGATemp[brd].config(text="{} {}".format(temps[4+i*6], " degC"))
			else: self.FPGATemp[brd].config(text="N.A.")		
		

	# ***************************************************************************************
	# Update HV Tab, only for A5202
	# ***************************************************************************************
	if '5202' in sh.Version:
		def UpdateHVTab(self, hvstring):	# DNIN: control over the brd index you are trying to turn on
			if len(hvstring) == 0: return
			hvs = hvstring.split()
			brd = int(hvs[0])
			hv_on = int(hvs[1]) & 1
			self.hvfail[brd] = (int(hvs[1]) >> 1) & 1
			#if self.DisableOnOffUpdateCnt > 0:
			#	self.DisableOnOffUpdateCnt = self.DisableOnOffUpdateCnt - 1
			#else:	
			if hv_on == 1: self.HVcb_status[brd].set(1)
			else: self.HVcb_status[brd].set(0)
			self.Vmon[brd].config(text=hvs[2] + ' V')
			self.Imon[brd].config(text=hvs[3] + ' mA')
			if float(hvs[4]) > 0 : 
				if float(hvs[4]) > 1: self.DTemp[brd].config(text=hvs[4] + ' degC')
				else: self.DTemp[brd].config(text='N.A.')
			if float(hvs[5]) > 0 : self.BTemp[brd].config(text=hvs[5] + ' degC')
			if float(hvs[6]) > 0 : self.FPGATemp[brd].config(text=hvs[6] + ' degC')
			vmon = float(hvs[2])
			# if vmon > 7: self.hvon[brd] = 1
			# else: self.hvon[brd] = 0
			# if 1 in self.hvfail: self.hvled.set_color("red")
			# elif 1 in self.hvon: self.hvled.set_color("green")
			# else: self.hvled.set_color("grey")
			# control hvbrdled
			try:
				if params['HV_Vbias'].value[brd] != "":
					vref = float(params['HV_Vbias'].value[brd].split(" ")[0])	
				else:
					vref = float(params['HV_Vbias'].default.split(" ")[0])
			except:
				vref = 20
			if self.hvfail[brd]: self.hvbrdled[brd].set_color(sh.ErCol)
			elif vmon > 0.95 * vref: 
				self.hvbrdled[brd].set_color(sh.OkCol)
				self.hvon[brd] = 1
			elif vmon < 22: 
				self.hvbrdled[brd].set_color(sh.OffCol)
				self.hvon[brd] = 0
			else: 
				self.hvbrdled[brd].set_color(sh.WrCol)
				self.hvon[brd] = 2	# ramping up/down
			# control hvled
			if 1 in self.hvfail: self.hvled.set_color(sh.ErCol)
			elif 2 in self.hvon: self.hvled.set_color(sh.WrCol)
			elif 1 in self.hvon: self.hvled.set_color(sh.OkCol)
			else: self.hvled.set_color(sh.OffCol)

		def HVonoff(self, brd):
			if self.HVcb_status[brd].get() == 1: # HV ON
				comm.SendCmd('H1 ' + str(brd))
			else: # HV OFF
				comm.SendCmd('H0 ' + str(brd))
			#self.DisableOnOffUpdateCnt = 3

		def UpdateVnom(self):
			if params['HV_Adjust_Range'].default == '4.5': 
				dacfs = 4.2
			elif params['HV_Adjust_Range'].default == '2.5': 
				dacfs = 2.5
			else:
				dacfs = 0
			stdunit = "V"	# DNIN: the manage of the unit is not yet implemented
			try:
				if params['HV_Vbias'].default.split()[1] == 'mV': stdunit = "mV"
				elif params['HV_Vbias'].default.split()[1] == 'uV': stdunit = "uV"
				elif params['HV_Vbias'].default.split()[1] == 'nV': stdunit = "nV"
				else: stdunit = "V"
			except:
				stdunit = "V"

			for brd in sh.Boards:
				for i in sh.Channels:
					if params['HV_Adjust_Range'].default == 'DISABLED': vdac = 4.5
					elif params['HV_IndivAdj'].value[brd][i] == '': 
						try:
							vdac = dacfs * float(255 - int(params['HV_IndivAdj'].default)) / 255
						except:
							vdac = 0	# default value
					else:	# control - overwrite if it is correct
						vdac = dacfs * float(255 - int(params['HV_IndivAdj'].value[brd][i])) / 255
					if params['HV_Vbias'].value[brd] == '': 
						try:
							vnom = float(params['HV_Vbias'].default.split()[0]) - vdac 
						except:
							vnom = 20	# default value
					else:	# control - overwrite if the value is correct
						vnom = float(params['HV_Vbias'].value[brd].split()[0]) - vdac
					self.par_ch_label['Vnom'][brd][i].config(text = '%.2f %s' % (vnom, stdunit)) 

	# ***************************************************************************************
	# Update Statistics Tab 
	# ***************************************************************************************
	def UpdateStatsTab(self, cmsg:str): 
		cmsg = cmsg.rstrip()
		if cmsg[0] == '0': return # exit, JanusC closed the comm forcibly 
		if cmsg[1] == 'b':	# write only if the active Brd is the one sending data
			if cmsg[2:] == str(self.ActiveBrd.get()): self.update_stats = True
			else: self.update_stats = False
		if cmsg[1] == 'c':  # channel value
			if '5202' in sh.Version:
				if (list(self.Mtabs_shown)[self.Mtabs_nb.index('current')] == 'Statistics'):
					for ch in range(64):
						ss = cmsg[8*ch+2:8*ch+10]
						if not self.update_stats: ss = '0.000'
						if ss.strip() == '0' or ss.strip() == '0.000': col = 'white'
						else: col = sh.DataCol
						self.ChCounts[ch].configure(text=ss, bg=col)
			else:
				mmsg = cmsg[2:].split()	# ChsAlmostFull0 ChsAlmostFull1 OtsAlmostFull data_ch0 data_ch1 ... data_ch63
				chsAF0 = "{0:064b}".format(int(mmsg[0]))
				chsAF1 = "{0:064b}".format(int(mmsg[1]))
				s_otsAF = "{0:032b}".format(int(mmsg[2]))
				i_otsAF = int(mmsg[2])

				# To be changed
				if '1' in chsAF0 or '1' in chsAF1 or '1' in s_otsAF: self.afled.set_color(sh.WrCol)  # Set AF led color
				else: self.afled.set_color(sh.OffCol)
				lst = {
					# "TRGB": [int, 0x000000FF, 0], 
					"ROB": [list, 0x0000FF00, 8], 
					"RPF": [list, 0x00FF0000, 16], 
					"LSOF": [int, 0x01000000, 24], 
					"TRGF": [int, 0x06000000, 25],
					"HLOSS": [int, 0x20000000, 29]
				} 
				for key in lst.keys():
					num = (i_otsAF & lst[key][1]) >> lst[key][2]
					if lst[key][0] == int: num = int(num > 0)	# OR of the flag
					stnum = "{0:08b}".format(num)	
					for i in range(len(self.AF_dict[key]['led'])):
						if '1' in stnum[-(1+i)]: self.AF_dict[key]['led'][i].set_color(sh.WrCol)
						else: self.AF_dict[key]['led'][i].set_color(sh.OffCol)

				# Set Ch_Label value and color
				if not (list(self.Mtabs_shown)[self.Mtabs_nb.index('current')] == 'Statistics'): return
				if self.ActiveTDC.get(): # With 128 channels, you can select the TDC0 or TDC1 
					shift = 64 
					chsAF = chsAF1
				else: 
					shift = 0
					chsAF = chsAF0 

				for ch in range(64): 
					ss = mmsg[ch+shift+3]
					AFch = int(chsAF[len(chsAF)-1-ch])
					if not self.update_stats: ss = '0.000'
					if AFch: col = sh.WrCol
					elif ss.strip() == '0' or ss.strip() == '0.000': col = 'white'
					# elif AFch: col = 'red'
					else: col = sh.DataCol
					self.ChCounts[ch + shift].configure(text=ss, bg=col)

		# elif cmsg[1] == 'g': # globa value
		# 	if (list(self.Mtabs)[self.Mtabs_nb.index('current')] == 'Statistics'):
		# 		i = int(cmsg[2])
		# 		tmp_msg = cmsg[3:]
		# 		if not self.update_stats: tmp_msg = cmsg.replace(cmsg[3:],"")
		# 		if i < len(self.GStats):
		# 			self.GStats[i].configure(text = tmp_msg)
		elif cmsg[1] == 'G': # define global stat
			i = int(cmsg[2])
			# if self.update_stats: cmsg[3:] = cmsg[3:].re
			if i == len(self.GStats):
				self.GStats.append(Label(self.Mtabs["Statistics"], width = 20, bg = 'White', anchor="e", font=("courier", 9), relief="groove"))
				self.GStatsLabel.append(Label(self.Mtabs["Statistics"], text = cmsg[3:], anchor="w", width = 12))
				y0 = self.Gstats_y0 + 22 * i
				if not self.change_statistics.get(): self.GStatsLabel[i].place(relx=5./sh.Win_Tabs_W, rely=y0/sh.Win_Tabs_H)  #  x = 5, y = y0)
				if not self.change_statistics.get(): self.GStats[i].place(relx=110./sh.Win_Tabs_W, rely=y0/sh.Win_Tabs_H)  #  x = 110, y = y0)
		elif cmsg[1] == 'g':
			if (list(self.Mtabs_shown)[self.Mtabs_nb.index('current')] == 'Statistics'):
				msg_spl = cmsg[2:].split("\t")
				self.StatsTypeLabel.configure(text = msg_spl[0], bg = "white")
				if not self.update_stats:
					for i in range(len(msg_spl)-1):
						self.GStats[i].configure(text = "")
				else:
					for i in range(len(msg_spl)-1):
						self.GStats[i].configure(text = msg_spl[i+1])
		elif cmsg[1] == 't': # channel Statistics title
			self.StatsTypeLabel.configure(text = cmsg[2:], bg = sh.DataCol)
		elif cmsg[1] == 'B':
			if '5202' in sh.Version:
				if (list(self.Mtabs_shown)[self.Mtabs_nb.index('current')] == 'Statistics'):
					msg_spl = cmsg[2:].split()
					msglen = len(self.AllBrdLabel)	# to shorten the variable name
					# Is still there the possibility to have message of differenet length?
					if len(msg_spl)%6 == 0: mlen = 6
					else: mlen = 7
					col = sh.DataCol
					if float(msg_spl[3]) < 1: col = 'white' 
					for b in range(int(len(msg_spl)/mlen)):
						if mlen == 6: msg_spl.insert(5+msglen*b, "-")
						for l in range(msglen): # adding the "-", in case of no tdl the actual len of the msg read is = len(AllBrdLabel)
							self.AllBrdCounts[msg_spl[msglen*b]][l].config(text = msg_spl[msglen*b+l], bg = col)
			else:
				msg_spl = cmsg[2:].split()
				msg_len = len(self.AllBrdLabel)
				mcol = sh.OffCol
				col = sh.DataCol
				for b in range(int(len(msg_spl)/(msg_len+1))):
					# set label color
					if float(msg_spl[(msg_len+1)*b + 2]) < 1: col = 'white'	# TRGID = 0
					else: col = sh.DataCol
					if int(msg_spl[(msg_len+1)*b + msg_len]): 
						mcol = sh.WrCol # AF flag
						col = mcol
					for l in range(msg_len):
						self.AllBrdCounts[msg_spl[(msg_len+1)*b]][l].config(text=msg_spl[(msg_len+1)*b+l], bg = col)
				self.afled.set_color(mcol)
		elif cmsg[1] == 'R':
			for i in range(len(self.GStats)):
				self.GStats[i].place_forget()
				self.GStatsLabel[i].place_forget()
			self.GStats.clear()
			self.GStatsLabel.clear()

	def ChgStatIntegr(self):
		if self.status_now == sh.ACQSTATUS_READY or self.status_now == sh.ACQSTATUS_RUNNING:
			comm.SendCmd("I{}".format(self.change_stat_integral.get()))	
	
	def ChgStatMode(self): 
		if self.ActiveTDC.get(): shift=64	# shift could be used as global variable
		else: shift = 0
		if self.status_now == sh.ACQSTATUS_READY or self.status_now == sh.ACQSTATUS_RUNNING:
			comm.SendCmd("\t{}".format(self.change_statistics.get()))	
		if self.change_statistics.get(): # remove the previous statistics
			self.sbox.place_forget()
			self.slabel.place_forget()
			self.sTDCbox.place_forget()	# If 128 chs then forget them ...
			self.sTDClabel.place_forget()
			for i in range(64):
				self.ChCounts[i+shift].place_forget()
				self.ChLabel[i+shift].place_forget()
			if len(self.GStatsLabel) > 1:
				for i in range(len(self.GStatsLabel)):
					self.GStatsLabel[i].place_forget()
					self.GStats[i].place_forget()
			for key in self.AF_dict.keys():
				self.AF_dict[key]['label'].place_forget()
				if key != 'AFB':
					try: 
						for el in self.AF_dict[key]['led']: 
							el.place_forget()
					except: pass
			# place new statistic
			xnew = 660/len(self.AllBrdLabel)
			xwidth = 0.87 - len(self.AllBrdLabel)/100
			for i in range(len(self.AllBrdLabel)): self.AllBrdLabel[i].place(relx=(15+(xnew)*i)/sh.Win_Tabs_W, rely=45/sh.Win_Tabs_H, relwidth=0.9/(len(self.AllBrdLabel)))  #  x = 20+111*i, y = 45)
			for i in sh.Boards:
				for j in range(len(self.AllBrdLabel)): 
					self.AllBrdCounts[str(i)][j].place(relx=(20+(xnew)*j)/sh.Win_Tabs_W, rely=(75+25*i)/sh.Win_Tabs_H, relwidth=xwidth/(len(self.AllBrdLabel)))  #  x = 20+111*j, y = 75 + 25*i) 
			# y0=90+25*16
			# for key in self.AF_dict_allbrd.keys():
			# 	self.AF_dict_allbrd[key]['led'].rel_place(xnew/sh.Win_Tabs_W, y0/sh.Win_Tabs_H)
			# 	y0=y0+12		
		else: # remove
			for i in range(len(self.AllBrdLabel)):
				self.AllBrdLabel[i].place_forget()
				for j in sh.Boards:
					self.AllBrdCounts[str(j)][i].place_forget()
			# for key in self.AF_dict_allbrd.keys():
			# 	self.AF_dict_allbrd[key]['led'].place_forget()
			# place back the old statistics
			self.sbox.place(relx=(sh.Win_Ctrl_W-65)/sh.Win_Tabs_W, rely=10./sh.Win_Tabs_H)   #   x = sh.Win_Tabs_W - 65, y = 10)
			self.slabel.place(relx=(sh.Win_Tabs_W-100)/sh.Win_Tabs_W, rely=10./sh.Win_Tabs_H)  #   x =  sh.Win_Tabs_W - 100, y = 10)

			self.sTDCbox.place(relx=(sh.Win_Ctrl_W-170)/sh.Win_Tabs_W, rely=10./sh.Win_Tabs_H)   #   x = sh.Win_Tabs_W - 65, y = 10)
			self.sTDClabel.place(relx=(sh.Win_Tabs_W-210)/sh.Win_Tabs_W, rely=10./sh.Win_Tabs_H)  #   x =  sh.Win_Tabs_W - 100, y = 10)
			for i in range(64):
				self.ChCounts[i+shift].place(relx=(21+85*(i%8))/sh.Win_Tabs_W, rely=(45+30*(int)(i/8))/sh.Win_Tabs_H)   #   x = 20 + 85 * (i % 8), y = 45 + 30 * (int)(i / 8))
				self.ChLabel[i+shift].place(relx=(85*(i%8))/sh.Win_Tabs_W, rely=(45+30*(int)(i/8))/sh.Win_Tabs_H)  #  x = 85 * (i % 8), y = 45 + 30 * (int)(i / 8))
			if len(self.GStatsLabel) > 1:
				for i in range(len(self.GStatsLabel)):	# Those two placements needs to be checked
					self.GStatsLabel[i].place(relx=5/sh.Win_Tabs_W, rely=(300+22*i)/sh.Win_Tabs_H)  #  x = 5, y = 300+22*i)
					self.GStats[i].place(relx=110/sh.Win_Tabs_W, rely=(300+22*i)/sh.Win_Tabs_H)  #   x = 110, y = 300+22*i)
			
			y0=self.Gstats_y0	
			self.AF_dict['AFB']['label'].place(relx=0.62, rely=(y0-10)/sh.Win_Tabs_H)
			y0 += 15
			for name in self.AF_dict.keys():
				if name != 'AFB':
					self.AF_dict[name]['label'].place(relx=self.AF_dict[name]['poslabel'][0], rely=self.AF_dict[name]['poslabel'][1])
					try: 
						for i in range(len(self.AF_dict[name]['led'])): 
							self.AF_dict[name]['led'][i].rel_place(self.AF_dict[name]['posled'][i][0], self.AF_dict[name]['posled'][i][1])
					except: pass
					y0 += 22

	def ChangeTDC(self):
		comm.SendCmd("Z{}".format(self.ActiveTDC.get())) # Changing TDC
		ts=85
		y0=45
		if self.ActiveTDC.get(): shift=64
		else: shift = 0
		for i in range(shift, 64+shift):
			self.ChCounts[(i+64)%128].place_forget()
			self.ChLabel[(i+64)%128].place_forget()
			self.ChCounts[i].place(relx=(21+ts*(i%8))/sh.Win_Tabs_W, rely=(y0+30*(int)((i%64)/8))/sh.Win_Tabs_H)  #  x = 20 + ts * (i % 8), y = y0 + 30 * (int)(i / 8))
			self.ChLabel[i].place(relx=(ts*(i%8))/sh.Win_Tabs_W, rely=(y0+30*(int)((i%64)/8))/sh.Win_Tabs_H)

	def PlaceTDCs(self):
		y0=10
		self.sTDClabel.place(relx=(sh.Win_Tabs_W-210)/sh.Win_Tabs_W, rely=y0/sh.Win_Tabs_H)  #   x =  sh.Win_Tabs_W - 100, y = y0)
		self.sTDCbox.place(relx=(sh.Win_Tabs_W-170)/sh.Win_Tabs_W, rely=y0/sh.Win_Tabs_H) 

	# ***************************************************************************************
	# Enable/Disable combobox write
	# ***************************************************************************************
	def combobox_state(self, en_status):
		if en_status: mystate = "normal"
		else: mystate = 'readonly'
		for param in params.values():
			if param.type == 'c':
				self.par_def_combo[param.name].config(state = mystate)

	# ***************************************************************************************
	# Popup window for Mask Setting
	# ***************************************************************************************
	def OpenMask(self, title, section, param_name):
		if not os.path.isfile(sh.PixelMap): return
		pm = open(sh.PixelMap, "r")
		self.pixmap = ["" for i in sh.Channels]
		for line in pm:
			p = line.split()
			ch = int(p[0])
			if ch >= 0 and ch < sh.MaxCh: self.pixmap[ch] = p[1]
		pm.close	

		self.en_pixel_map = IntVar()
		self.en_pixel_map.set(0)

		if self.MaskWinIsOpen: self.CloseMaskWin()
		xw = 215
		yw = 295
		self.MaskWin = Toplevel()
		self.MaskWin.geometry("{}x{}+{}+{}".format(xw, yw, 550, 300))
		#self.MaskWin.overrideredirect(1)  # no window bar
		self.MaskWin.wm_title("")
		self.MaskWin.protocol("WM_DELETE_WINDOW", self.CloseMaskWin)
		self.MaskWinIsOpen = True
		Frame(self.MaskWin, width=xw, height=yw, relief=RIDGE).place(x=0, y=0) # , bd=2

		cb = self.BrdTabs_nb[section].index('current')
		self.cbm = []
		self.BrdOpt = ['Global']
		for b in sh.Boards: self.BrdOpt.append(str(b))
		self.Mbrd = StringVar()
		self.Mbrd.set(str(cb))
		# print('Board mask = ' + self.Mbrd.get()) # DNIN: debug porpuse
		#self.Mbrd = self.BrdTabs_nb[section].index('current')
		if param_name[-1] == '0': shift = 0
		elif param_name[-1] == '2': shift = 2
		self.par0 = param_name[:-1] + f"{shift}"
		self.par1 = param_name[:-1] + f"{shift+1}"

		x0, y0 = 5, 5
		sp = 26
		Label(self.MaskWin, text = title).place(relx=float(x0/xw), rely=float(y0/yw))  #  x = x0, y = y0)
		Label(self.MaskWin, text = "Brd").place(relx=float((x0+140)/xw), rely=float(y0/yw))  #  x = x0 + 110, y = y0)
		ttk.Combobox(self.MaskWin, values=self.BrdOpt, textvariable=self.Mbrd, state='readonly').place(relx=float(x0+164)/xw, rely=y0/yw, relwidth=0.197, relheight=0.075)  # , width=7 x=x0+138, y=y0)
		self.Mbrd.trace('w', lambda name, index, mode: self.GetBrdMask())

		y0 += 25
		Button(self.MaskWin, text='Enable all',  command=self.EnableAll).place(relx=float(x0/xw), rely=float(y0/yw), relwidth=0.475, relheight=0.087) # , height = 1 , width=13 x = x0, y = y0)
		Button(self.MaskWin, text='Disable all', command=self.DisableAll).place(relx=float((x0+sp*4)/xw), rely=float(y0/yw), relwidth=0.475, relheight=0.087) # , height = 1 , width=13 x = x0 + sp*4, y = y0)
		#self.no_update = True  # prevent the update while setting the mask with initial values
		for y in range(8):	
			for x in range(8):
				i = 8*y+x
				# self.Mask[i].trace('w', lambda name, index, mode: self.UpdateMask())
				if "TDC1" in title:
					cs = 64
				else:
					cs = 0
				self.cbm.append(Checkbutton(self.MaskWin, text=str(i+cs), variable=self.Mask[i], indicatoron=0)) # , height = 1, width=2
				self.cbm[i].place(relx=float(x0+x*sp)/xw, rely=float(y0+(y+1)*sp)/yw, relwidth=float(sp-2)/xw, relheight=float(sp-2)/yw)  #DNIN: missing relwidth /height   x = x0+x*sp, y=y0+(y+1)*sp)
		if "5202" in sh.Version:
			Checkbutton(self.MaskWin, text='Pixel Map', variable=self.en_pixel_map, command=self.PixelMapTab(), indicatoron=0).place(relx=float(x0/xw), rely=float(1+y0+sp*9)/yw, relwidth=0.475, relheight=0.087) # , height=1, width=13 x=x0, y = 1 + y0 + sp*9)
			self.en_pixel_map.trace('w', lambda name, index, mode: self.PixelMapTab())
		Button(self.MaskWin, text='Done', command=self.CloseUpdateMaskWin, bg='light blue').place(relx=float(x0+sp*4)/xw, rely=float(1+y0+sp*9)/yw, relwidth=0.475, relheight=0.087) # , height = 1, width=13 x = x0+103, y = y0 + sp*9)
		#self.no_update = False
		self.GetBrdMask()
	
	def PixelMapTab(self):
		x0 = 5
		y0 = 30
		sp = 26
		for y in range(8):
			for x in range(8):
				i = 8*y+x
				if self.en_pixel_map.get() == 1:
					xp = ord(self.pixmap[i][0]) - ord('A')
					yp = 7 - (ord(self.pixmap[i][1]) - ord('1'))
				else:
					xp = x
					yp = y
				self.cbm[i].place(relx=float(x0+xp*sp)/215, rely=float(y0+(yp+1)*sp)/295)  #  x = x0+xp*sp, y=y0+(yp+1)*sp)

	def GetBrdMask(self):
		self.no_update = True
		if self.Mbrd.get() == 'Global': 
			mask0s = self.par_def_svar[self.par0].get()
			mask1s = self.par_def_svar[self.par1].get()
		else:	
			mask0s = self.par_brd_svar[self.par0][int(self.Mbrd.get())].get()
			mask1s = self.par_brd_svar[self.par1][int(self.Mbrd.get())].get()
		if mask0s == '': mask0s = "0x00000000"
		if mask0s[0:1] == '0x': mask0 = int(mask0s[2:], 16)
		else: mask0 = int(mask0s, 16)
		if mask1s == '': mask1s = "0x00000000"
		if mask1s[0:1] == '0x': mask1 = int(mask1s[2:], 16)
		else: mask1 = int(mask1s, 16)
		for y in range(8):
			for x in range(8):
				i = 8*y+x
				if (i<32): ec = (mask0 >> i) & 1
				else: ec = (mask1 >> (i - 32)) & 1	
				self.Mask[i].set(ec)
		self.no_update = False		

	def UpdateMask(self):
		if self.no_update: return
		mask0, mask1 = 0, 0
		for i in range(0, 64):
			if i < 32: mask0 += (2**i) * self.Mask[i].get()
			else: mask1 += (2**(i-32)) * self.Mask[i].get()
		if self.Mbrd.get() == 'Global': 
			self.par_def_svar[self.par0].set('0x'+hex(mask0)[2:].upper())
			self.par_def_svar[self.par1].set('0x'+hex(mask1)[2:].upper())
		else:	
			self.par_brd_svar[self.par0][int(self.Mbrd.get())].set('0x'+hex(mask0)[2:].upper())
			self.par_brd_svar[self.par1][int(self.Mbrd.get())].set('0x'+hex(mask1)[2:].upper())

	def EnableAll(self):
		self.no_update = True
		for i in range(64):
			self.Mask[i].set(1)
		self.no_update = False

	def DisableAll(self):
		self.no_update = True
		for i in range(64):
			self.Mask[i].set(0)
		self.no_update = False	

	def CloseMaskWin(self):
		# self.UpdateMask()
		self.MaskWin.destroy()
		# self.CfgChanged.set(1)
		self.MaskWinIsOpen = False

	def CloseUpdateMaskWin(self):
		self.UpdateMask()
		self.MaskWin.destroy()
		self.CfgChanged.set(1)
		self.MaskWinIsOpen = False	

	def CloseTab(self, parent):
		self.Mtabs_nb.destroy()

	# ----------------------------------------------------------------
	# POP-UP for setting WalkFitCoeff (ToA correction from ToT fit)
	# ----------------------------------------------------------------
	def Set_WalkFitCoeff(self): # DNIN: how using ';'  instead of ' '?
		self.fit_option = [u'F(x) = c\u2080 + c\u2081\u00B7x + c\u2082\u00B7x\u00B2 + c\u2083\u00B7x\u00B3 + c\u2084\u00B7x\u2074 + c\u2085\u00B7x\u2075', # 5th grade polynomial
							'c\u2080 + c\u2081\u00B7exp(c\u2082 + c\u2083\u00B7x)',
							'Unknown function'	# Exponential
							]	
		self.fit_function = StringVar() # DNIN: to be defined
		self.fit_function.set(self.fit_option[0])
		if self.FitWinIsOpen: self.CloseFitWin()
		xw = 315
		yw = 295
		self.FitWin = Toplevel()
		self.FitWin.geometry("{}x{}+{}+{}".format(xw, yw, 550, 300))
		#self.MaskWin.overrideredirect(1)  # no window bar
		self.FitWin.wm_title("Coefficients fit for ToA Walk Correction")
		self.FitWin.protocol("WM_DELETE_WINDOW", self.CloseFitWin)
		self.FitinIsOpen = True
		Frame(self.FitWin, width=xw, height=yw, relief=RIDGE).place(x=0, y=0) # , bd=2

		self.walk_coeff = [StringVar() for i in range(6)]
		# Label(self.FitWin, text="Coefficients fit for ToA Walk Correction").place(relx=0.05, rely=0.05)
		# ttk.Combobox(self.FitWin, value=self.fit_option, textvariable=self.fit_function).place(relx=0.05, rely=0.05, relwidth=0.9)
		Label(self.FitWin, text=self.fit_option[0], justify=CENTER, bg='white', font=("Arial Bold", 10)).place(relx=0.05, rely=0.05, relwidth=0.9)
		coeff = self.par_def_svar["WalkFitCoeff"].get().split(" ")
		a=('\u2080', '\u2081', '\u2082', '\u2083', '\u2084', '\u2085')
		valy = 0.18
		for i in range(6):
			Label(self.FitWin, text=u"c{}".format(a[i]), font=("Arial", 12)).place(relx=0.15, rely=valy+0.1*i-0.01)
			try:
				self.walk_coeff[i].set(coeff[i])
				Entry(self.FitWin, textvariable=self.walk_coeff[i], bg='white', justify='left').place(relx=0.25, rely=valy+0.1*i, relwidth=0.55)
			except:
				self.walk_coeff[i].set('0')
				Entry(self.FitWin, textvariable=self.walk_coeff[i], bg='white').place(relx=0.25, rely=valy+0.1*i, relwidth=0.55)
		
		Button(self.FitWin, text="DONE", bg='#00CC00', command=self.Set_Coeff).place(relx=0.2, rely=0.2+0.1*6, relwidth=0.6, relheight=0.15)

		return 0
	
	def Set_Coeff(self):
		tmps = ""
		for i in range(6):
			if self.walk_coeff[i].get() != "0":
				tmps += "{} ".format(self.walk_coeff[i].get())
		self.par_def_svar["WalkFitCoeff"].set(tmps)
		self.CfgChanged.set(1)
		self.CloseFitWin()

	def CloseFitWin(self):
		# self.UpdateMask()
		self.FitWin.destroy()
		# self.CfgChanged.set(1)
		self.FitWinIsOpen = False
	

	# ----------------------------------------------------------------
	# BASIC / ADVANCED GUI view mode
	# ----------------------------------------------------------------
	# Remove Str and Int, Identify in a different wat and add if is combo or spin in the Json
	# Change the options of combobox and spinbox from file
	def set_new_options(self, param, acqmode, measmode, jobenabled):	
		if self.new_options[param.name]["trace"] == 'measmode':
			try: new_option = self.new_options[param.name][measmode]
			except: new_option = []
		elif self.new_options[param.name]["trace"] == 'acqmode': # TOT_LSB changes because in Lead/Trail ToT cannot be larger than DeltaT Dynamic Range
			try: new_option = self.new_options[param.name][acqmode]
			except: new_option = []
		elif self.new_options[param.name]["trace"] == 'stoprunmode':
			try: new_option = self.new_options[param.name][jobenabled]
			except: new_option = []
		else: new_option = []

		if param.type == "c":
			self.par_def_combo[param.name]['values'] = new_option
			# if param.default not in new_option:

		elif param.type == "x": 
			if len(new_option) != 2: return	-1		
			self.par_def_spinbox[param.name]['from'] = new_option[0]
			self.par_def_spinbox[param.name]['to'] = new_option[1]


	def forget_widget(self, param):
		if params[param.name].type == 'm' or param.name == 'Open': return
		if params[param.name].type == '-':
			if param.name.find("_BLANK") < 0: self.par_def_label[param.name].place_forget()
			return
		self.par_def_label[param.name].place_forget()
		if params[param.name].type == 'c': 
			if params[param.name].distr == 'g': self.par_def_combo[param.name].place_forget()
			elif params[param.name].distr == 'b': [self.par_brd_combo[param.name][brd].place_forget() for brd in range(sh.MaxBrd)]
			elif params[param.name].distr == 'c': [self.par_ch_combo[param.name][brd][ch].place_forget() for brd in range(sh.MaxBrd) for ch in range(sh.MaxCh)]
		elif params[param.name].type == 'b': 
			if params[param.name].distr == 'g': self.par_def_checkbox[param.name].place_forget()
			elif params[param.name].distr == 'b': [self.par_brd_checkbox[param.name][brd].place_forget() for brd in range(sh.MaxBrd)]
			elif params[param.name].distr == 'c': [self.par_ch_checkbox[param.name][brd][ch].place_forget() for brd in range(sh.MaxBrd) for ch in range(sh.MaxCh)]
		elif params[param.name].type == 'x':
			self.par_def_spinbox[param.name].place_forget()
			if '5202' not in sh.Version: 
				self.timeval[param.name].place_forget()
				self.rangeval[param.name].place_forget()				
				try:
					for key, val in self.rangeval.items():
						val.place_forget()
					# self.rangeval["LeadingFRange"].place_forget()
					# self.rangeval["ToTFRange"].place_forget()
				except: pass		
		else:
			self.par_def_entry[param.name].place_forget()
			# TABMODE
			nch_t = 1
			if self.tabmode[param.section] == 2: nch_t = 8
			if params[param.name].distr == 'b': [self.par_brd_entry[param.name][brd][tch].place_forget() for brd in range(sh.MaxBrd) for tch in range(nch_t)]
			elif params[param.name].distr == 'c': [self.par_ch_entry[param.name][brd][ch].place_forget() for brd in range(sh.MaxBrd) for ch in range(sh.MaxCh)]

	def remove_tabs_widget(self):
		# Remove extra widgets
		for key, item in self.button_names.items():
			try: item[0].place_forget()
			except: [item[0][j].place_forget() for j in range(len(item))]
		# Remove widgets created with tabs
		for param in params.values(): self.forget_widget(param)
			
		for s in sections:
			self.Mtabs_nb.add(self.Mtabs[s], text=' ' + s + ' ')
			self.Mtabs_nb.forget(self.Mtabs[s])
		
	def load_par2remove(self, hiding_status, sel='h'):	# It would be easier
		hideparam = []
		tabs_removal = []
		with open(sh.GuiModeFile, "r") as hidefile:
			hideparam_nu = hidefile.read().splitlines()	# does not work with breakpoint :-/
			for h in range(len(hideparam_nu)):	
				tt = hideparam_nu[h].split("\t")			# removing white space before and after the name
				tt = list(filter(("").__ne__, tt))
				if len(tt) != 2 or tt[0][0] == "#": continue		# removing comments
				if not hiding_status.search(tt[1]): continue 			# check if the hiding attribute contains the hiding status
				h_n = tt[0].strip()	# Hide Name Par
				if h_n in self.rename_parname:					# check if the name is a real parameter
					if "Ch Enable Mask Chip" in h_n or "QD Mask Chip" in h_n or "TLogic Mask Chip" in h_n:	# the parameter is splitted for 2 chips, but removed together
						hideparam.append(self.rename_parname[h_n[:-1] + "0"])
						hideparam.append(self.rename_parname[h_n[:-1] + "1"])
					else: 
						hideparam.append(self.rename_parname[h_n]) 				
				elif h_n in self.rename_parname.values():	#	Accept both defs or renamed parameters name
					if "ChEnableMask" in h_n or "QDDiscrMask" in h_n or "Tlogic_Mask" in h_n:
						hideparam.append(h_n[0][:-1] + "0")
						hideparam.append(h_n[:-1] + "1")
					else:
						hideparam.append(h_n)					
				elif tt[0] in sh.sections:	# rem
					tabs_removal.append(h_n)
		if self.offline: tabs_removal.append('Regs')
		if sel=='h': return hideparam
		else: return tabs_removal

	def place_widgets(self, param, hideparam, yrow, x_def, x_brd):
		ypos = {}
		if param.name in hideparam: return
		if params[param.name].type == 'm' or param.name == 'Open': return
		# Re-define the widget position
		yd = yrow[param.section]  	# y position for parameter label and control (default setting)
		yb = yd #*14.1/13.1 - 24.756  # y position for relative placement (board setting)  yb = yd - 23 # y position for parameter label and control (board setting)
		yc = yd #*14.1/12.45 - 53.23  # y position for relative placement (channel setting) yd - 45 # y position for parameter label and control (channel setting)
		yrow[param.section] += 25

		m_xdef = x_def 
		lx = 0
		kk = yd
		if param.name == "OutputFiles":
			yrow[param.section] = 10
			yd = yrow[param.section]
			yrow[param.section] += 25
			lx = 330
		if param.name == "DataFilePath":
			kk = yd-3
			m_xdef = 480 #465
			lx = 330
		if "OF_" in param.name:
			if 'FileUnit' in param.name: m_xdef = 480 #465
			else: m_xdef = 480 #520
			lx = 330
		# Replace everything except hideparam! self.button_names[param.name][2]
		if param.name in self.button_names: #yd/sh.Win_Tabs_H
			try:
				if param.name != 'WalkFitCoeff':
					self.button_names[param.name][0].place(relx=self.button_names[param.name][1], rely=(kk+self.button_names[param.name][2])/sh.Win_Tabs_H, relwidth=self.button_names[param.name][3], relheight=self.button_names[param.name][4]) #          self.button_names[param.name][2], relwidth=self.button_names[param.name][3], relheight=self.button_names[param.name][4]) # kk/sh.Win_Tabs_H    x=self.button_names[param.name][1], y=yd)
				else:
					self.button_names[param.name][0].place(relx=self.button_names[param.name][1], rely=(yd-4)/sh.Win_Tabs_H, relwidth=self.button_names[param.name][3], relheight=self.button_names[param.name][4]) # kk/sh.Win_Tabs_H    x=self.button_names[param.name][1], y=yd)				
			except:
				for click in self.button_names[param.name][0]:
					click.place(relx=self.button_names[param.name][1], rely=(kk+self.button_names[param.name][2])/sh.Win_Tabs_H, relwidth=self.button_names[param.name][3], relheight=self.button_names[param.name][4])


		if param.name in self.timeval:
			self.timeval[param.name].place(relx=(m_xdef/sh.Win_Tabs_W), rely=yd/sh.Win_Tabs_H, relwidth=0.147, relheight=0.039)
			self.rangeval[param.name].place(relx=(m_xdef/sh.Win_Tabs_W + 2*0.18), rely=(yd)/sh.Win_Tabs_H, relwidth=0.12)
			if "Lead" in param.name:
				shift = -25
				# if 'TOT' in self.par_def_svar['MeasMode'].get(): shift = 25
				# if "LEAD_ONLY" not in self.par_def_svar['MeasMode'].get(): shift = 25
				self.rangeval["LeadTrailFRange"].place(relx=(m_xdef/sh.Win_Tabs_W + 0.19), rely=(yd)/sh.Win_Tabs_H)
				# self.rangeval["LeadTrailGate"].place(relx=(m_xdef/sh.Win_Tabs_W + 0.19), rely=(yd+25)/sh.Win_Tabs_H) 
				# self.rangeval["LeadTrailGateVal"].place(relx=(m_xdef/sh.Win_Tabs_W + 2*0.18), rely=(yd+25)/sh.Win_Tabs_H, relwidth=0.12)
				self.rangeval["LeadMax"].place(relx=(m_xdef/sh.Win_Tabs_W + 0.19), rely=(yd+100+shift)/sh.Win_Tabs_H)
				self.rangeval["LeadMaxVal"].place(relx=(m_xdef/sh.Win_Tabs_W + 2*0.18), rely=(yd+100+shift)/sh.Win_Tabs_H, relwidth=0.12)
				if 'TrailHistoMin' not in hideparam:
					self.rangeval["TrailMax"].place(relx=(m_xdef/sh.Win_Tabs_W + 0.19), rely=(yd+125+shift)/sh.Win_Tabs_H)
					self.rangeval["TrailMaxVal"].place(relx=(m_xdef/sh.Win_Tabs_W + 2*0.18), rely=(yd+125+shift)/sh.Win_Tabs_H, relwidth=0.12)
			if "ToT" in param.name or 'TRAIL' in self.par_def_svar['MeasMode'].get():
				shift = -25
				# if 'TrailHistoMin' not in hideparam: 
				# 	shift = 0
				# 	# self.rangeval["ToT_LSB"].place(relx=(m_xdef/sh.Win_Tabs_W + 2*0.18), rely=(yd)/sh.Win_Tabs_H, relwidth=0.12)
				# else: shift = -25
				self.rangeval["ToTFRange"].place(relx=(m_xdef/sh.Win_Tabs_W + 0.19), rely=(yd)/sh.Win_Tabs_H)
				# self.rangeval["ToTGate"].place(relx=(m_xdef/sh.Win_Tabs_W + 0.19), rely=(yd+25)/sh.Win_Tabs_H) 
				# self.rangeval["ToTGateVal"].place(relx=(m_xdef/sh.Win_Tabs_W + 2*0.18), rely=(yd+25)/sh.Win_Tabs_H, relwidth=0.12)
				self.rangeval["ToTMax"].place(relx=(m_xdef/sh.Win_Tabs_W + 0.19), rely=(yd+100+shift)/sh.Win_Tabs_H)
				self.rangeval["ToTMaxVal"].place(relx=(m_xdef/sh.Win_Tabs_W + 2*0.18), rely=(yd+100+shift)/sh.Win_Tabs_H, relwidth=0.12)
		if params[param.name].type == '-':
			if param.name.find("_BLANK") < 0: self.par_def_label[param.name].place(relx=lx/sh.Win_Tabs_W, rely=yd/sh.Win_Tabs_H) # x=0, y=yd)
			return
		self.par_def_label[param.name].place(relx=lx/sh.Win_Tabs_W, rely=float(yd)/sh.Win_Tabs_H)  #   x=0, y=yd) x=0, y=yd)
		if params[param.name].type == 'c': 
			if params[param.name].distr == 'g': self.par_def_combo[param.name].place(relx=float(m_xdef)/sh.Win_Tabs_W, rely=float(yd)/sh.Win_Tabs_H, relwidth=0.163, relheight=0.039)  #   x=x_def, y=yd)
			elif params[param.name].distr == 'b': [self.par_brd_combo[param.name][brd].place(relx=float(x_brd)/sh.Win_Tabs_W, rely=float(yb)/sh.Win_Tabs_H, relwidth=0.2, relheight=0.039) for brd in range(sh.MaxBrd)] #x=x_brd, y=self.yb) 
			elif params[param.name].distr == 'c': [self.par_ch_combo[param.name][brd][ch].place(relx=(x_brd+ch%8*81.5)/sh.Win_Tabs_W, rely=yc/sh.Win_Tabs_H, relwidth=0.11, relheight=0.041) for brd in range(sh.MaxBrd) for ch in range(sh.MaxCh)] # x=2 + ch%8 * 50, y=self.yc) 
		elif params[param.name].type == 'b':
			# if "OF_" in param.name:
			# 	m_xdef = 500
			if params[param.name].distr == 'g': self.par_def_checkbox[param.name].place(relx=float(m_xdef)/sh.Win_Tabs_W, rely=float(yd)/sh.Win_Tabs_H)  #   x=x_def, y=yd)
			elif params[param.name].distr == 'b': [self.par_brd_checkbox[param.name][brd].place(relx=float(x_brd)/sh.Win_Tabs_W, rely=float(yb)/sh.Win_Tabs_H) for brd in range(sh.MaxBrd)] #x=x_brd, y=yb) 
			elif params[param.name].distr == 'c': [self.par_ch_checkbox[param.name][brd][ch].place(relx=(x_brd+ch%8*81.5)/sh.Win_Tabs_W, rely=yc/sh.Win_Tabs_H) for brd in range(sh.MaxBrd) for ch in range(sh.MaxCh)] #x=2 + ch%8 * 50, y=yc) 
		elif params[param.name].type == 'x':
			self.par_def_spinbox[param.name].place(relx=(float(m_xdef)/sh.Win_Tabs_W+0.147), rely=yd/sh.Win_Tabs_H, width=12, relheight=0.042)
		else:
			nch_t = 1
			if self.tabmode[param.section] == 2: nch_t = 8
			self.par_def_entry[param.name].place(relx=float(m_xdef)/sh.Win_Tabs_W, rely=float(yd)/sh.Win_Tabs_H, relwidth=0.163, relheight=0.036)  #   x=x_def, y=yd)
			if params[param.name].distr == 'b': [self.par_brd_entry[param.name][brd][tch].place(relx=float(x_brd)/sh.Win_Tabs_W, rely=float(yb)/sh.Win_Tabs_H, relwidth=0.27, relheight=0.041) for brd in range(sh.MaxBrd) for tch in range(nch_t)] #x=x_brd, y=ybx=x_brd, y=yb) 
			elif params[param.name].distr == 'c': [self.par_ch_entry[param.name][brd][ch].place(relx=(2+ch%8*81.5)/sh.Win_Tabs_W, rely=yc/sh.Win_Tabs_H, relwidth=0.11, relheight=0.041) for brd in range(sh.MaxBrd) for ch in range(sh.MaxCh)] #x=2 + ch%8 * 50, y=yc) 

		# TDC1 LED in Statistics tab
		# if self.tdc_num == 2 and 
		
	def remove_label(self, hideparam):
		en_button = {		# to enable the widget added to the GUI
			"Q_DiscrMask0": ["Q_DiscrMask0", "Q_DiscrMask1", "QD_CoarseThreshold", 
							 "QD_FineThreshold", "Q-Discriminators"],
			"Tlogic_Mask0": ["FastShaperInput", "TD_CoarseThreshold", "TD_FineThreshold",
							 "Trg_HoldOff", "Tlogic_Mask0", "Tlogic_Mask1", "T-Discriminators"]
		}

		for item in en_button.values():
			val = item[0] in hideparam
			for i in range(len(item)-2):
				val = val and (item[i] in hideparam)
			if val:
				self.par_def_label[item[-1]].place_forget()

	def load_tabs_widget(self, basic_advanced, acqmode, measmode, ch_mode, jobenabled):
		x_def = 140	# x-pos of default entry/combo
		x_brd = 3	# x-pos of board entry/combo
		x_ch = 300	# x-pos of channel entry/combo
		yrow = {s: 10 for s in sections} # initial Y-position for default and channel rows (one variable per section)
		tabmodel = {s : 0 for s in sections}
		for param in params.values():
			if param.distr == 'c': 
				tabmodel[param.section] = 2
				yrow[param.section] = 40
			if param.distr == 'b' and tabmodel[param.section] == 0: 
				tabmodel[param.section] = 1
				yrow[param.section] = 10
				
		# Load inverse of rename (it can be with enumerate(self.param_rename))
		self.rename_parname = {}
		hidetab = []
		hideparam = []
		
		for key, val in self.param_rename.items(): # inverse rename parameters GUI name: C name
			self.rename_parname[val] = str(key)
		
		my_hiding_status = re.compile("["+ basic_advanced + self.AcqMode_Dict[acqmode] + self.MeasMode_Dict[measmode] + ch_mode +"]")
		
		hideparam = self.load_par2remove(my_hiding_status, 'h')	# get name to remove
		hidetab = self.load_par2remove(my_hiding_status, 't')
		for param in params.values():	# place everything that is not in gui file
			self.place_widgets(param, hideparam, yrow, x_def, x_brd)
			if param.name in list(self.new_options.keys()):
				self.set_new_options(param, self.AcqMode_Dict[acqmode], self.MeasMode_Dict[measmode], jobenabled)
				# Check that what is shown is in the new options
	
		self.remove_label(hideparam)
		self.Mtabs_shown.clear()
		
		for s in sections:	# remove the sections that are in the hiddenfile
			if s in hidetab: continue # and basic_advanced == '0': continue
			self.Mtabs_nb.add(self.Mtabs[s], text=' ' + s + ' ')
			self.Mtabs_shown[s] = self.Mtabs[s]

		return 0

		
	def update_guimode(self, basic_advanced):	
		# remove every widget - contorl if the GUIbasic/advanced file exists
		# If the entries related to a button are missing the button is removed 
		if not os.path.exists(sh.GuiModeFile):
			with open(sh.GuiModeFile, 'w') as f:
				if '5202' in sh.Version:
					f.write("# List of the parameters that won't be visualized in the different GUI views\n")
					f.write("# xNNN, where x=a, b, N=0 to 5 (multiple N allowed)\n")
					f.write("# x: a=Advanced, b=Basic\n")
					f.write("# N: SPECT=0, SPECT_TIME=1, TIME_CSTART=2, TIME_CSTOP=3, COUNT=4, WAVE=5 (see par_defs.txt for details)\n")
					f.write("# Es: Run Sleep			b01 (parameter removed in basic, spect and specttime modes\n")
					f.write("# Please, use 'tab' for spacing param_name and hiding attriute\n")
					f.write("# Param name		Hiding Attribute\n")
				else:
					f.write("# List of the parameters that won't be visualized in the different GUI views\n")
					f.write("# xNNNXXXCC, where x=a, b, N=0 to 5, X=A,B..., C=L,K, E=J,N (multiple N, X and C allowed)\n")
					f.write("# x: a=Advanced, b=Basic\n")
					f.write("# N: COMMON_START=0, COMMON_STOP=1, TRG_MATCHING=2, STREAMING=3 (see par_defs.txt for details)\n")
					f.write("# X: RISE_ONLY=A, RISE_FALL=B, RISE_TOT8=C, RISE_TOT11=D\n")
					f.write("# C: 64 channels=L, 128 channels=K\n")
					f.write("# E: JobEnalbed=J, JobNotEnabled=N\n")
					f.write("# Es: Run Sleep			b01BK (parameter removed in basic, common_start/stop and in rise_fall and 128 channels board\n")
					f.write("# Please, use 'tab' for spacing param_name and hiding attriute\n")
					f.write("# Param name		Hiding Attribute\n")

		acqmode = self.par_def_svar["AcquisitionMode"].get()
		try:
			measmode = self.par_def_svar["MeasMode"].get()
		except:
			measmode = ""

		if int(self.par_def_svar["EnableJobs"].get()): 
			jobenabled = "J"
		else: 
			jobenabled = "N"

		if acqmode not in self.AcqMode_Dict: return
		tab_idx = self.Mtabs_nb.select() # get the tab currently selected

		self.tdc_num.set(1)
		ch_mode = 'L'
		for info in self.info_board_model:
			if not len(info.cget('text')): break	# No more  
			if 'B' == info.cget('text')[-1]:
				ch_mode = 'K'
				self.tdc_num.set(2)
				break

		#if not_acq_ch:
		#	if basic_advanced == 'a': 
		#		self.Output.insert(END, "Switch to Advanced GUI view\n")
		#	elif basic_advanced == 'b': 
		#		self.Output.insert(END, "Switch to Basic GUI view\n")
		#else:
		#	self.Output.insert(END, "Switch to " +  acqmode + " view\n")
		#self.Output.yview_scroll(100, UNITS)

		if acqmode not in self.AcqMode_Dict or measmode not in self.MeasMode_Dict:
			# Send warning only when JanusC is not connected
			if self.status_now < 1: self.Output.insert(END, "Unknown AcqMode or MeasMode parameter. The GUI cannot update its view.\n", 'warning')
			return -1

		self.remove_tabs_widget()
		self.load_tabs_widget(basic_advanced, acqmode, measmode, ch_mode, jobenabled)

		# set tab Notebook to the last active one 
		self.Mtabs_nb.select(tab_idx)

		if params["MeasMode"].default not in self.par_def_combo["MeasMode"]['values']:
			self.par_def_svar["MeasMode"].set(self.par_def_combo["MeasMode"]['values'][0])

		if params["StopRunMode"].default not in self.par_def_combo["StopRunMode"]['values']:
			self.par_def_svar["StopRunMode"].set(self.par_def_combo["StopRunMode"]['values'][0])

	

