From 10df41b2a1c628639113b6b1508cab8ff0fe2c01 Mon Sep 17 00:00:00 2001
From: marcofilho <marco.filho@ess.eu>
Date: Thu, 6 Feb 2025 15:52:33 +0100
Subject: [PATCH] Reformulate naming convention. Add global configs.

hybrid.sub is created to add hybrid numbers to file, avoiding having to define that in st.cmd file.
Similar thing is done for VMM chips, since it's always going to be 2 per hybrid.

Add global configuration values. Global PVs should configure all parameters for all VMM FENS.
Channel global configurations need to connect to asyn port in order to correctly initialize the array record :(
---
 cmds/st.cmd                           |  68 +++++++---
 cmds/vmm.cmd                          |  13 ++
 vmmTbl.Makefile                       |   5 +-
 vmmTblApp/Db/channels-global.sub      |  20 +++
 vmmTblApp/Db/channels-global.template |  56 +++++++++
 vmmTblApp/Db/channels.sub             |  89 +++++++++++--
 vmmTblApp/Db/channels.template        |  18 +++
 vmmTblApp/Db/hyb-global.template      |  71 +++++++++++
 vmmTblApp/Db/hybrid.sub               |   8 ++
 vmmTblApp/Db/hybrid.template          |  78 ++++++++++++
 vmmTblApp/Db/vmm-fen-global.template  |   6 +
 vmmTblApp/Db/vmm-global.template      | 175 ++++++++++++++++++++++++++
 vmmTblApp/Db/vmm.template             |  36 ++++++
 vmmTblApp/Db/vmm_tbl.template         |   7 ++
 vmmTblApp/src/vmm_tbl.cpp             |  16 +++
 vmmTblApp/src/vmm_tbl.h               |   3 +
 16 files changed, 642 insertions(+), 27 deletions(-)
 create mode 100644 cmds/vmm.cmd
 create mode 100644 vmmTblApp/Db/channels-global.sub
 create mode 100644 vmmTblApp/Db/channels-global.template
 create mode 100644 vmmTblApp/Db/hyb-global.template
 create mode 100644 vmmTblApp/Db/hybrid.sub
 create mode 100644 vmmTblApp/Db/vmm-fen-global.template
 create mode 100644 vmmTblApp/Db/vmm-global.template

diff --git a/cmds/st.cmd b/cmds/st.cmd
index d3f2b18..9020df6 100644
--- a/cmds/st.cmd
+++ b/cmds/st.cmd
@@ -2,7 +2,7 @@ require vmmTbl
 
 epicsEnvSet("IPADDR", "192.168.50.2")
 epicsEnvSet("IPPORT", "65535")
-epicsEnvSet("P", "LAB-B02:")
+epicsEnvSet("P", "LAB-Marco:")
 epicsEnvSet("DIS", "NDet-")
 epicsEnvSet("RMM-DEV", "$(DIS)RMM-001:")
 
@@ -14,9 +14,6 @@ drvAsynIPPortConfigure("L0", "$(IPADDR):$(IPPORT) UDP", 0, 0, 1)
 
 RMMConfig("RMM", "$(IPADDR)", "$(IPPORT)", "$(E3_CMD_TOP)/config_file/lab_testbed.json")
 
-#VMMTblConfig("RMM portName", "VMMPortName", ring, number_hybrids)
-VMMTblConfig("RMM", "VMM", 0, 2)
-
 epicsEnvSet("VMM-DEV", "$(DIS)VMM-")
 epicsEnvSet("HYB-DEV", "$(DIS)VMMHYB-")
 epicsEnvSet("VMM3A-DEV", "$(DIS)VMM3A-")
@@ -26,22 +23,59 @@ dbLoadRecords($(rmm_DB)/rmm.db, "P=$(P), R=$(RMM-DEV), PORT=RMM, ADDR=0, TIMEOUT
 dbLoadRecords($(rmm_DB)/rmm_sensors.db, "P=$(P), R=$(RMM-DEV), PORT=RMM, ADDR=0, TIMEOUT=1")
 dbLoadRecords($(rmm_DB)/ring.db, "P=$(P), R=$(RMM-DEV), ADDR=0, PORT=RMM, ADDR=0, TIMEOUT=1")
 
-dbLoadRecords("$(rmm_DB)/rmm_packets.template", "P=$(P), R=$(RMM-DEV), PORT=RMM, RING=0, NODE=0, ADDR=0, TIMEOUT=1")
-dbLoadRecords("$(rmm_DB)/topology.template", "P=$(P), R=$(RMM-DEV), PORT=RMM, RING=0, NODE=0, ADDR=0, TIMEOUT=1")
+############## Global configurations
+
+epicsEnvSet("Glob", "G:")
+dbLoadRecords("$(vmmTbl_DB)/vmm-fen-global.db", "P=$(P), R=$(VMM-DEV)$(Glob)")
+dbLoadRecords("$(vmmTbl_DB)/hyb-global.db", "P=$(P), R=$(VMM-DEV)$(Glob)")
+dbLoadRecords("$(vmmTbl_DB)/channels-global.db", "P=$(P), R=$(VMM-DEV)$(Glob), PORT=VMM0, ADDR=0, TIMEOUT=1")
+
+############## Particular rings
 
 epicsEnvSet("RING", "00")
+epicsEnvSet("RING-1-DIGIT", "0")
+epicsEnvSet("PORT", "VMM0")
+epicsEnvSet("R-VMM", "$(VMM-DEV)$(RING):")
+epicsEnvSet("R-VMM0", "$(R-VMM)")
+epicsEnvSet("R-HYB", "$(HYB-DEV)$(RING)")
+epicsEnvSet("R-VMM3A", "$(VMM3A-DEV)$(RING)")
+< ./vmm.cmd
+
+epicsEnvSet("RING", "01")
+epicsEnvSet("RING-1-DIGIT", "1")
+epicsEnvSet("PORT", "VMM1")
+epicsEnvSet("R-VMM", "$(VMM-DEV)$(RING):")
+epicsEnvSet("R-VMM1", "$(R-VMM)")
+epicsEnvSet("R-HYB", "$(HYB-DEV)$(RING)")
+epicsEnvSet("R-VMM3A", "$(VMM3A-DEV)$(RING)")
+< ./vmm.cmd
+
+epicsEnvSet("RING", "02")
+epicsEnvSet("RING-1-DIGIT", "2")
+epicsEnvSet("PORT", "VMM2")
+epicsEnvSet("R-VMM", "$(VMM-DEV)$(RING):")
+epicsEnvSet("R-VMM2", "$(R-VMM)")
+epicsEnvSet("R-HYB", "$(HYB-DEV)$(RING)")
+epicsEnvSet("R-VMM3A", "$(VMM3A-DEV)$(RING)")
+< ./vmm.cmd
+
+epicsEnvSet("RING", "03")
+epicsEnvSet("RING-1-DIGIT", "3")
+epicsEnvSet("PORT", "VMM3")
+epicsEnvSet("R-VMM", "$(VMM-DEV)$(RING):")
+epicsEnvSet("R-VMM3", "$(R-VMM)")
+epicsEnvSet("R-HYB", "$(HYB-DEV)$(RING)")
+epicsEnvSet("R-VMM3A", "$(VMM3A-DEV)$(RING)")
+< ./vmm.cmd
+
+epicsEnvSet("RING", "04")
+epicsEnvSet("RING-1-DIGIT", "4")
+epicsEnvSet("PORT", "VMM4")
 epicsEnvSet("R-VMM", "$(VMM-DEV)$(RING):")
-                                                  # R = NDet-VMM-<RingNumber#2>:
-dbLoadRecords("$(vmmTbl_DB)/vmm_tbl.db", "P=$(P), R=$(R-VMM), PORT=VMM, RING=0, NODE=0, ADDR=0, TIMEOUT=1")
-                                                  # 'R' = NDet-VMM-<RingNumber#2><HybNumber#1>:
-dbLoadRecords("$(vmmTbl_DB)/hybrid.db", "P=$(P), R=$(HYB-DEV)$(RING), VMMPREFIX=$(P)$(R-VMM), PORT=VMM, HYB=0, ADDR=0, TIMEOUT=1")
-dbLoadRecords("$(vmmTbl_DB)/hybrid.db", "P=$(P), R=$(HYB-DEV)$(RING), VMMPREFIX=$(P)$(R-VMM), PORT=VMM, HYB=1, ADDR=0, TIMEOUT=1")
-
-                                                   # 'R' = NDet-VMM-<RingNumber#2><HybNumber#1><VmmNumber#1>
-dbLoadRecords("$(vmmTbl_DB)/channels.db", "P=$(P), R=$(VMM3A-DEV)$(RING), VMMPREFIX=$(P)$(R-VMM), HYBR=$(HYB-DEV)$(RING), HYB=0, VMM=0, C=:, PORT=VMM, ADDR=0, TIMEOUT=1")
-dbLoadRecords("$(vmmTbl_DB)/channels.db", "P=$(P), R=$(VMM3A-DEV)$(RING), VMMPREFIX=$(P)$(R-VMM), HYBR=$(HYB-DEV)$(RING), HYB=0, VMM=1, C=:, PORT=VMM, ADDR=0, TIMEOUT=1")
-dbLoadRecords("$(vmmTbl_DB)/channels.db", "P=$(P), R=$(VMM3A-DEV)$(RING), VMMPREFIX=$(P)$(R-VMM), HYBR=$(HYB-DEV)$(RING), HYB=1, VMM=0, C=:, PORT=VMM, ADDR=0, TIMEOUT=1")
-dbLoadRecords("$(vmmTbl_DB)/channels.db", "P=$(P), R=$(VMM3A-DEV)$(RING), VMMPREFIX=$(P)$(R-VMM), HYBR=$(HYB-DEV)$(RING), HYB=1, VMM=1, C=:, PORT=VMM, ADDR=0, TIMEOUT=1")
+epicsEnvSet("R-VMM4", "$(R-VMM)")
+epicsEnvSet("R-HYB", "$(HYB-DEV)$(RING)")
+epicsEnvSet("R-VMM3A", "$(VMM3A-DEV)$(RING)")
+< ./vmm.cmd
 
 iocInit()
 
diff --git a/cmds/vmm.cmd b/cmds/vmm.cmd
new file mode 100644
index 0000000..701bc93
--- /dev/null
+++ b/cmds/vmm.cmd
@@ -0,0 +1,13 @@
+dbLoadRecords("$(rmm_DB)/rmm_packets.template", "P=$(P), R=$(RMM-DEV), PORT=RMM, RING=$(RING-1-DIGIT), NODE=0, ADDR=0, TIMEOUT=1")
+dbLoadRecords("$(rmm_DB)/topology.template", "P=$(P), R=$(RMM-DEV), PORT=RMM, RING=$(RING-1-DIGIT), NODE=0, ADDR=0, TIMEOUT=1")
+
+#VMMTblConfig("RMM portName", "VMMPortName", ring, number_hybrids)
+VMMTblConfig("RMM", "$(PORT)", "$(RING-1-DIGIT)", 5)
+
+                                                  # R = NDet-VMM-<RingNumber#2>:
+dbLoadRecords("$(vmmTbl_DB)/vmm_tbl.db", "P=$(P), R=$(R-VMM), Glob=$(VMM-DEV)$(Glob), PORT=$(PORT), RING=$(RING), NODE=0, ADDR=0, TIMEOUT=1")
+                                                  # 'R' = NDet-VMM-<RingNumber#2><HybNumber#1>:
+dbLoadRecords("$(vmmTbl_DB)/hybrid.db", "P=$(P), R=$(R-HYB), Glob=$(VMM-DEV)$(Glob), VMMPREFIX=$(P)$(R-VMM), PORT=$(PORT), ADDR=0, TIMEOUT=1")
+
+                                                   # 'R' = NDet-VMM-<RingNumber#2><HybNumber#1><VmmNumber#1>
+dbLoadRecords("$(vmmTbl_DB)/channels.db", "P=$(P), R=$(R-VMM3A), Glob=$(VMM-DEV)$(Glob), VMMPREFIX=$(P)$(R-VMM), HYBR=$(R-HYB), C=:, PORT=$(PORT), ADDR=0, TIMEOUT=1")
diff --git a/vmmTbl.Makefile b/vmmTbl.Makefile
index 4654223..d13e476 100644
--- a/vmmTbl.Makefile
+++ b/vmmTbl.Makefile
@@ -7,9 +7,12 @@ APP:=vmmTblApp
 APPDB:=$(APP)/Db
 APPSRC:=$(APP)/src
 
-TMPS += $(APPDB)/hybrid.template
 TMPS += $(APPDB)/vmm_tbl.template
+TMPS += $(APPDB)/vmm-fen-global.template
+TMPS += $(APPDB)/hyb-global.template
 SUBS = $(APPDB)/channels.sub
+SUBS += $(APPDB)/hybrid.sub
+SUBS += $(APPDB)/channels-global.sub
 
 LIB_SYS_LIBS += vmmapi
 
diff --git a/vmmTblApp/Db/channels-global.sub b/vmmTblApp/Db/channels-global.sub
new file mode 100644
index 0000000..716e0f5
--- /dev/null
+++ b/vmmTblApp/Db/channels-global.sub
@@ -0,0 +1,20 @@
+file vmm-global.template {
+    pattern {CH}
+    {"SD"}
+}
+
+file channels-global.template {
+    pattern {CH}
+    { "ST" }
+    { "SC" }
+    { "SL" }
+    { "SM" }
+    { "STH" }
+    { "SMX" }
+    { "ST" }
+    { "SC" }
+    { "SL" }
+    { "SM" }
+    { "STH" }
+    { "SMX" }
+}
\ No newline at end of file
diff --git a/vmmTblApp/Db/channels-global.template b/vmmTblApp/Db/channels-global.template
new file mode 100644
index 0000000..53686f7
--- /dev/null
+++ b/vmmTblApp/Db/channels-global.template
@@ -0,0 +1,56 @@
+record(aao, "$(P)$(R)$(CH)-S") {
+    field(DESC, "Set $(CH) channels array (millivolt)")
+    field(NELM, "64")
+    field(FTVL, "CHAR")
+}
+
+record(bo, "$(P)$(R)All$(CH)-S") {
+    field(DESC, "Set all $(CH) channels for all VMMs")
+}
+
+record(acalcout, "$(P)$(R)#All$(CH)-S") {
+    field(NELM, "64")
+    field(OOPT, "On Change")
+    field(CALC, "A")
+    field(INPA, "$(P)$(R)All$(CH)-S CPP")
+    field(INAA, "$(P)$(R)$(CH)-S")
+    field(OUT,  "$(P)$(R)$(CH)-S PP")
+}
+
+record(aao, "$(P)$(R)V1$(CH)-S") {
+    field(DESC, "Set $(CH) channels array (millivolt)")
+    field(NELM, "64")
+    field(FTVL, "CHAR")
+}
+
+record(bo, "$(P)$(R)V1All$(CH)-S") {
+    field(DESC, "Set all $(CH) channels for all VMMs")
+}
+
+record(acalcout, "$(P)$(R)V1#All$(CH)-S") {
+    field(NELM, "64")
+    field(OOPT, "On Change")
+    field(CALC, "A")
+    field(INPA, "$(P)$(R)V1All$(CH)-S CPP")
+    field(INAA, "$(P)$(R)V1$(CH)-S")
+    field(OUT,  "$(P)$(R)V1$(CH)-S PP")
+}
+
+record(aao, "$(P)$(R)V0$(CH)-S") {
+    field(DESC, "Set $(CH) channels array (millivolt)")
+    field(NELM, "64")
+    field(FTVL, "CHAR")
+}
+
+record(bo, "$(P)$(R)V0All$(CH)-S") {
+    field(DESC, "Set all $(CH) channels for all VMMs")
+}
+
+record(acalcout, "$(P)$(R)V0#All$(CH)-S") {
+    field(NELM, "64")
+    field(OOPT, "On Change")
+    field(CALC, "A")
+    field(INPA, "$(P)$(R)V0All$(CH)-S CPP")
+    field(INAA, "$(P)$(R)V0$(CH)-S")
+    field(OUT,  "$(P)$(R)V0$(CH)-S PP")
+}
\ No newline at end of file
diff --git a/vmmTblApp/Db/channels.sub b/vmmTblApp/Db/channels.sub
index 4b4cb39..a2035e0 100644
--- a/vmmTblApp/Db/channels.sub
+++ b/vmmTblApp/Db/channels.sub
@@ -1,14 +1,85 @@
 file channels.template {
-pattern { CH }
-        { "ST" }
-        { "SC" }
-        { "SL" }
-        { "SM" }
-        { "STH" }
-        { "SMX" }
+pattern { CH, HYB, VMM }
+        { "ST",  "0", "0" }
+        { "SC",  "0", "0" }
+        { "SL",  "0", "0" }
+        { "SM",  "0", "0" }
+        { "STH", "0", "0" }
+        { "SMX", "0", "0" }
+        { "ST",  "0", "1" }
+        { "SC",  "0", "1" }
+        { "SL",  "0", "1" }
+        { "SM",  "0", "1" }
+        { "STH", "0", "1" }
+        { "SMX", "0", "1" }
+
+        { "ST",  "1", "0" }
+        { "SC",  "1", "0" }
+        { "SL",  "1", "0" }
+        { "SM",  "1", "0" }
+        { "STH", "1", "0" }
+        { "SMX", "1", "0" }
+        { "ST",  "1", "1" }
+        { "SC",  "1", "1" }
+        { "SL",  "1", "1" }
+        { "SM",  "1", "1" }
+        { "STH", "1", "1" }
+        { "SMX", "1", "1" }
+
+        { "ST",  "2", "0" }
+        { "SC",  "2", "0" }
+        { "SL",  "2", "0" }
+        { "SM",  "2", "0" }
+        { "STH", "2", "0" }
+        { "SMX", "2", "0" }
+        { "ST",  "2", "1" }
+        { "SC",  "2", "1" }
+        { "SL",  "2", "1" }
+        { "SM",  "2", "1" }
+        { "STH", "2", "1" }
+        { "SMX", "2", "1" }
+
+        { "ST",  "3", "0" }
+        { "SC",  "3", "0" }
+        { "SL",  "3", "0" }
+        { "SM",  "3", "0" }
+        { "STH", "3", "0" }
+        { "SMX", "3", "0" }
+        { "ST",  "3", "1" }
+        { "SC",  "3", "1" }
+        { "SL",  "3", "1" }
+        { "SM",  "3", "1" }
+        { "STH", "3", "1" }
+        { "SMX", "3", "1" }
+
+        { "ST",  "4", "0" }
+        { "SC",  "4", "0" }
+        { "SL",  "4", "0" }
+        { "SM",  "4", "0" }
+        { "STH", "4", "0" }
+        { "SMX", "4", "0" }
+        { "ST",  "4", "1" }
+        { "SC",  "4", "1" }
+        { "SL",  "4", "1" }
+        { "SM",  "4", "1" }
+        { "STH", "4", "1" }
+        { "SMX", "4", "1" }
 }
 
 file vmm.template { 
-pattern { CH }
-        { "SD" } 
+pattern { CH, HYB, VMM }
+        { "SD", "0", "0" }
+        { "SD", "0", "1" }
+
+        { "SD", "1", "0" }
+        { "SD", "1", "1" }
+
+        { "SD", "2", "0" }
+        { "SD", "2", "1" }
+
+        { "SD", "3", "0" }
+        { "SD", "3", "1" }
+
+        { "SD", "4", "0" }
+        { "SD", "4", "1" }
 }
\ No newline at end of file
diff --git a/vmmTblApp/Db/channels.template b/vmmTblApp/Db/channels.template
index dab00fe..0551e58 100644
--- a/vmmTblApp/Db/channels.template
+++ b/vmmTblApp/Db/channels.template
@@ -4,6 +4,24 @@
 #     The aao record sets the register channel by channel.
 #     The bo record sets all channels at once.
 
+record(aao, "$(P)$(R)$(HYB)$(VMM)$(C)#$(CH)-S") {
+    field(DESC, "Set global channels array forwarder")
+    field(DOL,  "$(P)$(Glob)$(CH)-S CP")
+    field(OMSL, "closed_loop")
+    field(OUT,  "$(P)$(R)$(HYB)$(VMM)$(C)$(CH)-S CP")
+    field(NELM, "64")
+    field(FTVL, "CHAR")
+}
+
+record(aao, "$(P)$(R)$(HYB)$(VMM)$(C)##$(CH)-S") {
+    field(DESC, "Global channels forwarder for VMM $(VMM)")
+    field(DOL,  "$(P)$(Glob)V$(VMM)$(CH)-S CP")
+    field(OMSL, "closed_loop")
+    field(OUT,  "$(P)$(R)$(HYB)$(VMM)$(C)$(CH)-S CP")
+    field(NELM, "64")
+    field(FTVL, "CHAR")
+}
+
 record(aao, "$(P)$(R)$(HYB)$(VMM)$(C)$(CH)-S") {
     field(DESC, "Set $(CH) channels array")
     field(DTYP, "asynInt8ArrayOut")
diff --git a/vmmTblApp/Db/hyb-global.template b/vmmTblApp/Db/hyb-global.template
new file mode 100644
index 0000000..24c605b
--- /dev/null
+++ b/vmmTblApp/Db/hyb-global.template
@@ -0,0 +1,71 @@
+record(bo, "$(P)$(R)Enable-S") {
+    field(DESC, "Enable All hybrids")
+    field(PINI, "NO")
+    field(ZNAM, "Disable")
+    field(ONAM, "Enable")
+}
+
+record(mbbo, "$(P)$(R)Skew-S"){
+    field(DESC, "Global set Skew")
+    field(PINI, "NO")
+    field(ZRST, "0 ns")
+    field(ZRVL, "0")
+    field(ONST, "2.83921 ns")
+    field(ONVL, "1")
+    field(TWST, "5.67842 ns")
+    field(TWVL, "2")
+    field(THST, "8.51764 ns")
+    field(THVL, "3")
+    field(FRST, "11.3568 ns")
+    field(FRVL, "4")
+    field(FVST, "14.1961 ns")
+    field(FVVL, "5")
+    field(SXST, "17.0353 ns")
+    field(SXVL, "6")
+    field(SVST, "19.8545 ns")
+    field(SVVL, "7")
+    field(EIST, "22.7137 ns")
+    field(EIVL, "8")
+    field(NIST, "25.5529 ns")
+    field(NIVL, "9")
+    field(TEST, "28.3921 ns")
+    field(TEVL, "10")
+    field(ELST, "31.2313 ns")
+    field(ELVL, "11")
+    field(TVST, "34.0705 ns")
+    field(TVVL, "12")
+    field(TTST, "36.9098 ns")
+    field(TTVL, "13")
+    field(FTST, "39.749 ns")
+    field(FTVL, "14")
+    field(FFST, "42.5882 ns")
+    field(FFVL, "15")
+}
+
+record(mbbo, "$(P)$(R)Width-S"){
+    field(DESC, "Global set width")
+    field(PINI, "NO")
+    field(ZRST, "128 x 22.7137")
+    field(ZRVL, "0")
+    field(ONST, "64 x 22.7137")
+    field(ONVL, "1")
+    field(TWST, "32 x 22.7137")
+    field(TWVL, "2")
+    field(THST, "16 x 22.7137")
+    field(THVL, "3")
+    field(FRST, "8 x 22.7137")
+    field(FRVL, "4")
+    field(FVST, "4 x 22.7137")
+    field(FVVL, "5")
+    field(SXST, "2 x 22.7137")
+    field(SXVL, "6")
+    field(SVST, "1 x 22.7137")
+    field(SVVL, "7")
+}
+
+record(bo, "$(P)$(R)Pol-S") {
+    field(DESC, "Global set polarity")
+    field(PINI, "NO")
+    field(ZNAM, "positive")
+    field(ONAM, "negative")
+}
\ No newline at end of file
diff --git a/vmmTblApp/Db/hybrid.sub b/vmmTblApp/Db/hybrid.sub
new file mode 100644
index 0000000..4f11757
--- /dev/null
+++ b/vmmTblApp/Db/hybrid.sub
@@ -0,0 +1,8 @@
+file hybrid.template {
+    pattern {HYB}
+    {"0"}
+    {"1"}
+    {"2"}
+    {"3"}
+    {"4"}
+}
\ No newline at end of file
diff --git a/vmmTblApp/Db/hybrid.template b/vmmTblApp/Db/hybrid.template
index dab8afc..09c99d3 100644
--- a/vmmTblApp/Db/hybrid.template
+++ b/vmmTblApp/Db/hybrid.template
@@ -6,6 +6,13 @@ record(stringin, "$(P)$(R)$(HYB):FwVersion-R") {
     field(SCAN, "I/O Intr")
 }
 
+record(bo, "$(P)$(R)$(HYB):#Enable-S") {
+    field(DESC, "Global enable PV forwarder")
+    field(DOL,  "$(P)$(Glob)Enable-S CP")
+    field(OMSL, "closed_loop")
+    field(OUT, "$(P)$(R)$(HYB):Enable-S CP")
+}
+
 record(bo, "$(P)$(R)$(HYB):Enable-S") {
     field(DESC, "Enable hybrid")
     field(DTYP, "asynInt32")
@@ -33,6 +40,45 @@ record(calc, "$(P)$(R)$(HYB):#CalcDISA") {
     field(CALC, "( (A = 0)||(B # 4)||(C = 1) ) ? 1 : 0")
 }
 
+record(mbbo, "$(P)$(R)$(HYB):#Skew-S"){
+    field(DESC, "Global set Skew forwarder")
+    field(DOL,  "$(P)$(Glob)Skew-S CP")
+    field(OMSL, "closed_loop")
+    field(OUT, "$(P)$(R)$(HYB):Skew-S CP")
+    field(ZRST, "0 ns")
+    field(ZRVL, "0")
+    field(ONST, "2.83921 ns")
+    field(ONVL, "1")
+    field(TWST, "5.67842 ns")
+    field(TWVL, "2")
+    field(THST, "8.51764 ns")
+    field(THVL, "3")
+    field(FRST, "11.3568 ns")
+    field(FRVL, "4")
+    field(FVST, "14.1961 ns")
+    field(FVVL, "5")
+    field(SXST, "17.0353 ns")
+    field(SXVL, "6")
+    field(SVST, "19.8545 ns")
+    field(SVVL, "7")
+    field(EIST, "22.7137 ns")
+    field(EIVL, "8")
+    field(NIST, "25.5529 ns")
+    field(NIVL, "9")
+    field(TEST, "28.3921 ns")
+    field(TEVL, "10")
+    field(ELST, "31.2313 ns")
+    field(ELVL, "11")
+    field(TVST, "34.0705 ns")
+    field(TVVL, "12")
+    field(TTST, "36.9098 ns")
+    field(TTVL, "13")
+    field(FTST, "39.749 ns")
+    field(FTVL, "14")
+    field(FFST, "42.5882 ns")
+    field(FFVL, "15")
+}
+
 record(mbbo, "$(P)$(R)$(HYB):Skew-S"){
     field(DESC, "Hybrid's #$(HYB) Skew")
     field(DTYP, "asynInt32")
@@ -112,6 +158,29 @@ record(mbbi, "$(P)$(R)$(HYB):Skew-RB"){
     field(PINI, "YES")
 }
 
+record(mbbo, "$(P)$(R)$(HYB):#Width-S"){
+    field(DESC, "Global set width forwarder")
+    field(DOL,  "$(P)$(Glob)Width-S CP")
+    field(OMSL, "closed_loop")
+    field(OUT, "$(P)$(R)$(HYB):Width-S CP")
+    field(ZRST, "128 x 22.7137")
+    field(ZRVL, "0")
+    field(ONST, "64 x 22.7137")
+    field(ONVL, "1")
+    field(TWST, "32 x 22.7137")
+    field(TWVL, "2")
+    field(THST, "16 x 22.7137")
+    field(THVL, "3")
+    field(FRST, "8 x 22.7137")
+    field(FRVL, "4")
+    field(FVST, "4 x 22.7137")
+    field(FVVL, "5")
+    field(SXST, "2 x 22.7137")
+    field(SXVL, "6")
+    field(SVST, "1 x 22.7137")
+    field(SVVL, "7")
+}
+
 record(mbbo, "$(P)$(R)$(HYB):Width-S"){
     field(DESC, "Hybrid's #$(HYB) Width")
     field(DTYP, "asynInt32")
@@ -159,6 +228,15 @@ record(mbbi, "$(P)$(R)$(HYB):Width-RB"){
     field(SCAN, "1 second")
 }
 
+record(bo, "$(P)$(R)$(HYB):#Pol-S") {
+    field(DESC, "Global set polarity forwarder")
+    field(DOL,  "$(P)$(Glob)Pol-S CP")
+    field(OMSL, "closed_loop")
+    field(OUT,  "$(P)$(R)$(HYB):Pol-S CP")
+    field(ZNAM, "positive")
+    field(ONAM, "negative")
+}
+
 record(bo, "$(P)$(R)$(HYB):Pol-S") {
     field(DESC, "Hybrid's #$(HYB) Polarity")
     field(SDIS, "$(P)$(R)$(HYB):#CalcDISA CP")
diff --git a/vmmTblApp/Db/vmm-fen-global.template b/vmmTblApp/Db/vmm-fen-global.template
new file mode 100644
index 0000000..fe602b9
--- /dev/null
+++ b/vmmTblApp/Db/vmm-fen-global.template
@@ -0,0 +1,6 @@
+record(bo, "$(P)$(R)Acquire-S") {
+    field(DESC, "Start/stop ALL FEN acquisition")
+    field(VAL,  "0")
+    field(ZNAM, "Done")
+    field(ONAM, "Acquire")
+}
\ No newline at end of file
diff --git a/vmmTblApp/Db/vmm-global.template b/vmmTblApp/Db/vmm-global.template
new file mode 100644
index 0000000..9142e25
--- /dev/null
+++ b/vmmTblApp/Db/vmm-global.template
@@ -0,0 +1,175 @@
+record(ao, "$(P)$(R)AnalogMon-S"){
+    field(DESC, "Global set analog monitor")
+    field(DRVL, "0")
+    field(DRVH, "67")
+}
+
+record(calcout, "$(P)$(R)#AnlgMonClc-S") {
+    field(DESC, "Auxiliary to AnalogMon")
+    field(INPA, "$(P)$(R)AnlgMonParam-S CP")
+    field(CALC, "A+64")
+    field(OUT,  "$(P)$(R)AnalogMon-S CP")
+}
+
+record(mbbo, "$(P)$(R)AnlgMonParam-S") {
+    field(DESC, "Auxiliar to set AnalogMon")
+    field(ZRST, "Pulser")
+    field(ZRVL, "64")
+    field(ONST, "Threshold")
+    field(ONVL, "65")
+    field(TWST, "Bandgap")
+    field(TWVL, "66")
+    field(THST, "Temperature")
+    field(THVL, "67")
+}
+
+record(ao, "$(P)$(R)V0AnalogMon-S"){
+    field(DESC, "Global analog monitor for VMM 0")
+    field(DRVL, "0")
+    field(DRVH, "67")
+}
+
+record(calcout, "$(P)$(R)V0#AnlgMonClc-S") {
+    field(DESC, "Auxiliary to AnalogMon")
+    field(INPA, "$(P)$(R)V0AnlgMonParam-S CP")
+    field(CALC, "A+64")
+    field(OUT,  "$(P)$(R)V0AnalogMon-S CP")
+}
+
+record(mbbo, "$(P)$(R)V0AnlgMonParam-S") {
+    field(DESC, "Auxiliar to set AnalogMon")
+    field(ZRST, "Pulser")
+    field(ZRVL, "64")
+    field(ONST, "Threshold")
+    field(ONVL, "65")
+    field(TWST, "Bandgap")
+    field(TWVL, "66")
+    field(THST, "Temperature")
+    field(THVL, "67")
+}
+
+record(ao, "$(P)$(R)V1AnalogMon-S"){
+    field(DESC, "Global analog monitor for VMM 1")
+    field(DRVL, "0")
+    field(DRVH, "67")
+}
+
+record(calcout, "$(P)$(R)V1#AnlgMonClc-S") {
+    field(DESC, "Auxiliary to AnalogMon")
+    field(INPA, "$(P)$(R)V1AnlgMonParam-S CP")
+    field(CALC, "A+64")
+    field(OUT,  "$(P)$(R)V1AnalogMon-S CP")
+}
+
+record(mbbo, "$(P)$(R)V1AnlgMonParam-S") {
+    field(DESC, "Auxiliar to set AnalogMon")
+    field(ZRST, "Pulser")
+    field(ZRVL, "64")
+    field(ONST, "Threshold")
+    field(ONVL, "65")
+    field(TWST, "Bandgap")
+    field(TWVL, "66")
+    field(THST, "Temperature")
+    field(THVL, "67")
+}
+
+record(aao, "$(P)$(R)$(CH)-S") {
+    field(DESC, "Set $(CH) channels array (millivolt)")
+    field(DTYP, "asynInt8ArrayOut")
+    field(NELM, "64")
+    field(FTVL, "CHAR")
+    field(OUT,  "@asyn($(PORT),$(ADDR),$(TIMEOUT))VMM_GLOBAL_SD")
+
+    info(asyn:READBACK, "1")
+}
+
+record(aai, "$(P)$(R)$(CH)-RB") {
+    field(DESC, "Read from setpoint to initialize")
+    field(DTYP, "asynInt8ArrayIn")
+    field(NELM, "64")
+    field(PINI, "YES")
+    field(FTVL, "CHAR")
+    field(SCAN, "I/O Intr")
+    field(INP,  "@asyn($(PORT),$(ADDR),$(TIMEOUT))VMM_GLOBAL_SD")
+}
+
+record(ao, "$(P)$(R)All$(CH)-S") {
+    field(DESC, "Set all $(CH) channels for all VMMs")
+    field(DRVH, "31")
+    field(DRVL, "0")
+}
+
+record(acalcout, "$(P)$(R)#All$(CH)-S") {
+    field(NELM, "64")
+    field(OOPT, "On Change")
+    field(CALC, "A")
+    field(INPA, "$(P)$(R)All$(CH)-S CPP")
+    field(INAA, "$(P)$(R)$(CH)-S")
+    field(OUT,  "$(P)$(R)$(CH)-S PP")
+}
+
+record(aao, "$(P)$(R)V0$(CH)-S") {
+    field(DESC, "Set $(CH) for all VMM 0")
+    field(DTYP, "asynInt8ArrayOut")
+    field(OUT,  "@asyn($(PORT),$(ADDR),$(TIMEOUT))VMM_GLOBAL_SD_VMM0")
+    field(NELM, "64")
+    field(FTVL, "CHAR")
+
+    info(asyn:READBACK, "1")
+}
+
+record(aai, "$(P)$(R)V0$(CH)-RB") {
+    field(DESC, "Read from setpoint to initialize")
+    field(DTYP, "asynInt8ArrayIn")
+    field(NELM, "64")
+    field(PINI, "YES")
+    field(FTVL, "CHAR")
+    field(SCAN, "I/O Intr")
+    field(INP,  "@asyn($(PORT),$(ADDR),$(TIMEOUT))VMM_GLOBAL_SD_VMM0")
+}
+
+record(ao, "$(P)$(R)V0All$(CH)-S") {
+    field(DESC, "Set all $(CH) channels for all VMMs")
+}
+
+record(acalcout, "$(P)$(R)V0#All$(CH)-S") {
+    field(NELM, "64")
+    field(OOPT, "On Change")
+    field(CALC, "A")
+    field(INPA, "$(P)$(R)V0All$(CH)-S CPP")
+    field(INAA, "$(P)$(R)V0$(CH)-S")
+    field(OUT,  "$(P)$(R)V0$(CH)-S PP")
+}
+
+record(aao, "$(P)$(R)V1$(CH)-S") {
+    field(DESC, "Set $(CH) for all VMM 1")
+    field(DTYP, "asynInt8ArrayOut")
+    field(OUT,  "@asyn($(PORT),$(ADDR),$(TIMEOUT))VMM_GLOBAL_SD_VMM1")
+    field(NELM, "64")
+    field(FTVL, "CHAR")
+
+    info(asyn:READBACK, "1")
+}
+
+record(aai, "$(P)$(R)V1$(CH)-RB") {
+    field(DESC, "Read from setpoint to initialize")
+    field(DTYP, "asynInt8ArrayIn")
+    field(NELM, "64")
+    field(PINI, "YES")
+    field(FTVL, "CHAR")
+    field(SCAN, "I/O Intr")
+    field(INP,  "@asyn($(PORT),$(ADDR),$(TIMEOUT))VMM_GLOBAL_SD_VMM1")
+}
+
+record(ao, "$(P)$(R)V1All$(CH)-S") {
+    field(DESC, "Set all $(CH) channels for all VMMs")
+}
+
+record(acalcout, "$(P)$(R)V1#All$(CH)-S") {
+    field(NELM, "64")
+    field(OOPT, "On Change")
+    field(CALC, "A")
+    field(INPA, "$(P)$(R)V1All$(CH)-S CPP")
+    field(INAA, "$(P)$(R)V1$(CH)-S")
+    field(OUT,  "$(P)$(R)V1$(CH)-S PP")
+}
\ No newline at end of file
diff --git a/vmmTblApp/Db/vmm.template b/vmmTblApp/Db/vmm.template
index 5b43625..47b38da 100644
--- a/vmmTblApp/Db/vmm.template
+++ b/vmmTblApp/Db/vmm.template
@@ -1,5 +1,23 @@
 ##### Records to configure a given vmm from a given hybrid
 
+record(aao, "$(P)$(R)$(HYB)$(VMM)$(C)##$(CH)-S") {
+    field(DESC, "Global channels forwarder for VMM $(VMM)")
+    field(DOL,  "$(P)$(Glob)V$(VMM)$(CH)-S CP")
+    field(OMSL, "closed_loop")
+    field(OUT,  "$(P)$(R)$(HYB)$(VMM)$(C)$(CH)-S CP")
+    field(NELM, "64")
+    field(FTVL, "CHAR")
+}
+
+record(aao, "$(P)$(R)$(HYB)$(VMM)$(C)#$(CH)-S") {
+    field(DESC, "Set global channels array forwarder")
+    field(DOL,  "$(P)$(Glob)$(CH)-S CP")
+    field(OMSL, "closed_loop")
+    field(OUT,  "$(P)$(R)$(HYB)$(VMM)$(C)$(CH)-S CP")
+    field(NELM, "64")
+    field(FTVL, "CHAR")
+}
+
 record(aao, "$(P)$(R)$(HYB)$(VMM)$(C)$(CH)-S") {
     field(DESC, "Set $(CH) channels array (millivolt)")
     field(DTYP, "asynInt8ArrayOut")
@@ -61,6 +79,24 @@ record(acalcout, "$(P)$(R)$(HYB)$(VMM)$(C)#All$(CH)-S") {
 # 64, 65, 66 and 67 are respectively for reading
 # Pulser, Threshold, Bandgap and Temperature respectively.
 
+record(ao, "$(P)$(R)$(HYB)$(VMM)$(C)##AnalogMon-S") {
+    field(DESC, "Global analogmon forwarder for VMM $(VMM)")
+    field(DOL,  "$(P)$(Glob)V$(VMM)AnalogMon-S CP")
+    field(OMSL, "closed_loop")
+    field(OUT,  "$(P)$(R)$(HYB)$(VMM)$(C)AnalogMon-S CP")
+    field(DRVL, "0")
+    field(DRVH, "67")
+}
+
+record(ao, "$(P)$(R)$(HYB)$(VMM)$(C)#AnalogMon-S"){
+    field(DESC, "Global set analogmon forwarder")
+    field(DOL,  "$(P)$(Glob)AnalogMon-S CP")
+    field(OMSL, "closed_loop")
+    field(OUT,  "$(P)$(R)$(HYB)$(VMM)$(C)AnalogMon-S CP")
+    field(DRVL, "0")
+    field(DRVH, "67")
+}
+
 record(ao, "$(P)$(R)$(HYB)$(VMM)$(C)AnalogMon-S"){
     field(DESC, "Select analog monitor (sm)")
     field(DTYP, "asynInt32")
diff --git a/vmmTblApp/Db/vmm_tbl.template b/vmmTblApp/Db/vmm_tbl.template
index 010c967..2fafa2c 100644
--- a/vmmTblApp/Db/vmm_tbl.template
+++ b/vmmTblApp/Db/vmm_tbl.template
@@ -1,3 +1,10 @@
+record(bo, "$(P)$(R)#Acquire-S") {
+    field(DESC, "Global acquire PV forwarder")
+    field(DOL,  "$(P)$(Glob)Acquire-S CP")
+    field(OMSL, "closed_loop")
+    field(OUT, "$(P)$(R)Acquire-S CP")
+}
+
 record(bo, "$(P)$(R)Acquire-S") {
     field(DESC, "Start/stop FEN acquisition")
     field(VAL,  "0")
diff --git a/vmmTblApp/src/vmm_tbl.cpp b/vmmTblApp/src/vmm_tbl.cpp
index 298b27c..0d49e1d 100644
--- a/vmmTblApp/src/vmm_tbl.cpp
+++ b/vmmTblApp/src/vmm_tbl.cpp
@@ -313,6 +313,9 @@ asynStatus VMMTbl::createEpicsParams() {
   createParam("VMM_FEN_ACQUIRING", asynParamInt32, &vmmIsAcquiring_);
   createParam("NUM_HYBRIDS", asynParamInt32, &vmmNumHybrids);
   createParam("IOC_MESSAGE", asynParamOctet, &IOCMessage);
+  createParam("VMM_GLOBAL_SD", asynParamInt8Array, &global_SD);
+  createParam("VMM_GLOBAL_SD_VMM0", asynParamInt8Array, &global_SD0);
+  createParam("VMM_GLOBAL_SD_VMM1", asynParamInt8Array, &global_SD1);
 
   std::tuple<std::string, asynParamType, std::vector<int> *> hyb_params_to_create[8] = {
       {"_FW_VERSION", asynParamOctet, &vmmHybFwVersion_},
@@ -564,6 +567,14 @@ asynStatus VMMTbl::readInt8Array(asynUser *pasynUser, epicsInt8 *value, size_t n
 
   if (function < FIRST_VMM_PARAM) return asynPortDriver::readInt8Array(pasynUser, value, nElements, nIn);
 
+  if (function == global_SD || function == global_SD0 || function == global_SD1) {
+    found_param = 0;
+    for (size_t i = 0; i < nElements; i++) {
+      value[i] = 0;  // This is used only to initialize the array
+    }
+    goto endOfReadInt8Array;
+  }
+
   found_param = VecUtils::getIndex(vmmSC_R, function, hyb_index, vmm_index);
   if (found_param == 0) {
     for (size_t i = 0; i < nElements; i++) {
@@ -723,6 +734,11 @@ asynStatus VMMTbl::writeInt8Array(asynUser *pasynUser, epicsInt8 *value, size_t
 
   if (function < FIRST_VMM_PARAM) return asynPortDriver::writeInt8Array(pasynUser, value, nElements);
 
+  if (function == global_SD || function == global_SD0 || function == global_SD1) {
+    found_param = 0;
+    goto endOfWriteInt8Array;
+  }
+
   found_param = VecUtils::getIndex(vmmSC_, function, hyb_index, vmm_index);
   if (found_param == 0) {
     for (size_t i = 0; i < nElements; i++) {
diff --git a/vmmTblApp/src/vmm_tbl.h b/vmmTblApp/src/vmm_tbl.h
index b5d6b4e..41e32ee 100644
--- a/vmmTblApp/src/vmm_tbl.h
+++ b/vmmTblApp/src/vmm_tbl.h
@@ -38,6 +38,9 @@ class VMMTbl : public asynPortDriver {
   int vmmIsAcquiring_;
   int vmmNumHybrids;
   int IOCMessage;
+  int global_SD;
+  int global_SD0;
+  int global_SD1;
   std::vector<int> vmmHybFwVersion_;
   std::vector<int> vmmHybId_;
   std::vector<int> vmmHybGeoPos_;
-- 
GitLab