From 9fcb1f571babc300e237d5a6bc596310469607a5 Mon Sep 17 00:00:00 2001 From: marcofilho <marco.filho@ess.eu> Date: Fri, 20 Dec 2024 16:19:30 +0100 Subject: [PATCH] MAJOR REFACTOR This commit was done with an inescrupulous "git add ." after several radical modifications. Anyway, the API was radically modified and basically the old way the code worked does not make any sense anymore. The desired architecture is the following: the API is going to be used as a class component. Each parameter will be created according to the desired number of enabled hybrids. Each parameter should use one simple API function. No information about the VMM or hybrids itself is stored in the VMMTbl class unless extremely needed. This commit leaves a few old parameters that should be removed in the future such as ADC_VALUE_VMM1, READ_ADC_VMMS, etc. This is only to serve as a reminder to add those later. --- vmmTbl.Makefile | 1 + vmmTblApp/Db/channels.template | 10 + vmmTblApp/Db/hybrid.template | 152 +++++++++++- vmmTblApp/Db/vmm_tbl.template | 8 + vmmTblApp/src/Utils.cpp | 63 +++++ vmmTblApp/src/Utils.h | 10 + vmmTblApp/src/vmm_tbl.cpp | 422 +++++++++++++++++++++++---------- vmmTblApp/src/vmm_tbl.h | 62 +++-- 8 files changed, 574 insertions(+), 154 deletions(-) create mode 100644 vmmTblApp/src/Utils.cpp create mode 100644 vmmTblApp/src/Utils.h diff --git a/vmmTbl.Makefile b/vmmTbl.Makefile index 585f59a..4654223 100644 --- a/vmmTbl.Makefile +++ b/vmmTbl.Makefile @@ -14,6 +14,7 @@ SUBS = $(APPDB)/channels.sub LIB_SYS_LIBS += vmmapi SOURCES += $(APPSRC)/vmm_tbl.cpp +SOURCES += $(APPSRC)/Utils.cpp DBDS += $(APPSRC)/vmm_tbl.dbd diff --git a/vmmTblApp/Db/channels.template b/vmmTblApp/Db/channels.template index 4347f5b..03ee4d6 100644 --- a/vmmTblApp/Db/channels.template +++ b/vmmTblApp/Db/channels.template @@ -9,9 +9,19 @@ record(aao, "$(P)$(R)$(HYB)$(VMM)$(C)$(CH)-S") { field(DTYP, "asynInt8ArrayOut") field(NELM, "64") field(FTVL, "CHAR") + field(FLNK, "$(P)$(R)$(HYB)$(VMM)$(C)$(CH)-R") field(OUT, "@asyn($(PORT),$(ADDR),$(TIMEOUT))HYB_$(HYB)_$(VMM)_$(CH)") } +record(aai, "$(P)$(R)$(HYB)$(VMM)$(C)$(CH)-R") { + field(DESC, "Get $(CH) channels array") + field(DTYP, "asynInt8ArrayIn") + field(NELM, "64") + field(FTVL, "CHAR") + field(SCAN, "I/O Intr") + field(INP, "@asyn($(PORT),$(ADDR),$(TIMEOUT))HYB_$(HYB)_$(VMM)_$(CH)") +} + record(bo, "$(P)$(R)$(HYB)$(VMM)$(C)All$(CH)-S") { field(DESC, "Set all $(CH) channels") field(VAL, "0") diff --git a/vmmTblApp/Db/hybrid.template b/vmmTblApp/Db/hybrid.template index 323e111..2770396 100644 --- a/vmmTblApp/Db/hybrid.template +++ b/vmmTblApp/Db/hybrid.template @@ -2,12 +2,160 @@ record(stringin, "$(P)$(R)Hyb$(HYB)FwVersion-R") { field(DESC, "Hybrid $(HYB) Firmware version") field(DTYP, "asynOctetRead") field(INP, "@asyn($(PORT),$(ADDR),$(TIMEOUT))HYB_$(HYB)_FW_VERSION") + field(PINI, "YES") field(SCAN, "I/O Intr") } +record(mbbo, "$(P)$(R)Hyb$(HYB)Skew-S"){ + field(DESC, "Hybrid's #$(HYB) Skew") + field(DTYP, "asynInt32") + field(OUT, "@asyn($(PORT),$(ADDR),$(TIMEOUT))HYB_$(HYB)_SKEW") + 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") + field(FLNK, "$(P)$(R)Hyb$(HYB)Skew-RB") +} + +record(mbbi, "$(P)$(R)Hyb$(HYB)Skew-RB"){ + field(DESC, "Hybrid's #$(HYB) Skew") + field(DTYP, "asynInt32") + field(INP, "@asyn($(PORT),$(ADDR),$(TIMEOUT))HYB_$(HYB)_SKEW") + 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") + field(SCAN, "I/O Intr") + field(PINI, "YES") +} + +record(mbbo, "$(P)$(R)Hyb$(HYB)Width-S"){ + field(DESC, "Hybrid's #$(HYB) Width") + field(DTYP, "asynInt32") + field(OUT, "@asyn($(PORT),$(ADDR),$(TIMEOUT))HYB_$(HYB)_WIDTH") + 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") + field(FLNK, "$(P)$(R)Hyb$(HYB)Width-RB") +} + +record(mbbi, "$(P)$(R)Hyb$(HYB)Width-RB"){ + field(DESC, "Hybrid's #$(HYB) Width") + field(DTYP, "asynInt32") + field(INP, "@asyn($(PORT),$(ADDR),$(TIMEOUT))HYB_$(HYB)_WIDTH") + field(PINI, "YES") + 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") + field(SCAN, "I/O Intr") +} + +record(bo, "$(P)$(R)Hyb$(HYB)Pol-S") { + field(DESC, "Hybrid's #$(HYB) Polarity") + field(DTYP, "asynInt32") + field(VAL, "0") + field(ZNAM, "positive") + field(ONAM, "negative") + field(OUT, "@asyn($(PORT),$(ADDR),$(TIMEOUT))HYB_$(HYB)_POLARITY") +} + +record(bi, "$(P)$(R)Hyb$(HYB)Pol-RB") { + field(DESC, "Hybrid's #$(HYB) Polarity") + field(DTYP, "asynInt32") + field(VAL, "0") + field(ZNAM, "positive") + field(ONAM, "negative") + field(INP, "@asyn($(PORT),$(ADDR),$(TIMEOUT))HYB_$(HYB)_POLARITY") + field(SCAN, "I/O Intr") + field(PINI, "YES") +} + record(stringin, "$(P)$(R)Hyb$(HYB)ID-R") { field(DESC, "Hybrid $(HYB) ID") field(DTYP, "asynOctetRead") + field(PINI, "YES") field(INP, "@asyn($(PORT),$(ADDR),$(TIMEOUT))HYB_$(HYB)_ID") field(SCAN, "I/O Intr") } @@ -15,12 +163,15 @@ record(stringin, "$(P)$(R)Hyb$(HYB)ID-R") { record(stringin, "$(P)$(R)Hyb$(HYB)GeoPos-R") { field(DESC, "Hybrid $(HYB) Geo Position") field(DTYP, "asynOctetRead") + field(PINI, "YES") field(INP, "@asyn($(PORT),$(ADDR),$(TIMEOUT))HYB_$(HYB)_GEOPOS") field(SCAN, "I/O Intr") } record(mbbi, "$(P)$(R)Hyb$(HYB)LinkStatus-R") { field(DESC, "Hybrid $(HYB) Link Status") + field(PINI, "YES") + field(DTYP, "asynInt32") field(ZRST, "not connected") field(ZRVL, "0") field(ONST, "start alignment") @@ -34,6 +185,5 @@ record(mbbi, "$(P)$(R)Hyb$(HYB)LinkStatus-R") { field(FVST, "acq") field(FVVL, "5") field(SCAN, "I/O Intr") - field(DTYP, "asynInt32") field(INP, "@asyn($(PORT),$(ADDR),$(TIMEOUT))HYB_$(HYB)_LINK_STATUS") } diff --git a/vmmTblApp/Db/vmm_tbl.template b/vmmTblApp/Db/vmm_tbl.template index 26af164..350c05d 100644 --- a/vmmTblApp/Db/vmm_tbl.template +++ b/vmmTblApp/Db/vmm_tbl.template @@ -56,3 +56,11 @@ record(bo, "$(P)$(R)Acquire-S") { field(DTYP, "asynInt32") field(OUT, "@asyn($(PORT),$(ADDR),$(TIMEOUT))VMM_FEN_ACQUIRE") } + +record(ai, "$(P)$(R)RegBankVersion-R"){ + field(DESC, "Register bank version") + field(PINI, "YES") + field(DTYP, "asynInt32") + field(INP, "@asyn($(PORT),$(ADDR=0),$(TIMEOUT=1))REG_BANK_VERSION") + field(SCAN, "I/O Intr") +} \ No newline at end of file diff --git a/vmmTblApp/src/Utils.cpp b/vmmTblApp/src/Utils.cpp new file mode 100644 index 0000000..4f21ae8 --- /dev/null +++ b/vmmTblApp/src/Utils.cpp @@ -0,0 +1,63 @@ +#include <bits/stdc++.h> + +#include "Utils.h" + +/** + * @brief Gets index of number in vector. + * @param vec Vector to find number in + * @param function number to find. + * @return -1 if number is not found. -2 if number is repeated. Index of element if number is found. + **/ +int VecUtils::getIndex(std::vector<int>& vec, int function){ + + int c = std::count(vec.begin(), vec.end(), function); + if (c == 0) return -1; + if (c > 1) return -2; + + auto it = std::find(vec.begin(), vec.end(), function); + + if (it != vec.end()) return std::distance(vec.begin(), it); + + return -1; + +} + +/** + * @brief Gets two indexes of number in vector<vector<int>>. + * @param vec Vector to find number in + * @param function number to find. + * @param hyb_index reference to put the hybrid index in. + * @param vmm_index reference to put the vmm index in. + * @return -1 if number is not found. -2 if number is repeated. 0 if number is found. + **/ +int VecUtils::getIndex(std::vector<std::vector<int>>& vec, int function, int &hyb_index, int &vmm_index) { + hyb_index = -1; + vmm_index = -1; + + int occurrences = 0; + + for (size_t i = 0; i < vec.size(); ++i) { + auto& subvec = vec[i]; + auto it = std::find(subvec.begin(), subvec.end(), function); + + if (it != subvec.end()) { + ++occurrences; + if (occurrences > 1) { + hyb_index = -2; + vmm_index = -2; + return -2; // Duplicated + } + + hyb_index = static_cast<int>(i); + vmm_index = static_cast<int>(std::distance(subvec.begin(), it)); + } + } + + if (occurrences == 0) { + hyb_index = -1; + vmm_index = -1; + return -1; // Not found + } + + return 0; // Found exactly once +} \ No newline at end of file diff --git a/vmmTblApp/src/Utils.h b/vmmTblApp/src/Utils.h new file mode 100644 index 0000000..f6880ef --- /dev/null +++ b/vmmTblApp/src/Utils.h @@ -0,0 +1,10 @@ +// Generic utilities for the module + +#include <vector> + +namespace VecUtils{ + +int getIndex(std::vector<int>&, int function); +int getIndex(std::vector<std::vector<int>>&, int function, int &hyb_index, int &vmm_index); + +} \ No newline at end of file diff --git a/vmmTblApp/src/vmm_tbl.cpp b/vmmTblApp/src/vmm_tbl.cpp index 4b5ce9c..b2c535e 100644 --- a/vmmTblApp/src/vmm_tbl.cpp +++ b/vmmTblApp/src/vmm_tbl.cpp @@ -6,8 +6,7 @@ VMMTbl::VMMTbl(RMM* rmm, const char *FENPortName, int ring, int node, int hybrid asynInt8ArrayMask | asynInt32Mask | asynInt64Mask | asynDrvUserMask | asynFloat64Mask | asynOctetMask, // Interfaces that we implement asynInt8ArrayMask | asynInt64Mask | asynInt32ArrayMask | asynFloat64Mask | asynInt32Mask | asynOctetMask, // Interfaces that do callbacks ASYN_MULTIDEVICE | ASYN_CANBLOCK, 1, /* ASYN_CANBLOCK=1, ASYN_MULTIDEVICE=1, autoConnect=1 */ - 0, 0), - number_hybrids(hybrids) + 0, 0) { pVmmAPI = FrontEndFactory::createAndRegister<VMMAPI>( @@ -15,183 +14,346 @@ VMMTbl::VMMTbl(RMM* rmm, const char *FENPortName, int ring, int node, int hybrid ring, node, "VmmTbl", - vmm_tbl_register_map); + vmm_tbl_register_map, + hybrids); createEpicsParams(); - setInitialEpicsParams(); rmm->updateTopologyPvs(ring, node, "vmmTbl"); - if (rmm->getRMMAPI()->checkRings() == rmmSuccess) { - for (int hyb = 0; hyb < number_hybrids; hyb++) { - pVmmAPI->enableHybrid(hyb, true); - setStringParam(vmmHybFwVersion_[hyb], pVmmAPI->readFwVersion(hyb).c_str()); - setStringParam(vmmHybId_[hyb], pVmmAPI->readIDChip(hyb).c_str()); - setStringParam(vmmHybGeoPos_[hyb], pVmmAPI->readGeoPos(hyb).c_str()); - setIntegerParam(vmmHybLinkStatus_[hyb], std::stoi(pVmmAPI->checkLinkStatus(hyb))); + +} + +asynStatus VMMTbl::readInt32(asynUser *pasynUser, epicsInt32 *value) { + int function = pasynUser->reason; + asynStatus status = asynSuccess; + uint32_t val; + int tmp_val; + bool tmp_val_bool; + uint8_t tmp_val_uint8; + int param_index; + + if (function < FIRST_VMM_PARAM) { + return asynPortDriver::readInt32(pasynUser, value); + } + + if (function == vmmRegBankVersion) { + vmmStatus result = this->pVmmAPI->getRegBankVersion(val); + if (result != vmmSuccess) status = asynError; + *value = val; + param_index = 10000; /// \todo So endOfReadInt32 won't return asynError; Maybe improve mechanism? + goto endOfReadInt32; + } + + //Search for parameter in all parameter vectors. If found, execute correct function for specific hybrid. + param_index = VecUtils::getIndex(vmmHybSkew_, function); + if (param_index >= 0) { + this->pVmmAPI->getSkew(param_index, tmp_val_uint8); + *value = tmp_val_uint8; + goto endOfReadInt32; + } + + param_index = VecUtils::getIndex(vmmHybLinkStatus_, function); + if (param_index >= 0) { + this->pVmmAPI->checkLinkStatus(param_index, tmp_val); + *value = tmp_val; + goto endOfReadInt32; + } + + param_index = VecUtils::getIndex(vmmHybWidth_, function); + if (param_index >= 0) { + this->pVmmAPI->getWidth(param_index, tmp_val_uint8); + *value = tmp_val_uint8; + goto endOfReadInt32; + } + + param_index = VecUtils::getIndex(vmmHybPolarity_, function); + if (param_index >= 0) { + this->pVmmAPI->getHybPolarity(param_index, tmp_val_bool); + *value = tmp_val_bool; + goto endOfReadInt32; + } + + endOfReadInt32: + if (param_index < 0) { + *value = 0; + return asynError; + } + + setIntegerParam(function, *value); + callParamCallbacks(); + + return asynSuccess; + +} + +asynStatus VMMTbl::readOctet(asynUser *pasynUser, char *value, + size_t nChars, size_t *nActual, + int *eomReason) +{ + + int status = asynSuccess; + int function = pasynUser->reason; + std::string read = ""; + + /* If this parameter belongs to a base class call its method */ + if (function < FIRST_VMM_PARAM) { + status = asynPortDriver::readOctet(pasynUser, value, nChars, nActual, + eomReason); + return (asynStatus)status; + } + + //Search for parameter in all parameter vectors. If found, execute correct function for specific hybrid. + int param_index = VecUtils::getIndex(vmmHybFwVersion_, function); + if (param_index >= 0) { + this->pVmmAPI->readFwVersion(param_index, read); + goto endOfReadOctet; } + + param_index = VecUtils::getIndex(vmmHybId_, function); + if (param_index >= 0) { + this->pVmmAPI->readIDChip(param_index, read); + goto endOfReadOctet; + } + + param_index = VecUtils::getIndex(vmmHybGeoPos_, function); + if (param_index >= 0) { + this->pVmmAPI->readGeoPos(param_index, read); + goto endOfReadOctet; } + + endOfReadOctet: + if (param_index < 0) { + value[0] = '\0'; + *nActual = 1; + return asynError; + } + size_t copy_size = std::min(read.size(), nChars); + strncpy(value, read.c_str(), copy_size); + setStringParam(function, value); + value[copy_size] = '\0'; + *nActual = copy_size; + *eomReason = ASYN_EOM_END; + callParamCallbacks(); + + return asynSuccess; + } -void VMMTbl::setInitialEpicsParams() { - puts("set_initial_epics_params"); +asynStatus VMMTbl::createParamAndStoreInVector(std::string paramName, asynParamType typ, + std::vector<int>* vectorToStore){ + + int paramIndex; + asynStatus status = createParam(paramName.c_str(), typ, ¶mIndex); + if (status != asynSuccess) { + asynPrint(pasynUserSelf, ASYN_TRACE_ERROR, + "%s:%s: Failed to create paramter %s.\n", + driverName, __FUNCTION__, paramName.c_str()); + return asynError; + } + vectorToStore->push_back(paramIndex); + return asynSuccess; + } asynStatus VMMTbl::createEpicsParams() { - createParam("SEL_ANALOG_MONITOR_VMM0", asynParamInt32, &vmmSelectMonitorVMM0_); - createParam("SEL_ANALOG_MONITOR_VMM1", asynParamInt32, &vmmSelectMonitorVMM1_); - createParam("READ_ADC_VMMS", asynParamInt32, &vmmProcessReadMonitorVMMs_); - createParam("ADC_VALUE_VMM0", asynParamFloat64, &vmmMonitorValueVMM0_); - createParam("ADC_VALUE_VMM1", asynParamFloat64, &vmmMonitorValueVMM1_); - createParam("VMM_FEN_ACQUIRE", asynParamInt32, &vmmAcquire_); - - for (int hyb = 0; hyb < number_hybrids; hyb++) { - std::ostringstream param_name; - param_name << "HYB_" << hyb <<"_FW_VERSION"; - createParam(param_name.str().c_str(), asynParamOctet, &vmmHybFwVersion_[hyb]); - param_name.str(""); - param_name << "HYB_" << hyb <<"_ID"; - createParam(param_name.str().c_str(), asynParamOctet, &vmmHybId_[hyb]); - param_name.str(""); - param_name << "HYB_" << hyb <<"_GEOPOS"; - createParam(param_name.str().c_str(), asynParamOctet, &vmmHybGeoPos_[hyb]); - param_name.str(""); - param_name << "HYB_" << hyb <<"_LINK_STATUS"; - createParam(param_name.str().c_str(), asynParamInt32, &vmmHybLinkStatus_[hyb]); - for (int vmm=0; vmm < VMMS_PER_HYBRID; vmm++) - { - param_name.str(""); - param_name << "HYB_" << hyb <<"_" << vmm << "_ST"; - createParam(param_name.str().c_str(), asynParamInt8Array, &vmmST_[hyb][vmm]); - param_name.str(""); - param_name << "HYB_" << hyb <<"_" << vmm << "_SC"; - createParam(param_name.str().c_str(), asynParamInt8Array, &vmmSC_[hyb][vmm]); - param_name.str(""); - param_name << "HYB_" << hyb <<"_" << vmm << "_SL"; - createParam(param_name.str().c_str(), asynParamInt8Array, &vmmSL_[hyb][vmm]); - param_name.str(""); - param_name << "HYB_" << hyb <<"_" << vmm << "_STH"; - createParam(param_name.str().c_str(), asynParamInt8Array, &vmmSTH_[hyb][vmm]); - param_name.str(""); - param_name << "HYB_" << hyb <<"_" << vmm << "_SM"; - createParam(param_name.str().c_str(), asynParamInt8Array, &vmmSM_[hyb][vmm]); - param_name.str(""); - param_name << "HYB_" << hyb <<"_" << vmm << "_SMX"; - createParam(param_name.str().c_str(), asynParamInt8Array, &vmmSMX_[hyb][vmm]); + + createParam("REG_BANK_VERSION", asynParamInt32, &vmmRegBankVersion); + + std::tuple<std::string, asynParamType, std::vector<int>*> + hyb_params_to_create[7] = {{"_FW_VERSION", asynParamOctet, &vmmHybFwVersion_}, + {"_ID", asynParamOctet, &vmmHybId_}, + {"_GEOPOS", asynParamOctet, &vmmHybGeoPos_}, + {"_LINK_STATUS", asynParamInt32, &vmmHybLinkStatus_}, + {"_SKEW", asynParamInt32, &vmmHybSkew_}, + {"_WIDTH", asynParamInt32, &vmmHybWidth_}, + {"_POLARITY", asynParamInt32, &vmmHybPolarity_}}; + + std::ostringstream param_name; + + for (int hyb = 0; hyb < this->pVmmAPI->getNumHybrids(true); hyb++) { + + for (const auto& hyb_param : hyb_params_to_create){ + const std::string& key = std::get<0>(hyb_param); + asynParamType typ = std::get<1>(hyb_param); + std::vector<int>* vec = std::get<2>(hyb_param); + createParamAndStoreInVector("HYB_" + std::to_string(hyb) + key, typ, vec); } + + std::vector<int> SC, SL, ST, STH, SM, SMX; + + for (int vmm=0; vmm < VMMS_PER_HYBRID; vmm++) { + + + param_name.str(""); + param_name << "HYB_" << hyb <<"_" << vmm << "_SC"; + createParamAndStoreInVector(param_name.str(), asynParamInt8Array, &SC); + + param_name.str(""); + param_name << "HYB_" << hyb <<"_" << vmm << "_SL"; + createParamAndStoreInVector(param_name.str(), asynParamInt8Array, &SL); + + param_name.str(""); + param_name << "HYB_" << hyb <<"_" << vmm << "_ST"; + createParamAndStoreInVector(param_name.str(), asynParamInt8Array, &ST); + + param_name.str(""); + param_name << "HYB_" << hyb <<"_" << vmm << "_STH"; + createParamAndStoreInVector(param_name.str(), asynParamInt8Array, &STH); + + param_name.str(""); + param_name << "HYB_" << hyb <<"_" << vmm << "_SM"; + createParamAndStoreInVector(param_name.str(), asynParamInt8Array, &SM); + + param_name.str(""); + param_name << "HYB_" << hyb <<"_" << vmm << "_SMX"; + createParamAndStoreInVector(param_name.str(), asynParamInt8Array, &SMX); + + } + + this->vmmSC_.push_back(SC); + this->vmmSL_.push_back(SL); + this->vmmST_.push_back(ST); + this->vmmSTH_.push_back(STH); + this->vmmSM_.push_back(SM); + this->vmmSMX_.push_back(SMX); + } return asynSuccess; } asynStatus VMMTbl::writeInt32(asynUser *pasynUser, epicsInt32 value) { + asynStatus status = asynSuccess; + vmmStatus vmm_stat; int function = pasynUser->reason; + int param_index = -1; - if ((value) && (function == vmmProcessReadMonitorVMMs_)) { - int adc_sensor = 0; - for (int vmm = 0; vmm <= 1; vmm++) { - getIntegerParam(vmmSelectMonitorVMM0_ + vmm, &adc_sensor); - std::cout << "adc_sensor" << adc_sensor << std::endl; - pVmmAPI->getHybrid(0).getVMM(vmm).setRegister("sm5_sm0", adc_sensor + 64); - pVmmAPI->configVMM(0, vmm); - int adc_read = pVmmAPI->readADC(0, vmm); - - std::cout << "adc_read" << adc_read << std::endl; - - if (adc_sensor == 3) { - double temperature = (725 - adc_read) / 1.85; - setDoubleParam(vmmMonitorValueVMM0_ + vmm, temperature); - } - else { - setDoubleParam(vmmMonitorValueVMM0_ + vmm, adc_read); - } - } + // if (function == vmmAcquire_) { + + // if (value) pVmmAPI->acquire(true); + // else pVmmAPI->acquire(false); + + // for (int hyb = 0; hyb < number_hybrids; hyb++) + // setIntegerParam(vmmHybLinkStatus_[hyb], std::stoi(pVmmAPI->checkLinkStatus(hyb))); + // } + + if (function < FIRST_VMM_PARAM) { + return asynPortDriver::writeInt32(pasynUser, value); } - else if (function == vmmAcquire_) { - - if (value) pVmmAPI->acquire(true); - else pVmmAPI->acquire(false); + //Search for parameter in all parameter vectors. If found, execute correct function for specific hybrid. + param_index = VecUtils::getIndex(vmmHybSkew_, function); + if (param_index >= 0) { + vmm_stat = this->pVmmAPI->setSkew(param_index, value); + if (vmm_stat != vmmSuccess) status = asynError; + goto endOfWriteInt32; + } + + param_index = VecUtils::getIndex(vmmHybWidth_, function); + if (param_index >= 0) { + vmm_stat = this->pVmmAPI->setWidth(param_index, value); + if (vmm_stat != vmmSuccess) status = asynError; + goto endOfWriteInt32; + } + + param_index = VecUtils::getIndex(vmmHybPolarity_, function); + if (param_index >= 0) { + vmm_stat = this->pVmmAPI->setHybPolarity(param_index, value); + if (vmm_stat != vmmSuccess) status = asynError; + goto endOfWriteInt32; + } - for (int hyb = 0; hyb < number_hybrids; hyb++) - setIntegerParam(vmmHybLinkStatus_[hyb], std::stoi(pVmmAPI->checkLinkStatus(hyb))); + endOfWriteInt32: + if (param_index < 0) { + status = asynError; } + setIntegerParam(function, value); + callParamCallbacks(); + return status; + } -asynStatus VMMTbl::writeInt8Array(asynUser *pasynUser, epicsInt8 *value, size_t nElements) -{ +asynStatus VMMTbl::readInt8Array(asynUser *pasynUser, epicsInt8 *value, size_t nElements, size_t *nIn){ - int function, addr; - int ncopy = CHANNELS_PER_VMM; - const char *paramName; - const char *functionName = "writeInt8Array"; - int status = asynSuccess; - std::vector<epicsInt8> int8Array; - Reg pair; + int function, hyb_index, vmm_index, found_param = -10, status = 0; + bool data; + const char* paramName; - status |= parseAsynUser(pasynUser, &function, &addr, ¶mName); + function = pasynUser->reason; getParamName(function, ¶mName); - status |= findRegister(function, &pair); - if (status) { - asynPrint(pasynUser, ASYN_TRACE_ERROR, - "%s:%s: function=%d, name=%s, value=%d. Cannot find which Hybrid-VMM pair is function related to.\n", - driverName, functionName, function, paramName, *value); - return (asynStatus) status; + + if (function < FIRST_VMM_PARAM) return asynPortDriver::readInt8Array(pasynUser, value, nElements, nIn); + + found_param = VecUtils::getIndex(vmmST_, function, hyb_index, vmm_index); + if (found_param == 0) { + for (size_t i = 0; i < nElements; i++) { + status |= (int)this->pVmmAPI->getST(hyb_index, vmm_index, i, data); + value[i] = data; + } + goto endOfReadInt8Array; + } + + endOfReadInt8Array: + if (found_param != 0) { + asynPrint(pasynUserSelf, ASYN_TRACE_ERROR, + "%s:%s: Failed to find paramter %s, index %d.\n", + driverName, __FUNCTION__, paramName, function); + *nIn = 0; + return asynError; } - asynPrint(pasynUser, ASYN_TRACEIO_DRIVER, - "%s:%s: function=%d, name=%s, value=%d, hybrid=%d, vmm=%d, register=%s\n", - driverName, functionName, function, paramName, *value, pair.hyb, pair.vmm, pair.rg.c_str()); + *nIn = nElements; - for (epicsInt8 i = 0; i < ncopy; ++i) { - int8Array.push_back(static_cast<int>(value[i]) >= 1 ? 1 : 0); - pVmmAPI->getHybrid(pair.hyb).getVMM(pair.vmm).setRegister(pair.rg.c_str(), - static_cast<int>(value[i]), - i); + if (status) { + asynPrint(pasynUserSelf, ASYN_TRACE_ERROR, + "%s:%s: Failed to get paramter %s, index %d.\n", + driverName, __FUNCTION__, paramName, function); + return asynError; } - status |= doCallbacksInt8Array(int8Array.data(), int8Array.size(), function, 0); - return (asynStatus) status; + return asynSuccess; } -asynStatus VMMTbl::findRegister(int function, Reg *reg_){ +asynStatus VMMTbl::writeInt8Array(asynUser *pasynUser, epicsInt8 *value, size_t nElements) +{ - int (*array)[VMMS_PER_HYBRID]; - std::map<std::string, int(*)[VMMS_PER_HYBRID]>::iterator it; + int function, hyb_index, vmm_index, status = 0, found_param = -10; + const char* paramName; - it = this->registers.begin(); + function = pasynUser->reason; + getParamName(function, ¶mName); - while ( it != this->registers.end() ){ - std::string reg_name = it->first; - array = registers[reg_name]; + if (function < FIRST_VMM_PARAM) return asynPortDriver::writeInt8Array(pasynUser, value, nElements); - for (int h = 0; h < number_hybrids; h++){ - for (int v = 0; v < VMMS_PER_HYBRID; v++) - { - if (array[h][v] == function){ - reg_->hyb = h; - reg_->vmm = v; - reg_->rg = reg_name; - return asynSuccess; - } - } + found_param = VecUtils::getIndex(vmmST_, function, hyb_index, vmm_index); + if (found_param == 0) { + for (size_t i = 0; i < nElements; i++) { + status |= (int)this->pVmmAPI->setST(hyb_index, vmm_index, i, (bool)value[i]); } - - it++; + goto endOfWriteInt8Array; } - return asynError; + endOfWriteInt8Array: + status |= (int)doCallbacksInt8Array(value, nElements, function, 0); // Comparing different statuses, yes. + if (found_param != 0) { + asynPrint(pasynUserSelf, ASYN_TRACE_ERROR, + "%s:%s: Failed to find paramter %s, index %d.\n", + driverName, __FUNCTION__, paramName, function); + return asynError; + } -} + if (status) { + asynPrint(pasynUserSelf, ASYN_TRACE_ERROR, + "%s:%s: Failed to set paramter %s.\n", + driverName, __FUNCTION__, paramName); + return asynError; + } -asynStatus VMMTbl::writeFloat64(asynUser *pasynUser, epicsFloat64 value) { - asynStatus status = asynSuccess; - int addr = 0; - getAddress(pasynUser, &addr); + return asynSuccess; - return status; } extern "C" { diff --git a/vmmTblApp/src/vmm_tbl.h b/vmmTblApp/src/vmm_tbl.h index 597fd5c..83a573f 100644 --- a/vmmTblApp/src/vmm_tbl.h +++ b/vmmTblApp/src/vmm_tbl.h @@ -2,49 +2,65 @@ #include "rmm.h" #include "VMMAPI.h" +#include "Utils.h" -/* Struct to hold Hyb, VMM pair values */ -struct Reg { - int hyb = -1; - int vmm = -1; - std::string rg = "\0"; +/* Struct to hold Hyb, VMM and epics parameter values */ +struct ParamValues { + int param = -1; + std::string value; }; /** Class definition for the VMMTbl class */ class VMMTbl : public asynPortDriver { public: VMMTbl(RMM* rmm, const char *FENPortName, int ring, int node, int hybrids); + + /* Epics parameter management */ asynStatus createEpicsParams(); virtual asynStatus writeInt32(asynUser *pasynUser, epicsInt32 value); - virtual asynStatus writeFloat64(asynUser *pasynUser, epicsFloat64 value); + // virtual asynStatus writeFloat64(asynUser *pasynUser, epicsFloat64 value); virtual asynStatus writeInt8Array(asynUser *pasynUser, epicsInt8 *value, size_t nElements); - void setInitialEpicsParams(); - asynStatus findRegister(int function, Reg *reg_); + virtual asynStatus readInt8Array(asynUser *pasynUser, epicsInt8 *value, size_t nElements, size_t *nIn); + virtual asynStatus readInt32(asynUser *pasynUser, epicsInt32 *value); + virtual asynStatus readOctet(asynUser *pasynUser, char *value, size_t maxChars, size_t *nActual, int *eomReason); + asynStatus createParamAndStoreInVector(std::string paramName, asynParamType typ, + std::vector<int>* vectorToStore); protected: + int vmmRegBankVersion; +#define FIRST_VMM_PARAM vmmRegBankVersion int vmmSelectMonitorVMM0_; int vmmSelectMonitorVMM1_; int vmmProcessReadMonitorVMMs_; int vmmMonitorValueVMM0_; int vmmMonitorValueVMM1_; int vmmAcquire_; - int vmmHybFwVersion_[HYBRIDS_PER_FEN]; - int vmmHybId_[HYBRIDS_PER_FEN]; - int vmmHybGeoPos_[HYBRIDS_PER_FEN]; - int vmmHybLinkStatus_[HYBRIDS_PER_FEN]; - //Registers channels per hybrid, per VMM - int vmmST_[HYBRIDS_PER_FEN][VMMS_PER_HYBRID]; - int vmmSL_[HYBRIDS_PER_FEN][VMMS_PER_HYBRID]; - int vmmSC_[HYBRIDS_PER_FEN][VMMS_PER_HYBRID]; - int vmmSTH_[HYBRIDS_PER_FEN][VMMS_PER_HYBRID]; - int vmmSM_[HYBRIDS_PER_FEN][VMMS_PER_HYBRID]; - int vmmSMX_[HYBRIDS_PER_FEN][VMMS_PER_HYBRID]; - std::map<std::string, int(*)[VMMS_PER_HYBRID]> registers{{"st", vmmST_}, {"sc", vmmSC_}, - {"sl", vmmSL_}, {"sth", vmmSTH_}, - {"sm", vmmSM_}, {"smx", vmmSMX_}}; + std::vector<int> vmmHybFwVersion_; + std::vector<int> vmmHybId_; + std::vector<int> vmmHybGeoPos_; + std::vector<int> vmmHybLinkStatus_; + std::vector<int> vmmHybSkew_; + std::vector<int> vmmHybWidth_; + std::vector<int> vmmHybPolarity_; + std::vector<std::vector<int>> vmmSC_; + std::vector<std::vector<int>> vmmSL_; + std::vector<std::vector<int>> vmmST_; + std::vector<std::vector<int>> vmmSTH_; + std::vector<std::vector<int>> vmmSM_; + std::vector<std::vector<int>> vmmSD_; + std::vector<std::vector<int>> vmmSMX_; + // //Registers channels per hybrid, per VMM + // int vmmST_[HYBRIDS_PER_FEN][VMMS_PER_HYBRID]; + // int vmmSL_[HYBRIDS_PER_FEN][VMMS_PER_HYBRID]; + // int vmmSC_[HYBRIDS_PER_FEN][VMMS_PER_HYBRID]; + // int vmmSTH_[HYBRIDS_PER_FEN][VMMS_PER_HYBRID]; + // int vmmSM_[HYBRIDS_PER_FEN][VMMS_PER_HYBRID]; + // int vmmSMX_[HYBRIDS_PER_FEN][VMMS_PER_HYBRID]; + // std::map<std::string, int(*)[VMMS_PER_HYBRID]> registers{{"st", vmmST_}, {"sc", vmmSC_}, + // {"sl", vmmSL_}, {"sth", vmmSTH_}, + // {"sm", vmmSM_}, {"smx", vmmSMX_}}; private: static constexpr const char *driverName = "VMMTbl"; std::shared_ptr<VMMAPI> pVmmAPI; - int number_hybrids; }; -- GitLab