diff --git a/Ccs/ccs_function_lib.py b/Ccs/ccs_function_lib.py
index d97061997d704eea1f1cfea5bd90ffa9efaf6dec..ce311a50b60997a80553060d583345caad1cd524 100644
--- a/Ccs/ccs_function_lib.py
+++ b/Ccs/ccs_function_lib.py
@@ -82,9 +82,10 @@ SEG_CRC_LEN = 2
 pid_offset = int(cfg.get('ccs-misc', 'pid_offset'))
 
 fmtlist = {'INT8': 'b', 'UINT8': 'B', 'INT16': 'h', 'UINT16': 'H', 'INT32': 'i', 'UINT32': 'I', 'INT64': 'q',
-           'UINT64': 'Q', 'FLOAT': 'f', 'DOUBLE': 'd', 'INT24': 'i24', 'UINT24': 'I24', 'bit*': 'bit'}
+           'UINT64': 'Q', 'FLOAT': 'f', 'DOUBLE': 'd', 'INT24': 'i24', 'UINT24': 'I24', 'uint*': 'uint',
+           'ascii*': 'ascii', 'oct*': 'oct'}
 
-personal_fmtlist = ['uint', 'ascii', 'oct']
+personal_fmtlist = []
 
 fmtlengthlist = {'b': 1, 'B': 1, 'h': 2, 'H': 2, 'i': 4, 'I': 4, 'q': 8,
                  'Q': 8, 'f': 4, 'd': 8, 'i24': 3, 'I24': 3}
@@ -115,8 +116,6 @@ if cfg.has_section('ccs-user_defined_packets'):
 else:
     user_tm_decoders = {}
 
-# Notify.init('cfl')
-
 
 def _add_log_socket_handler():
     global logger
@@ -584,13 +583,10 @@ def set_monitor(pool_name=None, param_set=None):
 
 
 def user_tm_decoders_func():
-
     if cfg.has_section('ccs-user_defined_packets'):
-        user_tm_decoders = {k: json.loads(cfg['ccs-user_defined_packets'][k])
-                                 for k in cfg['ccs-user_defined_packets']}
+        user_tm_decoders = {k: json.loads(cfg['ccs-user_defined_packets'][k]) for k in cfg['ccs-user_defined_packets']}
     else:
         user_tm_decoders = {}
-
     return user_tm_decoders
 
 
@@ -629,13 +625,11 @@ def Tmformatted(tm, separator='\n', sort_by_name=False, textmode=True, UDEF=Fals
 #  Decode source data field of TM packet
 #  @param tm TM packet bytestring
 def Tmdata(tm, UDEF=False, *args):
-    tmdata = None
-    tmname = None
     tpsd = None
     params = None
     dbcon = scoped_session_idb
 
-    # This will be used to first check if an UDEF exists and used this to decode, if not the ÍDB will be checked
+    # This will be used to first check if an UDEF exists and used this to decode, if not the IDB will be checked
     if UDEF:
         try:
             header, data, crc = Tmread(tm)
@@ -702,6 +696,7 @@ def Tmdata(tm, UDEF=False, *args):
             if params is None:
                 dbres = dbcon.execute(que)
                 spid, tpsd, dfhsize = dbres.fetchall()[0]
+        # TODO: proper handling of super-commutated parameters
         if tpsd == -1 and params is None:
             que = 'SELECT pcf.pcf_name,pcf.pcf_descr,plf_offby,plf_offbi,pcf.pcf_ptc,pcf.pcf_pfc,\
             pcf.pcf_unit,pcf.pcf_pid,pcf.pcf_width FROM plf LEFT JOIN pcf ON plf.plf_name=pcf.pcf_name WHERE \
@@ -709,7 +704,6 @@ def Tmdata(tm, UDEF=False, *args):
             ORDER BY plf_offby,plf_offbi'.format(spid)
             dbres = dbcon.execute(que)
             params = dbres.fetchall()
-            #o = data.unpack(','.join([ptt[i[4]][i[5]] for i in params]))
             vals_params = decode_pus(data, params)
             tmdata = [(get_calibrated(i[0], j[0]), i[6], i[1], pidfmt(i[7]), j) for i, j in zip(params, vals_params)]
 
@@ -721,7 +715,6 @@ def Tmdata(tm, UDEF=False, *args):
             else: #Decode according to given order, length is then 11
                 vals_params = read_variable_pckt(data, params)
 
-            #vals_params = decode_pus(data, params)
             tmdata = [(get_calibrated(i[0], j[0]), i[6], i[1], pidfmt(i[7]), j) for i, j in zip(params, vals_params)]
         else:
             que = 'SELECT pcf.pcf_name,pcf.pcf_descr,pcf.pcf_ptc,pcf.pcf_pfc,pcf.pcf_curtx,pcf.pcf_width,\
@@ -742,7 +735,6 @@ def Tmdata(tm, UDEF=False, *args):
             tmname = ['USER DEFINED: {}'.format(user_label)]
     except Exception as failure:
         raise Exception('Packet data decoding failed: ' + str(failure))
-        # logger.info('Packet data decoding failed.' + str(failure))
     finally:
         dbcon.close()
     return tmdata, tmname
@@ -1300,7 +1292,7 @@ def get_calibrated(pcf_name, rawval, properties=None, numerical=False, dbcon=Non
         fetch = dbres.fetchall()
         dbcon.close()
         if len(fetch) == 0:
-            return rawval[0]
+            return rawval if isinstance(rawval, int) else rawval[0]
 
         ptc, pfc, categ, curtx = fetch[0]
 
@@ -1310,7 +1302,10 @@ def get_calibrated(pcf_name, rawval, properties=None, numerical=False, dbcon=Non
     try:
         type_par = ptt(ptc, pfc)
     except NotImplementedError:
-        type_par = None
+        try:
+            return rawval if isinstance(rawval, int) else rawval[0]
+        except IndexError:
+            return rawval
 
     if type_par == timepack[0]:
         #return timecal(rawval, 'uint:32,uint:15,uint:1')
@@ -1384,7 +1379,7 @@ def get_txp_altxt(pcf_name, alval, dbcon=None):
 #  @param st_filter Save only packets of this service type
 def Tmdump(filename, tmlist, mode='hex', st_filter=None, check_crc=False):
     if st_filter is not None:
-        tmlist = Tm_filter_st(tmlist, *st_filter)
+        tmlist = Tm_filter_st(tmlist, **st_filter)
 
     if check_crc:
         tmlist = (tm for tm in tmlist if not crc_check(tm))
@@ -1405,39 +1400,32 @@ def Tmdump(filename, tmlist, mode='hex', st_filter=None, check_crc=False):
         for tm in tmlist:
             try:
                 txtlist.append(Tmformatted(tm, separator='; '))
-            except:
+            except Exception as err:
+                # logger.warning(err)
                 txtlist.append(Tm_header_formatted(tm) + '; ' + str(tm[TM_HEADER_LEN:]))
         with open(filename, 'w') as f:
             f.write('\n'.join(txtlist))
 
 
-##
-#  Filter by service (sub-)type
-#
-#  Return list of TM packets filtered by service type and sub-type
-#  @param tmlist List of TM packets
-#  @param st     Service type
-#  @param        Service sub-type
-def Tm_filter_st(tmlist, st=None, sst=None, apid=None, sid=None, time_from=None, time_to=None, eventId=None,
-                 procId=None):
-    """From tmlist return list of packets with specified st,sst"""
-    # stsst=pack('2*uint:8',st,sst).bytes
-    # filtered=[tmlist[i] for i in np.argwhere([a==stsst for a in [i[7:9] for i in tmlist]]).flatten()]
-    if (st is not None) and (sst is not None):
-        tmlist = [tm for tm in tmlist if ((tm[7], tm[8]) == (st, sst))]
+def Tm_filter_st(tmlist, st=None, sst=None, apid=None, sid=None, time_from=None, time_to=None):
+    """From tmlist return list of packets with specified criteria"""
+    if st is not None:
+        tmlist = [tm for tm in tmlist if tm[7] == st]
 
-    if sid is not None:
-        tmlist = [tm for tm in list(tmlist) if (tm[TM_HEADER_LEN] == sid or tm[TM_HEADER_LEN] + tm[TM_HEADER_LEN + 1] == sid)] # two possibilities for SID because of  different definition (length) for SMILE and CHEOPS
+    if sst is not None:
+        tmlist = [tm for tm in tmlist if tm[8] == sst]
 
     if apid is not None:
-        tmlist = [tm for tm in list(tmlist) if ((struct.unpack('>H', tm[:2])[0] & 2047) == (apid))]
+        # tmlist = [tm for tm in list(tmlist) if ((struct.unpack('>H', tm[:2])[0] & 2047) == apid)]
+        tmlist = [tm for tm in list(tmlist) if (int.from_bytes(tm[:2], 'big') & 0x7FF) == apid]
 
-    if eventId is not None:
-        tmlist = [tm for tm in list(tmlist) if (struct.unpack('>H', tm[TM_HEADER_LEN:TM_HEADER_LEN + 2])[0] == eventId)]
+    if sid is not None:
+        if st is None or sst is None or apid is None:
+            raise ValueError('Must provide st, sst and apid if filtering by sid')
 
-    if procId is not None:
-        tmlist = [tm for tm in list(tmlist) if
-                  (struct.unpack('>H', tm[TM_HEADER_LEN + 2:TM_HEADER_LEN + 4])[0] == procId)]
+        sid_offset, sid_bitlen = get_sid(st, sst, apid)
+        tobyte = sid_offset + sid_bitlen // 8
+        tmlist = [tm for tm in list(tmlist) if int.from_bytes(tm[sid_offset:tobyte], 'big') == sid]
 
     if time_from is not None:
         tmlist = [tm for tm in list(tmlist) if (time_from <= get_cuctime(tm))]
@@ -1519,12 +1507,14 @@ def get_pool_rows(pool_name, check_existence=False):
 
 
 #  get values of parameter from HK packets
-def get_param_values(tmlist=None, hk=None, param=None, last=0, numerical=False):
+def get_param_values(tmlist=None, hk=None, param=None, last=0, numerical=False, tmfilter=True, pool_name=None):
 
     if param is None:
         return
 
-    # with self.poolmgr.lock:
+    if tmlist is None and pool_name is not None:
+        tmlist = get_pool_rows(pool_name, check_existence=True)
+
     dbcon = scoped_session_idb
     if hk is None:
         que = 'SELECT plf.plf_name,plf.plf_spid,plf.plf_offby,plf.plf_offbi,pcf.pcf_ptc,pcf.pcf_pfc,pcf.pcf_unit,\
@@ -1535,8 +1525,9 @@ def get_param_values(tmlist=None, hk=None, param=None, last=0, numerical=False):
         name, spid, offby, offbi, ptc, pfc, unit, descr, apid, st, sst, hk, sid = dbres.fetchall()[0]
         if not isinstance(tmlist, list):
             tmlist = tmlist.filter(DbTelemetry.stc == st, DbTelemetry.sst == sst, DbTelemetry.apid == apid,
-                                   func.mid(DbTelemetry.data, SID_OFFSET - TM_HEADER_LEN + 1, SID_SIZE) == struct.pack(SID_FORMAT[SID_SIZE], sid)).order_by(
-                DbTelemetry.idx.desc())
+                                   func.mid(DbTelemetry.data, get_sid(st, sst, apid)[0] - TM_HEADER_LEN + 1,
+                                            get_sid(st, sst, apid)[1] // 8) == sid.to_bytes(get_sid(st, sst, apid)[1] // 8, 'big')
+                                   ).order_by(DbTelemetry.idx.desc())
             if tmlist is not None:
                 if last > 1:
                     tmlist_filt = [tm.raw for tm in tmlist[:last]]
@@ -1545,96 +1536,84 @@ def get_param_values(tmlist=None, hk=None, param=None, last=0, numerical=False):
             else:
                 tmlist_filt = []
         else:
-            if (st, sst) == (3, 25):
-                tmlist_filt = Hk_filter(tmlist, st, sst, apid, sid)[-last:]
-            else:
-                tmlist_filt = Tm_filter_st(tmlist, st=st, sst=sst, apid=apid)[-last:]
-        #ufmt = ptt['hk'][ptc][pfc]
+            sid = None if sid == 0 else sid
+            tmlist_filt = Tm_filter_st(tmlist, st=st, sst=sst, apid=apid, sid=sid)[-last:] if tmfilter else tmlist[-last:]
+
         ufmt = ptt(ptc, pfc)
+
     elif hk != 'User defined' and not hk.startswith('UDEF|'):
-        if not isinstance(param, int):
-            pass  # param=self.get_pid(param)
         que = 'SELECT pid_descr, pid_type,pid_stype,pid_pi1_val,pid_apid,plf.plf_name,plf.plf_spid,plf.plf_offby,plf.plf_offbi,\
                    pcf.pcf_ptc,pcf.pcf_pfc,pcf.pcf_unit,pcf.pcf_descr,pcf.pcf_pid from pid left join plf on\
                    pid.pid_spid=plf.plf_spid left join pcf on plf.plf_name=pcf.pcf_name where\
                    pcf.pcf_descr="%s" and pid.pid_descr="%s"' % (param, hk)
         dbres = dbcon.execute(que)
         hkdescr, st, sst, sid, apid, name, spid, offby, offbi, ptc, pfc, unit, descr, pid = dbres.fetchall()[0]
-        if sid == 0:
-            sid = None
-        tmlist_filt = Tm_filter_st(tmlist, st=st, sst=sst, apid=apid, sid=sid)[-last:]
-        #ufmt = ptt['hk'][ptc][pfc]
+
+        sid = None if sid == 0 else sid
+        tmlist_filt = Tm_filter_st(tmlist, st=st, sst=sst, apid=apid, sid=sid)[-last:] if tmfilter else tmlist[-last:]
+
         ufmt = ptt(ptc, pfc)
 
     elif hk.startswith('UDEF|'):
-        label = hk.strip('UDEF|')
+        label = hk.replace('UDEF|', '')
         hkref = [k for k in user_tm_decoders if user_tm_decoders[k][0] == label][0]
         pktinfo = user_tm_decoders[hkref][1]
         parinfo = [x for x in pktinfo if x[1] == param][0]
         pktkey = hkref.split('-')
 
+        st = int(pktkey[0])
+        sst = int(pktkey[1])
         apid = int(pktkey[2]) if pktkey[2] != 'None' else None
-        sid = int(pktkey[3])
+        sid = int(pktkey[3]) if pktkey[3] != 'None' else None
         name, descr, _, offbi, ptc, pfc, unit, _, bitlen = parinfo
 
-        offby = sum(
-            [x[-1] for x in pktinfo[:pktinfo.index(parinfo)]]) // 8 + TM_HEADER_LEN  # +TM_HEADER_LEN for header!
-        st = 3
-        sst = 25
-        tmlist_filt = Hk_filter(tmlist, st, sst, apid, sid)[-last:]
-        #ufmt = ptt['hk'][ptc][pfc]
+        offby = sum([x[-1] for x in pktinfo[:pktinfo.index(parinfo)]]) // 8 + TM_HEADER_LEN  # +TM_HEADER_LEN for header
+        tmlist_filt = Tm_filter_st(tmlist, st, sst, apid, sid)[-last:] if tmfilter else tmlist[-last:]
         ufmt = ptt(ptc, pfc)
+
     else:
         userpar = json.loads(cfg[CFG_SECT_PLOT_PARAMETERS][param])
-        if ('SID' not in userpar.keys()) or (userpar['SID'] is None):
-            tmlist_filt = Tm_filter_st(tmlist, userpar['ST'], userpar['SST'], apid=userpar['APID'])[-last:]
-        else:
-            tmlist_filt = Tm_filter_st(tmlist, userpar['ST'], userpar['SST'], apid=userpar['APID'],
-                                            sid=userpar['SID'])[-last:]
+        sid = None if (('SID' not in userpar.keys()) or (userpar['SID'] is None)) else userpar['SID']
+        tmlist_filt = Tm_filter_st(tmlist, userpar['ST'], userpar['SST'], apid=userpar['APID'], sid=sid)[-last:] if tmfilter else tmlist[-last:]
         offby, ufmt = userpar['bytepos'], userpar['format']
-        if 'offbi' in userpar:
-            offbi = userpar['offbi']
-        else:
-            offbi = 0
+        offbi = userpar['offbi'] if 'offbi' in userpar else 0
         descr, unit, name = param, None, None
 
     bylen = csize(ufmt)
-    #print(tmlist_filt)
-    #tms = io.BytesIO(tmlist_filt)
     if name is not None:
         que = 'SELECT pcf.pcf_categ,pcf.pcf_curtx from pcf where pcf_name="%s"' % name
         dbres = dbcon.execute(que)
         fetch = dbres.fetchall()
+
+        if not fetch:
+            logger.error('Parameter {} not found in MIB.'.format(name))
+            return
+
         categ, curtx = fetch[0]
         xy = [(get_cuctime(tm),
                get_calibrated(name, read_stream(io.BytesIO(tm[offby:offby + bylen]), ufmt, offbi=offbi),
-                                   properties=[ptc, pfc, categ, curtx], numerical=numerical)) for tm in tmlist_filt]
+                              properties=[ptc, pfc, categ, curtx], numerical=numerical)) for tm in tmlist_filt]
 
     else:
         xy = [(get_cuctime(tm), read_stream(io.BytesIO(tm[offby:offby + bylen]), ufmt, offbi=offbi)) for tm in tmlist_filt]
     dbcon.close()
+
     try:
         return np.array(np.array(xy).T, dtype='float'), (descr, unit)
     except ValueError:
         return np.array(xy, dtype='float, U32'), (descr, unit)
 
 
-##
-#  Filter HK TMs by SID and APID
-#  @param tmlist List of TM(3,25) packets
-#  @param apid   APID by which to filter
-#  @param sid    SID by which to filter
 def Hk_filter(tmlist, st, sst, apid=None, sid=None):
-    # hks=self.Tm_filter_st(tmlist,3,25)
-    # hkfiltered=[tm for tm in hks if ccs.Tmread(tm)[3]==apid and tm[16]==sid]
 
-    if apid in (None, '') and sid not in (0, None):
-        return [tm for tm in tmlist if (
-                len(tm) > TM_HEADER_LEN and (tm[7], tm[8], tm[TM_HEADER_LEN]) == (st, sst, sid))]
-    elif sid not in (0, None):
-        return [tm for tm in tmlist if (
-                len(tm) > TM_HEADER_LEN and (tm[7], tm[8], struct.unpack('>H', tm[:2])[0] & 0b0000011111111111,
-                                             tm[TM_HEADER_LEN]) == (st, sst, apid, sid))]
+    # if apid in (None, '') and sid not in (0, None):
+    #     return [tm for tm in tmlist if (
+    #             len(tm) > TM_HEADER_LEN and (tm[7], tm[8], tm[TM_HEADER_LEN]) == (st, sst, sid))]
+    # elif sid not in (0, None):
+    #     return [tm for tm in tmlist if (
+    #             len(tm) > TM_HEADER_LEN and (tm[7], tm[8], struct.unpack('>H', tm[:2])[0] & 0b0000011111111111,
+    #                                          tm[TM_HEADER_LEN]) == (st, sst, apid, sid))]
+    return Tm_filter_st(tmlist, st=st, sst=sst, apid=apid, sid=sid)
 
 
 def show_extracted_packet():
@@ -3307,7 +3286,7 @@ def _get_spid(st, sst, apid=None, pi1val=0):
     return spid, tpsd
 
 
-def get_data_pool_items(pcf_descr=None, src_file=None):
+def get_data_pool_items(pcf_descr=None, src_file=None, as_dict=False):
     if not isinstance(src_file, (str, type(None))):
         raise TypeError('src_file must be str, is {}.'.format(type(src_file)))
 
@@ -3324,7 +3303,13 @@ def get_data_pool_items(pcf_descr=None, src_file=None):
                 else:
                     raise ValueError('Wrong format of input line in {}.'.format(src_file))
 
-        return data_pool
+        if as_dict:
+            data_pool_dict = {int(row[0]): {'descr': row[1], 'fmt': fmtlist[row[2]]} for row in data_pool if row[2] in fmtlist}
+            if len(data_pool_dict) != len(data_pool):
+                logger.warning('Data pool items were rejected because of unknown format ({})'.format(len(data_pool) - len(data_pool_dict)))
+            return data_pool_dict
+        else:
+            return data_pool
 
     elif pcf_descr is None and not src_file:
         data_pool = scoped_session_idb.execute('SELECT pcf_pid, pcf_descr, pcf_ptc, pcf_pfc '
@@ -3336,10 +3321,13 @@ def get_data_pool_items(pcf_descr=None, src_file=None):
 
     scoped_session_idb.close()
 
-    data_pool_dict = {}
+    if not as_dict:
+        return data_pool
+
+    data_pool_dict = {int(row[0]): {'descr': row[1], 'fmt': ptt(row[2], row[3])} for row in data_pool}
 
-    for row in data_pool:
-        data_pool_dict.setdefault(row[0:4], []).append(row[5:])
+    # for row in data_pool:
+    #     data_pool_dict.setdefault(row[0:4], []).append(row[5:])
 
     return data_pool_dict
 
@@ -3530,67 +3518,29 @@ def change_main_communication(new_main, new_main_nbr, main_instance, own_bus_nam
     return
 
 
-def add_decode_parameter(label=None, format=None, bytepos=None, parentwin=None):
+def add_decode_parameter(parentwin=None):  # , label=None, fmt=None, bytepos=None):
     """
-    Add a Parameter which can be used in the User Defined Package, only defined by the format and can therefore only be
+    Add a parameter which can be used in a User DEFined packet, only defined by the format and can therefore only be
     used if the package is decoded in the given order
-    :param label: Name of the parameter
-    :param format: The format of the Parameter given as the actual String or the location in the ptt definition
-    :param bytepos: The offset where a parameter is located in a packet
     :param parentwin: For graphical usage
     :return:
     """
 
-    pos = None
-    fmt = None
-
-    if format and label:
-        #if label in cfg['ccs-plot_parameters']:
-        #    print('Please choose a different name for the parameter, can not exist as plot and decode parameter')
-        #    return
-        if isinstance(format, str):
-            try:
-                dummy = ptt_reverse(format)
-                fmt = format
-            except NotImplementedError:
-                if format not in fmtlist.keys():
-                    logger.error('Please give a correct Format')
-                    return
-                else:
-                    fmt = fmtlist[format]
-        elif isinstance(format, (list, tuple)):
-            if len(format) == 2:
-                try:
-                    fmt = ptt(format[0], format[1])
-                except NotImplementedError:
-                    logger.error('Give valid location of format')
-                    return
-            else:
-                logger.error('Please give a correct PTC/PFC format tuple')
-                return
-
-        if bytepos:
-            pos = bytepos
-
-    elif parentwin is not None:
+    if parentwin is not None:
         dialog = TmParameterDecoderDialog(parent=parentwin)
 
         response = dialog.run()
         if response == Gtk.ResponseType.OK:
             label = dialog.label.get_text()
-            #if label in cfg['ccs-plot_parameters']:
-            #    print('Please choose a different name for the parameter, can not exist as plot and decode parameter')
-            #    dialog.destroy()
-            #    return
-            pos = dialog.bytepos.get_active_text()
             fmt = dialog.format.get_active_text()
             if fmt in fmtlist:
                 fmt = fmtlist[fmt]
-                if fmt == 'bit':
+                if fmt in ('uint', 'ascii', 'oct'):
                     fmt += str(dialog.bitlen.get_text())
 
             else:
                 fmt += str(dialog.bitlen.get_text())
+                fmt = fmt.replace('*', '')
                 if fmt.upper() in fmtlist:
                     fmt = fmtlist[fmt.upper()]
             dialog.destroy()
@@ -3599,63 +3549,32 @@ def add_decode_parameter(label=None, format=None, bytepos=None, parentwin=None):
             return
 
     else:
-        logger.error('Please give a Format')
+        logger.error('Please give a valid format')
         return
 
-    # If a position was found the parameter will be stored in user_decoder layer in cfg
-    leng = None
-    if pos:
-        if fmt in fmtlengthlist:
-            leng = fmtlengthlist[fmt]
-        elif fmt.startswith(('bit', 'oct')):
-            len_test = int(fmt[3:])
-            if len_test % 8 == 0:
-                leng = len_test
-        elif fmt.startswith('uint'):
-            len_test = int(fmt[4:])
-            if len_test % 8 == 0:
-                leng = len_test
-        elif fmt.startswith('ascii'):
-            len_test = int(fmt[5:])
-            if len_test % 8 == 0:
-                leng = len_test
-        else:
-            # print('Something went wrong')
-            logger.error('Failed generating UDEF Parameter')
-            return
-
-        if leng:
-            dump = {'bytepos': str(pos), 'bytelen': str(leng), 'format': str(fmt)}
-            cfg.save_option_to_file('ccs-user_decoders', label, json.dumps(dump))
-        else:
-            dump = {'bytepos': str(pos), 'format': str(fmt)}
-            cfg.save_option_to_file('ccs-user_decoders', label, json.dumps(dump))
-    else:
-        cfg['ccs-decode_parameters'][label] = json.dumps(('format', str(fmt)))
-        cfg.save_option_to_file('ccs-decode_parameters', label, json.dumps(('format', str(fmt))))
+    cfg.save_option_to_file('ccs-decode_parameters', label, json.dumps({'format': str(fmt)}))
 
     if fmt:
-        return fmt
+        return {'format': str(fmt)}
     else:
         return
 
 
-# Let one add an additional User defined Package
-# Which can than be decoded
-def add_tm_decoder(label=None, st=None, sst=None, apid=None, sid=None, parameters=None, idb_pos=False, parentwin=None):
+def add_tm_decoder(label=None, st=None, sst=None, apid=None, sid=None, parameters=None, parentwin=None):
     """
-    Add decoding info for TM not defined in IDB
+    Add User DEFined packet with decoding info for TM not defined in IDB
     @param label: Name of new defined packet
     @param st: Service Type
     @param sst: Sub Service Type
     @param apid:
     @param sid:
     @param parameters: list of parameters
-    @param idb_pos: False decode in given order, True decode in given/IBD given positiontm
+    @param parentwin:
     @return:
     """
 
     if label and st and sst and apid:
+        sid = sid if sid else 0
         tag = '{}-{}-{}-{}'.format(st, sst, apid, sid)
 
     elif parentwin is not None:
@@ -3663,14 +3582,10 @@ def add_tm_decoder(label=None, st=None, sst=None, apid=None, sid=None, parameter
 
         response = dialog.run()
         if response == Gtk.ResponseType.OK:
-            slots = dialog.get_content_area().get_children()[0].get_children()[1].get_children()
-            parameters_name = []
-            model = slots[0].get_children()[1].get_child().get_model()
-            parameters_name.append([par[1] for par in model])
-            parameters = parameters_name[0]
-            tag = '{}-{}-{}-{}'.format(dialog.st.get_text(), dialog.sst.get_text(), dialog.apid.get_text(), dialog.sid.get_text())
+            parameters = [par for par in dialog.parameter_list]
+            sid = dialog.sid.get_text() if dialog.sid.get_text() else 0
+            tag = '{}-{}-{}-{}'.format(dialog.st.get_text(), dialog.sst.get_text(), dialog.apid.get_text(), sid)
             label = dialog.label.get_text()
-            idb_pos = dialog.idb_position.get_active()
             dialog.destroy()
         else:
             dialog.destroy()
@@ -3678,144 +3593,113 @@ def add_tm_decoder(label=None, st=None, sst=None, apid=None, sid=None, parameter
     else:
         logger.error('Please give: label, st, sst and apid')
         return
-    dbcon = scoped_session_idb
 
-    if sid is not None:
-        parameters = ['Sid'] + parameters
-    if None in parameters: # Check if a User defined Parameter was selected
-        parameters_descr = []
-        parameters_descr.append([par[0] for par in model])
-        parameters_descr = parameters_descr[0]
-
-        # The values of the Parameters which are in the database can be found via SQL, the UD parameters have to be looked up in the config file
-        params = []
-        i =0
-        if idb_pos: #Parameters should be decoded by there position given in the IDB or config file
-
-            while i < len(parameters_descr): # Check for each parameter if it is User-defined or IDB
-                if parameters[i] is not None: # If parameter is in IDB get its values with SQL Query
-                    que = 'SELECT DISTINCT pcf.pcf_name,pcf.pcf_descr,plf_offby,plf_offbi,pcf.pcf_ptc,pcf.pcf_pfc,\
-                        pcf.pcf_unit,pcf.pcf_pid,pcf.pcf_width FROM plf LEFT JOIN pcf ON plf.plf_name=pcf.pcf_name  \
-                        WHERE pcf_name ="%s"' %parameters[i]
-
-                    dbres = dbcon.execute(que)
-                    params_value = dbres.fetchall()
-                    params.append(params_value[0])
-                else: # Parameter is User Defined get the values from the config file
-                    try:
-                        params_values = json.loads(cfg['ccs-user_decoders'][parameters_descr[i]])
-                    except:
-                        # print('Parameter: {} can only be decoded in given order'.format(parameters_descr[i]))
-                        logger.info('Parameter: {} can only be decoded in given order'.format(parameters_descr[i]))
-                        return
-                    ptt_value = ptt_reverse(params_values['format'])
-                    params_value = ['user_defined', parameters_descr[i],
-                                    params_values['bytepos'] if 'bytepos' in params_values else None,
-                                    params_values['bytelen'] if 'bytelen' in params_values else None,
-                                    ptt_value[0], ptt_value[1],
-                                    None, None, None]
-                    params.append(tuple(params_value))
-                i += 1
-
-        else: #Parameters will be decoded in the given order
-            while i < len(parameters_descr):  # Check for each parameter if it is User-defined or IDB
-                if parameters[i] is not None:  # If parameter is in IDB get its values with SQL Query
-                    #que = 'SELECT pcf.pcf_name,pcf.pcf_descr,pcf.pcf_ptc,pcf.pcf_pfc,pcf.pcf_curtx, \
-                    #        pcf.pcf_width,pcf.pcf_unit,pcf.pcf_pid,vpd_pos,vpd_grpsize,vpd_fixrep from vpd  \
-                    #        left join pcf on vpd.vpd_name=pcf.pcf_name WHERE pcf_name ="%s"' % parameters[i]
-
-
-                    # Most parameters do not have an entry in the vpd table, therefore most of the time the query
-                    # would give no result. But what would be needed would be 3 entries with null at the end. This
-                    # is done manually here.
-                    # Furthermore this means that parameters are only treathed as fixed parameters
-
-                    que = 'SELECT pcf.pcf_name,pcf.pcf_descr,pcf.pcf_ptc,pcf.pcf_pfc,pcf.pcf_curtx, \
-                            pcf.pcf_width,pcf.pcf_unit,pcf.pcf_pid,null,null,null from pcf \
-                            WHERE pcf_name ="%s"' % parameters[i]
-
-                    dbres = dbcon.execute(que)
-                    params_value = dbres.fetchall()
-                    params.append(params_value[0])
-
-                else:  # Parameter is User Defined get the values from the config file
-                    try: # Check where parameter is defined
-                        params_values = json.loads(cfg['ccs-user_decoders'][parameters_descr[i]])
-                        format = 'bit' + params_values['bytelen']
-                        ptt_value = ptt_reverse(format)
-                    except:
-                        params_values = json.loads(cfg['ccs-decode_parameters'][parameters_descr[i]])
-                        ptt_value = ptt_reverse(params_values['format'])
-
-                    params_value = ['user_defined', parameters_descr[i], ptt_value[0],
-                                    ptt_value[1], None, None, None, None, None, None, None]
-
-                    params.append(tuple(params_value))
-                i += 1
+    if not parameters:
+        logger.warning('No parameters given, cannot create custom TM')
+        return
+
+    params = [_parameter_decoding_info(par, check_curtx=True) for par in parameters]
+    logger.debug('Created custom TM decoder {} with parameters: {}'.format(label, [x[1] for x in params]))
+    user_tm_decoders[tag] = (label, params)
+
+    if not cfg.has_section('ccs-user_defined_packets'):
+        cfg.add_section('ccs-user_defined_packets')
+    cfg.save_option_to_file('ccs-user_defined_packets', tag, json.dumps((label, [tuple(x) for x in params])))
+
+    return label
+
+
+def _parameter_decoding_info(param, check_curtx=False):
+    """
+    Return parameter info tuple used for TM decoding
+    @param param:
+    @return:
+    """
+
+    if param[1] not in ['user_defined', 'user_defined_nopos', 'dp_item']:
+        que = 'SELECT pcf.pcf_name,pcf.pcf_descr,pcf.pcf_ptc,pcf.pcf_pfc,pcf.pcf_curtx,pcf.pcf_width,pcf.pcf_unit,' \
+              'pcf.pcf_pid,null,null,null from pcf WHERE pcf_name ="{}"'.format(param[1])
+        dinfo = scoped_session_idb.execute(que).fetchall()[0]
+
+    elif param[1] == 'user_defined':
+        fmt = json.loads(cfg[CFG_SECT_PLOT_PARAMETERS][param[0]])['format']
+        ptc, pfc = ptt_reverse(fmt)
+        dinfo = [param[1], param[0], ptc, pfc, None, csize(fmt) * 8, None, None, None, None, None]
+
+    elif param[1] == 'user_defined_nopos':
+        fmt = json.loads(cfg[CFG_SECT_DECODE_PARAMETERS][param[0]])['format']
+        ptc, pfc = ptt_reverse(fmt)
+        dinfo = [param[1], param[0], ptc, pfc, None, csize(fmt) * 8, None, None, None, None, None]
+
+    elif param[1] == 'dp_item':
+        if isinstance(param[0], int):
+            dp_id = param[0]
+            dp_descr = DP_IDS_TO_ITEMS[param[0]]
+        else:
+            dp_id = DP_ITEMS_TO_IDS[param[0].split(' ')[0]]  # strip IDs in parentheses if present from parameter dialog model
+            dp_descr = DP_IDS_TO_ITEMS[dp_id]
+
+        if check_curtx:
+            try:
+                que = 'SELECT pcf.pcf_name,pcf.pcf_descr,pcf.pcf_ptc,pcf.pcf_pfc,pcf.pcf_curtx,pcf.pcf_width,pcf.pcf_unit,' \
+                      'pcf.pcf_pid,null,null,null from pcf WHERE pcf_pid ="{}"'.format(dp_id)
+                dinfo = scoped_session_idb.execute(que).fetchall()[0]
+                return dinfo
+            except IndexError:
+                logger.debug('PID {} not in MIB.'.format(dp_id))
+
+        ptc, pfc = ptt_reverse(_dp_items[dp_id]['fmt'])
+        dinfo = [param[1], dp_descr, ptc, pfc, None, csize(_dp_items[dp_id]['fmt']) * 8, None, None, None, None, None]
 
     else:
-        if idb_pos: #Parameters should be decoded by there position given in the IDB or config file
-            # Check if the User used the PCF Name to describe the parameters or the PCF DESCR
-            if 'DPT' in parameters[0]:
-                que = 'SELECT DISTINCT pcf.pcf_name,pcf.pcf_descr,plf_offby,plf_offbi,pcf.pcf_ptc,pcf.pcf_pfc,\
-                    pcf.pcf_unit,pcf.pcf_pid,pcf.pcf_width FROM plf LEFT JOIN pcf ON plf.plf_name=pcf.pcf_name WHERE \
-                    pcf_name in {} ORDER BY FIELD({},'.format(tuple(parameters), 'pcf_name')\
-                    + str(tuple(parameters))[1:]
+        logger.warning('Info for parameter "{}" cannot be obtained'.format(param[0]))
+        dinfo = None
 
-                dbres = dbcon.execute(que)
-                params = dbres.fetchall()
+    return dinfo
 
-            else:
-                que = 'SELECT DISTINCT pcf.pcf_name,pcf.pcf_descr,plf_offby,plf_offbi,pcf.pcf_ptc,pcf.pcf_pfc,\
-                    pcf.pcf_unit,pcf.pcf_pid,pcf.pcf_width FROM plf LEFT JOIN pcf ON plf.plf_name=pcf.pcf_name WHERE \
-                    pcf_descr in {} ORDER BY FIELD({},'.format(tuple(parameters), 'pcf_descr')\
-                    + str(tuple(parameters))[1:]
 
-                dbres = dbcon.execute(que)
-                params = dbres.fetchall()
-        else: #Parameters will be decoded in the given order
-            # Check if the User used the PCF Name to describe the parameters or the PCF DESCR
-            if 'DPT' in parameters[0]:
-                #que = 'SELECT pcf.pcf_name,pcf.pcf_descr,pcf.pcf_ptc,pcf.pcf_pfc,pcf.pcf_curtx, \
-                #        pcf.pcf_width,pcf.pcf_unit,pcf.pcf_pid,vpd_pos,vpd_grpsize,vpd_fixrep from vpd left join pcf on \
-                #        vpd.vpd_name=pcf.pcf_name WHERE pcf_name in {} ORDER BY FIELD({},'.format(tuple(parameters),
-                #        'pcf_name') + str(tuple(parameters))[1:]
-
-                que = 'SELECT pcf.pcf_name,pcf.pcf_descr,pcf.pcf_ptc,pcf.pcf_pfc,pcf.pcf_curtx, \
-                        pcf.pcf_width,pcf.pcf_unit,pcf.pcf_pid, null,null,null from pcf WHERE pcf_name in {} \
-                        ORDER BY FIELD({},'.format(tuple(parameters), 'pcf_name') + str(tuple(parameters))[1:]
+def create_hk_decoder(sid, *dp_ids, apid=None):
+    parameters = [(dp_id, 'dp_item') for dp_id in dp_ids]
 
-                dbres = dbcon.execute(que)
-                params = dbres.fetchall()
+    if apid is None:
+        que = 'SELECT pic_apid FROM pic WHERE pic_type=3 AND pic_stype=25'
+        res = scoped_session_idb.execute(que).fetchall()
+        apid = int(res[0][0])
 
-            else:
-                #que = 'SELECT pcf.pcf_name,pcf.pcf_descr,pcf.pcf_ptc,pcf.pcf_pfc,pcf.pcf_curtx, \
-                #        pcf.pcf_width,pcf.pcf_unit,pcf.pcf_pid,vpd_pos,vpd_grpsize,vpd_fixrep from vpd left join pcf on \
-                #        vpd.vpd_name=pcf.pcf_name WHERE pcf_descr in {} ORDER BY FIELD({},'.format(tuple(parameters),
-                #        'pcf_descr') + str(tuple(parameters))[1:]
 
-                que = 'SELECT pcf.pcf_name,pcf.pcf_descr,pcf.pcf_ptc,pcf.pcf_pfc,pcf.pcf_curtx, \
-                        pcf.pcf_width,pcf.pcf_unit,pcf.pcf_pid,null,null,null from pcf WHERE pcf_descr in {} \
-                        ORDER BY FIELD({},'.format(tuple(parameters), 'pcf_descr') + str(tuple(parameters))[1:]
+    sid_off, sid_width = SID_LUT[(3, 25, apid)]
 
-                dbres = dbcon.execute(que)
-                parmas = dbres.fetchall()
+    que = 'SELECT plf_name, pcf_descr FROM pid left join plf on PLF_SPID=PID_SPID left join pcf on ' \
+                'PCF_NAME=PLF_NAME where PID_TYPE=3 and PID_STYPE=25 and PID_APID={} and plf_offby={}'.format(apid, sid_off)
+    sid_name, sid_descr = scoped_session_idb.execute(que).fetchall()[0]
 
-    # print('Created custom TM decoder {} with parameters: {}'.format(label, [x[1] for x in params]))
-    logger.debug('Created custom TM decoder {} with parameters: {}'.format(label, [x[1] for x in params]))
-    user_tm_decoders[tag] = (label, params)
-    dbcon.close()
+    if sid_off != TM_HEADER_LEN:
+        logger.warning('Inconsistent definition of SID parameter')
 
-    if not cfg.has_section('ccs-user_defined_packets'):
-        cfg.add_section('ccs-user_defined_packets')
-    cfg.save_option_to_file('ccs-user_defined_packets', tag, json.dumps((label, [tuple(x) for x in params])))
+    parameters = [(sid_descr, sid_name)] + parameters
+    label = add_tm_decoder(label='HK_{}'.format(sid), st=3, sst=25, apid=apid, parameters=parameters, sid=sid)
+    return label
 
 
-# Add a User defined Parameter
-def add_user_parameter(parameter=None, apid=None, st=None, sst=None, sid=None, bytepos=None, fmt=None, offbi=None, bitlen=None, parentwin=None):
+def add_user_parameter(parameter=None, apid=None, st=None, sst=None, sid=None, bytepos=None, fmt=None, offbi=None,
+                       bitlen=None, parentwin=None):
+    """
+    Add a stand-alone (i.e. with positional info) User DEFined parameter
+    @param parameter:
+    @param apid:
+    @param st:
+    @param sst:
+    @param sid:
+    @param bytepos:
+    @param fmt:
+    @param offbi:
+    @param bitlen:
+    @param parentwin:
+    @return:
+    """
     # If a Gtk Parent Window is given, open the Dialog window to specify the details for the parameter
     if parentwin is not None:
-        dialog = AddUserParamerterDialog(parent=parentwin)
+        dialog = UserParameterDialog(parent=parentwin)
 
         response = dialog.run()
         if response == Gtk.ResponseType.OK:
@@ -3829,7 +3713,7 @@ def add_user_parameter(parameter=None, apid=None, st=None, sst=None, sid=None, b
                 offbi = int(offbi, 0) if offbi != '' else 0
 
                 bytepos, fmt = int(dialog.bytepos.get_text(), 0), fmtlist[dialog.format.get_active_text()]
-                if fmt == 'bit':
+                if fmt in ('uint', 'ascii', 'oct'):
                     fmt += dialog.bitlen.get_text()
             except Exception as err:
                 logger.error(err)
@@ -3847,16 +3731,16 @@ def add_user_parameter(parameter=None, apid=None, st=None, sst=None, sid=None, b
         dialog.destroy()
         return
 
-    # Else If parameter is given as the name of the parameter the others have to exist as well and the parameter is created
+    # Else if parameter is given the others have to exist as well and the parameter is created
     if isinstance(parameter, str):
         label = parameter
         if isinstance(apid, int) and isinstance(st, int) and isinstance(sst, int) and isinstance(bytepos, int) and fmt:
-            if fmt == 'bit':
+            if fmt in ('uint', 'ascii', 'oct'):
                 if bitlen:
                     fmt += bitlen
                 else:
                     # print('Please give a bitlen (Amount of Bits) if fmt (Parameter Type) is set to "bit"')
-                    logger.error('Parameter could not be created, no bitlen was given, while fmt was set to  "bit"')
+                    logger.error('Parameter could not be created, no length was given.')
                     return
 
             if not isinstance(sid,int):
@@ -3867,7 +3751,7 @@ def add_user_parameter(parameter=None, apid=None, st=None, sst=None, sid=None, b
             # print('Please give all neaded parameters in the correct format')
             logger.error('Parameter could not be created, because not all specifications were given correctly')
             return
-    # Esle if the Parameter is given as a Dictionary get all the needed informations and create the parameter
+    # Else if the Parameter is given as a Dictionary get all the needed informations and create the parameter
     elif isinstance(parameter, dict):
         label = parameter['label']
         apid = parameter['apid']
@@ -3876,12 +3760,12 @@ def add_user_parameter(parameter=None, apid=None, st=None, sst=None, sid=None, b
         byteps = parameter['bytepos']
         fmt = parameter['fmt']
         if isinstance(label, str) and isinstance(apid, int) and isinstance(st, int) and isinstance(sst, int) and isinstance(bytepos, int) and fmt:
-            if fmt == 'bit':
+            if fmt in ('uint', 'ascii', 'oct'):
                 if bitlen:
                     fmt += bitlen
                 else:
                     # print('Please give a bitlen (Amount of Bits) if fmt (Parameter Type) is set to "bit"')
-                    logger.error('Parameter could not be created, no bitlen was given, while fmt was set to "bit"')
+                    logger.error('Parameter could not be created, no length was given.')
                     return
 
             if not isinstance(parameter['sid'], int):
@@ -3915,27 +3799,23 @@ def remove_user_parameter(parname=None, parentwin=None):
         return parname
 
     # Else if a Parent Gtk window is given open the dialog to select a parameter
-    elif parentwin is not None:
-        dialog = RemoveUserParameterDialog(cfg, parentwin)
-        response = dialog.run()
-        if response == Gtk.ResponseType.OK:
-            param = dialog.remove_name.get_active_text()
-
-            cfg.remove_option_from_file(CFG_SECT_PLOT_PARAMETERS, param)
-
-            return param
-
-        else:
-            dialog.destroy()
-
-        return
+    # elif parentwin is not None:
+    #     dialog = RemoveUserParameterDialog(cfg, parentwin)
+    #     response = dialog.run()
+    #     if response == Gtk.ResponseType.OK:
+    #         param = dialog.remove_name.get_active_text()
+    #
+    #         cfg.remove_option_from_file(CFG_SECT_PLOT_PARAMETERS, param)
+    #
+    #         return param
+    #
+    #     else:
+    #         dialog.destroy()
+    #
+    #     return
 
     elif parname is not None:
-        logger.error('Selected User Defined Paramter could not be found, please select a new one.')
-        return
-
-    else:
-        return
+        logger.error('Unknown parameter {}. Cannot remove.'.format(parname))
 
 
 # Edit an existing user defined Parameter
@@ -3944,7 +3824,7 @@ def edit_user_parameter(parentwin=None, parname=None):
     # if an existing parameter is given, open same window as for adding a parameter, but pass along the existing information
     # simply overwrite the existing parameter with the new one
     if parname and cfg.has_option(CFG_SECT_PLOT_PARAMETERS, parname):
-        dialog = AddUserParamerterDialog(parentwin, parname)
+        dialog = UserParameterDialog(parentwin, parname)
         response = dialog.run()
         if response == Gtk.ResponseType.OK:
             try:
@@ -3957,14 +3837,13 @@ def edit_user_parameter(parentwin=None, parname=None):
                 offbi = int(offbi, 0) if offbi != '' else 0
 
                 bytepos, fmt = int(dialog.bytepos.get_text(), 0), fmtlist[dialog.format.get_active_text()]
-                if fmt == 'bit':
+                if fmt in ('uint', 'ascii', 'oct'):
                     fmt += dialog.bitlen.get_text()
             except ValueError as error:
                 logger.error(error)
                 dialog.destroy()
                 return
 
-            # TODO: replace param if label changed
             if label != parname:
                 cfg.remove_option_from_file(CFG_SECT_PLOT_PARAMETERS, parname)
 
@@ -3983,23 +3862,25 @@ def edit_user_parameter(parentwin=None, parname=None):
     # Else Open a Window to select a parameter and call the same function again with an existing parameter
     # The upper code will be executed
     else:
-        if parname is not None:
-            logger.warning('User defined parameter "{}" could not be found, please select a new one'.format(parname))
-
-        dialog = EditUserParameterDialog(cfg, parentwin)
-        response = dialog.run()
-        if response == Gtk.ResponseType.OK:
-            param = dialog.edit_name.get_active_text()
-            dialog.destroy()
-            ret = edit_user_parameter(parentwin, param)
-            if ret:
-                label, apid, st, sst, sid, bytepos, fmt, offbi = ret
-                return label, apid, st, sst, sid, bytepos, fmt, offbi
-            else:
-                return
-        else:
-            dialog.destroy()
-            return
+        logger.error('Unknown parameter {}'.format(parname))
+        return
+        # if parname is not None:
+        #     logger.warning('User defined parameter "{}" could not be found, please select a new one'.format(parname))
+        #
+        # dialog = EditUserParameterDialog(cfg, parentwin)
+        # response = dialog.run()
+        # if response == Gtk.ResponseType.OK:
+        #     param = dialog.edit_name.get_active_text()
+        #     dialog.destroy()
+        #     ret = edit_user_parameter(parentwin, param)
+        #     if ret:
+        #         label, apid, st, sst, sid, bytepos, fmt, offbi = ret
+        #         return label, apid, st, sst, sid, bytepos, fmt, offbi
+        #     else:
+        #         return
+        # else:
+        #     dialog.destroy()
+        #     return
 
 
 def read_plm_gateway_data(raw):
@@ -4735,7 +4616,7 @@ class TestExecGUI(Gtk.MessageDialog):
 
 class TmParameterDecoderDialog(Gtk.Dialog):
     def __init__(self, parent=None):
-        Gtk.Dialog.__init__(self, "Add User Decoder Parameter", parent, 0,
+        Gtk.Dialog.__init__(self, "Add User Parameter", parent, 0,
                             buttons=(Gtk.STOCK_OK, Gtk.ResponseType.OK, Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL))
 
         self.set_border_width(5)
@@ -4747,21 +4628,22 @@ class TmParameterDecoderDialog(Gtk.Dialog):
         bytebox = Gtk.HBox()
 
         self.format = Gtk.ComboBoxText()
-        self.format.set_model(self.create_format_model())
+        self.format.set_model(create_format_model())
         self.format.set_tooltip_text('Format type')
         self.format.connect('changed', self.bitlen_active)
+        self.format.connect('changed', self.check_ok_sensitive, ok_button)
+        # self.offbi = Gtk.Entry()
+        # self.offbi.set_placeholder_text('Bit offset')
+        # self.offbi.set_tooltip_text('Bit offset from byte alignment')
+        # self.offbi.set_sensitive(False)
         self.bitlen = Gtk.Entry()
-        self.bitlen.set_placeholder_text('BitLength')
-        self.bitlen.set_tooltip_text('Length in bits')
+        self.bitlen.set_placeholder_text('Length')
+        self.bitlen.set_tooltip_text('Length in bits (for uint*) or bytes (ascii*, oct*)')
         self.bitlen.set_sensitive(False)
-        self.bytepos = Gtk.Entry()
-        self.bytepos.set_placeholder_text('Byte Offset')
-        self.bytepos.set_tooltip_text('(Optional) Including {} ({} for TCs) header bytes, e.g. byte 0 in source data -> offset={}'
-                                      .format(TM_HEADER_LEN, TC_HEADER_LEN, TM_HEADER_LEN))
 
         bytebox.pack_start(self.format, 0, 0, 0)
+        # bytebox.pack_start(self.offbi, 0, 0, 0)
         bytebox.pack_start(self.bitlen, 0, 0, 0)
-        bytebox.pack_start(self.bytepos, 0, 0, 0)
         bytebox.set_spacing(5)
 
         self.label = Gtk.Entry()
@@ -4774,30 +4656,26 @@ class TmParameterDecoderDialog(Gtk.Dialog):
 
         self.show_all()
 
-    def create_format_model(self):
-        store = Gtk.ListStore(str)
-        for fmt in fmtlist.keys():
-            store.append([fmt])
-        for pers in personal_fmtlist:
-            store.append([pers])
-        return store
-
     def check_ok_sensitive(self, unused_widget, button):
-        if len(self.label.get_text()) == 0:
+        if len(self.label.get_text()) == 0 or not self.format.get_active_text():
             button.set_sensitive(False)
         else:
             button.set_sensitive(True)
 
     def bitlen_active(self, widget):
-        if widget.get_active_text() == 'bit*' or widget.get_active_text() not in fmtlist.keys():
+        if widget.get_active_text().endswith('*'):
             self.bitlen.set_sensitive(True)
+            # if widget.get_active_text().startswith(('ascii', 'oct')):
+            #     self.offbi.set_sensitive(False)
+            # else:
+            #     self.offbi.set_sensitive(True)
         else:
             self.bitlen.set_sensitive(False)
 
 
 class TmDecoderDialog(Gtk.Dialog):
     def __init__(self, logger, parameter_set=None, parent=None):
-        Gtk.Dialog.__init__(self, "Build User Defined Packet", parent, 0)
+        Gtk.Dialog.__init__(self, "Build User Defined Packet Structure", parent, 0)
         self.add_buttons(Gtk.STOCK_OK, Gtk.ResponseType.OK, Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL)
 
         # self.set_default_size(780,560)
@@ -4838,17 +4716,19 @@ class TmDecoderDialog(Gtk.Dialog):
         self.apid.set_placeholder_text('APID')
         self.st.set_placeholder_text('Service Type')
         self.sst.set_placeholder_text('Service Subtype')
-        self.label.set_placeholder_text('Label for the current configuration')
+        self.label.set_placeholder_text('Label')
+        self.label.set_tooltip_text('Label for the current configuration')
 
         self.sid = Gtk.Entry()
         self.sid.set_placeholder_text('SID')
+        self.sid.set_tooltip_text('Discriminant, only applicable if ST and SST have a SID defined in the MIB.')
 
         self.apid.connect('changed', self.check_entry)
         self.st.connect('changed', self.check_entry)
         self.sst.connect('changed', self.check_entry)
         self.label.connect('changed', self.check_entry)
 
-        entrybox.pack_start(self.label,0, 0, 0)
+        entrybox.pack_start(self.label, 0, 0, 0)
         entrybox.pack_start(self.apid, 0, 0, 0)
         entrybox.pack_start(self.st, 0, 0, 0)
         entrybox.pack_start(self.sst, 0, 0, 0)
@@ -4857,15 +4737,15 @@ class TmDecoderDialog(Gtk.Dialog):
         entrybox.set_homogeneous(True)
         entrybox.set_spacing(5)
 
-        decisionbox = Gtk.HBox()
-
-        self.given_poition = Gtk.RadioButton.new_with_label_from_widget(None, 'Local')
-        self.given_poition.set_tooltip_text('Decode in given order')
-        self.idb_position = Gtk.RadioButton.new_with_label_from_widget(self.given_poition, 'IDB')
-        self.idb_position.set_tooltip_text('Decode by parameter position given in IDB')
-
-        decisionbox.pack_start(self.given_poition, 0, 0, 0)
-        decisionbox.pack_start(self.idb_position, 0, 0, 0)
+        # decisionbox = Gtk.HBox()
+        #
+        # self.given_poition = Gtk.RadioButton.new_with_label_from_widget(None, 'Local')
+        # self.given_poition.set_tooltip_text('Decode in given order')
+        # self.idb_position = Gtk.RadioButton.new_with_label_from_widget(self.given_poition, 'IDB')
+        # self.idb_position.set_tooltip_text('Decode by parameter position given in IDB')
+        #
+        # decisionbox.pack_start(self.given_poition, 0, 0, 0)
+        # decisionbox.pack_start(self.idb_position, 0, 0, 0)
 
         if parameter_set is not None:
 
@@ -4901,14 +4781,13 @@ class TmDecoderDialog(Gtk.Dialog):
             slot = self.create_slot()
             slotbox.pack_start(slot, 1, 1, 0)
 
-        note = Gtk.Label(label="Note: User-Defined_IDB parameter can only be used if IDB order is chosen, "
-                               "User-Defined_Local only for Local order")
+        # note = Gtk.Label(label="Note: User-Defined_IDB parameter can only be used if IDB order is chosen, User-Defined_Local only for Local order")
 
         box = Gtk.VBox()
         box.pack_start(parameter_view, 1, 1, 5)
-        box.pack_start(note, 0,0,0)
+        # box.pack_start(note, 0,0,0)
         box.pack_start(slotbox, 1, 1, 2)
-        box.pack_start(decisionbox, 1, 1, 2)
+        # box.pack_start(decisionbox, 1, 1, 2)
         box.pack_start(entrybox, 0, 0, 3)
 
         return box
@@ -4934,6 +4813,7 @@ class TmDecoderDialog(Gtk.Dialog):
     def create_slot(self, group=None):
         self.parameter_list = Gtk.ListStore(str, str)
         treeview = Gtk.TreeView(self.parameter_list)
+        treeview.set_reorderable(True)
 
         treeview.append_column(Gtk.TreeViewColumn("Parameters", Gtk.CellRendererText(), text=0))
         hidden_column = Gtk.TreeViewColumn("PCF_NAME", Gtk.CellRendererText(), text=1)
@@ -4978,37 +4858,93 @@ class TmDecoderDialog(Gtk.Dialog):
         else:
             return None, None
 
+    # def create_parameter_model_old(self):
+    #     parameter_model = Gtk.TreeStore(str, str)
+    #
+    #     dbcon = self.session_factory_idb
+    #     #dbres = dbcon.execute('SELECT pid_descr,pid_spid from pid where pid_type=3 and pid_stype=25')
+    #     dbres = dbcon.execute('SELECT pid_descr,pid_spid from pid order by pid_type,pid_pi1_val')
+    #     hks = dbres.fetchall()
+    #     for hk in hks:
+    #         it = parameter_model.append(None, [hk[0], None])
+    #         dbres = dbcon.execute('SELECT pcf.pcf_descr, pcf.pcf_name from pcf left join plf on\
+    #          pcf.pcf_name=plf.plf_name left join pid on plf.plf_spid=pid.pid_spid where pid.pid_spid={}'.format(hk[1]))
+    #         params = dbres.fetchall()
+    #         [parameter_model.append(it, [par[0], par[1]]) for par in params]
+    #     dbcon.close()
+    #     self.useriter_IDB = parameter_model.append(None, ['User-defined_IDB', None])
+    #     self.useriter_local = parameter_model.append(None, ['User-defined_local', None])
+    #     for userpar in self.cfg['ccs-user_decoders']:
+    #         parameter_model.append(self.useriter_IDB, [userpar, None])
+    #     for userpar in self.cfg['ccs-decode_parameters']:
+    #         parameter_model.append(self.useriter_local, [userpar, None])
+    #
+    #     return parameter_model
+
     def create_parameter_model(self):
         parameter_model = Gtk.TreeStore(str, str)
+        self.store = parameter_model
 
         dbcon = self.session_factory_idb
-        #dbres = dbcon.execute('SELECT pid_descr,pid_spid from pid where pid_type=3 and pid_stype=25')
-        dbres = dbcon.execute('SELECT pid_descr,pid_spid from pid order by pid_type,pid_pi1_val')
+        dbres = dbcon.execute('SELECT pid_descr,pid_spid,pid_type from pid order by pid_type,pid_stype,pid_pi1_val')
         hks = dbres.fetchall()
+
+        topleveliters = {}
         for hk in hks:
-            it = parameter_model.append(None, [hk[0], None])
-            dbres = dbcon.execute('SELECT pcf.pcf_descr, pcf.pcf_name from pcf left join plf on\
-             pcf.pcf_name=plf.plf_name left join pid on plf.plf_spid=pid.pid_spid where pid.pid_spid={}'.format(hk[1]))
+
+            if not hk[2] in topleveliters:
+                serv = parameter_model.append(None, ['Service ' + str(hk[2]), None])
+                topleveliters[hk[2]] = serv
+
+            it = parameter_model.append(topleveliters[hk[2]], [hk[0], None])
+
+            dbres = dbcon.execute('SELECT pcf.pcf_descr, pcf.pcf_name from pcf left join plf on pcf.pcf_name=plf.plf_name left join pid on \
+                                   plf.plf_spid=pid.pid_spid where pid.pid_spid={} ORDER BY pcf.pcf_descr'.format(hk[1]))
             params = dbres.fetchall()
-            [parameter_model.append(it, [par[0], par[1]]) for par in params]
+            for par in params:
+                parameter_model.append(it, [*par])
+
         dbcon.close()
-        self.useriter_IDB = parameter_model.append(None, ['User-defined_IDB', None])
-        self.useriter_local = parameter_model.append(None, ['User-defined_local', None])
-        for userpar in self.cfg['ccs-user_decoders']:
-            parameter_model.append(self.useriter_IDB, [userpar, None])
-        for userpar in self.cfg['ccs-decode_parameters']:
-            parameter_model.append(self.useriter_local, [userpar, None])
+
+        # # add user defined PACKETS
+        # self.user_tm_decoders = user_tm_decoders_func()
+        # topit = parameter_model.append(None, ['UDEF'])
+        # for hk in self.user_tm_decoders:
+        #     it = parameter_model.append(topit, ['UDEF|{}'.format(self.user_tm_decoders[hk][0])])
+        #     for par in self.user_tm_decoders[hk][1]:
+        #         parameter_model.append(it, [par[1]])
+
+        # add data pool items
+        self.useriter = parameter_model.append(None, ['Data pool', None])
+        for dp in _dp_items:
+            dp_item = '{} ({})'.format(_dp_items[dp]['descr'], dp)
+            parameter_model.append(self.useriter, [dp_item, 'dp_item'])
+
+        # add user defined PARAMETERS with positional info
+        self.useriter = parameter_model.append(None, ['User defined', None])
+        for userpar in self.cfg[CFG_SECT_PLOT_PARAMETERS]:
+            parameter_model.append(self.useriter, [userpar, 'user_defined'])
+
+        # add user defined PARAMETERS without positional info
+        for userpar in self.cfg[CFG_SECT_DECODE_PARAMETERS]:
+            parameter_model.append(self.useriter, [userpar, 'user_defined_nopos'])
 
         return parameter_model
 
     def add_parameter(self, widget, listmodel):
         par_model, par_iter = self.treeview.get_selection().get_selected()
-        hk = par_model[par_iter].parent[0]
+        if par_model[par_iter][1] is None:
+            return
+
+        # hk = par_model[par_iter].parent[0]
+
         if par_model[par_iter].parent is None:
             return
-        elif hk not in ['User-defined_IDB', 'User-defined_local']:
-            param = par_model[par_iter]
-            listmodel.append([*param])
+
+        # elif hk not in ['User-defined_IDB', 'User-defined_local']:
+        #     param = par_model[par_iter]
+        #     listmodel.append([*param])
+
         else:
             param = par_model[par_iter]
             listmodel.append([*param])
@@ -5032,7 +4968,7 @@ class TmDecoderDialog(Gtk.Dialog):
             self.ok_button.set_sensitive(False)
 
 
-class AddUserParamerterDialog(Gtk.MessageDialog):
+class UserParameterDialog(Gtk.MessageDialog):
     def __init__(self, parent=None, edit=None):
         Gtk.Dialog.__init__(self, "Edit User Parameter", parent, 0,
                             buttons=(Gtk.STOCK_OK, Gtk.ResponseType.OK, Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL))
@@ -5050,11 +4986,14 @@ class AddUserParamerterDialog(Gtk.MessageDialog):
         self.st = Gtk.Entry()
         self.sst = Gtk.Entry()
         self.apid.set_placeholder_text('APID')
+        self.apid.connect('changed', self.check_entry, ok_button)
         self.st.set_placeholder_text('Service Type')
+        self.st.connect('changed', self.check_entry, ok_button)
         self.sst.set_placeholder_text('Service Subtype')
+        self.sst.connect('changed', self.check_entry, ok_button)
         self.sid = Gtk.Entry()
         self.sid.set_placeholder_text('SID')
-        self.sid.set_tooltip_text('Further discriminant (i.e. PI1VAL)')
+        self.sid.set_tooltip_text('Discriminant (i.e. PI1VAL)')
 
         hbox.pack_start(self.apid, 0, 0, 0)
         hbox.pack_start(self.st, 0, 0, 0)
@@ -5067,18 +5006,20 @@ class AddUserParamerterDialog(Gtk.MessageDialog):
 
         self.bytepos = Gtk.Entry()
         self.bytepos.set_placeholder_text('Byte Offset')
-        self.bytepos.set_tooltip_text('Including {} ({} for TCs) header bytes, e.g. byte 0 in source data -> offset={}'
+        self.bytepos.set_tooltip_text('Including {} ({} for TCs) header bytes, e.g. byte 0 in TM source data -> offset={}'
                                       .format(TM_HEADER_LEN, TC_HEADER_LEN, TM_HEADER_LEN))
+        self.bytepos.connect('changed', self.check_entry, ok_button)
         self.format = Gtk.ComboBoxText()
-        self.format.set_model(self.create_format_model())
+        self.format.set_model(create_format_model())
         self.format.set_tooltip_text('Format type')
         self.format.connect('changed', self.bitlen_active)
         self.offbi = Gtk.Entry()
         self.offbi.set_placeholder_text('Bit Offset')
         self.offbi.set_tooltip_text('Bit Offset (optional)')
+        self.offbi.set_sensitive(False)
         self.bitlen = Gtk.Entry()
-        self.bitlen.set_placeholder_text('Bitlength')
-        self.bitlen.set_tooltip_text('Length in bits')
+        self.bitlen.set_placeholder_text('Length')
+        self.bitlen.set_tooltip_text('Length in bits (for uint*) and bytes (ascii*, oct*)')
         self.bitlen.set_sensitive(False)
 
         bytebox.pack_start(self.bytepos, 0, 0, 0)
@@ -5089,7 +5030,7 @@ class AddUserParamerterDialog(Gtk.MessageDialog):
 
         self.label = Gtk.Entry()
         self.label.set_placeholder_text('Parameter Label')
-        self.label.connect('changed', self.check_ok_sensitive, ok_button)
+        self.label.connect('changed', self.check_entry, ok_button)
 
         box.pack_start(self.label, 0, 0, 0)
         box.pack_end(bytebox, 0, 0, 0)
@@ -5112,9 +5053,11 @@ class AddUserParamerterDialog(Gtk.MessageDialog):
             if 'format' in pars:
                 fmt_dict = {a: b for b, a in fmtlist.items()}
                 fmt = pars['format']
-                if fmt.startswith('bit'):
-                    self.bitlen.set_text(fmt.strip('bit'))
-                    fmt = 'bit'
+                for fk in ('uint', 'ascii', 'oct'):
+                    if fmt.startswith(fk):
+                        self.bitlen.set_text(fmt.replace(fk, ''))
+                        fmt = fk
+                        break
                 model = self.format.get_model()
                 it = [row.iter for row in model if row[0] == fmt_dict[fmt]][0]
                 self.format.set_active_iter(it)
@@ -5123,108 +5066,105 @@ class AddUserParamerterDialog(Gtk.MessageDialog):
 
         self.show_all()
 
-    def create_format_model(self):
-        store = Gtk.ListStore(str)
-        for fmt in fmtlist.keys():
-            store.append([fmt])
-        return store
-
-    def check_ok_sensitive(self, unused_widget, button):
-        if len(self.label.get_text()) == 0:
-            button.set_sensitive(False)
+    def check_entry(self, widget, ok_button):
+        if self.apid.get_text_length() and self.st.get_text_length() and self.sst.get_text_length \
+                and self.label.get_text_length() and self.bytepos.get_text_length():
+            ok_button.set_sensitive(True)
         else:
-            button.set_sensitive(True)
+            ok_button.set_sensitive(False)
 
     def bitlen_active(self, widget):
-        if widget.get_active_text() == 'bit*':
+        if widget.get_active_text() == 'uint*':
             self.bitlen.set_sensitive(True)
             self.offbi.set_sensitive(True)
+        elif widget.get_active_text() in ('ascii*', 'oct*'):
+            self.bitlen.set_sensitive(True)
+            self.offbi.set_sensitive(False)
         else:
             self.bitlen.set_sensitive(False)
             self.offbi.set_sensitive(False)
 
 
-class RemoveUserParameterDialog(Gtk.Dialog):
-    def __init__(self, cfg, parent=None):
-        Gtk.Dialog.__init__(self, "Remove User Defined Parameter", parent, 0)
-        self.add_buttons(Gtk.STOCK_OK, Gtk.ResponseType.OK, Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL)
-
-        self.cfg = cfg
-
-        box = self.get_content_area()
-
-        self.ok_button = self.get_widget_for_response(Gtk.ResponseType.OK)
-        self.ok_button.set_sensitive(False)
-
-
-        self.remove_name = Gtk.ComboBoxText.new_with_entry()
-        self.remove_name.set_tooltip_text('Parameter')
-        self.remove_name_entry = self.remove_name.get_child()
-        self.remove_name_entry.set_placeholder_text('Label')
-        self.remove_name_entry.set_width_chars(5)
-        self.remove_name.connect('changed', self.fill_remove_mask)
-
-        self.remove_name.set_model(self.create_remove_model())
-
-        box.pack_start(self.remove_name, 0, 0, 0)
-
-        self.show_all()
-
-    def create_remove_model(self):
-        model = Gtk.ListStore(str)
-
-        for decoder in self.cfg[CFG_SECT_PLOT_PARAMETERS].keys():
-            model.append([decoder])
-        return model
-
-    def fill_remove_mask(self, widget):
-        decoder = widget.get_active_text()
-
-        if self.cfg.has_option(CFG_SECT_PLOT_PARAMETERS, decoder):
-            self.ok_button.set_sensitive(True)
-        else:
-            self.ok_button.set_sensitive(False)
-
-
-class EditUserParameterDialog(Gtk.Dialog):
-    def __init__(self, cfg, parent=None):
-        Gtk.Dialog.__init__(self, "Edit User Defined Parameter", parent, 0)
-        self.add_buttons(Gtk.STOCK_OK, Gtk.ResponseType.OK, Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL)
-
-        self.cfg = cfg
-
-        box = self.get_content_area()
-
-        self.ok_button = self.get_widget_for_response(Gtk.ResponseType.OK)
-        self.ok_button.set_sensitive(False)
-
-        self.edit_name = Gtk.ComboBoxText.new_with_entry()
-        self.edit_name.set_tooltip_text('Parameter')
-        self.edit_name_entry = self.edit_name.get_child()
-        self.edit_name_entry.set_placeholder_text('Label')
-        self.edit_name_entry.set_width_chars(5)
-        self.edit_name.connect('changed', self.fill_edit_mask)
-
-        self.edit_name.set_model(self.create_edit_model())
-
-        box.pack_start(self.edit_name, 0, 0, 0)
-
-        self.show_all()
-
-    def create_edit_model(self):
-        model = Gtk.ListStore(str)
-
-        for decoder in self.cfg[CFG_SECT_PLOT_PARAMETERS].keys():
-            model.append([decoder])
-        return model
+# class RemoveUserParameterDialog(Gtk.Dialog):
+#     def __init__(self, cfg, parent=None):
+#         Gtk.Dialog.__init__(self, "Remove User Defined Parameter", parent, 0)
+#         self.add_buttons(Gtk.STOCK_OK, Gtk.ResponseType.OK, Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL)
+#
+#         self.cfg = cfg
+#
+#         box = self.get_content_area()
+#
+#         self.ok_button = self.get_widget_for_response(Gtk.ResponseType.OK)
+#         self.ok_button.set_sensitive(False)
+#
+#         self.remove_name = Gtk.ComboBoxText.new_with_entry()
+#         self.remove_name.set_tooltip_text('Parameter')
+#         self.remove_name_entry = self.remove_name.get_child()
+#         self.remove_name_entry.set_placeholder_text('Label')
+#         self.remove_name_entry.set_width_chars(5)
+#         self.remove_name.connect('changed', self.fill_remove_mask)
+#
+#         self.remove_name.set_model(self.create_remove_model())
+#
+#         box.pack_start(self.remove_name, 0, 0, 0)
+#
+#         self.show_all()
+#
+#     def create_remove_model(self):
+#         model = Gtk.ListStore(str)
+#
+#         for decoder in self.cfg[CFG_SECT_PLOT_PARAMETERS].keys():
+#             model.append([decoder])
+#         return model
+#
+#     def fill_remove_mask(self, widget):
+#         decoder = widget.get_active_text()
+#
+#         if self.cfg.has_option(CFG_SECT_PLOT_PARAMETERS, decoder):
+#             self.ok_button.set_sensitive(True)
+#         else:
+#             self.ok_button.set_sensitive(False)
 
-    def fill_edit_mask(self, widget):
-        decoder = widget.get_active_text()
 
-        if self.cfg.has_option(CFG_SECT_PLOT_PARAMETERS, decoder):
-            self.ok_button.set_sensitive(True)
-        else:
-            self.ok_button.set_sensitive(False)
+# class EditUserParameterDialog(Gtk.Dialog):
+#     def __init__(self, cfg, parent=None):
+#         Gtk.Dialog.__init__(self, "Edit User Defined Parameter", parent, 0)
+#         self.add_buttons(Gtk.STOCK_OK, Gtk.ResponseType.OK, Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL)
+#
+#         self.cfg = cfg
+#
+#         box = self.get_content_area()
+#
+#         self.ok_button = self.get_widget_for_response(Gtk.ResponseType.OK)
+#         self.ok_button.set_sensitive(False)
+#
+#         self.edit_name = Gtk.ComboBoxText.new_with_entry()
+#         self.edit_name.set_tooltip_text('Parameter')
+#         self.edit_name_entry = self.edit_name.get_child()
+#         self.edit_name_entry.set_placeholder_text('Label')
+#         self.edit_name_entry.set_width_chars(5)
+#         self.edit_name.connect('changed', self.fill_edit_mask)
+#
+#         self.edit_name.set_model(self.create_edit_model())
+#
+#         box.pack_start(self.edit_name, 0, 0, 0)
+#
+#         self.show_all()
+#
+#     def create_edit_model(self):
+#         model = Gtk.ListStore(str)
+#
+#         for decoder in self.cfg[CFG_SECT_PLOT_PARAMETERS].keys():
+#             model.append([decoder])
+#         return model
+#
+#     def fill_edit_mask(self, widget):
+#         decoder = widget.get_active_text()
+#
+#         if self.cfg.has_option(CFG_SECT_PLOT_PARAMETERS, decoder):
+#             self.ok_button.set_sensitive(True)
+#         else:
+#             self.ok_button.set_sensitive(False)
 
 
 class ChangeCommunicationDialog(Gtk.Dialog):
@@ -5448,23 +5388,24 @@ class ProjectDialog(Gtk.Dialog):
             sys.exit()
 
 
-# some default parameter definitions that require functions defined above
+# some default variable definitions that require functions defined above
 
 # create local look-up tables for data pool items from MIB
 try:
     DP_ITEMS_SRC_FILE = cfg.get('database', 'datapool-items')
     if DP_ITEMS_SRC_FILE:
         # get DP from file
-        _dp_items = get_data_pool_items(src_file=DP_ITEMS_SRC_FILE)
+        _dp_items = get_data_pool_items(src_file=DP_ITEMS_SRC_FILE, as_dict=True)
     else:
         raise ValueError
 except (FileNotFoundError, ValueError, confignator.config.configparser.NoOptionError):
     DP_ITEMS_SRC_FILE = None
     logger.warning('Could not load data pool from file: {}. Using MIB instead.'.format(DP_ITEMS_SRC_FILE))
-    _dp_items = get_data_pool_items()
+    _dp_items = get_data_pool_items(as_dict=True)
 finally:
-    DP_IDS_TO_ITEMS = {int(k[0]): k[1] for k in _dp_items}
-    DP_ITEMS_TO_IDS = {k[1]: int(k[0]) for k in _dp_items}
+    # DP_IDS_TO_ITEMS = {int(k[0]): k[1] for k in _dp_items}
+    DP_IDS_TO_ITEMS = {k: _dp_items[k]['descr'] for k in _dp_items}
+    DP_ITEMS_TO_IDS = {_dp_items[k]['descr']: k for k in _dp_items}
 
 # S13 header/offset info
 try:
diff --git a/Ccs/monitor.py b/Ccs/monitor.py
index 8f440ee2fe2b06e4565f9e291ec8fc7aa0b9846e..0a43954e81a28777f4bb0b8a06ce8ff690c19570 100644
--- a/Ccs/monitor.py
+++ b/Ccs/monitor.py
@@ -182,9 +182,9 @@ class ParameterMonitor(Gtk.Window):
         # Popover creates the popup menu over the button and lets one use multiple buttons for the same one
         self.popover = Gtk.Popover()
         # Add the different Starting Options
-        vbox = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=10)
+        vbox = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=5, margin=4)
         for name in self.cfg['ccs-dbus_names']:
-            start_button = Gtk.Button.new_with_label("Start " + name.capitalize() + '   ')
+            start_button = Gtk.Button.new_with_label("Start " + name.capitalize())
             start_button.connect("clicked", cfl.on_open_univie_clicked)
             vbox.pack_start(start_button, False, True, 0)
 
@@ -784,6 +784,7 @@ class MonitorSetupDialog(Gtk.Dialog):
     def create_slot(self, group=None):
         parameter_list = Gtk.ListStore(str, str)
         treeview = Gtk.TreeView(model=parameter_list)
+        treeview.set_reorderable(True)
 
         treeview.append_column(Gtk.TreeViewColumn("Parameters", Gtk.CellRendererText(), text=0))
         hidden_column = Gtk.TreeViewColumn("ID", Gtk.CellRendererText(), text=1)
diff --git a/Ccs/plotter.py b/Ccs/plotter.py
index f907ba733baf98d518814e44d58d9f237ed6c252..a4c833b481409f70ddc69a400c88a1b1ce957694 100644
--- a/Ccs/plotter.py
+++ b/Ccs/plotter.py
@@ -50,8 +50,10 @@ ActivePoolInfo = NamedTuple(
         ('pool_name', str),
         ('live', bool)])
 
-fmtlist = {'INT8': 'b', 'UINT8': 'B', 'INT16': 'h', 'UINT16': 'H', 'INT32': 'i', 'UINT32': 'I', 'INT64': 'q',
-           'UINT64': 'Q', 'FLOAT': 'f', 'DOUBLE': 'd', 'INT24': 'i24', 'UINT24': 'I24', 'bit*': 'bit'}
+# fmtlist = {'INT8': 'b', 'UINT8': 'B', 'INT16': 'h', 'UINT16': 'H', 'INT32': 'i', 'UINT32': 'I', 'INT64': 'q',
+#            'UINT64': 'Q', 'FLOAT': 'f', 'DOUBLE': 'd', 'INT24': 'i24', 'UINT24': 'I24', 'bit*': 'bit'}
+
+# pi1_length_in_bits = {8: 'B', 16: 'H'}
 
 
 class PlotViewer(Gtk.Window):
@@ -68,6 +70,9 @@ class PlotViewer(Gtk.Window):
 
         self.data_dict = {}
         self.max_datapoints = 0
+        self.data_min_idx = None
+        self.data_max_idx = None
+        self.pi1_lut = {}
 
         self.cfg = confignator.get_config()
 
@@ -188,15 +193,33 @@ class PlotViewer(Gtk.Window):
 
         toolbar.pack_start(Gtk.Separator.new(Gtk.Orientation.VERTICAL), 0, 0, 0)
 
-        max_data_label = Gtk.Label(label='NMAX:')
-        max_data_label.set_tooltip_text('At most ~NMAX data points plotted (0 for unlimited)')
+        max_data_label = Gtk.Label(label='#')
+        max_data_label.set_tooltip_text('Plot at most ~NMAX data points (0 for unlimited), between MIN and MAX packet indices.')
         self.max_data = Gtk.Entry()
         self.max_data.set_width_chars(6)
-        self.max_data.connect('activate', self._set_max_datapoints)
-        self.max_data.set_tooltip_text('0')
+        self.max_data.set_alignment(1)
+        self.max_data.set_placeholder_text('NMAX')
+        self.max_data.set_input_purpose(Gtk.InputPurpose.DIGITS)
+        # self.max_data.connect('activate', self._set_max_datapoints)
+        self.max_data.set_tooltip_text('At most ~NMAX data points plotted (0 for unlimited)')
         toolbar.pack_start(max_data_label, 0, 0, 3)
         toolbar.pack_start(self.max_data, 0, 0, 0)
 
+        self.min_idx = Gtk.Entry()
+        self.min_idx.set_width_chars(7)
+        self.min_idx.set_alignment(1)
+        self.min_idx.set_placeholder_text('MIN')
+        self.min_idx.set_input_purpose(Gtk.InputPurpose.DIGITS)
+        self.min_idx.set_tooltip_text('Get parameters starting from packet index')
+        self.max_idx = Gtk.Entry()
+        self.max_idx.set_width_chars(7)
+        self.max_idx.set_alignment(1)
+        self.max_idx.set_placeholder_text('MAX')
+        self.max_idx.set_input_purpose(Gtk.InputPurpose.DIGITS)
+        self.max_idx.set_tooltip_text('Get parameters up to packet index')
+        toolbar.pack_start(self.min_idx, 0, 0, 0)
+        toolbar.pack_start(self.max_idx, 0, 0, 0)
+
         toolbar.pack_start(Gtk.Separator.new(Gtk.Orientation.VERTICAL), 0, 0, 0)
 
         self.live_plot_switch = Gtk.Switch()
@@ -529,11 +552,12 @@ class PlotViewer(Gtk.Window):
                 parname = model[parpath][0]
                 param_values = cfl.edit_user_parameter(self, parname)
                 if param_values:
+                    self.user_parameters.pop(parname)
                     label, apid, st, sst, sid, bytepos, fmt, offbi = param_values
                     self.user_parameters[label] = json.dumps(
                         {'APID': apid, 'ST': st, 'SST': sst, 'SID': sid, 'bytepos': bytepos, 'format': fmt, 'offbi': offbi})
 
-                    model[parpath][0] = label  # TODO: update listview when edit changed parname
+                    model[parpath][0] = label
 
             else:
                 return
@@ -567,16 +591,16 @@ class PlotViewer(Gtk.Window):
         # Popover creates the popup menu over the button and lets one use multiple buttons for the same one
         self.popover = Gtk.Popover()
         # Add the different Starting Options
-        vbox = Gtk.Box(orientation=Gtk.Orientation.VERTICAL)
+        vbox = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=5, margin=4)
         for name in self.cfg['ccs-dbus_names']:
-            start_button = Gtk.Button.new_with_label("Start " + name.capitalize() + '   ')
+            start_button = Gtk.Button.new_with_label("Start " + name.capitalize())
             start_button.connect("clicked", cfl.on_open_univie_clicked)
-            vbox.pack_start(start_button, False, True, 10)
+            vbox.pack_start(start_button, False, True, 0)
 
         # Add the manage connections option
         conn_button = Gtk.Button.new_with_label('Communication')
         conn_button.connect("clicked", self.on_communication_dialog)
-        vbox.pack_start(conn_button, False, True, 10)
+        vbox.pack_start(conn_button, False, True, 0)
 
         # Add the option to see the Credits
         about_button = Gtk.Button.new_with_label('About')
@@ -608,29 +632,36 @@ class PlotViewer(Gtk.Window):
     def get_active_pool_name(self):
         return self.pool_selector.get_active_text()
 
-    def sid_position_query(self, st, sst, sid):
-        length_in_bits = {8: 'B', 16: 'H'}
-
-        sid_search = b''
+    def sid_position_query(self, st, sst, apid, sid):
 
-        dbcon = self.session_factory_idb
-        que = 'SELECT PIC_PI1_OFF, PIC_PI1_WID FROM pic WHERE PIC_TYPE ="{}" AND PIC_STYPE ="{}"'.format(st, sst)
-        dbres = dbcon.execute(que)
-        sid_offset, sid_length = dbres.fetchall()[0]
+        if (st, sst, apid) in self.pi1_lut:
+            sid_offset, sid_bitlen = self.pi1_lut[(st, sst, apid)]
+        else:
+            # dbcon = self.session_factory_idb
+            # que = 'SELECT PIC_PI1_OFF, PIC_PI1_WID FROM pic WHERE PIC_TYPE ="{}" AND PIC_STYPE ="{}" AND PIC_APID ="{}"'.format(st, sst, apid)
+            # dbres = dbcon.execute(que)
+            # sid_offset, sid_bitlen = dbres.fetchall()[0]
+            # dbcon.close()
+            sidinfo = cfl.get_sid(st, sst, apid)
+            if sidinfo:
+                sid_offset, sid_bitlen = sidinfo
+                self.pi1_lut[(st, sst, apid)] = (sid_offset, sid_bitlen)
+            else:
+                return
 
         if sid_offset == -1 or sid == 0:
-            return b'%'
-
-        i = 0
-        while i < sid_offset:
-            i += 1
-            sid_search += b'_'
+            return
 
-        sid_search += struct.pack('>' + length_in_bits[sid_length], sid)
-        sid_search += b'%'
+        # sid_search = b''
+        # i = 0
+        # while i < sid_offset:
+        #     i += 1
+        #     sid_search += b'_'
+        #
+        # sid_search += struct.pack('>' + pi1_length_in_bits[sid_length], sid)
+        # sid_search += b'%'
 
-        dbcon.close()
-        return sid_search
+        return sid_offset, sid_bitlen // 8
 
     def plot_parameter(self, widget=None, parameter=None):
         if parameter is not None:
@@ -639,24 +670,39 @@ class PlotViewer(Gtk.Window):
             selection = self.treeview.get_selection()
             model, treepath = selection.get_selected()
             parameter = model[treepath][0]
+
+            if model[treepath].parent is None:
+                return
+
             hk = model[treepath].parent[0]
 
-        # pool_name = self.loaded_pool.pool_name
         rows = cfl.get_pool_rows(self.loaded_pool.filename)
+
+        # TODO filter by idx
+        rows = self.set_plot_range(rows)
+
         dbcon = self.session_factory_idb
 
         if hk != 'User defined' and not hk.startswith('UDEF|'):
-            que = 'SELECT pid_type,pid_stype,pid_pi1_val FROM pid LEFT JOIN plf ON pid.pid_spid=plf.plf_spid LEFT JOIN pcf ' \
+            que = 'SELECT pid_type,pid_stype,pid_pi1_val,pid_apid FROM pid LEFT JOIN plf ON pid.pid_spid=plf.plf_spid LEFT JOIN pcf ' \
                   'ON plf.plf_name=pcf.pcf_name WHERE pcf.pcf_descr="{}" AND pid.pid_descr="{}"'.format(parameter, hk)
-            dbres = dbcon.execute(que)
-            st, sst, sid = dbres.fetchall()[0]
+            dbres = dbcon.execute(que).fetchall()
 
-            rows = rows.filter(DbTelemetry.stc == st, DbTelemetry.sst == sst,
-                               DbTelemetry.raw.like(self.sid_position_query(st, sst, sid)))
-            #if sid == 0:
-            #    rows = rows.filter(DbTelemetry.stc == st, DbTelemetry.sst == sst)
-            #else:
-            #    rows = rows.filter(DbTelemetry.stc == st, DbTelemetry.sst == sst, DbTelemetry.data.like(struct.pack('>B', sid) + b'%'))
+            if not dbres:
+                self.logger.error('{} is not a valid parameter.'.format(parameter))
+                return
+
+            st, sst, sid, apid = dbres[0]
+
+            sid_pos = self.sid_position_query(st, sst, apid, sid)
+
+            if sid_pos is not None:
+                sid_offset, sid_size = sid_pos
+                rows = rows.filter(DbTelemetry.stc == st, DbTelemetry.sst == sst, DbTelemetry.apid == apid,
+                                   func.mid(DbTelemetry.data, sid_offset - TM_HEADER_LEN + 1, sid_size) ==
+                                            sid.to_bytes(sid_size, 'big'))
+            else:
+                rows = rows.filter(DbTelemetry.stc == st, DbTelemetry.sst == sst, DbTelemetry.apid == apid)
 
         elif hk.startswith('UDEF|'):
             label = hk.strip('UDEF|')
@@ -664,29 +710,44 @@ class PlotViewer(Gtk.Window):
             pktinfo = tag.split('-')
             st = int(pktinfo[0])
             sst = int(pktinfo[1])
-            sid = int(pktinfo[3])
-            #rows = rows.filter(DbTelemetry.stc == st, DbTelemetry.sst == sst,
-            #                   DbTelemetry.data.like(struct.pack('>B', sid) + b'%'))#
-            rows = rows.filter(DbTelemetry.stc == st, DbTelemetry.sst == sst,
-                               DbTelemetry.data.like(self.sid_position_query(st, sst, sid)))
+            apid = int(pktinfo[2]) if pktinfo[2] != 'None' else None
+            sid = int(pktinfo[3]) if pktinfo[3] != 'None' else None
+
+            sid_pos = self.sid_position_query(st, sst, apid, sid)
+
+            if sid_pos is not None:
+                sid_offset, sid_size = sid_pos
+
+                rows = rows.filter(DbTelemetry.stc == st, DbTelemetry.sst == sst, DbTelemetry.sst == apid,
+                                   func.mid(DbTelemetry.data, sid_offset - TM_HEADER_LEN + 1, sid_size) ==
+                                            sid.to_bytes(sid_size, 'big'))
+            else:
+                rows = rows.filter(DbTelemetry.stc == st, DbTelemetry.sst == sst, DbTelemetry.apid == apid)
         else:
             userpar = json.loads(self.cfg[cfl.CFG_SECT_PLOT_PARAMETERS][parameter])
             rows = rows.filter(DbTelemetry.stc == userpar['ST'], DbTelemetry.sst == userpar['SST'],
                                DbTelemetry.apid == userpar['APID'])
             if 'SID' in userpar and userpar['SID']:
-                #rows = rows.filter(DbTelemetry.data.like(struct.pack('>B', int(userpar['SID'])) + b'%'))
-                rows = rows.filter(DbTelemetry.raw.like(self.sid_position_query(userpar['ST'], userpar['SST'], userpar['SID'])))
+                try:
+                    sid_offset, sid_size = self.sid_position_query(userpar['ST'], userpar['SST'], userpar['APID'], userpar['SID'])
+                except TypeError:
+                    self.logger.error('{}: SID not applicable.'.format(parameter))
+                    return
+
+                rows = rows.filter(func.mid(DbTelemetry.data, sid_offset - TM_HEADER_LEN + 1, sid_size) ==
+                                            userpar['SID'].to_bytes(sid_size, 'big'))
+
         if not self.filter_tl2.get_active():
             rows = rows.filter(func.left(DbTelemetry.timestamp, func.length(DbTelemetry.timestamp) - 1) > 2.)
+
         try:
-            #xy, (descr, unit) = cfl.get_param_values(rows.yield_per(1000).raw, hk, parameter, numerical=True)  ######yield per and the for loop do not work, no idea why not
             xy, (descr, unit) = cfl.get_param_values([row.raw for row in rows.yield_per(1000)], hk, parameter,
-                                                     numerical=True)
-
+                                                     numerical=True, tmfilter=False)
             if len(xy) == 0:
                 return
-        except ValueError:
-            Notify.Notification.new("Can't plot {}".format(parameter)).show()
+
+        except (ValueError, TypeError):
+            self.logger.error("Can't plot {}".format(parameter))
             return
 
         self.data_dict[hk + ':' + descr] = xy
@@ -694,13 +755,18 @@ class PlotViewer(Gtk.Window):
         # if npoints > self.max_datapoints > 0:
         #     xy = xy.T[::npoints // self.max_datapoints + 1].T
         self.subplot.autoscale(enable=not self.scaley.get_active(), axis='y')
-        if self.plot_diff.get_active():
-            x, y = xy
-            x1 = x[1:]
-            dy = np.diff(y)
-            line = self.subplot.plot(x1, dy, marker='.', label=descr, gid=hk)
-        else:
-            line = self.subplot.plot(*xy, marker='.', label=descr, gid=hk)
+        try:
+            if self.plot_diff.get_active():
+                x, y = xy
+                x1 = x[1:]
+                dy = np.diff(y)
+                line = self.subplot.plot(x1, dy, marker='.', label=descr, gid=hk)
+            else:
+                line = self.subplot.plot(*xy, marker='.', label=descr, gid=hk)
+        except TypeError:
+            self.logger.error("Can't plot data of type {}".format(xy.dtype[1]))
+            return
+
         self.reduce_datapoints(self.subplot.get_xlim(), self.subplot.get_ylim(), fulldata=False)
 
         # draw limits if available
@@ -711,7 +777,6 @@ class PlotViewer(Gtk.Window):
         limits = dbres.fetchall()
         dbcon.close()
 
-
         try:
             nlims = limits[0][-3]
             if nlims is not None:
@@ -735,25 +800,36 @@ class PlotViewer(Gtk.Window):
                     limitline.set_visible(show_limits)
                     self.parameter_limits.add(limitline)
         except IndexError:
-            #self.logger.error('Parameter {} does not exist - cannot add!'.format(parameter))
             self.logger.info('Parameter {} does not have limits to plot'.format(parameter))
-            #return
 
         # self.subplot.fill_between([-1e9,1e9],[1,1],[2,2],facecolor='orange',alpha=0.5,hatch='/')
         # self.subplot.fill_between([-1e9,1e9],2,10,facecolor='red',alpha=0.5)
 
-        self.subplot.legend(loc=2,
-                            framealpha=0.5)  # bbox_to_anchor=(0., 1.02, 1., .102),mode="expand", borderaxespad=0)
+        self.subplot.legend(loc=2, framealpha=0.5)  # bbox_to_anchor=(0.,1.02,1.,.102),mode="expand", borderaxespad=0)
         if self.subplot.get_legend() is not None:
             self.subplot.get_legend().set_visible(self.show_legend.get_active())
 
         self.subplot.set_ylabel('[{}]'.format(unit))
-        # print('#################' + descr + '####################')
         self.canvas.draw()
-        # except IndexError:
-        #    print('nothing to plot')
-        # except NameError:
-        #    print('unknown plotting error')
+
+    def set_plot_range(self, rows):
+        try:
+            self.data_min_idx = int(self.min_idx.get_text())
+            rows = rows.filter(DbTelemetry.idx >= self.data_min_idx)
+        except (TypeError, ValueError):
+            self.data_min_idx = None
+        try:
+            self.data_max_idx = int(self.max_idx.get_text())
+            rows = rows.filter(DbTelemetry.idx <= self.data_max_idx)
+        except (TypeError, ValueError):
+            self.data_max_idx = None
+
+        try:
+            self.max_datapoints = int(self.max_data.get_text())
+        except (TypeError, ValueError):
+            self.max_datapoints = 0
+
+        return rows
 
     def _toggle_limits(self, widget=None):
         if widget.get_active():
@@ -764,20 +840,20 @@ class PlotViewer(Gtk.Window):
                 line.set_visible(0)
         self.canvas.draw()
 
-    def _set_max_datapoints(self, widget=None):
-        try:
-            n = int(widget.get_text())
-            if n < 0:
-                widget.set_text('0')
-                n = 0
-        except ValueError:
-            if widget.get_text() == '':
-                n = 0
-                widget.set_text('0')
-            else:
-                widget.set_text('0')
-                return
-        self.max_datapoints = n
+    # def _set_max_datapoints(self, widget=None):
+    #     try:
+    #         n = int(widget.get_text())
+    #         if n < 0:
+    #             widget.set_text('0')
+    #             n = 0
+    #     except (TypeError, ValueError):
+    #         if widget.get_text() == '':
+    #             n = 0
+    #             widget.set_text('0')
+    #         else:
+    #             widget.set_text('0')
+    #             return
+    #     self.max_datapoints = n
 
     def reduce_datapoints(self, xlim, ylim, fulldata=True):
         ax = self.canvas.figure.get_axes()[0]
@@ -1273,117 +1349,6 @@ class NavigationToolbarX(NavigationToolbar):
 
         self.push_current()
         self.release(event)
-'''
-class UserParameterDialog(Gtk.MessageDialog):
-    def __init__(self, parent=None, edit=None):
-        Gtk.Dialog.__init__(self, "Add User Parameter", parent, 0,
-                            buttons=(Gtk.STOCK_OK, Gtk.ResponseType.OK, Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL))
-
-        self.set_border_width(5)
-
-        box = self.get_content_area()
-        ok_button = self.get_action_area().get_children()[0]
-        ok_button.set_sensitive(False)
-
-        hbox = Gtk.HBox()
-
-        self.apid = Gtk.Entry()
-        self.st = Gtk.Entry()
-        self.sst = Gtk.Entry()
-        self.apid.set_placeholder_text('APID')
-        self.st.set_placeholder_text('Service Type')
-        self.sst.set_placeholder_text('Service Subtype')
-        self.sid = Gtk.Entry()
-        self.sid.set_placeholder_text('SID')
-        self.sid.set_tooltip_text('First byte in source data (optional)')
-
-        hbox.pack_start(self.apid, 0, 0, 0)
-        hbox.pack_start(self.st, 0, 0, 0)
-        hbox.pack_start(self.sst, 0, 0, 0)
-        hbox.pack_start(self.sid, 0, 0, 0)
-        hbox.set_homogeneous(True)
-        hbox.set_spacing(5)
-
-        bytebox = Gtk.HBox()
-
-        self.bytepos = Gtk.Entry()
-        self.bytepos.set_placeholder_text('Byte Offset')
-        self.bytepos.set_tooltip_text('Including {} ({} for TCs) header bytes, e.g. byte 0 in source data -> offset={}'
-                                      .format(TM_HEADER_LEN, TC_HEADER_LEN, TM_HEADER_LEN))
-        self.format = Gtk.ComboBoxText()
-        self.format.set_model(self.create_format_model())
-        self.format.set_tooltip_text('Format type')
-        self.format.connect('changed', self.bitlen_active)
-        self.offbi = Gtk.Entry()
-        self.offbi.set_placeholder_text('Bit Offset')
-        self.offbi.set_tooltip_text('Bit Offset (optional)')
-        self.bitlen = Gtk.Entry()
-        self.bitlen.set_placeholder_text('Bitlength')
-        self.bitlen.set_tooltip_text('Length in bits')
-        self.bitlen.set_sensitive(False)
-
-        bytebox.pack_start(self.bytepos, 0, 0, 0)
-        bytebox.pack_start(self.format, 0, 0, 0)
-        bytebox.pack_start(self.offbi, 0, 0, 0)
-        bytebox.pack_start(self.bitlen, 0, 0, 0)
-        bytebox.set_spacing(5)
-
-        self.label = Gtk.Entry()
-        self.label.set_placeholder_text('Parameter Label')
-        self.label.connect('changed', self.check_ok_sensitive, ok_button)
-
-        box.pack_start(self.label, 0, 0, 0)
-        box.pack_end(bytebox, 0, 0, 0)
-        box.pack_end(hbox, 0, 0, 0)
-        box.set_spacing(10)
-
-        if edit is not None:
-            pars = json.loads(parent.cfg['plot_parameters'][edit])
-            self.label.set_text(edit)
-            if 'ST' in pars:
-                self.st.set_text(str(pars['ST']))
-            if 'SST' in pars:
-                self.sst.set_text(str(pars['SST']))
-            if 'APID' in pars:
-                self.apid.set_text(str(pars['APID']))
-            if 'SID' in pars and pars['SID'] is not None:
-                self.sid.set_text(str(pars['SID']))
-            if 'bytepos' in pars:
-                self.bytepos.set_text(str(pars['bytepos']))
-            if 'format' in pars:
-                fmt_dict = {a: b for b, a in fmtlist.items()}
-                fmt = pars['format']
-                if fmt.startswith('bit'):
-                    self.bitlen.set_text(fmt.strip('bit'))
-                    fmt = 'bit'
-                model = self.format.get_model()
-                it = [row.iter for row in model if row[0] == fmt_dict[fmt]][0]
-                self.format.set_active_iter(it)
-            if 'offbi' in pars:
-                self.offbi.set_text(str(pars['offbi']))
-
-        self.show_all()
-
-    def create_format_model(self):
-        store = Gtk.ListStore(str)
-        for fmt in fmtlist.keys():
-            store.append([fmt])
-        return store
-
-    def check_ok_sensitive(self, unused_widget, button):
-        if len(self.label.get_text()) == 0:
-            button.set_sensitive(False)
-        else:
-            button.set_sensitive(True)
-
-    def bitlen_active(self, widget):
-        if widget.get_active_text() == 'bit*':
-            self.bitlen.set_sensitive(True)
-            self.offbi.set_sensitive(True)
-        else:
-            self.bitlen.set_sensitive(False)
-            self.offbi.set_sensitive(False)
-'''
 
 
 class DataWindow(Gtk.Window):
@@ -1406,7 +1371,7 @@ class SelectPoolDialog(Gtk.Dialog):
         self.add_buttons(Gtk.STOCK_OK, Gtk.ResponseType.OK, Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL)
 
         self.explain_label = Gtk.Label()
-        self.explain_label.set_text("Please select one of the shown Pools to Plot ")
+        self.explain_label.set_text("Please select one of the shown pools to plot.")
 
         self.set_border_width(5)
 
@@ -1428,7 +1393,7 @@ class SelectPoolDialog(Gtk.Dialog):
 
         else:
             self.label = Gtk.Label()
-            self.label.set_text("No Pools could be found")
+            self.label.set_text("No pools could be found")
             ok_button.set_sensitive(False)
 
         box.pack_start(self.explain_label, 0, 0, 0)
@@ -1497,17 +1462,13 @@ if __name__ == "__main__":
 
     # Important to tell Dbus that Gtk loop can be used before the first dbus command
     DBusGMainLoop(set_as_default=True)
-
     if pool:
         win = PlotViewer(loaded_pool=pool)
     else:
         win = PlotViewer()
-
     Bus_Name = cfg.get('ccs-dbus_names', 'plotter')
     # DBusGMainLoop(set_as_default=True)
     DBus_Basic.MessageListener(win, Bus_Name, *sys.argv)
-
     win.connect("delete-event", win.quit_func)
     win.show_all()
-
     Gtk.main()
\ No newline at end of file
diff --git a/Ccs/poolview_sql.py b/Ccs/poolview_sql.py
index 4406522a7dfc1dc288f52258feb7c51d2ae3d02d..79a77a877d7f7a7376a556d12db9e575346acdf3 100644
--- a/Ccs/poolview_sql.py
+++ b/Ccs/poolview_sql.py
@@ -50,8 +50,8 @@ ActivePoolInfo = NamedTuple(
         ('pool_name', str),
         ('live', bool)])
 
-fmtlist = {'INT8': 'b', 'UINT8': 'B', 'INT16': 'h', 'UINT16': 'H', 'INT32': 'i', 'UINT32': 'I', 'INT64': 'q',
-           'UINT64': 'Q', 'FLOAT': 'f', 'DOUBLE': 'd', 'INT24': 'i24', 'UINT24': 'I24', 'bit*': 'bit'}
+# fmtlist = {'INT8': 'b', 'UINT8': 'B', 'INT16': 'h', 'UINT16': 'H', 'INT32': 'i', 'UINT32': 'I', 'INT64': 'q',
+#            'UINT64': 'Q', 'FLOAT': 'f', 'DOUBLE': 'd', 'INT24': 'i24', 'UINT24': 'I24', 'bit*': 'bit'}
 
 Telemetry = {'PUS': DbTelemetry, 'RMAP': RMapTelemetry, 'FEE': FEEDataTelemetry}
 
@@ -2169,16 +2169,26 @@ class TMPoolView(Gtk.Window):
         # Popover creates the popup menu over the button and lets one use multiple buttons for the same one
         self.popover = Gtk.Popover()
         # Add the different Starting Options
-        vbox = Gtk.Box(orientation=Gtk.Orientation.VERTICAL)
+        vbox = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=5, margin=4)
         for name in self.cfg['ccs-dbus_names']:
-            start_button = Gtk.Button.new_with_label("Start " + name.capitalize() + '   ')
+            start_button = Gtk.Button.new_with_label("Start " + name.capitalize())
             start_button.connect("clicked", cfl.on_open_univie_clicked)
-            vbox.pack_start(start_button, False, True, 10)
+            vbox.pack_start(start_button, False, True, 0)
+
+        # Add the TST option
+        conn_button = Gtk.Button.new_with_label('Test Specification Tool')
+        conn_button.connect("clicked", cfl.start_tst)
+        vbox.pack_start(conn_button, True, True, 0)
 
         # Add the manage connections option
         conn_button = Gtk.Button.new_with_label('Communication')
         conn_button.connect("clicked", self.on_communication_dialog)
-        vbox.pack_start(conn_button, False, True, 10)
+        vbox.pack_start(conn_button, True, True, 0)
+
+        # Add the configuration manager option
+        conn_button = Gtk.Button.new_with_label('Preferences')
+        conn_button.connect("clicked", cfl.start_config_editor)
+        vbox.pack_start(conn_button, True, True, 0)
 
         # Add the option to see the Credits
         about_button = Gtk.Button.new_with_label('About')
@@ -2223,7 +2233,7 @@ class TMPoolView(Gtk.Window):
         changed = False
         #self.select_pool(False, new_pool=pool_name)
         model = self.pool_selector.get_model()
-        #It will check all entries in the Pool selector and change to the one if possible
+        # It will check all entries in the Pool selector and change to the one if possible
         count = 0
         while count < len(model):
             value = model.get_value(model.get_iter(count), 0)  # Get the value
@@ -2256,9 +2266,10 @@ class TMPoolView(Gtk.Window):
 
         self.rawswitch = Gtk.CheckButton.new_with_label('Decode Source Data')
         self.rawswitch.connect('toggled', self.set_tm_data_view, None, True)
+        self.rawswitch.connect('toggled', self._update_user_tm_decoders)
         # self.sortswitch = Gtk.CheckButton.new_with_label('Sort by Name')
         # self.sortswitch.connect('toggled', self.set_tm_data_view, )
-        #switchbox = Gtk.Box(Gtk.Orientation.HORIZONTAL)
+        # switchbox = Gtk.Box(Gtk.Orientation.HORIZONTAL)
         switchbox = Gtk.HBox()
         switchbox.pack_start(self.rawswitch, 0, 0, 0)
         # switchbox.pack_end(self.sortswitch, 0, 0, 0)
@@ -2342,22 +2353,26 @@ class TMPoolView(Gtk.Window):
         box = Gtk.VBox()
 
         box1 = Gtk.HBox()
-        package_button = Gtk.Button(label = 'Add Package to Decode')
+        package_button = Gtk.Button(label='Create TM Structure')
         package_button.set_image(Gtk.Image.new_from_icon_name('list-add', Gtk.IconSize.MENU))
-        package_button.set_tooltip_text('Add User Defined Package to Decode')
+        package_button.set_tooltip_text('Create user defined TM packet structure')
         package_button.set_always_show_image(True)
 
-        parameter_button = Gtk.Button()
+        parameter_button = Gtk.Button(label='Create Parameter')
         parameter_button.set_image(Gtk.Image.new_from_icon_name('list-add', Gtk.IconSize.MENU))
-        parameter_button.set_tooltip_text('Add User Defined Parameter to use in Package')
+        parameter_button.set_tooltip_text('Create user defined parameter')
         parameter_button.set_always_show_image(True)
 
+        decode_udef_check = Gtk.CheckButton.new_with_label('UDEF')
+        decode_udef_check.set_tooltip_text('Force decoding with custom packet structures')
+
         package_button.connect('clicked', self.add_new_user_package)
         parameter_button.connect('clicked', self.add_decode_parameter)
+        decode_udef_check.connect('toggled', self.set_decoding_order)
 
         box1.pack_start(package_button, 0, 0, 0)
         box1.pack_start(parameter_button, 0, 0, 0)
-
+        box1.pack_start(decode_udef_check, 0, 0, 2)
 
         box2 = Gtk.HBox()
 
@@ -2365,37 +2380,32 @@ class TMPoolView(Gtk.Window):
         decoder_name.set_tooltip_text('Label')
         decoder_name_entry = decoder_name.get_child()
         decoder_name_entry.set_placeholder_text('Label')
-        decoder_name_entry.set_width_chars(5)
+        decoder_name_entry.set_width_chars(10)
 
         decoder_name.set_model(self.create_decoder_model())
 
         bytepos = Gtk.Entry()
-        bytepos.set_placeholder_text('Offset+{}'.format(TM_HEADER_LEN))
-        bytepos.set_tooltip_text('Offset+{}'.format(TM_HEADER_LEN))
-        bytepos.set_width_chars(5)
+        bytepos.set_placeholder_text('Offset')  # +{}'.format(TM_HEADER_LEN))
+        bytepos.set_tooltip_text('Offset')  # +{}'.format(TM_HEADER_LEN))
+        bytepos.set_width_chars(7)
 
         bytelength = Gtk.Entry()
         bytelength.set_placeholder_text('Length')
         bytelength.set_tooltip_text('Length')
-        bytelength.set_width_chars(5)
+        bytelength.set_width_chars(7)
 
         add_button = Gtk.Button(label=' Decoder')
         add_button.set_image(Gtk.Image.new_from_icon_name('list-add', Gtk.IconSize.MENU))
+        add_button.set_tooltip_text('Add byte decoder')
         add_button.set_always_show_image(True)
 
-        decode_udef_check = Gtk.CheckButton.new_with_label('UDEF')
-        decode_udef_check.set_tooltip_text('Use User-defined Packets first for Decoding')
-
         decoder_name.connect('changed', self.fill_decoder_mask, bytepos, bytelength)
         add_button.connect('clicked', self.add_decoder, decoder_name, bytepos, bytelength)
-        decode_udef_check.connect('toggled', self.set_decoding_order)
 
-
-        box2.pack_start(decoder_name, 0, 0, 0)
-        box2.pack_start(bytepos, 0, 0, 1)
-        box2.pack_start(bytelength, 0, 0, 1)
+        box2.pack_start(decoder_name, 0, 1, 0)
+        box2.pack_start(bytepos, 0, 0, 0)
+        box2.pack_start(bytelength, 0, 0, 0)
         box2.pack_start(add_button, 0, 0, 0)
-        box2.pack_start(decode_udef_check, 0, 0, 0)
 
         box.pack_start(box1, 0, 0, 0)
         box.pack_start(box2, 0, 0, 0)
@@ -2442,16 +2452,15 @@ class TMPoolView(Gtk.Window):
         # if not self.cfg.has_option('user_decoders',decoder):
         #    return
 
-        if self.cfg.has_option('ccs-plot_parameters', decoder):
-            data = json.loads(self.cfg['ccs-plot_parameters'][decoder])
+        if self.cfg.has_option('ccs-user_decoders', decoder):
+            data = json.loads(self.cfg['ccs-user_decoders'][decoder])
 
             bytepos.set_text(str(data['bytepos']))
-            bytelen.set_text(str(struct.calcsize(data['format'])))
+            bytelen.set_text(str(data['bytelen']))
 
     def add_decoder(self, widget, decoder_name, byteoffset, bytelength):
         try:
-            label, bytepos, bytelen = decoder_name.get_active_text(), int(byteoffset.get_text()), int(
-                bytelength.get_text())
+            label, bytepos, bytelen = decoder_name.get_active_text(), int(byteoffset.get_text()), int(bytelength.get_text())
         except:
             return
 
@@ -2498,7 +2507,7 @@ class TMPoolView(Gtk.Window):
         self.show_all()
 
     def set_decoder_view(self, tm):
-        decoders = self.decoder_box.get_children()[1:]
+        decoders = self.decoder_box.get_children()[0].get_children()[2:]
 
         for decoder in decoders:
             try:
@@ -2522,6 +2531,10 @@ class TMPoolView(Gtk.Window):
                 value = model[treepath[0]][3]
                 self.hexview.set_text(value)
 
+    def _update_user_tm_decoders(self, widget):
+        if widget.get_active():
+            importlib.reload(cfl)
+
     @delayed(10)
     def set_tm_data_view(self, selection=None, event=None, change_columns=False):
         if not self.active_pool_info:
@@ -3082,7 +3095,7 @@ class TMPoolView(Gtk.Window):
         res = self.session_factory_storage.execute(que)
         return [row[1] for row in res]
 
-    def plot_parameters(self, widget=None, parameters={}, start_live=False):
+    def plot_parameters(self, widget=None, parameters=None, start_live=False):
         #if self.active_pool_info is None:
         #    self.logger.warning('Cannot open plot window without pool!')
         #    print('Cannot open plot window without pool!')
@@ -3252,10 +3265,7 @@ class TMPoolView(Gtk.Window):
             # cnt = rows.count()
             cnt = rows.order_by(Telemetry[self.decoding_type].idx.desc()).first().idx
             # print(cnt)
-            rows = rows.filter(Telemetry[self.decoding_type].idx > (cnt - 100)).offset(100 - 25
-                                                                     ).limit(
-                25
-            ).all()
+            rows = rows.filter(Telemetry[self.decoding_type].idx > (cnt - 100)).offset(100 - 25).limit(25).all()
             # rr=[row for row in rows]
             self.logger.info('fetched', rows[-1].idx, cnt, 'at', time.time())
             dbcon.close()
diff --git a/Ccs/scripts/connection_setup.py b/Ccs/scripts/connection_setup.py
index af5f44b26dd6f79e7f11ea1d358b0c4d35bfd798..2e76052d6cc4431111fb65dd5e15568ddf11c2cf 100644
--- a/Ccs/scripts/connection_setup.py
+++ b/Ccs/scripts/connection_setup.py
@@ -13,4 +13,3 @@ cfl.start_pv()
 #! CCS.BREAKPOINT
 ### Monitor ###
 cfl.start_monitor('LIVE')
-