diff --git a/Ccs/ccs_function_lib.py b/Ccs/ccs_function_lib.py
index cbff75a292786d0a184aa345436e6969ea745546..3c9d0b4391267ce940d3841844038f66251019f3 100644
--- a/Ccs/ccs_function_lib.py
+++ b/Ccs/ccs_function_lib.py
@@ -3318,29 +3318,33 @@ def _tcsend_common(tc_bytes, apid, st, sst, sleep=0., pool_name='LIVE', pkt_time
 #   @param pool_name: name of the pool
 #   @param string: <boolean> if true the CUC timestamp is returned as a string, otherwise as a float
 #   @return: <CUC> timestamp or None if failing
-def get_last_pckt_time(pool_name='LIVE', string=True):
+def get_last_pckt_time(pool_name='LIVE', string=True, use_pmgr=False):
     """
 
     :param pool_name:
     :param string:
     :return:
     """
-    pmgr = dbus_connection('poolmanager', communication['poolmanager'])
 
-    if not pmgr:
-        logger.warning('Accessing PMGR failed!')
-        return
+    if use_pmgr:
+        pmgr = dbus_connection('poolmanager', communication['poolmanager'])
 
-    packet = None
-    # fetch the pool_name
-    try:
-        poolname = pmgr.Dictionaries('loaded_pools', pool_name)
-    except (dbus.DBusException, KeyError):
-        logger.error('Pool {} is not connected/accessible!'.format(pool_name))
-        return
+        if not pmgr:
+            logger.warning('Accessing PMGR failed!')
+            return
+
+        packet = None
+        # fetch the pool_name
+        try:
+            poolname = pmgr.Dictionaries('loaded_pools', pool_name)
+        except (dbus.DBusException, KeyError):
+            logger.error('Pool {} is not connected/accessible!'.format(pool_name))
+            return
 
-    filename = poolname[2]  # 3rd entry is the filename of the named tuple, named tuple not possible via dbus
-    if not filename:
+        filename = poolname[2]  # 3rd entry is the filename of the named tuple, named tuple not possible via dbus
+        if not filename:
+            filename = pool_name
+    else:
         filename = pool_name
 
     # get the first packet from the pool
@@ -3381,6 +3385,26 @@ def get_last_pckt_time(pool_name='LIVE', string=True):
     return cuc
 
 
+def get_last_tc(pool_name, idbytes=False):
+    dbcon = scoped_session_storage
+    row = dbcon.query(
+        DbTelemetry
+    ).join(
+        DbTelemetryPool,
+        DbTelemetry.pool_id == DbTelemetryPool.iid
+    ).filter(
+        DbTelemetryPool.pool_name == pool_name, DbTelemetry.is_tm == 1
+    ).order_by(
+        DbTelemetry.idx.desc()
+    ).first()
+    dbcon.close()
+
+    if idbytes:
+        return row.raw[:4]  # return first 4 header bytes used for identification in PUS Ack service
+    else:
+        return row
+
+
 def _has_tc_connection(pool_name, pmgr_handle):
     try:
         if not pmgr_handle.Functions('_is_tc_connection_active', pool_name):
@@ -6315,6 +6339,76 @@ class DbTools:
             new_session.close()
 
 
+class Verification:
+    """
+    Packet verification tools
+    """
+
+    PKTIDLEN = 4
+
+    @classmethod
+    def await_tc_ack(cls, pool_name, pktid=None, idx_from=None, time_from=None, acktypes=(1, 7), timeout=3.):
+
+        t1 = time.time()
+
+        acks_remain = list(acktypes)
+
+        if pktid is None:
+            pkt = get_last_tc(pool_name)
+            pktid = pkt.raw[:cls.PKTIDLEN]
+
+            if idx_from is None:
+                idx_from = pkt.idx
+
+        elif isinstance(pktid, (tuple, list)):
+            pktid = cls.mk_pktid(*pktid)
+
+        elif isinstance(pktid, DbTelemetry):
+            pktid = pktid.raw[:cls.PKTIDLEN]
+
+            if idx_from is None:
+                idx_from = pktid.idx
+
+        else:
+            if len(pktid) != cls.PKTIDLEN or not isinstance(pktid, (bytes, bytearray)):
+                raise ValueError
+
+        while time.time() - t1 < timeout:
+
+            acks = cls.get_acks(pool_name, idx_from=idx_from, time_from=time_from)
+            # filter by pktid
+            acks_found = filter_by_discr(acks, TM_HEADER_LEN, cls.PKTIDLEN, pktid)
+
+            for ack in acks_found:
+                if ack.sst in acks_remain:
+                    acks_remain.remove(ack.sst)
+
+            if len(acks_remain) == 0:
+                return True, acks_found.all()
+
+            time.sleep(.1)
+
+        return False, acks_found.all() if len(acks_found) != 0 else False, []
+
+    @staticmethod
+    def get_acks(pool_name, idx_from=None, time_from=None):
+
+        rows = get_pool_rows(pool_name)
+        acks = filter_rows(rows, st=1, idx_from=idx_from, time_from=time_from)
+
+        return acks
+
+    @classmethod
+    def mk_pktid(cls, apid, sc):
+        pktid = TCHeader()
+        pktid.bits.SEC_HEAD_FLAG = 1
+        pktid.bits.APID = apid
+        pktid.bits.SEQ_FLAGS = 3
+        pktid.bits.PKT_SEQ_CNT = sc
+
+        return pktid.raw[:cls.PKTIDLEN]
+
+
 class LoadInfo(Gtk.Window):
     def __init__(self, parent=None, title="DB Loader"):
         Gtk.Window.__init__(self, transient_for=parent, destroy_with_parent=True)