diff --git a/Ccs/ccs_function_lib.py b/Ccs/ccs_function_lib.py index 1677e126af5775932d9e2fb2d6269aadef8d98c0..10bd82c814c8beb6e4eb281bdbfb239107ea40db 100644 --- a/Ccs/ccs_function_lib.py +++ b/Ccs/ccs_function_lib.py @@ -330,7 +330,7 @@ def dbus_connection(name, instance=1): return dbuscon except: # print('Please start ' + str(name) + ' if it is not running') - logger.warning('Connection to ' + str(name) + ' is not possible.') + logger.info('Connection to ' + str(name) + ' is not possible.') return False @@ -594,8 +594,8 @@ def user_tm_decoders_func(): # # Return a formatted string containing all the decoded source data of TM packet _tm_ # @param tm TM packet bytestring -def Tmformatted(tm, separator='\n', sort_by_name=False, textmode=True, UDEF=False): - sourcedata, tmtcnames = Tmdata(tm, UDEF=UDEF) +def Tmformatted(tm, separator='\n', sort_by_name=False, textmode=True, udef=False): + sourcedata, tmtcnames = Tmdata(tm, udef=udef) tmtcname = " / ".join(tmtcnames) if textmode: if sourcedata is not None: @@ -624,17 +624,18 @@ 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): +def Tmdata(tm, udef=False): 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 IDB will be checked - if UDEF: + # check if a UDEF exists and use to decode, if not the IDB will be checked + if udef: try: header, data, crc = Tmread(tm) st, sst, apid = header.SERV_TYPE, header.SERV_SUB_TYPE, header.APID que = 'SELECT pic_pi1_off,pic_pi1_wid from pic where pic_type=%s and pic_stype=%s' % (st, sst) + # que = 'SELECT pic_pi1_off,pic_pi1_wid from pic where pic_type=%s and pic_stype=%s and pic_apid=%s' % (st, sst, apid) dbres = dbcon.execute(que) pi1, pi1w = dbres.fetchall()[0] @@ -642,41 +643,46 @@ def Tmdata(tm, UDEF=False, *args): tag = '{}-{}-{}-{}'.format(st, sst, apid, pi1val) user_label, params = user_tm_decoders[tag] spid = None - #o = data.unpack(','.join([ptt[i[4]][i[5]] for i in params])) - if len(params[0]) == 9: #Length of a parameter which should be decoded acording to given position + + # Length of a parameter which should be decoded acording to given position + if len(params[0]) == 9: vals_params = decode_pus(data, params) - else: #Decode according to given order, length is then 11 + # Decode according to given order, length is then 11 + else: vals_params = read_variable_pckt(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)] tmname = ['USER DEFINED: {}'.format(user_label)] return tmdata, tmname - except: - logger.info('UDEF could not be found, search in IDB') + + except Exception as err: + logger.info('UDEF could not be found, search in IDB ({})'.format(err)) + finally: + dbcon.close() try: if (tm[0] >> 4) & 1: - return Tcdata(tm, *args) - # with poolmgr.lock: + return Tcdata(tm) + header, data, crc = Tmread(tm) - # data = tm_list[-2] st, sst, apid = header.SERV_TYPE, header.SERV_SUB_TYPE, header.APID que = 'SELECT pic_pi1_off,pic_pi1_wid from pic where pic_type=%s and pic_stype=%s' % (st, sst) dbres = dbcon.execute(que) pi1, pi1w = dbres.fetchall()[0] + if pi1 != -1: - #print(tm[pi1:pi1 + pi1w]) - # pi1val = Bits(tm)[pi1 * 8:pi1 * 8 + pi1w].uint pi1val = int.from_bytes(tm[pi1:pi1 + pi1w//8], 'big') que = 'SELECT pid_spid,pid_tpsd,pid_dfhsize from pid where pid_type=%s and pid_stype=%s and ' \ 'pid_apid=%s and pid_pi1_val=%s' % (st, sst, apid, pi1val) else: que = 'SELECT pid_spid,pid_tpsd,pid_dfhsize from pid where pid_type=%s and pid_stype=%s and ' \ 'pid_apid=%s' % (st, sst, apid) + dbres = dbcon.execute(que) fetch = dbres.fetchall() + # if APID or SID does not match: if len(fetch) != 0: spid, tpsd, dfhsize = fetch[0] @@ -696,6 +702,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,\ @@ -708,14 +715,15 @@ def Tmdata(tm, UDEF=False, *args): tmdata = [(get_calibrated(i[0], j[0]), i[6], i[1], pidfmt(i[7]), j) for i, j in zip(params, vals_params)] elif params is not None: - #o = data.unpack(','.join([ptt[i[4]][i[5]] for i in params])) - - if len(params[0]) == 9: #Length of a parameter which should be decoded acording to given position + # Length of a parameter which should be decoded acording to given position + if len(params[0]) == 9: vals_params = decode_pus(data, params) - else: #Decode according to given order, length is then 11 + # Decode according to given order, length is then 11 + else: vals_params = read_variable_pckt(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,\ pcf.pcf_unit,pcf.pcf_pid,vpd_pos,vpd_grpsize,vpd_fixrep from vpd left join pcf on \ @@ -733,10 +741,13 @@ def Tmdata(tm, UDEF=False, *args): tmname = dbres.fetchall()[0] else: tmname = ['USER DEFINED: {}'.format(user_label)] + except Exception as failure: raise Exception('Packet data decoding failed: ' + str(failure)) + finally: dbcon.close() + return tmdata, tmname @@ -803,7 +814,7 @@ def read_stream(stream, fmt, pos=None, offbi=0): x = x.decode('ascii') except UnicodeDecodeError as err: logger.warning(err) - x = str(data) + x = x.decode('utf-8', errors='replace') elif fmt == timepack[0]: x = timecal(data) else: @@ -812,7 +823,7 @@ def read_stream(stream, fmt, pos=None, offbi=0): return x -def csize(fmt, offbi=0): +def csize(fmt, offbi=0, bitsize=False): """ Returns the amount of bytes required for the input format @param fmt: Input String that defines the format @@ -866,6 +877,10 @@ def none_to_empty(s): return '' if s is None else s +def str_to_int(itr): + return int(itr) if itr.lower() != 'none' else None + + def Tm_header_formatted(tm, detailed=False): """unpack APID, SEQCNT, PKTLEN, TYPE, STYPE, SOURCEID""" @@ -965,13 +980,15 @@ def parameter_tooltip_text(x): h = hex(x)[3:].upper() elif isinstance(x, float): h = struct.pack('>f', x).hex().upper() + elif isinstance(x, bytes): + return x.hex().upper() else: # h = str(x) return str(x) return 'HEX: 0x{}\nDEC: {}'.format(h, x) -def Tcdata(tm, *args): +def Tcdata(tm): header, data, crc = Tmread(tm) st, sst, apid = header.SERV_TYPE, header.SERV_SUB_TYPE, header.APID dbcon = scoped_session_idb @@ -1201,7 +1218,7 @@ def read_stream_recursive(tms, parameters, decoded=None): continue grp = par[-2] - if grp is None: # None happens for UDFP, would give error using None + if grp is None: # None happens for UDEF grp = 0 fmt = ptt(par[2], par[3]) @@ -1285,6 +1302,7 @@ def pidfmt_reverse(val): # @param pcf_name PCF_NAME # @param rawval Raw value of the parameter def get_calibrated(pcf_name, rawval, properties=None, numerical=False, dbcon=None): + if properties is None: dbcon = scoped_session_idb que = 'SELECT pcf.pcf_ptc,pcf.pcf_pfc,pcf.pcf_categ,pcf.pcf_curtx from pcf where pcf_name="%s"' % pcf_name @@ -1292,7 +1310,7 @@ def get_calibrated(pcf_name, rawval, properties=None, numerical=False, dbcon=Non fetch = dbres.fetchall() dbcon.close() if len(fetch) == 0: - return rawval if isinstance(rawval, (int, float)) else rawval[0] + return rawval if isinstance(rawval, (int, float, str, bytes)) else rawval[0] ptc, pfc, categ, curtx = fetch[0] @@ -1419,7 +1437,7 @@ def Tm_filter_st(tmlist, st=None, sst=None, apid=None, sid=None, time_from=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 (int.from_bytes(tm[:2], 'big') & 0x7FF) == apid] - if sid is not None: + if sid: if st is None or sst is None or apid is None: raise ValueError('Must provide st, sst and apid if filtering by sid') @@ -1436,6 +1454,65 @@ def Tm_filter_st(tmlist, st=None, sst=None, apid=None, sid=None, time_from=None, return tmlist +def filter_rows(rows, st=None, sst=None, apid=None, sid=None, time_from=None, time_to=None, idx_from=None, idx_to=None, + tmtc=None, get_last=False): + """ + Filter SQL query object by any of the given arguments, return filtered query. + @param rows: + @param st: + @param sst: + @param apid: + @param sid: + @param time_from: + @param time_to: + @param idx_from: + @param idx_to: + @param tmtc: + @param get_last: + """ + + if st is not None: + rows = rows.filter(DbTelemetry.stc == st) + + if sst is not None: + rows = rows.filter(DbTelemetry.sst == sst) + + if apid is not None: + rows = rows.filter(DbTelemetry.apid == apid) + + if sid: + if st is None or sst is None or apid is None: + raise ValueError('Must provide st, sst and apid if filtering by sid') + + sid_offset, sid_bitlen = get_sid(st, sst, apid) + if sid_offset != -1: + sid_size = sid_bitlen // 8 + rows = rows.filter( + func.mid(DbTelemetry.data, sid_offset - TM_HEADER_LEN + 1, sid_size) == sid.to_bytes(sid_size, 'big')) + else: + logger.error('SID ({}) not applicable for {}-{}-{}'.format(sid, st, sst, apid)) + + if time_from is not None: + rows = rows.filter(func.left(DbTelemetry.timestamp, func.length(DbTelemetry.timestamp) - 1) >= time_from) + + if time_to is not None: + rows = rows.filter(func.left(DbTelemetry.timestamp, func.length(DbTelemetry.timestamp) - 1) <= time_to) + + if idx_from is not None: + rows = rows.filter(DbTelemetry.idx >= idx_from) + + if idx_to is not None: + rows = rows.filter(DbTelemetry.idx <= idx_to) + + if tmtc is not None: + rows = rows.filter(DbTelemetry.is_tm == tmtc) + + if get_last: + rows = rows.order_by(DbTelemetry.idx.desc()).first() + + return rows + + ## # CRC check # @@ -1506,9 +1583,8 @@ def get_pool_rows(pool_name, check_existence=False): return rows -# get values of parameter from HK packets -def get_param_values(tmlist=None, hk=None, param=None, last=0, numerical=False, tmfilter=True, pool_name=None): - +# get values of parameter from HK packets +def get_param_values(tmlist=None, hk=None, param=None, last=0, numerical=False, tmfilter=True, pool_name=None, mk_array=True): if param is None: return @@ -1524,20 +1600,21 @@ def get_param_values(tmlist=None, hk=None, param=None, last=0, numerical=False, dbres = dbcon.execute(que) 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, 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: + # tmlist = tmlist.filter(DbTelemetry.stc == st, DbTelemetry.sst == sst, DbTelemetry.apid == apid, + # 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()) + tmlist_rows = filter_rows(tmlist, st=st, sst=sst, apid=apid, sid=sid) + if tmlist_rows is not None: if last > 1: - tmlist_filt = [tm.raw for tm in tmlist[:last]] + tmlist = [tm.raw for tm in tmlist_rows[-last:]] else: - tmlist_filt = [tmlist.first().raw] + tmlist = [tmlist_rows.order_by(DbTelemetry.idx.desc()).first().raw] else: - tmlist_filt = [] + tmlist = [] else: 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:] + # tmlist_filt = Tm_filter_st(tmlist, st=st, sst=sst, apid=apid, sid=sid)[-last:] if tmfilter else tmlist[-last:] ufmt = ptt(ptc, pfc) @@ -1550,9 +1627,8 @@ def get_param_values(tmlist=None, hk=None, param=None, last=0, numerical=False, hkdescr, st, sst, sid, apid, name, spid, offby, offbi, ptc, pfc, unit, descr, pid = dbres.fetchall()[0] 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) + # tmlist_filt = Tm_filter_st(tmlist, st=st, sst=sst, apid=apid, sid=sid)[-last:] if tmfilter else tmlist[-last:] elif hk.startswith('UDEF|'): label = hk.replace('UDEF|', '') @@ -1565,21 +1641,30 @@ def get_param_values(tmlist=None, hk=None, param=None, last=0, numerical=False, sst = int(pktkey[1]) apid = int(pktkey[2]) if pktkey[2] != 'None' else None 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 - tmlist_filt = Tm_filter_st(tmlist, st, sst, apid, sid)[-last:] if tmfilter else tmlist[-last:] + # name, descr, _, offbi, ptc, pfc, unit, _, bitlen = parinfo + _, descr, ptc, pfc, curtx, bitlen, _, _, _, _, _ = parinfo + unit = None + name = None + offbi = 0 + + offby = sum([x[5] 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]) - 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:] + st = int(userpar['ST']) + sst = int(userpar['SST']) + apid = int(userpar['APID']) + sid = None if (('SID' not in userpar) or (userpar['SID'] is None)) else int(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'] offbi = userpar['offbi'] if 'offbi' in userpar else 0 descr, unit, name = param, None, None bylen = csize(ufmt) + tmlist_filt = Tm_filter_st(tmlist, st=st, sst=sst, apid=apid, sid=sid)[-last:] if tmfilter else tmlist[-last:] + if name is not None: que = 'SELECT pcf.pcf_categ,pcf.pcf_curtx from pcf where pcf_name="%s"' % name dbres = dbcon.execute(que) @@ -1600,7 +1685,10 @@ def get_param_values(tmlist=None, hk=None, param=None, last=0, numerical=False, dbcon.close() try: - return np.array(np.array(xy).T, dtype='float'), (descr, unit) + if mk_array: + return np.array(np.array(xy).T, dtype='float'), (descr, unit) + else: + return xy, (descr, unit) except ValueError: return np.array(xy, dtype='float, U32'), (descr, unit) @@ -1656,9 +1744,9 @@ def get_module_handle(module_name, instance=1, timeout=5): if module: break else: - time.sleep(1.) + time.sleep(.2) except dbus.DBusException as err: - logger.warning(err) + logger.info(err) module = False time.sleep(0.5) @@ -2138,9 +2226,10 @@ def get_sid(st, sst, apid): return SID_LUT[(st, sst, apid)] else: try: + logger.warning('APID {} not known'.format(apid)) return SID_LUT[(st, sst, None)] except KeyError: - return None + return ## @@ -2505,28 +2594,36 @@ def Tcsend_bytes(tc_bytes, pool_name='LIVE', pmgr_handle=None): # Send command to C&C socket # @param pool_name Name of the pool bound to the socket for CnC/TC communication # @param cmd Command string to be sent to C&C socket -def CnCsend(cmd, pool_name=None): +def CnCsend(cmd, pool_name=None, apid=1804): global counters # One can only Change variable as global since we are static - - pmgr = dbus_connection('poolmanager', communication['poolmanager']) + # pmgr = dbus_connection('poolmanager', communication['poolmanager']) + pmgr = get_module_handle('poolmanager') if pool_name is None: pool_name = pmgr.Variables('tc_name') - packed_data = CnCpack(data=cmd, sc=counters.setdefault(1804, 1)) + pid = (apid >> 4) & 0x7F + cat = apid & 0xF + packed_data = CnCpack(data=cmd, pid=pid, cat=cat, sc=counters.setdefault(apid, 1)) - logger.info('[CNC sent:]' + str(packed_data)) received = pmgr.Functions('socket_send_packed_data', packed_data, pool_name, signature='says') - if received is not None: - counters[1804] += 1 + logger.info('[CNC sent:]' + str(packed_data)) + + try: + msg = bytes(received) + except TypeError as err: + logger.error(err) + return + + if msg: + counters[apid] += 1 try: - received = bytes(received, encoding='utf-8', errors='replace') + msg = msg.decode('ascii', errors='replace') except Exception as err: logger.error(err) - return None - - logger.info('[CNC response:]' + received.decode(encoding='utf-8', errors='replace')) + return - return received + logger.info('[CNC response:] ' + msg) + return msg ## @@ -2542,6 +2639,10 @@ def CnCsend(cmd, pool_name=None): # @param gflags Segmentation flags # @param sc Sequence counter def CnCpack(data=b'', version=0b011, typ=1, dhead=0, pid=112, cat=12, gflags=0b11, sc=0): + + if isinstance(data, str): + data = data.encode('ascii') + header = PHeader() header.bits.PKT_VERS_NUM = version header.bits.PKT_TYPE = typ @@ -2551,7 +2652,7 @@ def CnCpack(data=b'', version=0b011, typ=1, dhead=0, pid=112, cat=12, gflags=0b1 header.bits.PKT_SEQ_CNT = sc header.bits.PKT_LEN = len(data) - 1 - return bytes(header.bin) + data.encode() + return bytes(header.bin) + data ## @@ -3465,6 +3566,12 @@ def get_data_pool_items(pcf_descr=None, src_file=None, as_dict=False): return data_pool_dict +def get_dp_fmt_info(dp_name): + que = 'SELECT pcf_name FROM pcf where pcf_pid is not NULL and pcf_descr="{}"'.format(dp_name) + mib_name = scoped_session_idb.execute(que).fetchall()[0] + return mib_name + + # def get_dp_items(source='mib'): # fmt = {3: {4: 'UINT8', 12: 'UINT16', 14: 'UINT32'}, 4: {4: 'INT8', 12: 'INT16', 14: 'INT32'}, 5: {1: 'FLOAT'}, 9: {18: 'CUC'}, 7: {1: '1OCT'}} # @@ -4278,7 +4385,7 @@ def extract_spw(stream): header.bits.PKT_TYPE == 0 and header.bits.WRITE == 1): pktsize = hsize else: - pktsize = hsize + header.bits.DATA_LEN# + pc.RMAP_PEC_LEN # TODO: no data CRC from FEEsim? + pktsize = hsize + header.bits.DATA_LEN + pc.RMAP_PEC_LEN # TODO: no data CRC from FEEsim? while len(buf) < pktsize: data = stream.read(pktsize - len(buf)) diff --git a/Ccs/monitor.py b/Ccs/monitor.py index 0a43954e81a28777f4bb0b8a06ce8ff690c19570..7636522c2d686493c9256123ea71bde5dd33655f 100644 --- a/Ccs/monitor.py +++ b/Ccs/monitor.py @@ -54,8 +54,7 @@ class ParameterMonitor(Gtk.Window): self.events = {'Error LOW': [(5, 2), 0], 'Error MEDIUM': [(5, 3), 0], 'Error HIGH': [(5, 4), 0]} self.evt_reset_values = {'Error LOW': 0, 'Error MEDIUM': 0, 'Error HIGH': 0} - # self.box = Gtk.VBox() - # self.menubar = Gtk.MenuBar() + self.evt_pkt_idx_last = 0 # last packet idx up to which the evts were counted self.grid = Gtk.Grid() self.grid.set_column_homogeneous(True) @@ -64,10 +63,12 @@ class ParameterMonitor(Gtk.Window): hbox = Gtk.HBox() self.add(hbox) + self._res_evt_cnt_callback = None self.evt_cnt = self.create_event_counter() self.evt_check_enabled = True self.evt_check_tocnt = 0 + self.pool_id = None # used to track "clear pool" events self.pool_name = pool_name self.parameter_set = parameter_set self.parameters = {} @@ -78,8 +79,8 @@ class ParameterMonitor(Gtk.Window): hbox.pack_start(self.grid, 1, 1, 0) # Add Univie Button - univie_box = self.create_univie_box() - hbox.pack_start(univie_box, 0, 1, 0) + # univie_box = self.create_univie_box() + # hbox.pack_start(univie_box, 0, 1, 0) hbox.set_spacing(20) @@ -95,7 +96,8 @@ class ParameterMonitor(Gtk.Window): def check_for_pools(self): try: - poolmgr = cfl.dbus_connection('poolmanager', cfl.communication['poolmanager']) + # poolmgr = cfl.dbus_connection('poolmanager', cfl.communication['poolmanager']) + poolmgr = cfl.get_module_handle('poolmanager') pools = poolmgr.Functions('loaded_pools_export_func') if len(pools) == 1: pool_name = pools[0][0] @@ -151,9 +153,11 @@ class ParameterMonitor(Gtk.Window): evt_cnt.pack_start(box, 0, 0, 0) reset_button = Gtk.Button(label='Reset') - reset_button.connect('clicked', self.reset_evt_cnt) + reset_button.set_tooltip_text('Reset warning threshold to current # of evt pkts') + self._res_evt_cnt_callback = reset_button.connect('clicked', self.reset_evt_cnt) - set_button = Gtk.Button(label='Set Parameter') + set_button = Gtk.Button(label='Set Parameters') + set_button.set_tooltip_text('Select/create set of monitored parameters') set_button.connect('clicked', self.add_evt_cnt) evt_cnt.pack_start(reset_button, 0, 0, 0) @@ -233,9 +237,12 @@ class ParameterMonitor(Gtk.Window): self.pdescr = {x[0]: x[1] for x in descrs} if self.cfg.has_option('ccs-monitor_parameter_sets', parameter_set): parameters = json.loads(self.cfg['ccs-monitor_parameter_sets'][parameter_set]) - self.setup_grid(parameters) + try: + self.setup_grid(parameters) + except KeyError as err: + self.logger.error('Failed to load parameter set "{}" ({})'.format(parameter_set, err)) else: - self.logger.warning('Parameter set "{}" does not exist'.format(parameter_set)) + self.logger.error('Parameter set "{}" does not exist'.format(parameter_set)) def setup_grid(self, parameters): @@ -246,39 +253,75 @@ class ParameterMonitor(Gtk.Window): for ncol, col in enumerate(parameters): for nrow, parameter in enumerate(col): box = Gtk.HBox() - parameter, *pktid = eval(parameter) - box.pktid = tuple(pktid) - dbres = dbcon.execute('SELECT pcf.pcf_name,pcf.pcf_descr,pcf.pcf_categ,pcf.pcf_unit,ocf.ocf_nbool,\ - ocp.ocp_lvalu,ocp.ocp_hvalu from pcf left join ocf on pcf.pcf_name=ocf.ocf_name\ - left join ocp on ocf_name=ocp_name where pcf.pcf_name="{}"'.format(parameter)) + parinfo = eval(parameter) + if len(parinfo) == 2: + parameter, pktid = parinfo[0], eval(parinfo[1]) + else: + parameter, *pktid = parinfo + + if parameter.startswith('UDEF:'): + box.pktid = tuple(pktid) + parameter, udtype = parameter.split(':')[1:] + if udtype == 'dp_item': + dbres = dbcon.execute('SELECT pcf.pcf_name,pcf.pcf_descr,pcf.pcf_categ,pcf.pcf_unit,ocf.ocf_nbool,\ + ocp.ocp_lvalu,ocp.ocp_hvalu from pcf left join ocf on pcf.pcf_name=ocf.ocf_name\ + left join ocp on ocf_name=ocp_name where pcf.pcf_descr="{}" and pcf_pid is not NULL'.format(parameter)) + boxdata = dbres.fetchall() + if not boxdata: + udid = '{}:{}'.format(udtype, cfl.DP_ITEMS_TO_IDS[parameter]) + boxdata = [[udid, parameter, 'N', None, None, None, None]] + elif udtype in ['user_defined', 'user_defined_nopos']: + udid = '{}:{}'.format(udtype, parameter) + boxdata = [[udid, parameter, 'N', None, None, None, None]] + else: + dbres = dbcon.execute('SELECT pcf.pcf_name,pcf.pcf_descr,pcf.pcf_categ,pcf.pcf_unit,ocf.ocf_nbool,\ + ocp.ocp_lvalu,ocp.ocp_hvalu from pcf left join ocf on pcf.pcf_name=ocf.ocf_name\ + left join ocp on ocf_name=ocp_name where pcf.pcf_name="{}"'.format(udtype)) + boxdata = dbres.fetchall() + + elif parameter.startswith('user_defined'): + udtype, parameter = parameter.split(':') + box.pktid = ((pktid['bytepos'], pktid['offbi'], pktid['format']), pktid['ST'], pktid['SST'], + pktid['APID'], pktid['SID'], None, None) + udid = '{}:{}'.format(udtype, parameter) + boxdata = [[udid, parameter, 'N', None, None, None, None]] + + else: + box.pktid = tuple(pktid) + dbres = dbcon.execute('SELECT pcf.pcf_name,pcf.pcf_descr,pcf.pcf_categ,pcf.pcf_unit,ocf.ocf_nbool,\ + ocp.ocp_lvalu,ocp.ocp_hvalu from pcf left join ocf on pcf.pcf_name=ocf.ocf_name\ + left join ocp on ocf_name=ocp_name where pcf.pcf_name="{}"'.format(parameter)) + boxdata = dbres.fetchall() - boxdata = dbres.fetchall() try: nlims = boxdata[0][-3] if nlims in (1, None): - box.param_id, plabel, box.format, unit, _, lolim, hilim = boxdata[0] + box.param_id, plabel, categ, unit, _, lolim, hilim = boxdata[0] hardlim = (lolim, hilim) softlim = (None, None) else: - box.param_id, plabel, box.format, unit = boxdata[0][:4] + box.param_id, plabel, categ, unit = boxdata[0][:4] softlim, hardlim = [(x[-2], x[-1]) for x in boxdata] + box.format = self.get_fstr(box.param_id, plabel, categ=categ) except IndexError: self.logger.error('Parameter {} does not exist - cannot add!'.format(parameter)) continue + # override with user defined limits - if self.pdescr.get(parameter) in self.user_limits: + if self.pdescr.get(parameter, parameter) in self.user_limits: try: - softlim = self.user_limits[self.pdescr[parameter]]['soft'] + softlim = self.user_limits[self.pdescr.get(parameter, parameter)]['soft'] except KeyError: softlim = (None, None) - hardlim = self.user_limits[self.pdescr[parameter]]['hard'] + hardlim = self.user_limits[self.pdescr.get(parameter, parameter)]['hard'] box.limits = (softlim, hardlim) pname, pvalue = Gtk.Label(), Gtk.TextView() - pname.set_markup('<span size="large" weight="bold">{} [{}]</span>'.format(plabel, unit)) + unit_txt = '[{}]'.format(unit) if unit is not None else '' + pname.set_markup('<span size="large" weight="bold">{} {}</span>'.format(plabel, unit_txt)) pname.set_xalign(0) - pname.set_tooltip_text(box.param_id) + pname.set_tooltip_text(box.param_id.split(':')[-1]) buf = Gtk.TextBuffer() buf.insert_markup(buf.get_start_iter(), @@ -312,8 +355,10 @@ class ParameterMonitor(Gtk.Window): self.monitored_pkts = {self.parameters[k]['pktid']: {'pkttime': 0, 'reftime': time.time(), 'data': None} for k in self.parameters} + # LUT for user defined parameter names by pktid + self.pname_from_pktid = {self.parameters[k]['pktid']: k.split(':')[-1] for k in self.parameters} + self.grid.show_all() - return def update_parameter_view(self, interval=INTERVAL, max_age=MAX_AGE): self.interval = interval @@ -332,25 +377,23 @@ class ParameterMonitor(Gtk.Window): start = time.time() self.update_parameters_worker() dt = time.time() - start - # print(dt) + # print('#', threading.enumerate(), dt) + if dt > self.interval: + self.logger.warning('Monitoring cycle takes longer than requested interval ({:.3f} > {:.3f})!'.format(dt, self.interval)) + # self.disable_evt_cnt() time.sleep(self.interval - min(self.interval, dt)) def update_parameters_worker(self): rows = cfl.get_pool_rows(self.pool_name) - if self.evt_check_enabled: - ctime = time.time() - self.check_evts(rows) - cdt = time.time() - ctime - # disable check_evts if it causes too much delay - if cdt > 0.7 * self.interval: - self.evt_check_tocnt += 1 - if self.evt_check_tocnt > 5: - self.disable_evt_cnt() + try: + pool_id = rows.first().pool_id # keep track of monitored pool + except AttributeError: + self.logger.debug('No rows in pool yet') + return for pktid in self.monitored_pkts: pktinfo = self.get_last_pkt_with_id(rows, pktid) - if pktinfo is None: continue @@ -359,8 +402,18 @@ class ParameterMonitor(Gtk.Window): self.monitored_pkts[pktid]['reftime'] = time.time() self.monitored_pkts[pktid]['pkttime'] = pkttime - tm = cfl.Tmdata(pkt)[0] - self.monitored_pkts[pktid]['data'] = {par[4][1][0]: par[0] for par in tm} + if isinstance(pktid[0], tuple): + pname = self.pname_from_pktid[pktid] + xy, par = cfl.get_param_values(tmlist=[pkt], hk='User defined', param=pname, last=1, tmfilter=False, mk_array=False) + udtype = 'user_defined' + self.monitored_pkts[pktid]['data'] = {'{}:{}'.format(udtype, par[0]): xy[0][1]} + else: + try: + tm = cfl.Tmdata(pkt)[0] + self.monitored_pkts[pktid]['data'] = {self.get_param_id(par): par[0] for par in tm} + except Exception as err: + self.logger.info('{} {}'.format(err, pktid)) + continue checktime = time.time() for pname in self.parameters: @@ -399,13 +452,36 @@ class ParameterMonitor(Gtk.Window): '<span size="large" foreground="{}" weight="bold">{}</span>'.format( self.parameters[par]['alarm'], '--'), -1) else: - buf.insert_markup(buf.get_start_iter(), - '<span size="large" foreground="{}" weight="bold">{:{fstr}}</span>'.format( - self.parameters[par]['alarm'], self.parameters[par]['value'], - fstr=self.parameter_types[self.parameters[par]['format']]), -1) + val = self.parameters[par]['value'] + if isinstance(val, bytes): + txt = '<span size="large" foreground="{}" weight="bold">0x{}</span>'.format( + self.parameters[par]['alarm'], val.hex().upper()) + else: + txt = '<span size="large" foreground="{}" weight="bold">{:{fstr}}</span>'.format( + self.parameters[par]['alarm'], val, fstr=self.parameters[par]['format']) + + buf.insert_markup(buf.get_start_iter(), txt, -1) GLib.idle_add(updt_buf) + if self.evt_check_enabled: + ctime = time.time() + self.check_evts(rows, incremental=True) + cdt = time.time() - ctime + # disable check_evts if it causes too much delay + if cdt > (0.7 * self.interval): + self.evt_check_tocnt += 1 + if self.evt_check_tocnt > 5: + self.disable_evt_cnt() + + if (pool_id != self.pool_id) and (self.pool_id is not None): + self.logger.warning('Monitored pool has changed ({})'.format(pool_id)) + self.evt_pkt_idx_last = 0 + self.events = {'Error LOW': [(5, 2), 0], 'Error MEDIUM': [(5, 3), 0], 'Error HIGH': [(5, 4), 0]} + self.evt_reset_values = {'Error LOW': 0, 'Error MEDIUM': 0, 'Error HIGH': 0} + + self.pool_id = pool_id + # def updt_bg_color(): # alarms = [self.parameters[x]['alarm'] for x in self.parameters.keys()] # if alarms.count('red'): @@ -425,25 +501,59 @@ class ParameterMonitor(Gtk.Window): # GLib.idle_add(updt_bg_color) # return - def get_last_pkt_with_id(self, rows, pktid): + def get_last_pkt_with_id(self, rows, pktid, pidx=0): spid, st, sst, apid, pi1, pi1off, pi1wid = pktid - if pi1off != -1: - rows = rows.filter(DbTelemetry.stc == st, DbTelemetry.sst == sst, DbTelemetry.apid == apid, - func.mid(DbTelemetry.data, pi1off - cfl.TM_HEADER_LEN + 1, pi1wid // 8) == pi1.to_bytes( - pi1wid // 8, 'big')).order_by(DbTelemetry.idx.desc()).first() + if pi1off != -1: # and (pi1off is not None): + # rows = rows.filter(DbTelemetry.stc == st, DbTelemetry.sst == sst, DbTelemetry.apid == apid, + # func.mid(DbTelemetry.data, pi1off - cfl.TM_HEADER_LEN + 1, pi1wid // 8) == pi1.to_bytes( + # pi1wid // 8, 'big'), DbTelemetry.idx>=pidx).order_by(DbTelemetry.idx.desc()).first() + rows = cfl.filter_rows(rows, st=st, sst=sst, apid=apid, sid=pi1, idx_from=pidx).order_by(DbTelemetry.idx.desc()).first() else: - rows = rows.filter(DbTelemetry.stc == st, DbTelemetry.sst == sst, DbTelemetry.apid == apid).order_by(DbTelemetry.idx.desc()).first() - + # rows = rows.filter(DbTelemetry.stc == st, DbTelemetry.sst == sst, DbTelemetry.apid == apid, DbTelemetry.idx>=pidx).order_by(DbTelemetry.idx.desc()).first() + rows = cfl.filter_rows(rows, st=st, sst=sst, apid=apid, idx_from=pidx).order_by(DbTelemetry.idx.desc()).first() if rows is None: return return float(rows.timestamp[:-1]), rows.raw - def pckt_counter(self, rows, st, sst): - npckts = rows.filter(DbTelemetry.stc == st, DbTelemetry.sst == sst).count() + def get_param_id(self, pinfo): + """ + Get param_id from parinfo as returned by Tmdata for look-up in monitored packets data + @param par: + """ + par = pinfo[4][1] + + if par[0] == 'dp_item': + return '{}:{}'.format(par[0], cfl.DP_ITEMS_TO_IDS[par[1]]) + elif par[0] in ['user_defined', 'user_defined_nopos']: + return '{}:{}'.format(par[0], par[1]) + else: + return par[0] + + def get_fstr(self, param_id, name, categ=None): + + if categ == 'S': + return 's' + + udtype = param_id.split(':')[0] + pinfo = cfl._parameter_decoding_info((name, udtype), check_curtx=True) + + ptc, pfc = pinfo[2:4] + + if ptc in [7]: + return '' + elif ptc in [5, 9]: + return '.13G' + elif ptc in [8]: + return 's' + else: + return 'd' + + def pckt_counter(self, rows, st, sst, pidx=0): + npckts = rows.filter(DbTelemetry.stc == st, DbTelemetry.sst == sst, DbTelemetry.idx > pidx).count() return npckts - def check_evts(self, rows): + def check_evts(self, rows, incremental=True): def updt_buf(buf, evt): buf.delete(*buf.get_bounds()) buf.insert_markup(buf.get_start_iter(), @@ -454,18 +564,23 @@ class ParameterMonitor(Gtk.Window): for event in self.evt_cnt.get_children()[:-2]: evt = event.get_children()[0].get_text() - self.events[evt][1] = self.pckt_counter(rows, *self.events[evt][0]) + if incremental: + self.events[evt][1] += self.pckt_counter(rows, *self.events[evt][0], pidx=self.evt_pkt_idx_last) + else: + self.events[evt][1] = self.pckt_counter(rows, *self.events[evt][0]) buf = event.get_children()[1].get_buffer() GLib.idle_add(updt_buf, buf, evt) - def updt_bg_color(): - if self.events['Error HIGH'][1] > self.evt_reset_values['Error HIGH']: - self.override_background_color(Gtk.StateType.NORMAL, self.alarm_colors['red']) - self.present() - elif self.events['Error MEDIUM'][1] > self.evt_reset_values['Error MEDIUM']: - self.override_background_color(Gtk.StateType.NORMAL, self.alarm_colors['orange']) + self.evt_pkt_idx_last = rows.order_by(DbTelemetry.idx.desc()).first().idx + + # def updt_bg_color(): + # if self.events['Error HIGH'][1] > self.evt_reset_values['Error HIGH']: + # self.override_background_color(Gtk.StateType.NORMAL, self.alarm_colors['red']) + # self.present() + # elif self.events['Error MEDIUM'][1] > self.evt_reset_values['Error MEDIUM']: + # self.override_background_color(Gtk.StateType.NORMAL, self.alarm_colors['orange']) # GLib.idle_add(updt_bg_color) @@ -494,9 +609,33 @@ class ParameterMonitor(Gtk.Window): rbutton = self.evt_cnt.get_children()[-2] rbutton.set_label('Count EVTs') - rbutton.set_tooltip_text('Event counting has been disabled because of heavy load, probably because of a too large pool.\nClick to force count update.') + rbutton.set_tooltip_text('Event counting has been disabled because of heavy load, probably because of a too large pool. Click to force count update.') + rbutton.disconnect(self._res_evt_cnt_callback) + self._res_evt_cnt_callback = rbutton.connect('clicked', self.reenable_evt_cnt) self.logger.warning('Counting events takes too long - disabling.') + def reenable_evt_cnt(self, widget): + self.evt_check_enabled = True + self.evt_check_tocnt = 0 + + def updt_buf(cbuf, cevt): + cbuf.delete(*cbuf.get_bounds()) + cbuf.insert_markup(cbuf.get_start_iter(), '<span size="large" foreground="{}" weight="bold">{}</span>'.format( + 'black', self.events[cevt][1]), -1) + + for evt in self.evt_cnt.get_children()[:-2]: + evt.set_sensitive(True) + buf = evt.get_children()[1] + + GLib.idle_add(updt_buf, buf.get_buffer(), evt.get_children()[0].get_text()) + + widget.set_label('Reset') + widget.set_tooltip_text('Reset warning threshold to current # of evt pkts') + widget.disconnect(self._res_evt_cnt_callback) + self._res_evt_cnt_callback = widget.connect('clicked', self.reset_evt_cnt) + + self.logger.info('Event counting re-enabled') + def add_evt_cnt(self, widget=None): self.monitor_setup() @@ -510,9 +649,9 @@ class ParameterMonitor(Gtk.Window): def monitor_setup(self, parameter_set=None, nslots=3): if parameter_set is not None: - parameters = json.loads(self.cfg['ccs-monitor_parameter_sets'][parameter_set]) - self.setup_grid(parameters) - + # parameters = json.loads(self.cfg['ccs-monitor_parameter_sets'][parameter_set]) + # self.setup_grid(parameters) + self.set_parameter_view(parameter_set) return dialog = MonitorSetupDialog(logger=self.logger, nslots=nslots, parameter_set=parameter_set, parent=self) @@ -838,6 +977,7 @@ class MonitorSetupDialog(Gtk.Dialog): hks = dbres.fetchall() topleveliters = {} + # packets in MIB for hk in hks: if not hk[2] in topleveliters: @@ -854,13 +994,29 @@ class MonitorSetupDialog(Gtk.Dialog): params = dbres.fetchall() - [parameter_model.append(it, [par[0], str(par[1:])]) for par in params] + for par in params: + parameter_model.append(it, [par[0], str(par[1:])]) dbcon.close() + # UDEF packets + udpkts = self.monitor.cfg['ccs-user_defined_packets'] + self.useriter = parameter_model.append(None, ['UDEF packets', None]) + for userpacket in udpkts: + st, sst, apid, sid = map(cfl.str_to_int, userpacket.split('-')) + sid_off, sid_bitlen = cfl.get_sid(st, sst, apid) + pktdef = json.loads(udpkts[userpacket]) + pktiter = parameter_model.append(self.useriter, [pktdef[0], None]) + for userpar in pktdef[1]: + name = 'UDEF:{}:{}'.format(userpar[1], userpar[0]) + parameter_model.append(pktiter, [userpar[1], str([name, None, st, sst, apid, sid, sid_off, sid_bitlen])]) + + # user-defined stand-alone ("plot") parameters self.useriter = parameter_model.append(None, ['User defined', None]) for userpar in self.monitor.cfg['ccs-plot_parameters']: - parameter_model.append(self.useriter, [userpar, None]) + name = 'user_defined:{}'.format(userpar) + parameter_model.append(self.useriter, [userpar, str([name, + self.monitor.cfg['ccs-plot_parameters'][userpar]])]) return parameter_model @@ -904,22 +1060,13 @@ class MonitorSetupDialog(Gtk.Dialog): for slots in param_set: i += 1 pnames = {eval(par)[0]: par for par in slots} - if len(pnames) > 1: - dbres = dbcon.execute('SELECT pcf.pcf_descr, pcf.pcf_name FROM pcf where pcf.pcf_name in {}'.format(tuple(pnames))) - params = dbres.fetchall() - elif len(pnames) == 1: - dbres = dbcon.execute('SELECT pcf.pcf_descr, pcf.pcf_name FROM pcf where pcf.pcf_name="{}"'.format(pnames[0])) - params = dbres.fetchall() - else: - continue - - for par in params: - self.slots[i][3].append([par[0], pnames[par[1]]]) + for par in pnames: + self.slots[i][3].append([par.split(':')[1], pnames[par]]) dbcon.close() else: - self.logger.info('Given Set name could not be found in config File') + self.logger.error('Parameter set {} not found'.format(entry)) if __name__ == "__main__": @@ -953,6 +1100,10 @@ if __name__ == "__main__": elif len(sys.argv) == 1: is_pool = win.check_for_pools() + else: + win.quit_func() + sys.exit() + if is_pool == 0: win.quit_func() sys.exit() diff --git a/Ccs/plotter.py b/Ccs/plotter.py index a4c833b481409f70ddc69a400c88a1b1ce957694..2413dc654bab42576786bb4584c94525c6f4f9d5 100644 --- a/Ccs/plotter.py +++ b/Ccs/plotter.py @@ -69,6 +69,7 @@ class PlotViewer(Gtk.Window): self.parameter_limits = set() self.data_dict = {} + self.data_dict_info = {} # row idx of last data point in data_dict self.max_datapoints = 0 self.data_min_idx = None self.data_max_idx = None @@ -253,7 +254,7 @@ class PlotViewer(Gtk.Window): def _create_navbar(self): # navbar = NavigationToolbarX(self.canvas, self) - navbar = NavigationToolbar(self.canvas, self) + navbar = NavigationToolbar(self.canvas, window=self) limits = Gtk.HBox() self.xmin = Gtk.Entry() @@ -438,8 +439,10 @@ class PlotViewer(Gtk.Window): # Or check between which Pools should be selected all_pools = None if cfl.is_open('poolmanager'): - pmgr = cfl.dbus_connection('poolmanager', cfl.communication['poolmanager']) - all_pools = cfl.Dictionaries(pmgr, 'loaded_pools') + # pmgr = cfl.dbus_connection('poolmanager', cfl.communication['poolmanager']) + pmgr = cfl.get_module_handle('poolmanager') + all_pools = pmgr.Dictionaries('loaded_pools') + # all_pools = cfl.Dictionaries(pmgr, 'loaded_pools') #if not all_pools: # found_pools = None #elif len(active_pool) == 1: @@ -451,7 +454,9 @@ class PlotViewer(Gtk.Window): elif cfl.is_open('poolviewer'): pv = cfl.dbus_connection('poolviewer', cfl.communication['poolviewer']) - all_pools = cfl.Variables(pv, 'active_pool_info') + pv = cfl.get_module_handle('poolviewer') + all_pools = pv.Variables('active_pool_info') + # all_pools = cfl.Variables(pv, 'active_pool_info') #if all_pools: #loaded_pool = ActivePoolInfo(active_pool[0],active_pool[1],active_pool[2],active_pool[3]) # found_pools = all_pools[2] @@ -669,6 +674,10 @@ class PlotViewer(Gtk.Window): else: selection = self.treeview.get_selection() model, treepath = selection.get_selected() + + if treepath is None: + return + parameter = model[treepath][0] if model[treepath].parent is None: @@ -677,15 +686,14 @@ class PlotViewer(Gtk.Window): hk = model[treepath].parent[0] 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,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) + 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).fetchall() if not dbres: @@ -694,18 +702,8 @@ class PlotViewer(Gtk.Window): 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|') + label = hk.replace('UDEF|', '') tag = [k for k in self.user_tm_decoders if self.user_tm_decoders[k][0] == label][0] pktinfo = tag.split('-') st = int(pktinfo[0]) @@ -713,32 +711,27 @@ class PlotViewer(Gtk.Window): 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']) + st, sst, apid = userpar['ST'], userpar['SST'], userpar['APID'] + if 'SID' in userpar and 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 + sid = userpar['SID'] + else: + sid = None + + if self.sid_position_query(st, sst, apid, sid) is None: + if sid: + self.logger.error('{}: SID not applicable.'.format(parameter)) + return + + sid = None - rows = rows.filter(func.mid(DbTelemetry.data, sid_offset - TM_HEADER_LEN + 1, sid_size) == - userpar['SID'].to_bytes(sid_size, 'big')) + rows = cfl.filter_rows(rows, st=st, sst=sst, apid=apid, sid=sid) if not self.filter_tl2.get_active(): - rows = rows.filter(func.left(DbTelemetry.timestamp, func.length(DbTelemetry.timestamp) - 1) > 2.) + rows = cfl.filter_rows(rows, time_from=2.) + # rows = rows.filter(func.left(DbTelemetry.timestamp, func.length(DbTelemetry.timestamp) - 1) > 2.) try: xy, (descr, unit) = cfl.get_param_values([row.raw for row in rows.yield_per(1000)], hk, parameter, @@ -746,15 +739,25 @@ class PlotViewer(Gtk.Window): if len(xy) == 0: return - except (ValueError, TypeError): + except (ValueError, TypeError) as err: + self.logger.debug(err) self.logger.error("Can't plot {}".format(parameter)) return + # store packet info for update worker self.data_dict[hk + ':' + descr] = xy + self.data_dict_info[hk + ':' + descr] = {} + self.data_dict_info[hk + ':' + descr]['idx_last'] = rows.order_by(DbTelemetry.idx.desc()).first().idx + self.data_dict_info[hk + ':' + descr]['st'] = st + self.data_dict_info[hk + ':' + descr]['sst'] = sst + self.data_dict_info[hk + ':' + descr]['apid'] = apid + self.data_dict_info[hk + ':' + descr]['sid'] = sid + # npoints = self.count_datapoints(self.subplot.get_xlim(), self.subplot.get_ylim()) # 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') + try: if self.plot_diff.get_active(): x, y = xy @@ -856,19 +859,21 @@ class PlotViewer(Gtk.Window): # self.max_datapoints = n def reduce_datapoints(self, xlim, ylim, fulldata=True): + ax = self.canvas.figure.get_axes()[0] - n_datapoints = self.count_datapoints(xlim, ylim) - if n_datapoints > self.max_datapoints > 0: - red_fac = n_datapoints // self.max_datapoints + 1 - for line in ax.lines: - if not line.get_label().startswith('_lim_'): - x, y = self.data_dict[line.get_gid() + ':' + line.get_label()] - if self.plot_diff.get_active(): - x = x[1:] - y = np.diff(y) - line.set_xdata(x[::red_fac]) - line.set_ydata(y[::red_fac]) + if self.max_datapoints > 0: + n_datapoints = self.count_datapoints(xlim, ylim) + if n_datapoints > self.max_datapoints: + red_fac = n_datapoints // self.max_datapoints + 1 + for line in ax.lines: + if not line.get_label().startswith('_lim_'): + x, y = self.data_dict[line.get_gid() + ':' + line.get_label()] + if self.plot_diff.get_active(): + x = x[1:] + y = np.diff(y) + line.set_xdata(x[::red_fac]) + line.set_ydata(y[::red_fac]) elif fulldata: for line in ax.lines: if not line.get_label().startswith('_lim_'): @@ -890,6 +895,7 @@ class PlotViewer(Gtk.Window): def clear_parameter(self, widget): self.data_dict.clear() + self.data_dict_info.clear() self.parameter_limits.clear() self.subplot.clear() self.subplot.grid() @@ -902,7 +908,8 @@ class PlotViewer(Gtk.Window): def update_plot_worker(self, plot=None, parameter=None): # pool_name = self.pool_box.get_active_text() - rows = cfl.get_pool_rows(self.loaded_pool.filename).filter(DbTelemetry.stc == 3, DbTelemetry.sst == 25) + rows = cfl.get_pool_rows(self.loaded_pool.filename) + rows = self.set_plot_range(rows) # xmin, xmax = self.subplot.get_xlim() lines = self.subplot.lines @@ -912,28 +919,22 @@ class PlotViewer(Gtk.Window): hk = line.get_gid() xold, yold = self.data_dict[hk + ':' + parameter] - time_last = round(float(xold[-1]), 6) # np.float64 not properly understood in sql comparison below - new_rows = rows.filter( - func.left(DbTelemetry.timestamp, func.length(DbTelemetry.timestamp) - 1) > time_last) + # time_last = round(float(xold[-1]), 6) # np.float64 not properly understood in sql comparison below + # new_rows = rows.filter(func.left(DbTelemetry.timestamp, func.length(DbTelemetry.timestamp) - 1) > time_last) + pinfo = self.data_dict_info[hk + ':' + parameter] + new_rows = cfl.filter_rows(rows, st=pinfo['st'], sst=pinfo['sst'], apid=pinfo['apid'], + sid=pinfo['sid'], idx_from=pinfo['idx_last'] + 1) + try: - xnew, ynew = cfl.get_param_values([row.raw for row in new_rows], hk, parameter, - numerical=True)[0] + # xnew, ynew = cfl.get_param_values([row.raw for row in new_rows], hk, parameter, numerical=True)[0] + xnew, ynew = cfl.get_param_values([row.raw for row in new_rows], hk, parameter, numerical=True, tmfilter=False)[0] + idx_new = new_rows.order_by(DbTelemetry.idx.desc()).first().idx except ValueError: continue xy = np.stack([np.append(xold, xnew), np.append(yold, ynew)], -1).T self.data_dict[hk + ':' + parameter] = xy - - # line.set_data(xy) - - # npoints = xy.shape[1] - # if npoints > self.max_datapoints > 0: - # line.set_data(xy.T[::npoints//self.max_datapoints].T) - # else: - # line.set_data(xy) - # line.set_xdata(np.append(xold, xnew)) - # line.set_ydata(np.append(yold, ynew)) - # self.subplot.draw_artist(line) + self.data_dict_info[hk + ':' + parameter]['idx_last'] = idx_new self.reduce_datapoints(self.subplot.get_xlim(), self.subplot.get_ylim()) @@ -1119,7 +1120,8 @@ class PlotViewer(Gtk.Window): #if self.loaded_pool: # return if cfl.is_open('poolviewer'): - pv = cfl.dbus_connection('poolviewer', cfl.communication['poolviewer']) + # pv = cfl.dbus_connection('poolviewer', cfl.communication['poolviewer']) + pv = cfl.get_module_handle('poolviewer') active_pool = cfl.Variables(pv, 'active_pool_info') #active_pool = pv.Variables('active_pool_info') if active_pool and active_pool[0]: @@ -1131,7 +1133,8 @@ class PlotViewer(Gtk.Window): # self.loaded_pool = None elif cfl.is_open('poolmanager'): - pmgr = cfl.dbus_connection('poolmanager', cfl.communication['poolmanager']) + # pmgr = cfl.dbus_connection('poolmanager', cfl.communication['poolmanager']) + pmgr = cfl.get_module_handle('poolmanager') active_pool = cfl.Dictionaries(pmgr, 'loaded_pools') #active_pool = pmgr.Dictionaries('loaded_pools') #if not active_pool: @@ -1162,7 +1165,6 @@ class PlotViewer(Gtk.Window): #if self.loaded_pool: # self.select_pool(pool=self.loaded_pool) - def quit_func(self, *args): # Try to tell terminal in the editor that the variable is not longer availabe for service in dbus.SessionBus().list_names(): @@ -1407,7 +1409,8 @@ class SelectPoolDialog(Gtk.Dialog): # Or check between which Pools should be selected if cfl.is_open('poolmanager'): - pmgr = cfl.dbus_connection('poolmanager', cfl.communication['poolmanager']) + # pmgr = cfl.dbus_connection('poolmanager', cfl.communication['poolmanager']) + pmgr = cfl.get_module_handle('poolmanager') self.all_pools = pmgr.Dictionaries('loaded_pools') if not self.all_pools: self.loaded_pool = None @@ -1419,7 +1422,8 @@ class SelectPoolDialog(Gtk.Dialog): self.loaded_pool = list(self.all_pools.keys()) elif cfl.is_open('poolviewer'): - pv = cfl.dbus_connection('poolviewer', cfl.communication['poolmanager']) + # pv = cfl.dbus_connection('poolviewer', cfl.communication['poolmanager']) + pv = cfl.get_module_handle('poolviewer') self.all_pools = pv.Variables('active_pool_info') if self.all_pools: #loaded_pool = ActivePoolInfo(active_pool[0],active_pool[1],active_pool[2],active_pool[3]) diff --git a/Ccs/poolview_sql.py b/Ccs/poolview_sql.py index 79a77a877d7f7a7376a556d12db9e575346acdf3..76dd8479074c54560eb1327689dc000a279edeb3 100644 --- a/Ccs/poolview_sql.py +++ b/Ccs/poolview_sql.py @@ -2430,8 +2430,6 @@ class TMPoolView(Gtk.Window): self.set_tm_data_view() - return - def create_decoder_model(self): model = Gtk.ListStore(str) @@ -2461,7 +2459,8 @@ class TMPoolView(Gtk.Window): 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()) - except: + except Exception as err: + self.logger.info(err) return if label in (None, ''): @@ -2608,7 +2607,7 @@ class TMPoolView(Gtk.Window): datamodel.clear() try: if self.UDEF: - data = cfl.Tmformatted(tm, textmode=False, UDEF=True) + data = cfl.Tmformatted(tm, textmode=False, udef=True) buf = Gtk.TextBuffer(text=cfl.Tm_header_formatted(tm) + '\n{}\n'.format(data[1])) self._feed_tm_data_view_model(datamodel, data[0]) else: @@ -3096,10 +3095,6 @@ class TMPoolView(Gtk.Window): return [row[1] for row in res] 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!') - # return cfl.start_plotter(pool_name=self.active_pool_info.pool_name) diff --git a/Ccs/pus_datapool.py b/Ccs/pus_datapool.py index 1dd350c373104baee6f8e1c2de97e3d3c638805a..3574e8a6e6553175e76af14db34a7b15452ae1a2 100644 --- a/Ccs/pus_datapool.py +++ b/Ccs/pus_datapool.py @@ -822,7 +822,7 @@ class DatapoolManager: else: self.decode_tmdump_and_process_packets_internal(buf, process_tm, checkcrc=False) except socket.timeout as e: - self.logger.info('Socket timeout ({}:{})'.format(host, port)) + self.logger.debug('Socket timeout ({}:{})'.format(host, port)) new_session.commit() continue except socket.error as e: @@ -1573,20 +1573,20 @@ class DatapoolManager: def socket_send_packed_data(self, packdata, poolname): cncsocket = self.tc_connections[poolname]['socket'] cncsocket.send(packdata) - received = None + received = b'' try: received = cncsocket.recv(MAX_PKT_LEN) # self.logger.info.write(logtf(self.tnow()) + ' ' + recv[6:].decode() + ' [CnC]\n') - self.logger.info(received.decode(errors='replace') + ' [CnC]') + self.logger.info(received.decode('utf-8', errors='replace') + ' [CnC]') # logfile.flush() # s.close() # self.counters[1804] += 1 except socket.timeout: - self.logger.error('Got a timeout') - self.logger.exception(socket.timeout) + # self.logger.error('Got a timeout') + self.logger.error(socket.timeout) # Dbus does not like original data type - if received is not None: + if received: received = dbus.ByteArray(received) return received @@ -1761,7 +1761,7 @@ class DatapoolManager: header.bits.PKT_TYPE == 0 and header.bits.WRITE == 1): pktsize = hsize else: - pktsize = hsize + header.bits.DATA_LEN# + RMAP_PEC_LEN # TODO: data CRC from FEEsim? + pktsize = hsize + header.bits.DATA_LEN + RMAP_PEC_LEN # TODO: data CRC from FEEsim? while len(buf) < pktsize: d = sockfd.recv(pktsize - len(buf))