From b43c9ee57e6347674ce66d68f4999286809b8e58 Mon Sep 17 00:00:00 2001
From: dspitzba <daniel.spitzbart@cern.ch>
Date: Mon, 6 Nov 2023 15:29:55 -0500
Subject: [PATCH 1/4] adding MODULEID as forced argument, consistency between
 threshold scan options

---
 test_ETROC.py | 74 ++++++++++++++++++++++++++++++++++-----------------
 1 file changed, 49 insertions(+), 25 deletions(-)

diff --git a/test_ETROC.py b/test_ETROC.py
index b1f5ded..d6ecd07 100644
--- a/test_ETROC.py
+++ b/test_ETROC.py
@@ -155,11 +155,25 @@ if __name__ == '__main__':
     argParser.add_argument('--row', action='store', default=4, help="Pixel row to be tested")
     argParser.add_argument('--col', action='store', default=3, help="Pixel column to be tested")
     argParser.add_argument('--pixel_mask', action='store', default=None, help="Pixel mask to apply")
+    argParser.add_argument('--moduleid', action='store', default=0, help="")
     args = argParser.parse_args()
 
+    assert int(args.moduleid)>0, "Module ID is not specified. This is a new feature, please run with --moduleid MODULEID, where MODULEID is the number on the module test board."
+    MID = args.moduleid
 
-    if not os.path.isdir("results/"):
-        os.makedirs("results/")
+    timestamp = time.time()
+
+    result_dir = f"results/{MID}/{timestamp}/"
+    out_dir = f"outputs/{MID}/{timestamp}/"
+
+    if not os.path.isdir(result_dir):
+        os.makedirs(result_dir)
+
+    if not os.path.isdir(out_dir):
+        os.makedirs(out_dir)
+
+    print(f"Will test module with ID {MID}.")
+    print(f"All results will be stored under timestamp {timestamp}")
 
     if args.test_readwrite:
         # ==============================
@@ -447,6 +461,7 @@ if __name__ == '__main__':
 
         print("\n - Getting internal test data")
 
+        etroc.wr_reg("DAC", 0, broadcast=True)  # make sure that we're not additionally picking up any noise
         etroc.wr_reg("selfTestOccupancy", 2, broadcast=True)
         if not args.partial:
             etroc.wr_reg("workMode", 0x1, broadcast=True)
@@ -515,7 +530,6 @@ if __name__ == '__main__':
         print(f"Events with at least one hit {n_events_hit=}")
         print(f"Events with some error in data unpacking {n_events_err=}")
 
-        plot_dir = './output/'
         fig, ax = plt.subplots(1,1,figsize=(7,7))
         hit_matrix.plot2d(
             ax=ax,
@@ -532,8 +546,8 @@ if __name__ == '__main__':
                 fontsize=15,
             )
         name = 'hit_matrix_internal_test_pattern'
-        fig.savefig(os.path.join(plot_dir, "{}.pdf".format(name)))
-        fig.savefig(os.path.join(plot_dir, "{}.png".format(name)))
+        fig.savefig(os.path.join(result_dir, f"{name}.pdf"))
+        fig.savefig(os.path.join(tesult_dir, f"{name}.png"))
 
         fifo.reset()
         print("\n - Testing fast command communication - Sending two L1As")
@@ -610,8 +624,8 @@ if __name__ == '__main__':
                         fontsize=15,
                     )
                 name = 'hit_matrix_external_L1A'
-                fig.savefig(os.path.join(plot_dir, "{}.pdf".format(name)))
-                fig.savefig(os.path.join(plot_dir, "{}.png".format(name)))
+                fig.savefig(os.path.join(result_dir, "{}.pdf".format(name)))
+                fig.savefig(os.path.join(result_dir, "{}.png".format(name)))
 
 
                 print("\nOccupancy vs column:")
@@ -619,6 +633,7 @@ if __name__ == '__main__':
                 print("\nOccupancy vs row:")
                 hit_matrix[{"col":sum}].show(columns=100)
 
+        # Set the chip back into well-defined workMode 0
         etroc.wr_reg("workMode", 0x0, broadcast=True)
 
         if args.threshold == 'auto':
@@ -661,8 +676,8 @@ if __name__ == '__main__':
             ax.set_xlabel(r'$Column$')
             fig.colorbar(cax,ax=ax)
             name = 'baseline_auto_individual'
-            fig.savefig(os.path.join(plot_dir, "{}.pdf".format(name)))
-            fig.savefig(os.path.join(plot_dir, "{}.png".format(name)))
+            fig.savefig(os.path.join(result_dir, "{}.pdf".format(name)))
+            fig.savefig(os.path.join(result_dir, "{}.png".format(name)))
 
             fig, ax = plt.subplots(1,1,figsize=(7,7))
             cax = ax.matshow(noise_width)
@@ -670,10 +685,13 @@ if __name__ == '__main__':
             ax.set_xlabel(r'$Column$')
             fig.colorbar(cax,ax=ax)
             name = 'noisewidth_auto_individual'
-            fig.savefig(os.path.join(plot_dir, "{}.pdf".format(name)))
-            fig.savefig(os.path.join(plot_dir, "{}.png".format(name)))
+            fig.savefig(os.path.join(result_dir, "{}.pdf".format(name)))
+            fig.savefig(os.path.join(result_dir, "{}.png".format(name)))
+
+            with open(f'{result_dir}/thresholds.yaml', 'w') as f:
+                dump((baseline+noise_width).tolist(), f)
 
-        if args.scan == 'full':
+        elif args.threshold == "manual":
 
             # Prescanning a random pixel to get an idea of the threshold
             row = 4
@@ -759,13 +777,13 @@ if __name__ == '__main__':
             cax2 = ax[1].matshow(noise_matrix)
             fig.colorbar(cax1,ax=ax[0])
             fig.colorbar(cax2,ax=ax[1])
-            
+
             ax[0].set_xticks(np.arange(N_pix_w))
             ax[0].set_yticks(np.arange(N_pix_w))
 
             ax[1].set_xticks(np.arange(N_pix_w))
             ax[1].set_yticks(np.arange(N_pix_w))
-            
+
             for i in range(N_pix_w):
                 for j in range(N_pix_w):
                     text = ax[0].text(j, i, int(max_matrix[i,j]),
@@ -773,9 +791,8 @@ if __name__ == '__main__':
 
                     text1 = ax[1].text(j, i, int(noise_matrix[i,j]),
                             ha="center", va="center", color="w", fontsize="xx-small")
-                    
-            #fig.savefig(f'results/peak_thresholds.png')
-            fig.savefig(f'results/peak_and_noiseWidth_thresholds.png')
+
+            fig.savefig(f'{result_dir}/peak_and_noiseWidth_thresholds.png')
             plt.show()
 
             plt.close(fig)
@@ -797,16 +814,26 @@ if __name__ == '__main__':
             ax.set_xlabel("Column")
             ax.set_ylabel("Row")
 
-            fig.savefig(f'results/thresholds.png')
+            fig.savefig(f'{result_dir}/thresholds.png')
             plt.show()
 
             plt.close(fig)
             del fig, ax
 
-            with open('results/thresholds.yaml', 'w') as f:
+            with open(f'{result_dir}/thresholds.yaml', 'w') as f:
                 dump(threshold_matrix.tolist(), f)
 
-        elif args.scan == 'simple':
+        else:
+
+            print(f"Trying to load tresholds from the following file: {args.threshold}")
+            with open(f'{result_dir}/thresholds.yaml', 'r') as f:
+                threshold_matrix = load(f)
+
+            for row in range(16):
+                for col in range(16):
+                    etroc.wr_reg('DAC', threshold_matrix[row][col], row=row, col=col)
+
+        if args.pixelscan == 'simple':
             row = 4
             col = 3
 
@@ -849,7 +876,7 @@ if __name__ == '__main__':
             print(vth)
             print(count)
 
-        elif args.scan =="internal":
+        elif args.pixelscan =="internal":
 
             row = int(args.row)
             col = int(args.col)
@@ -907,7 +934,7 @@ if __name__ == '__main__':
             plt.legend()
 
             now = datetime.datetime.now().strftime("%Y%m%d_%H%M%S")
-            fig.savefig(f'results/scan_internal_row_{row}_col_{col}_{now}.png')
+            fig.savefig(f'{result_dir}/scan_internal_row_{row}_col_{col}_{now}.png')
 
         if args.internal_data:
             # this still gives type == 0 data (with TOA, TOT, CAL)
@@ -988,8 +1015,6 @@ if __name__ == '__main__':
         if args.qinj:
             etroc.reset()
             etroc.wr_reg("disDataReadout", 1, broadcast=True)
-            with open('results/thresholds.yaml', 'r') as f:
-                threshold_matrix = load(f, Loader)
 
             N_pix   = 16*16 # total # of pixels
             N_pix_w = 16 # N_pix in NxN layout
@@ -1022,7 +1047,6 @@ if __name__ == '__main__':
             charge = int(args.charge) - 1
             for row, col in pixels:
                 etroc.wr_reg("disDataReadout", 0, row=row, col=col, broadcast=False)
-                etroc.wr_reg("DAC", int(threshold_matrix[row][col]), row=row, col=col)
                 etroc.wr_reg("QSel", charge, row=row, col=col)
                 etroc.wr_reg("QInjEn", 1, row=row, col=col)
 
-- 
GitLab


From 123379d2b17e1e4f2128c9d2dbf2fe037c7091b3 Mon Sep 17 00:00:00 2001
From: dspitzba <daniel.spitzbart@cern.ch>
Date: Mon, 6 Nov 2023 16:08:51 -0500
Subject: [PATCH 2/4] fix it for software emulator / CI

---
 test_ETROC.py | 7 +++++--
 1 file changed, 5 insertions(+), 2 deletions(-)

diff --git a/test_ETROC.py b/test_ETROC.py
index d6ecd07..9716704 100644
--- a/test_ETROC.py
+++ b/test_ETROC.py
@@ -158,8 +158,11 @@ if __name__ == '__main__':
     argParser.add_argument('--moduleid', action='store', default=0, help="")
     args = argParser.parse_args()
 
-    assert int(args.moduleid)>0, "Module ID is not specified. This is a new feature, please run with --moduleid MODULEID, where MODULEID is the number on the module test board."
-    MID = args.moduleid
+    if args.test_chip or args.config_chip:
+        assert int(args.moduleid)>0, "Module ID is not specified. This is a new feature, please run with --moduleid MODULEID, where MODULEID is the number on the module test board."
+        MID = args.moduleid
+    else:
+        MID = "software"
 
     timestamp = time.time()
 
-- 
GitLab


From e0a361012d422267bc2061a7b450f7ab28f35398 Mon Sep 17 00:00:00 2001
From: dspitzba <daniel.spitzbart@cern.ch>
Date: Tue, 7 Nov 2023 12:43:28 -0500
Subject: [PATCH 3/4] making output more verbose, fixing minor issues. tested
 with module v0b

---
 test_ETROC.py | 37 ++++++++++++++++++++++++-------------
 1 file changed, 24 insertions(+), 13 deletions(-)

diff --git a/test_ETROC.py b/test_ETROC.py
index 9716704..f2fb427 100644
--- a/test_ETROC.py
+++ b/test_ETROC.py
@@ -146,9 +146,9 @@ if __name__ == '__main__':
     argParser.add_argument('--charge', action='store', default=15, help="Charge to be injected")
     argParser.add_argument('--hard_reset', action='store_true', default=False, help="Hard reset of selected ETROC2 chip")
     argParser.add_argument('--skip_sanity_checks', action='store_true', default=False, help="Don't run sanity checks of ETROC2 chip")
-    argParser.add_argument('--scan', action='store', default=['full'], choices=['none', 'full', 'simple', 'internal'], help="Which threshold scan to run with ETROC2")
-    argParser.add_argument('--mode', action='store', default=['dual'], choices=['dual', 'single'], help="Port mode for ETROC2")
-    argParser.add_argument('--threshold', action='store', default=['manual'], choices=['manual', 'auto'], help="Use thresholds from manual or automatic scan?")
+    argParser.add_argument('--pixelscan', action='store', default='none', choices=['none', 'full', 'simple', 'internal'], help="Which threshold scan to run with ETROC2")
+    argParser.add_argument('--mode', action='store', default='dual', choices=['dual', 'single'], help="Port mode for ETROC2")
+    argParser.add_argument('--threshold', action='store', default='auto', help="Use thresholds from manual or automatic scan?")
     argParser.add_argument('--internal_data', action='store_true', help="Set up internal data generation")
     argParser.add_argument('--enable_power_board', action='store_true', help="Enable Power Board (all modules). Jumpers must still be set as well.")
     argParser.add_argument('--timing_scan', action='store_true', help="Perform L1Adelay timing scan")
@@ -164,7 +164,7 @@ if __name__ == '__main__':
     else:
         MID = "software"
 
-    timestamp = time.time()
+    timestamp = time.strftime("%Y-%m-%d-%H-%M-%S")
 
     result_dir = f"results/{MID}/{timestamp}/"
     out_dir = f"outputs/{MID}/{timestamp}/"
@@ -550,7 +550,7 @@ if __name__ == '__main__':
             )
         name = 'hit_matrix_internal_test_pattern'
         fig.savefig(os.path.join(result_dir, f"{name}.pdf"))
-        fig.savefig(os.path.join(tesult_dir, f"{name}.png"))
+        fig.savefig(os.path.join(result_dir, f"{name}.png"))
 
         fifo.reset()
         print("\n - Testing fast command communication - Sending two L1As")
@@ -576,7 +576,7 @@ if __name__ == '__main__':
 
                 #etroc.QInj_set(30, 0, row=3, col=3, broadcast=False)
                 start_time = time.time()
-                with tqdm(total=65536) as pbar:
+                with tqdm(total=65536, bar_format='{l_bar}{bar:20}{r_bar}{bar:-20b}') as pbar:
                     while not fifo.is_full():
                         fifo.send_l1a()
                         #fifo.send_QInj(delay=j)
@@ -666,13 +666,24 @@ if __name__ == '__main__':
                 fig.savefig(os.path.join(plot_dir, "{}.png".format(name)))
 
             # not using broadcast
-            print ("Using auto-threshold calibration for individual pixels")
+            print ("\n - Using auto-threshold calibration for individual pixels")
             baseline = np.empty([16, 16])
             noise_width = np.empty([16, 16])
-            for i in range(16):
-                for j in range(16):
-                    baseline[i][j], noise_width[i][j] = etroc.auto_threshold_scan(row=i, col=j, broadcast=False)
-
+            #pixel = 0
+            with tqdm(total=255, bar_format='{l_bar}{bar:20}{r_bar}{bar:-20b}') as pbar:
+                for pixel in range(256):
+                    row = pixel & 0xF
+                    col = (pixel & 0xF0) >> 4
+                    #print(pixel, row, col)
+                    baseline[row][col], noise_width[row][col] = etroc.auto_threshold_scan(row=row, col=col, broadcast=False)
+                    #print(pixel)
+                    pbar.update()
+            #pbar.close()
+                    #pixel += 1
+            #for i, j in pixels: in range(16):
+            #    for j in range(16):
+
+            print ("Done with threshold scan")
             fig, ax = plt.subplots(1,1,figsize=(7,7))
             cax = ax.matshow(baseline)
             ax.set_ylabel(r'$Row$')
@@ -1087,7 +1098,7 @@ if __name__ == '__main__':
                     text = ax.text(j, i, int(hit_matrix[i,j]),
                             ha="center", va="center", color="w", fontsize="xx-small")
 
-            fig.savefig(f'results/hit_matrix.png')
+            fig.savefig(f'{result_dir}/hit_matrix_qinj.png')
             plt.show()
 
             plt.close(fig)
@@ -1096,7 +1107,7 @@ if __name__ == '__main__':
 
             import struct
             fifo.reset()
-            with open(f"output/output_qinj_{args.charge}fC.dat", mode="wb") as f:
+            with open(f"{out_dir}/output_qinj_{args.charge}fC.dat", mode="wb") as f:
                 for i in range(50):
                     fifo.send_QInj(1000, delay=etroc.QINJ_delay)
                     data = fifo.read(dispatch=True)
-- 
GitLab


From 1f8174c5111bfbf42d6366eb88051ad29834f15b Mon Sep 17 00:00:00 2001
From: dspitzba <daniel.spitzbart@cern.ch>
Date: Wed, 8 Nov 2023 10:48:08 -0500
Subject: [PATCH 4/4] fix progress bar

---
 test_ETROC.py | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/test_ETROC.py b/test_ETROC.py
index f2fb427..b5160e2 100644
--- a/test_ETROC.py
+++ b/test_ETROC.py
@@ -670,7 +670,7 @@ if __name__ == '__main__':
             baseline = np.empty([16, 16])
             noise_width = np.empty([16, 16])
             #pixel = 0
-            with tqdm(total=255, bar_format='{l_bar}{bar:20}{r_bar}{bar:-20b}') as pbar:
+            with tqdm(total=256, bar_format='{l_bar}{bar:20}{r_bar}{bar:-20b}') as pbar:
                 for pixel in range(256):
                     row = pixel & 0xF
                     col = (pixel & 0xF0) >> 4
-- 
GitLab