From ba2b667cc6035db1c6091f4e640e4956fb75c24f Mon Sep 17 00:00:00 2001
From: dspitzba <daniel.spitzbart@cern.ch>
Date: Thu, 3 Mar 2022 14:28:17 -0500
Subject: [PATCH] find uplink alignment in ETROC emulator mode and FIFO
 debugging

---
 configs/uplink_alignment_RB02_data.yaml | 102 ++++++++++++++++++++++++
 tamalero/FIFO.py                        |  23 ++++--
 tamalero/ReadoutBoard.py                |  84 ++++++++++++++-----
 test_tamalero.py                        |   4 +-
 4 files changed, 183 insertions(+), 30 deletions(-)
 create mode 100644 configs/uplink_alignment_RB02_data.yaml

diff --git a/configs/uplink_alignment_RB02_data.yaml b/configs/uplink_alignment_RB02_data.yaml
new file mode 100644
index 0000000..09cda01
--- /dev/null
+++ b/configs/uplink_alignment_RB02_data.yaml
@@ -0,0 +1,102 @@
+daq:
+  alignment:
+    0: 0
+    1: 0
+    2: 0
+    3: 0
+    4: 0
+    5: 0
+    6: 4
+    7: 0
+    8: 0
+    9: 0
+    10: 3
+    11: 0
+    12: 0
+    13: 0
+    14: 0
+    15: 0
+    16: 0
+    17: 0
+    18: 0
+    19: 0
+    20: 0
+    21: 0
+    22: 0
+    23: 0
+  inversion:
+    0: 0
+    1: 0
+    2: 0
+    3: 0
+    4: 0
+    5: 0
+    6: 1
+    7: 0
+    8: 0
+    9: 0
+    10: 0
+    11: 0
+    12: 0
+    13: 0
+    14: 0
+    15: 0
+    16: 0
+    17: 0
+    18: 0
+    19: 0
+    20: 0
+    21: 0
+    22: 0
+    23: 0
+trigger:
+  alignment:
+    0: 0
+    1: 0
+    2: 0
+    3: 0
+    4: 0
+    5: 0
+    6: 0
+    7: 0
+    8: 0
+    9: 0
+    10: 0
+    11: 0
+    12: 0
+    13: 0
+    14: 0
+    15: 0
+    16: 0
+    17: 0
+    18: 0
+    19: 0
+    20: 0
+    21: 0
+    22: 0
+    23: 0
+  inversion:
+    0: 0
+    1: 0
+    2: 0
+    3: 0
+    4: 0
+    5: 0
+    6: 0
+    7: 0
+    8: 0
+    9: 0
+    10: 0
+    11: 0
+    12: 0
+    13: 0
+    14: 0
+    15: 0
+    16: 0
+    17: 0
+    18: 0
+    19: 0
+    20: 0
+    21: 0
+    22: 0
+    23: 0
diff --git a/tamalero/FIFO.py b/tamalero/FIFO.py
index 8663ec5..6488c91 100644
--- a/tamalero/FIFO.py
+++ b/tamalero/FIFO.py
@@ -12,6 +12,10 @@ class FIFO:
     def __init__(self, rb, elink=0, ETROC='ETROC1'):
         self.rb = rb
         self.rb.kcu.write_node("READOUT_BOARD_%s.FIFO_ELINK_SEL"%self.rb.rb, elink)
+        self.rb.kcu.write_node("READOUT_BOARD_%s.LPGBT.DAQ.DOWNLINK.DL_SRC"%self.rb.rb, 3)
+        self.rb.kcu.write_node("READOUT_BOARD_%s.LPGBT.DAQ.DOWNLINK.FAST_CMD_IDLE"%self.rb.rb, 0xC1)
+        self.rb.kcu.write_node("READOUT_BOARD_%s.LPGBT.DAQ.DOWNLINK.FAST_CMD_DATA"%self.rb.rb, 0xC5)
+
 
         self.rb.kcu.write_node("READOUT_BOARD_%s.FIFO_TRIG0"%self.rb.rb, 0x00)
         self.rb.kcu.write_node("READOUT_BOARD_%s.FIFO_TRIG0_MASK"%self.rb.rb, 0x00)
@@ -39,15 +43,18 @@ class FIFO:
         #self.rb.kcu.write_node("READOUT_BOARD_%s.FIFO_FORCE_TRIG" % self.rb.rb, 1)
 
     def dump(self, block=255):
-        # make sure the fifo is not empty
-        #while (self.rb.kcu.read_node("READOUT_BOARD_%s.FIFO_EMPTY"%self.rb.rb)):
-        #    print(self.rb.kcu.read_node("READOUT_BOARD_%s.FIFO_ARMED"%self.rb.rb))
-        #    pass
-        self.rb.kcu.hw.dispatch()
+        self.rb.kcu.write_node("READOUT_BOARD_%s.LPGBT.DAQ.DOWNLINK.FAST_CMD_PULSE"%self.rb.rb, 0x01)  # FIXME confirm this
+        for i in range(10):
+            if self.rb.kcu.read_node("READOUT_BOARD_%s.FIFO_EMPTY"%self.rb.rb).value() < 1: break
         res = self.rb.kcu.hw.getNode("DAQ_0.FIFO").readBlock(block)
-        self.rb.kcu.hw.dispatch()
-        hex_dump = [ '{0:0{1}x}'.format(r,2) for r in res.value() ]
-        return hex_dump
+        try:
+            self.rb.kcu.hw.dispatch()
+            hex_dump = [ '{0:0{1}x}'.format(r,2) for r in res.value() ]
+            return hex_dump
+        except:
+            # NOTE: not entirely understood, but it seems this happens if FIFO is (suddenly?) empty
+            return []
+
 
     def giant_dump(self, block=3000, subblock=255):
         res = []
diff --git a/tamalero/ReadoutBoard.py b/tamalero/ReadoutBoard.py
index dd9b183..80f03c3 100644
--- a/tamalero/ReadoutBoard.py
+++ b/tamalero/ReadoutBoard.py
@@ -1,7 +1,7 @@
 import os
 from tamalero.LPGBT import LPGBT
 from tamalero.SCA import SCA
-from tamalero.utils import get_temp
+from tamalero.utils import get_temp, chunk
 from tamalero.VTRX import VTRX
 
 from time import sleep
@@ -76,7 +76,7 @@ class ReadoutBoard:
         self.DAQ_LPGBT.set_gpio(bit, 0)
         self.DAQ_LPGBT.set_gpio(bit, 1)
 
-    def find_uplink_alignment(self, scan_time=0.01, default=0):  # default scan time of 0.01 is enough
+    def find_uplink_alignment(self, scan_time=0.01, default=0, data_mode=False):  # default scan time of 0.01 is enough
         # TODO: check the FEC mode and set the number of links appropriately
         n_links = 24  #  NOTE: there are 28 e-links if the board is in FEC5 mode, but we are operating in FEC12 where there are only 24
         print ("Scanning for uplink alignment")
@@ -90,25 +90,41 @@ class ReadoutBoard:
         # TODO: the scan should check the pattern checkers first, and skip the scan for any where the pattern check is already ok
 
         # now, scan
-        for inv in [False, True]:
-            for shift in range(8):
-                for channel in range(n_links):
-                    self.DAQ_LPGBT.set_uplink_alignment(channel, shift, quiet=True)
-                    self.DAQ_LPGBT.set_uplink_invert(channel, inv)
-                    if self.trigger:
-                        self.TRIG_LPGBT.set_uplink_alignment(channel, shift, quiet=True)
-                        self.TRIG_LPGBT.set_uplink_invert(channel, inv)
-                self.DAQ_LPGBT.set_uplink_group_data_source("normal")  # actually needed??
-                self.DAQ_LPGBT.set_downlink_data_src('upcnt')
-                self.DAQ_LPGBT.reset_pattern_checkers()
-                sleep(scan_time)
-                res = self.DAQ_LPGBT.read_pattern_checkers(log_dir=None, quiet=True)
-                for link in ['Link 0', 'Link 1']:
-                    for channel in range(n_links):
-                        if res[link]['UPCNT'][channel]['error'][0] == 0:
-                            print ("Found uplink alignment for %s, channel %s: %s, inverted: %s"%(link, channel, shift, inv==0x0a))
+        if data_mode:
+            link = 'Link 0'
+            for channel in range(n_links):
+                res = 0
+                for inv in [False, True]:
+                    for shift in range(8):
+                        self.DAQ_LPGBT.set_uplink_alignment(channel, shift, quiet=True)
+                        self.DAQ_LPGBT.set_uplink_invert(channel, inv)
+                        tmp = self.check_data_integrity(channel=channel)
+                        if tmp>res:
+                            print ("Found improved uplink alignment for %s, channel %s: %s, inverted: %s"%(link, channel, shift, inv))
+                            print (tmp, res)
                             alignment[link][channel] = shift
                             inversion[link][channel] = inv
+                            res = tmp
+        else:
+            for inv in [False, True]:
+                for shift in range(8):
+                    for channel in range(n_links):
+                        self.DAQ_LPGBT.set_uplink_alignment(channel, shift, quiet=True)
+                        self.DAQ_LPGBT.set_uplink_invert(channel, inv)
+                        if self.trigger:
+                            self.TRIG_LPGBT.set_uplink_alignment(channel, shift, quiet=True)
+                            self.TRIG_LPGBT.set_uplink_invert(channel, inv)
+                    self.DAQ_LPGBT.set_uplink_group_data_source("normal")  # actually needed??
+                    self.DAQ_LPGBT.set_downlink_data_src('upcnt')
+                    self.DAQ_LPGBT.reset_pattern_checkers()
+                    sleep(scan_time)
+                    res = self.DAQ_LPGBT.read_pattern_checkers(log_dir=None, quiet=True)
+                    for link in ['Link 0', 'Link 1']:
+                        for channel in range(n_links):
+                            if res[link]['UPCNT'][channel]['error'][0] == 0:
+                                print ("Found uplink alignment for %s, channel %s: %s, inverted: %s"%(link, channel, shift, inv))
+                                alignment[link][channel] = shift
+                                inversion[link][channel] = inv
 
         # Reset alignment to default values for the channels where no good alignment has been found
         print ("Now setting uplink alignment to optimal values (default values if no good alignment was found)")
@@ -163,6 +179,32 @@ class ReadoutBoard:
         self.kcu.print_reg(self.kcu.hw.getNode("READOUT_BOARD_%s.LPGBT.TRIGGER.UPLINK.READY" % self.rb), use_color=True)
         self.kcu.print_reg(self.kcu.hw.getNode("READOUT_BOARD_%s.LPGBT.TRIGGER.UPLINK.FEC_ERR_CNT" % self.rb), use_color=True, invert=True)
 
+    def check_data_integrity(self, channel=0):
+        '''
+        Not sure where this function should live.
+        It's not necessarily a part of the RB.
+        FIXME: Needs to become transparent to the data format.
+        '''
+        from tamalero.FIFO import FIFO
+        fifo = FIFO(self, elink=channel)
+        fifo.set_trigger(word0=0x35, word1=0x55, mask0=0xff, mask1=0xff)
+        fifo.reset()
+        n_header = 0
+        n_trailer = 0
+        data  = []
+        for i in range(10):
+            data += ['35', '55'] + fifo.giant_dump(3000)  # + ['35', '55'] + fifo.giant_dump(3000)
+            fifo.reset()
+
+        long_st = ''.join(data)
+        for line in chunk(data, 5):
+            n_header  += (line[0:3] == ['35','55','55'])
+            n_trailer += (line[0:3] == ['95','55','55'])
+
+        #print (n_header, n_trailer)
+        return n_header + n_trailer
+
+
     def get_FEC_error_count(self, quiet=False):
         if not quiet:
             print("{:<8}{:<8}{:<50}{:<8}".format("Address", "Perm.", "Name", "Value"))
@@ -182,7 +224,7 @@ class ReadoutBoard:
             print("Error counts after reset:")
             self.get_FEC_error_count()
 
-    def configure(self, alignment=None):
+    def configure(self, alignment=None, data_mode=False):
 
         ## DAQ
         #for i in range(28):
@@ -207,7 +249,7 @@ class ReadoutBoard:
         if alignment is not None:
             self.load_uplink_alignment(alignment)
         else:
-            _ = self.find_uplink_alignment()
+            _ = self.find_uplink_alignment(data_mode=data_mode)
 
         # SCA init
         self.sca_hard_reset()
diff --git a/test_tamalero.py b/test_tamalero.py
index 11bfd53..a481922 100644
--- a/test_tamalero.py
+++ b/test_tamalero.py
@@ -31,6 +31,8 @@ if __name__ == '__main__':
 
     header()
 
+    if args.read_fifo: data_mode = True
+
     print ("Using KCU at address: %s"%args.kcu)
 
     kcu = KCU(name="my_device",
@@ -74,7 +76,7 @@ if __name__ == '__main__':
             alignment = load_alignment_from_file(args.load_alignment)
         else:
             alignment = None
-        rb_0.configure(alignment=alignment)  # this is very slow, especially for the trigger lpGBT.
+        rb_0.configure(alignment=alignment, data_mode=data_mode)  # this is very slow, especially for the trigger lpGBT.
         if rb_0.trigger:
             rb_0.DAQ_LPGBT.reset_trigger_mgts() 
         time.sleep(1.0)
-- 
GitLab