From a88cf40865e229ef0f64fc9acaee83746587e009 Mon Sep 17 00:00:00 2001
From: Marko Mecina <marko.mecina@univie.ac.at>
Date: Wed, 9 Mar 2022 16:47:33 +0100
Subject: [PATCH] fix "clear_pool" function for poolviewer

+ minor code cleanups
---
 Ccs/ccs_function_lib.py |   2 +-
 Ccs/poolview_sql.py     | 162 ++++++++++++++++++----------------------
 Ccs/pus_datapool.py     |  86 ++++++++++++---------
 3 files changed, 125 insertions(+), 125 deletions(-)

diff --git a/Ccs/ccs_function_lib.py b/Ccs/ccs_function_lib.py
index dc787ff..4f00ecc 100644
--- a/Ccs/ccs_function_lib.py
+++ b/Ccs/ccs_function_lib.py
@@ -1503,7 +1503,7 @@ def get_pool_rows(pool_name, dbcon=None):
     return rows
 
 #  get values of parameter from HK packets
-def get_param_values(tmlist=None, hk=None, param=None, last=0, numerical=False, dbcon=None):
+def get_param_values(tmlist=None, hk=None, param=None, last=0, numerical=False):
     # with self.poolmgr.lock:
     dbcon = scoped_session_idb
     if hk is None:
diff --git a/Ccs/poolview_sql.py b/Ccs/poolview_sql.py
index bf6d80d..d2988fa 100644
--- a/Ccs/poolview_sql.py
+++ b/Ccs/poolview_sql.py
@@ -140,6 +140,7 @@ class TMPoolView(Gtk.Window):
 
         #if not pool_name:
         #    self.active_pool_info = ActivePoolInfo(None,None,None,None)
+        self.refresh_treeview_active = False
         self.cnt = 0
         self.active_pool_info = ActivePoolInfo(None, None, None, None)
         self.set_border_width(2)
@@ -589,7 +590,7 @@ class TMPoolView(Gtk.Window):
 
         self.treeview = Gtk.TreeView()
         self.treeview.set_model(self.pool_liststore)
-        self.treeview.set_rubber_banding(True)
+        self.treeview.set_rubber_banding(False)
         self.treeview.set_activate_on_single_click(True)
         # self.treeview.set_fixed_height_mode(True)
 
@@ -682,9 +683,9 @@ class TMPoolView(Gtk.Window):
     def set_number_of_treeview_rows(self, widget=None, allocation=None):
         # alloc = widget.get_allocation()
         height = self.treeview.get_allocated_height()
-        cell = self.treeview.get_columns()[0].cell_get_size()[-1] + 2
+        cell = 25  #self.treeview.get_columns()[0].cell_get_size()[-1] + 2
         nlines = height // cell
-        self.adj.set_page_size(nlines-4)
+        self.adj.set_page_size(nlines - 1)
         # self._scroll_treeview()
         self.reselect_rows()
 
@@ -1357,7 +1358,6 @@ class TMPoolView(Gtk.Window):
             self.shown_lock.release()
 
 
-
         '''
         running = True
         self.shown_lock.acquire()
@@ -1502,7 +1502,7 @@ class TMPoolView(Gtk.Window):
         # print(event.direction.value_name, event.delta_x, event.delta_y)
         self.only_scroll = True
         if event.direction.value_name == 'GDK_SCROLL_SMOOTH':
-            scroll_lines = 3 * event.delta_y
+            scroll_lines = 3 * max(-1, event.delta_y)
             if scroll_lines < 0:
                 self.autoscroll = 0
             elif scroll_lines > 3:
@@ -1546,28 +1546,32 @@ class TMPoolView(Gtk.Window):
                     if scroll_lines == -int(self.adj.get_page_size()):
                         self.offset -= int(self.adj.get_page_size())
                     else:
-                        self.offset = self.shown_all_rows[int(position + scroll_lines)][0] if (position + scroll_lines) > 0 else 0
+                        self.offset = self.shown_all_rows[int(position + scroll_lines)][0] if (position + scroll_lines) >= 0 else 0
                 else:
                     if len(self.shown_all_rows) < (self.shown_limit):
-                        self.offset = self.shown_all_rows[-self.adj.get_page_size()][0]
+                        self.offset = self.shown_all_rows[-int(self.adj.get_page_size())][0]
                     else:
-                        self.offset = self.shown_all_rows[int(position + scroll_lines)][0] if (position + scroll_lines) > 0 else 0
-            except:
-                upper_limit = self.adj.get_upper() - self.adj.get_page_size()
+                        self.offset = self.shown_all_rows[int(position + scroll_lines)][0] if (position + scroll_lines) >= 0 else 0
+            except IndexError:
+                upper_limit = max(0, self.adj.get_upper() - self.adj.get_page_size())
                 self.offset = int(min(upper_limit, self.adj.get_value() + scroll_lines))
 
+        if self.offset < 0:
+            return
+
         self.limit = int(self.adj.get_page_size())
-        #self.feed_lines_to_view(
-        #    self.fetch_lines_from_db(self.offset, self.limit, sort=sort, order=order, rows=rows, force_import=force_db_import))
         self.fetch_lines_from_db(self.offset, self.limit, sort=sort, order=order, rows=rows, scrolled=True, force_import=force_db_import)
         self.adj.set_value(self.offset)
 
     def key_pressed(self, widget=None, event=None):
-        def unselect_rows():
+        def unselect_rows(clear=False):
             # selection = widget.get_selection()
             # self.selection.disconnect_by_func(self.tree_selection_changed)
-            model, paths = self.selection.get_selected_rows()
-            self.currently_selected = {model[path][0] for path in paths}
+            if clear:
+                self.currently_selected = set()
+            else:
+                model, paths = self.selection.get_selected_rows()
+                self.currently_selected = {model[path][0] for path in paths}
             self.reselect_rows()
             # self.selection.connect('changed', self.tree_selection_changed)
 
@@ -1610,17 +1614,19 @@ class TMPoolView(Gtk.Window):
             self.autoscroll = True
             self.autoselect = True
             self.scroll_to_bottom()
-            unselect_rows()
+            unselect_rows(clear=True)
         elif event.keyval == Gdk.KEY_Page_Up:
             # cursor_path = self.treeview.get_cursor()[0]
             self._scroll_treeview(-self.limit)
-            self.treeview.set_cursor(cursor_path)
+            if cursor_path is not None:
+                self.treeview.set_cursor(cursor_path)
             self.autoscroll = False
             unselect_rows()
         elif event.keyval == Gdk.KEY_Page_Down:
             # cursor_path = self.treeview.get_cursor()[0]
             self._scroll_treeview(self.limit)
-            self.treeview.set_cursor(cursor_path)
+            if cursor_path is not None:
+                self.treeview.set_cursor(cursor_path)
             self.autoscroll = False
             unselect_rows()
             # else:
@@ -1669,9 +1675,9 @@ class TMPoolView(Gtk.Window):
                 try:
                     self.selection.select_path(model.get_path(model.get_iter(row[0] - self.offset - 1)))
                 except ValueError:
-                    pass
+                    print('valerr')
                 except TypeError:
-                    pass
+                    print('typerr')
 
     def unselect_bottom(self, widget=None):
         if widget.count_selected_rows() > 1:
@@ -1916,41 +1922,41 @@ class TMPoolView(Gtk.Window):
         #self._on_scrollbar_changed()
         pass
 
-    def resize_scrollbar(self):
-
-        if self.first_run or self.resize_thread.is_alive():
-            self.first_run = False
-            self.resize_thread = threading.Thread(target=self.small_refresh_function)
-            return
-
-        self.resize_thread = threading.Thread(target=self.scrollbar_size_worker)
-        self.resize_thread.setDaemon(True)
-        self.resize_thread.start()
-
-    def scrollbar_size_worker(self):
-        #print(1)
-        new_session = self.session_factory_storage
-        rows = new_session.query(
-            Telemetry[self.decoding_type]
-        ).join(
-            DbTelemetryPool,
-            Telemetry[self.decoding_type].pool_id == DbTelemetryPool.iid
-        ).filter(
-            DbTelemetryPool.pool_name == self.active_pool_info.filename
-        )
-        #new_session.close()
-        cnt = rows.count()
-        #print(cnt)
-        rows = self._filter_rows(rows)
-        cnt = rows.count()
-        #count_q = que.statement.with_only_columns([func.count()]).order_by(None)
-        #cnt = new_session.execute(count_q).scalar()
-        #cnt = new_session.query(que).count()
-        #print(2)
-        #print(cnt)
-        GLib.idle_add(self.adj.set_upper, cnt,)
-        #print(3)
-        new_session.close()
+    # def resize_scrollbar(self):
+    #
+    #     if self.first_run or self.resize_thread.is_alive():
+    #         self.first_run = False
+    #         self.resize_thread = threading.Thread(target=self.small_refresh_function)
+    #         return
+    #
+    #     self.resize_thread = threading.Thread(target=self.scrollbar_size_worker)
+    #     self.resize_thread.setDaemon(True)
+    #     self.resize_thread.start()
+    #
+    # def scrollbar_size_worker(self):
+    #     #print(1)
+    #     new_session = self.session_factory_storage
+    #     rows = new_session.query(
+    #         Telemetry[self.decoding_type]
+    #     ).join(
+    #         DbTelemetryPool,
+    #         Telemetry[self.decoding_type].pool_id == DbTelemetryPool.iid
+    #     ).filter(
+    #         DbTelemetryPool.pool_name == self.active_pool_info.filename
+    #     )
+    #     #new_session.close()
+    #     cnt = rows.count()
+    #     #print(cnt)
+    #     rows = self._filter_rows(rows)
+    #     cnt = rows.count()
+    #     #count_q = que.statement.with_only_columns([func.count()]).order_by(None)
+    #     #cnt = new_session.execute(count_q).scalar()
+    #     #cnt = new_session.query(que).count()
+    #     #print(2)
+    #     #print(cnt)
+    #     GLib.idle_add(self.adj.set_upper, cnt,)
+    #     #print(3)
+    #     new_session.close()
 
     def _toggle_rule(self, widget=None, data=None):
         self.filter_rules_active = widget.get_active()
@@ -2166,26 +2172,11 @@ class TMPoolView(Gtk.Window):
         if pool_name is None:
             return
 
-        #self.pool._clear_pool(pool_name)
-        #self.active_pool_info = self.pool.loaded_pools[pool_name]
         poolmgr.Functions('_clear_pool', pool_name)
         # self.active_pool_info = poolmgr.Dictionaries('loaded_pools', pool_name)
         self.Active_Pool_Info_append(poolmgr.Dictionaries('loaded_pools', pool_name))
+        self.offset = 0
 
-        # new_session = self.dbcon
-        # new_session.execute(
-        #     'UPDATE tm_pool SET pool_name="---TO-BE-DELETED---" WHERE tm_pool.pool_name="{}"'.format(
-        #         self.get_active_pool_name()))
-        # new_session.commit()
-        #
-        # # new_session.execute(
-        # #     'delete tm from tm inner join tm_pool on tm.pool_id=tm_pool.iid where tm_pool.pool_name="{}"'.format(
-        # #         self.active_pool_info.filename))
-        # # new_session.execute('delete tm_pool from tm_pool where tm_pool.pool_name="{}"'.format(
-        # #     self.active_pool_info.filename))
-        # # # new_session.flush()
-        # # new_session.commit()
-        # new_session.close()
         self.adj.set_upper(self.count_current_pool_rows())
         self._on_scrollbar_changed()
         widget.set_sensitive(True)
@@ -2587,6 +2578,9 @@ class TMPoolView(Gtk.Window):
             datamodel.clear()
             return
 
+        if selection is None:
+            return
+
         model, treepath = selection.get_selected_rows()
 
         if len(treepath) == 0:
@@ -3233,9 +3227,10 @@ class TMPoolView(Gtk.Window):
         return
 
     def refresh_treeview(self, pool_name):
-        # thread = threading.Thread(target=self.refresh_treeview_worker, args=[pool_name])
-        # thread.daemon = True
-        # thread.start()
+        if self.refresh_treeview_active:
+            return
+
+        self.refresh_treeview_active = True
         self.n_pool_rows = 0
         GLib.timeout_add(self.pool_refresh_rate * 1000, self.refresh_treeview_worker2,
                          pool_name)  # , priority=GLib.PRIORITY_HIGH)
@@ -3257,36 +3252,23 @@ class TMPoolView(Gtk.Window):
 
     def refresh_treeview_worker2(self, pool_name):
         if pool_name != self.active_pool_info.pool_name:
+            self.refresh_treeview_active = False
             return False
 
-        #if not self.active_pool_info.live:
-        #    return False
-        #if cfl.is_open('poolmanager', cfl.communication['poolmanager']):
-        #    poolmgr = cfl.dbus_connection('poolmanager', cfl.communication['poolmanager'])
-        #else:
-        #    return False
-
-        # Get value of dict connections, with key self.active... and key recording, True to get
-        #pool_connection_recording = poolmgr.Dictionaries('connections', self.active_pool_info.pool_name, 'recording',
-        #                                                 True)
-        #pool_connection = poolmgr.Dictionaries('connections', self.active_pool_info.pool_name)
         if self.active_pool_info.live:
-        #if self.pool.connections[self.active_pool_info.pool_name]['recording']:
             rows = self.get_current_pool_rows()
             if rows.first() is None:
                 cnt = 0
             else:
                 cnt = rows.order_by(Telemetry[self.decoding_type].idx.desc()).first().idx
             if cnt != self.n_pool_rows:
-                # self.selection.disconnect_by_func(self.tree_selection_changed)
                 self.scroll_to_bottom(n_pool_rows=cnt, rows=rows)
-                # self.selection.connect('changed', self.tree_selection_changed)
                 self.n_pool_rows = cnt
                 return True
             else:
                 return True
         else:
-            #self.stop_recording()
+            self.refresh_treeview_active = False
             return False
 
     def dbtest(self, pool_name, sleep=0.1):
@@ -3353,7 +3335,7 @@ class TMPoolView(Gtk.Window):
                 trashbytes = 0
         '''
         if not self.active_pool_info.live:
-            return
+            return False
 
         if not instance:
             instance = 1
diff --git a/Ccs/pus_datapool.py b/Ccs/pus_datapool.py
index 0346e7c..9790fe4 100644
--- a/Ccs/pus_datapool.py
+++ b/Ccs/pus_datapool.py
@@ -1,24 +1,21 @@
-import datetime
+# import datetime
 import io
-import signal
-import socket
-import struct
+# import signal
+# import socket
+# import struct
 import sys
 import time
 import os
 import datetime
 import socket
-import select
+# import select
 import crcmod
 import struct
-# from bitstring import BitArray, BitStream, Bits, ConstBitStream, ReadError
-import traceback
+# import traceback
 import DBus_Basic
 import dbus
 import dbus.service
 from dbus.mainloop.glib import DBusGMainLoop
-#cfl.Tcsend_DB('SASW ModHkPeriodCmd', 1, 8, pool_name='new_tmtc_pool')
-import configparser
 import confignator
 import gi
 
@@ -321,14 +318,14 @@ class DatapoolManager:
         finally:
             new_session.close()
 
-    def _clear_pool(self, pool_name):  # TODO: not working
+    def _clear_pool(self, pool_name):
+
         if pool_name not in self.connections:
             self.logger.warning('Cannot clear static pool "{}".'.format(pool_name))
             return
+
         new_session = self.session_factory_storage
-        # get protocol type
-        pkttype = self.loaded_pools[pool_name].packet_type
-        if self.connections[pool_name]['socket'].fileno() < 0:
+        if self.connections[pool_name]['socket'].fileno() < 0:  # if true, socket is closed, just "delete" pool
             n_del_pools, = new_session.execute(
                 'SELECT COUNT(*) FROM tm_pool WHERE pool_name LIKE "---TO-BE-DELETED%"').fetchall()[0]
             new_session.execute(
@@ -338,12 +335,25 @@ class DatapoolManager:
             new_session.close()
             self.logger.info('Content of pool "{}" deleted!'.format(pool_name))
             return
+
         self.connections[pool_name]['paused'] = True
         while self.connections[pool_name]['recv-thread'].is_alive():
             time.sleep(0.1)
         sockfd = self.connections[pool_name]['socket']
-        self.tm_recv_start(sockfd, pool_name, try_delete=False)
+        protocol = self.connections[pool_name]['protocol']
+
+        if protocol == 'SPW':
+            self.spw_recv_start(sockfd, pool_name, try_delete=False, force_clean=True)
+        elif protocol in ['PUS', 'PLMSIM']:
+            self.tm_recv_start(sockfd, pool_name, protocol=protocol, try_delete=False, force_clean=True)
+        else:
+            self.logger.warning('"{}" is not a supported protocol, aborting.'.format(protocol))
+            return
+
+        # self.tm_recv_start(sockfd, pool_name, try_delete=False)
+
         self.logger.info('Content of pool "{}" deleted!'.format(pool_name))
+
         while True:
             dbrow = new_session.query(DbTelemetryPool).filter(DbTelemetryPool.pool_name == pool_name).first()
             if dbrow is None:
@@ -354,6 +364,7 @@ class DatapoolManager:
                 timestamp = dbrow.modification_time
                 new_session.close()
                 break
+
         self.loaded_pools[pool_name] = ActivePoolInfo(pool_name, timestamp, pool_name, True)
         self.logger.info('Resuming recording from {}:{}'.format(*sockfd.getpeername()))
 
@@ -391,7 +402,7 @@ class DatapoolManager:
             try:
                 sockfd.connect((host, port))
             except ConnectionRefusedError:
-                self.logger.error("Connection to {}:{} refused".format(host, port))
+                self.logger.warning("Connection to {}:{} refused".format(host, port))
                 return
         self.connections[pool_name] = {'socket': sockfd, 'recording': True, 'protocol': protocol}
 
@@ -568,7 +579,7 @@ class DatapoolManager:
         if self.own_gui:
             self.own_gui.disconnect_incoming_via_code(param=[pool_name, None, None])  # Updates the gui
 
-        #Tell the Poolviewer to stop updating
+        # Tell the Poolviewer to stop updating
         if cfl.is_open('poolviewer', cfl.communication['poolviewer']):
             pv = cfl.dbus_connection('poolviewer', cfl.communication['poolviewer'])
             cfl.Functions(pv, 'stop_recording_info', str(pool_name))
@@ -588,7 +599,7 @@ class DatapoolManager:
                 self.tc_connections[pool_name]['socket'].close()
                 del self.tc_connections[pool_name]
 
-        #Tell the Poolviewer to stop updating
+        # Tell the Poolviewer to stop updating
         if cfl.is_open('poolviewer', cfl.communication['poolviewer']):
             pv = cfl.dbus_connection('poolviewer', cfl.communication['poolviewer'])
             cfl.Functions(pv, 'stop_recording_info', str(pool_name))
@@ -599,9 +610,14 @@ class DatapoolManager:
         return datetime.datetime.utcnow().strftime("%Y-%m-%d %T UTC: ")
 
     def tm_recv_start(self, sockfd, pool_name, protocol='PUS', drop_rx=False, drop_tx=False,
-                      delete_abandoned=False, try_delete=True, pckt_filter=None):
+                      delete_abandoned=False, try_delete=True, pckt_filter=None, force_clean=False):
 
-        self.tm_receiver_del_old_pool(pool_name, delete_abandoned=delete_abandoned, try_delete=try_delete)
+        if pool_name in self.loaded_pools and self.loaded_pools[pool_name].live and not force_clean and pool_name in self.state:
+            self.logger.info('Pool "{}" is live. Skipping deletion of previous data.')
+            start_new = False
+        else:
+            self.tm_receiver_del_old_pool(pool_name, delete_abandoned=delete_abandoned, try_delete=try_delete)
+            start_new = True
 
         self.connections[pool_name]['paused'] = False
 
@@ -612,7 +628,9 @@ class DatapoolManager:
                                       'protocol': protocol,
                                       'drop_rx': drop_rx,
                                       'drop_tx': drop_tx,
-                                      'pckt_filter': pckt_filter})
+                                      'pckt_filter': pckt_filter,
+                                      'start_new': start_new})
+
         thread.daemon = True
         thread.name = '{}-tm_recv_worker'.format(pool_name)
         # thread.stopRecording = False
@@ -621,21 +639,21 @@ class DatapoolManager:
         thread.start()
         return thread
 
-    def tm_recv_worker(self, sockfd, pool_name, protocol='PUS', drop_rx=False, drop_tx=False, pckt_filter=None):
+    def tm_recv_worker(self, sockfd, pool_name, protocol='PUS', drop_rx=False, drop_tx=False, pckt_filter=None, start_new=True):
         host, port = sockfd.getpeername()
 
         # Check if a Pool has already been started with only TC
-        start_new = True
-        if pool_name in self.loaded_pools:
-            if self.loaded_pools[pool_name].live:
-                start_new = False
-        if not pool_name in self.state:
-            start_new = True
+        # start_new = True
+        # if pool_name in self.loaded_pools:
+        #     if self.loaded_pools[pool_name].live:
+        #         start_new = False
+        # if not pool_name in self.state:
+        #     start_new = True
 
         new_session = self.session_factory_storage
+
         # If no TC Pool has been started start new one
         if start_new:
-
             pool_row = DbTelemetryPool(
                 pool_name=pool_name,
                 modification_time=time.time(),
@@ -810,7 +828,7 @@ class DatapoolManager:
         self.logger.warning('Disconnected from ' + str(host) + ':' + str(port))
         sockfd.close()
 
-    def tm_receiver_del_old_pool(self, pool_name, delete_abandoned=False, try_delete=True):
+    def tm_receiver_del_old_pool(self, pool_name, delete_abandoned=False, try_delete=True, force=False):
         new_session = self.session_factory_storage
         pool_row = new_session.query(DbTelemetryPool).filter(DbTelemetryPool.pool_name == pool_name).first()
         if pool_row:
@@ -824,10 +842,10 @@ class DatapoolManager:
                 if pool_name in self.state:
                     del self.state[pool_name]
 
-            # If the pool is started by TC do not delete
-            elif pool_name in self.loaded_pools:
-                if self.loaded_pools[pool_name].live:
-                    return
+            # If the pool is started by TC do not delete  //MM: this is taken care of outside this function
+            # elif pool_name in self.loaded_pools:
+            #     if self.loaded_pools[pool_name].live:
+            #         return
 
             if rows_in_pool < 1000 and try_delete:
                 new_session.execute(
@@ -1596,7 +1614,7 @@ class DatapoolManager:
                     delete_thread.start()
         new_session.close()
 
-    def spw_recv_start(self, sockfd, pool_name, drop_rx=False, delete_abandoned=False, try_delete=True):
+    def spw_recv_start(self, sockfd, pool_name, drop_rx=False, delete_abandoned=False, try_delete=True, force_clean=False):
 
         # delete existing pool rows
         self.spw_receiver_del_old_pool(pool_name, delete_abandoned=delete_abandoned, try_delete=try_delete)
-- 
GitLab