2 #include "otsdaq-epics/ControlsInterfacePlugins/EpicsInterface.h"
3 #include "otsdaq/Macros/SlowControlsPluginMacros.h"
4 #include "otsdaq/TablePlugins/SlowControlsTableBase/SlowControlsTableBase.h"
5 #include "otsdaq/ConfigurationInterface/ConfigurationManager.h"
8 #pragma GCC diagnostic push
21 #pragma GCC diagnostic pop
25 #define PV_FILE_NAME std::string(getenv("SERVICE_DATA_PATH")) + "/SlowControlsDashboardData/pv_list.dat";
26 #define PV_CSV_DIR "/home/mu2edcs/mu2e-dcs/make_db/csv";
30 const std::string EpicsInterface::EPICS_NO_ALARM =
"NO_ALARM";
31 const std::string EpicsInterface::EPICS_INVALID_ALARM =
"INVALID";
32 const std::string EpicsInterface::EPICS_MINOR_ALARM =
"MINOR";
33 const std::string EpicsInterface::EPICS_MAJOR_ALARM =
"MAJOR";
37 EpicsInterface::EpicsInterface(
const std::string& pluginType,
38 const std::string& interfaceUID,
39 const ConfigurationTree& theXDAQContextConfigTree,
40 const std::string& controlsConfigurationPath)
41 : SlowControlsVInterface(pluginType, interfaceUID, theXDAQContextConfigTree, controlsConfigurationPath)
44 SEVCHK(ca_context_create(ca_enable_preemptive_callback),
45 "EpicsInterface::EpicsInterface() : "
46 "ca_enable_preemptive_callback_init()");
49 EpicsInterface::~EpicsInterface() { destroy(); }
51 void EpicsInterface::destroy()
54 for(
auto it = mapOfPVInfo_.begin(); it != mapOfPVInfo_.end(); it++)
56 cancelSubscriptionToChannel(it->first);
57 destroyChannel(it->first);
58 delete(it->second->parameterPtr);
60 mapOfPVInfo_.erase(it);
64 SEVCHK(ca_poll(),
"EpicsInterface::destroy() : ca_poll");
69 void EpicsInterface::initialize()
71 __GEN_COUT__ <<
"Epics Interface now initializing!";
78 std::vector<std::string> EpicsInterface::getChannelList()
80 std::vector<std::string> pvList;
81 pvList.resize(mapOfPVInfo_.size());
82 for(
auto pv : mapOfPVInfo_)
84 __GEN_COUT__ <<
"getPVList() add: " + pv.first << __E__;
85 pvList.push_back(pv.first);
90 std::string EpicsInterface::getList(
const std::string& format)
94 std::string refreshRate =
"";
102 __GEN_COUT__ <<
"Epics Interface now retrieving pvList!";
106 __GEN_COUT__ <<
"Getting list in JSON format! There are " << mapOfPVInfo_.size() <<
" pv's.";
109 for(
auto it = mapOfPVInfo_.begin(); it != mapOfPVInfo_.end(); it++)
111 if(dcsArchiveDbConnStatus_ == 1)
113 res = PQexec(dcsArchiveDbConn, buffer);
114 snprintf(buffer,
sizeof(buffer),
"SELECT smpl_mode_id, smpl_per FROM channel WHERE name = '%s'", (it->first).c_str());
116 if(PQresultStatus(res) == PGRES_TUPLES_OK)
121 smplMode = std::stoi(PQgetvalue(res, 0, 0));
123 catch(
const std::exception& e)
127 refreshRate = PQgetvalue(res, 0, 1);
129 __GEN_COUT__ <<
"getList() \"sample rate\" SELECT result: " << it->first <<
":" << refreshRate <<
" (smpl_mode_id = " << smplMode <<
")"
134 __GEN_COUT__ <<
"SELECT failed: " << PQerrorMessage(dcsArchiveDbConn) << __E__;
139 pvList +=
"\"" + it->first +
"\", ";
142 pvList.resize(pvList.size() - 2);
144 __GEN_COUT__ << pvList << __E__;
150 void EpicsInterface::subscribe(
const std::string& pvName)
152 if(!checkIfPVExists(pvName))
154 __GEN_COUT__ << pvName <<
" doesn't exist!" << __E__;
157 createChannel(pvName);
159 subscribeToChannel(pvName, mapOfPVInfo_.find(pvName)->second->channelType);
166 void EpicsInterface::subscribeJSON(
const std::string& JSONNameString)
170 std::string JSON =
"{\"PVList\" :";
172 std::string pvList = JSONNameString;
174 if(pvList.find(JSON) != std::string::npos)
176 pvList = pvList.substr(pvList.find(JSON) + JSON.length(), std::string::npos);
179 pvList = pvList.substr(pvList.find(
"\"") + 1,
181 pvName = pvList.substr(0, pvList.find(
"\""));
183 pvList = pvList.substr(pvList.find(
"\"") + 1, std::string::npos);
186 if(checkIfPVExists(pvName))
188 createChannel(pvName);
189 subscribeToChannel(pvName, mapOfPVInfo_.find(pvName)->second->channelType);
190 SEVCHK(ca_poll(),
"EpicsInterface::subscribeJSON : ca_poll");
194 __GEN_COUT__ << pvName <<
" not found in file! Not subscribing!" << __E__;
197 }
while(pvList.find(
",") != std::string::npos);
203 void EpicsInterface::unsubscribe(
const std::string& pvName)
205 if(!checkIfPVExists(pvName))
207 __GEN_COUT__ << pvName <<
" doesn't exist!" << __E__;
211 cancelSubscriptionToChannel(pvName);
219 void EpicsInterface::eventCallback(
struct event_handler_args eha)
222 if(eha.status == ECA_NORMAL)
225 union db_access_val* pBuf = (
union db_access_val*)eha.dbr;
228 printf(
"channel %s: ", ca_name(eha.chid));
245 case DBR_CTRL_DOUBLE:
248 __COUT__ <<
"Response Type: DBR_CTRL_DOUBLE" << __E__;
251 ->writePVControlValueToRecord(ca_name(eha.chid),
252 ((
struct dbr_ctrl_double*)eha.dbr));
257 __COUT__ <<
"Response Type: DBR_DOUBLE" << __E__;
259 ((
EpicsInterface*)eha.usr)->writePVValueToRecord(ca_name(eha.chid),
260 std::to_string(*((
double*)eha.dbr)));
265 __COUT__ <<
"Response Type: DBR_STS_STRING" << __E__;
268 ->writePVAlertToQueue(ca_name(eha.chid), epicsAlarmConditionStrings[pBuf->sstrval.status], epicsAlarmSeverityStrings[pBuf->sstrval.severity]);
283 __COUT__ <<
"Response Type: DBR_STS_SHORT" << __E__;
286 ->writePVAlertToQueue(ca_name(eha.chid), epicsAlarmConditionStrings[pBuf->sshrtval.status], epicsAlarmSeverityStrings[pBuf->sshrtval.severity]);
300 __COUT__ <<
"Response Type: DBR_STS_FLOAT" << __E__;
303 ->writePVAlertToQueue(ca_name(eha.chid), epicsAlarmConditionStrings[pBuf->sfltval.status], epicsAlarmSeverityStrings[pBuf->sfltval.severity]);
317 __COUT__ <<
"Response Type: DBR_STS_ENUM" << __E__;
320 ->writePVAlertToQueue(ca_name(eha.chid), epicsAlarmConditionStrings[pBuf->senmval.status], epicsAlarmSeverityStrings[pBuf->senmval.severity]);
333 __COUT__ <<
"Response Type: DBR_STS_CHAR" << __E__;
336 ->writePVAlertToQueue(ca_name(eha.chid), epicsAlarmConditionStrings[pBuf->schrval.status], epicsAlarmSeverityStrings[pBuf->schrval.severity]);
350 __COUT__ <<
"Response Type: DBR_STS_LONG" << __E__;
353 ->writePVAlertToQueue(ca_name(eha.chid), epicsAlarmConditionStrings[pBuf->slngval.status], epicsAlarmSeverityStrings[pBuf->slngval.severity]);
367 __COUT__ <<
"Response Type: DBR_STS_DOUBLE" << __E__;
370 ->writePVAlertToQueue(ca_name(eha.chid), epicsAlarmConditionStrings[pBuf->sdblval.status], epicsAlarmSeverityStrings[pBuf->sdblval.severity]);
381 if(ca_name(eha.chid))
385 __COUT__ <<
" EpicsInterface::eventCallback: PV Name = " << ca_name(eha.chid) << __E__;
386 __COUT__ << (
char*)eha.dbr << __E__;
388 ((
EpicsInterface*)eha.usr)->writePVValueToRecord(ca_name(eha.chid),
396 printf(
"channel %s: get operation failed\n", ca_name(eha.chid));
401 void EpicsInterface::staticChannelCallbackHandler(
struct connection_handler_args cha)
403 __COUT__ <<
"webClientChannelCallbackHandler" << __E__;
409 void EpicsInterface::channelCallbackHandler(
struct connection_handler_args& cha)
412 if(cha.op == CA_OP_CONN_UP)
414 __GEN_COUT__ << pv << cha.chid <<
" connected! " << __E__;
416 mapOfPVInfo_.find(pv)->second->channelType = ca_field_type(cha.chid);
425 __GEN_COUT__ << pv <<
" disconnected!" << __E__;
430 bool EpicsInterface::checkIfPVExists(
const std::string& pvName)
434 __GEN_COUT__ <<
"EpicsInterface::checkIfPVExists(): PV Info Map Length is " << mapOfPVInfo_.size() << __E__;
437 if(mapOfPVInfo_.find(pvName) != mapOfPVInfo_.end())
443 void EpicsInterface::loadListOfPVs()
445 __GEN_COUT__ <<
"LOADING LIST OF PVS!!!!";
524 if(dcsArchiveDbConnStatus_ == 1)
529 std::string cluster =
"Mu2e";
531 __GEN_COUT__ <<
"Reading database PVS List" << __E__;
532 snprintf(buffer,
sizeof(buffer),
"SELECT COUNT(%s) FROM channel", std::string(
"channel_id").c_str());
533 res = PQexec(dcsArchiveDbConn, buffer);
535 if(PQresultStatus(res) == PGRES_TUPLES_OK)
538 rows = std::stoi(PQgetvalue(res, 0, 0));
540 for (
int i = 1; i <= rows; i++)
542 snprintf(buffer,
sizeof(buffer),
"SELECT name FROM channel WHERE channel_id = '%d'", i);
543 res = PQexec(dcsArchiveDbConn, buffer);
544 if(PQresultStatus(res) == PGRES_TUPLES_OK)
546 pv_name = PQgetvalue(res, 0, 0);
547 mapOfPVInfo_[pv_name] =
new PVInfo(DBR_STRING);
550 __GEN_COUT__ <<
"SELECT failed: mapOfPVInfo_ not filled for channel_id: "<< i << PQerrorMessage(dcsArchiveDbConn) << __E__;
552 __GEN_COUT__ <<
"Finished reading database PVs List!" << __E__;
557 __GEN_COUT__ <<
"SELECT failed: " << PQerrorMessage(dcsArchiveDbConn) << __E__;
562 __GEN_COUT__ <<
"Here is our pv list!" << __E__;
564 for(
auto pv : mapOfPVInfo_)
566 __GEN_COUT__ << pv.first << __E__;
579 __GEN_COUT__ <<
"Finished reading file and subscribing to pvs!" << __E__;
580 SEVCHK(ca_pend_event(0.0),
581 "EpicsInterface::subscribe() : ca_pend_event(0.0)");
586 void EpicsInterface::getControlValues(
const std::string& pvName)
590 __GEN_COUT__ <<
"EpicsInterface::getControlValues(" << pvName <<
")" << __E__;
592 if(!checkIfPVExists(pvName))
594 __GEN_COUT__ << pvName <<
" doesn't exist!" << __E__;
598 SEVCHK(ca_array_get_callback(
602 mapOfPVInfo_.find(pvName)->second->channelID,
605 "ca_array_get_callback");
610 void EpicsInterface::createChannel(
const std::string& pvName)
612 if(!checkIfPVExists(pvName))
614 __GEN_COUT__ << pvName <<
" doesn't exist!" << __E__;
617 __GEN_COUT__ <<
"Trying to create channel to " << pvName <<
":" << mapOfPVInfo_.find(pvName)->second->channelID << __E__;
619 if(mapOfPVInfo_.find(pvName)->second != NULL)
622 if(mapOfPVInfo_.find(pvName)->second->channelID != NULL)
626 if(ca_state(mapOfPVInfo_.find(pvName)->second->channelID) == cs_conn)
630 __GEN_COUT__ <<
"Channel to " << pvName <<
" already exists!" << __E__;
636 __GEN_COUT__ <<
"Channel to " << pvName <<
" exists, but is not connected! Destroying current channel." << __E__;
638 destroyChannel(pvName);
642 if(mapOfPVInfo_.find(pvName)->second->parameterPtr == NULL)
650 pvName.c_str(), staticChannelCallbackHandler, mapOfPVInfo_.find(pvName)->second->parameterPtr, 0, &(mapOfPVInfo_.find(pvName)->second->channelID)),
651 "EpicsInterface::createChannel() : ca_create_channel");
652 __GEN_COUT__ <<
"channelID: " << pvName << mapOfPVInfo_.find(pvName)->second->channelID << __E__;
654 SEVCHK(ca_replace_access_rights_event(mapOfPVInfo_.find(pvName)->second->channelID, accessRightsCallback),
655 "EpicsInterface::createChannel() : ca_replace_access_rights_event");
662 void EpicsInterface::destroyChannel(
const std::string& pvName)
664 if(mapOfPVInfo_.find(pvName)->second != NULL)
666 if(mapOfPVInfo_.find(pvName)->second->channelID != NULL)
668 status_ = ca_clear_channel(mapOfPVInfo_.find(pvName)->second->channelID);
669 SEVCHK(status_,
"EpicsInterface::destroyChannel() : ca_clear_channel");
670 if(status_ == ECA_NORMAL)
672 mapOfPVInfo_.find(pvName)->second->channelID = NULL;
675 __GEN_COUT__ <<
"Killed channel to " << pvName << __E__;
678 SEVCHK(ca_poll(),
"EpicsInterface::destroyChannel() : ca_poll");
684 __GEN_COUT__ <<
"No channel to " << pvName <<
" exists" << __E__;
691 void EpicsInterface::accessRightsCallback(
struct access_rights_handler_args args)
693 chid chid = args.chid;
695 printChidInfo(chid,
"EpicsInterface::createChannel() : accessRightsCallback");
698 void EpicsInterface::printChidInfo(chid chid,
const std::string& message)
700 __COUT__ << message.c_str() << __E__;
701 __COUT__ <<
"pv: " << ca_name(chid) <<
" type(" << ca_field_type(chid) <<
") nelements(" << ca_element_count(chid) <<
") host(" << ca_host_name(chid) <<
")"
703 __COUT__ <<
"read(" << ca_read_access(chid) <<
") write(" << ca_write_access(chid) <<
") state(" << ca_state(chid) <<
")" << __E__;
706 void EpicsInterface::subscribeToChannel(
const std::string& pvName, chtype )
708 if(!checkIfPVExists(pvName))
710 __GEN_COUT__ << pvName <<
" doesn't exist!" << __E__;
715 __GEN_COUT__ <<
"Trying to subscribe to " << pvName <<
":" << mapOfPVInfo_.find(pvName)->second->channelID << __E__;
718 if(mapOfPVInfo_.find(pvName)->second != NULL)
722 if(mapOfPVInfo_.find(pvName)->second->eventID != NULL)
726 __GEN_COUT__ <<
"Already subscribed to " << pvName <<
"!" << __E__;
740 SEVCHK(ca_create_subscription(dbf_type_to_DBR(mapOfPVInfo_.find(pvName)->second->channelType),
742 mapOfPVInfo_.find(pvName)->second->channelID,
743 DBE_VALUE | DBE_ALARM | DBE_PROPERTY,
746 &(mapOfPVInfo_.find(pvName)->second->eventID)),
747 "EpicsInterface::subscribeToChannel() : ca_create_subscription "
750 SEVCHK(ca_create_subscription(DBR_STS_DOUBLE,
752 mapOfPVInfo_.find(pvName)->second->channelID,
753 DBE_VALUE | DBE_ALARM | DBE_PROPERTY,
756 &(mapOfPVInfo_.find(pvName)->second->eventID)),
757 "EpicsInterface::subscribeToChannel() : ca_create_subscription "
760 SEVCHK(ca_create_subscription(DBR_CTRL_DOUBLE,
762 mapOfPVInfo_.find(pvName)->second->channelID,
763 DBE_VALUE | DBE_ALARM | DBE_PROPERTY,
766 &(mapOfPVInfo_.find(pvName)->second->eventID)),
767 "EpicsInterface::subscribeToChannel() : ca_create_subscription");
771 __GEN_COUT__ <<
"EpicsInterface::subscribeToChannel: Created Subscription to " << mapOfPVInfo_.find(pvName)->first <<
"!\n" << __E__;
777 void EpicsInterface::cancelSubscriptionToChannel(
const std::string& pvName)
779 if(mapOfPVInfo_.find(pvName)->second != NULL)
780 if(mapOfPVInfo_.find(pvName)->second->eventID != NULL)
782 status_ = ca_clear_subscription(mapOfPVInfo_.find(pvName)->second->eventID);
784 "EpicsInterface::cancelSubscriptionToChannel() : "
785 "ca_clear_subscription");
786 if(status_ == ECA_NORMAL)
788 mapOfPVInfo_.find(pvName)->second->eventID = NULL;
791 __GEN_COUT__ <<
"Killed subscription to " << pvName << __E__;
794 SEVCHK(ca_poll(),
"EpicsInterface::cancelSubscriptionToChannel() : ca_poll");
800 __GEN_COUT__ << pvName <<
"does not have a subscription!" << __E__;
811 void EpicsInterface::readValueFromPV(
const std::string& )
820 void EpicsInterface::writePVControlValueToRecord(
const std::string& pvName,
823 struct dbr_ctrl_double* pdata)
827 __GEN_COUT__ <<
"Reading Control Values from " << pvName <<
"!" << __E__;
830 if(!checkIfPVExists(pvName))
832 __GEN_COUT__ << pvName <<
" doesn't exist!" << __E__;
835 mapOfPVInfo_.find(pvName)->second->settings = *pdata;
839 __GEN_COUT__ <<
"pvName: " << pvName << __E__;
840 __GEN_COUT__ <<
"status: " << pdata->status << __E__;
841 __GEN_COUT__ <<
"severity: " << pdata->severity << __E__;
842 __GEN_COUT__ <<
"units: " << pdata->units << __E__;
843 __GEN_COUT__ <<
"upper disp limit: " << (int)(pdata->upper_disp_limit) << __E__;
844 __GEN_COUT__ <<
"lower disp limit: " << pdata->lower_disp_limit << __E__;
845 __GEN_COUT__ <<
"upper alarm limit: " << pdata->upper_alarm_limit << __E__;
846 __GEN_COUT__ <<
"upper warning limit: " << pdata->upper_warning_limit << __E__;
847 __GEN_COUT__ <<
"lower warning limit: " << pdata->lower_warning_limit << __E__;
848 __GEN_COUT__ <<
"lower alarm limit: " << pdata->lower_alarm_limit << __E__;
849 __GEN_COUT__ <<
"upper control limit: " << pdata->upper_ctrl_limit << __E__;
850 __GEN_COUT__ <<
"lower control limit: " << pdata->lower_ctrl_limit << __E__;
852 __GEN_COUT__ <<
"Value: " << pdata->value << __E__;
858 void EpicsInterface::writePVValueToRecord(
const std::string& pvName,
const std::string& pdata)
860 std::pair<time_t, std::string> currentRecord(time(0), pdata);
862 if(!checkIfPVExists(pvName))
864 __GEN_COUT__ << pvName <<
" doesn't exist!" << __E__;
869 PVInfo* pvInfo = mapOfPVInfo_.find(pvName)->second;
871 if(pvInfo->mostRecentBufferIndex != pvInfo->dataCache.size() - 1 && pvInfo->mostRecentBufferIndex != (
unsigned int)(-1))
873 if(pvInfo->dataCache[pvInfo->mostRecentBufferIndex].first == currentRecord.first)
875 pvInfo->valueChange =
true;
879 pvInfo->valueChange =
true;
882 ++pvInfo->mostRecentBufferIndex;
883 pvInfo->dataCache[pvInfo->mostRecentBufferIndex] = currentRecord;
887 pvInfo->dataCache[0] = currentRecord;
888 pvInfo->mostRecentBufferIndex = 0;
895 void EpicsInterface::writePVAlertToQueue(
const std::string& pvName,
const char* status,
const char* severity)
897 if(!checkIfPVExists(pvName))
899 __GEN_COUT__ << pvName <<
" doesn't exist!" << __E__;
902 PVAlerts alert(time(0), status, severity);
903 mapOfPVInfo_.find(pvName)->second->alerts.push(alert);
912 void EpicsInterface::readPVRecord(
const std::string& pvName)
914 status_ = ca_array_get_callback(dbf_type_to_DBR_STS(mapOfPVInfo_.find(pvName)->second->channelType),
915 ca_element_count(mapOfPVInfo_.find(pvName)->second->channelID),
916 mapOfPVInfo_.find(pvName)->second->channelID,
919 SEVCHK(status_,
"EpicsInterface::readPVRecord(): ca_array_get_callback");
923 void EpicsInterface::debugConsole(
const std::string& pvName)
925 __GEN_COUT__ <<
"==============================================================="
928 for(
unsigned int it = 0; it < mapOfPVInfo_.find(pvName)->second->dataCache.size() - 1; it++)
930 if(it == mapOfPVInfo_.find(pvName)->second->mostRecentBufferIndex)
932 __GEN_COUT__ <<
"-----------------------------------------------------------"
936 __GEN_COUT__ <<
"Iteration: " << it <<
" | " << mapOfPVInfo_.find(pvName)->second->mostRecentBufferIndex <<
" | "
937 << mapOfPVInfo_.find(pvName)->second->dataCache[it].second << __E__;
938 if(it == mapOfPVInfo_.find(pvName)->second->mostRecentBufferIndex)
940 __GEN_COUT__ <<
"-----------------------------------------------------------"
945 __GEN_COUT__ <<
"==============================================================="
948 __GEN_COUT__ <<
"Status: "
949 <<
" | " << mapOfPVInfo_.find(pvName)->second->alerts.size() <<
" | " << mapOfPVInfo_.find(pvName)->second->alerts.front().status << __E__;
950 __GEN_COUT__ <<
"Severity: "
951 <<
" | " << mapOfPVInfo_.find(pvName)->second->alerts.size() <<
" | " << mapOfPVInfo_.find(pvName)->second->alerts.front().severity << __E__;
952 __GEN_COUT__ <<
"==============================================================="
959 void EpicsInterface::popQueue(
const std::string& pvName)
963 __GEN_COUT__ <<
"EpicsInterface::popQueue() " << __E__;
965 mapOfPVInfo_.find(pvName)->second->alerts.pop();
967 if(mapOfPVInfo_.find(pvName)->second->alerts.empty())
969 readPVRecord(pvName);
970 SEVCHK(ca_poll(),
"EpicsInterface::popQueue() : ca_poll");
976 std::array<std::string, 4> EpicsInterface::getCurrentValue(
const std::string& pvName)
978 __GEN_COUT__ <<
"void EpicsInterface::getCurrentValue() reached" << __E__;
980 if(mapOfPVInfo_.find(pvName) != mapOfPVInfo_.end())
982 PVInfo* pv = mapOfPVInfo_.find(pvName)->second;
983 std::string time, value, status, severity;
985 int index = pv->mostRecentBufferIndex;
987 __GEN_COUT__ << pv << index << __E__;
989 if(0 <= index && index < pv->circularBufferSize)
994 time = std::to_string(pv->dataCache[index].first);
995 value = pv->dataCache[index].second;
996 status = pv->alerts.back().status;
997 severity = pv->alerts.back().severity;
1011 severity =
"INVALID";
1015 __GEN_COUT__ <<
"Index: " << index << __E__;
1016 __GEN_COUT__ <<
"Time: " << time << __E__;
1017 __GEN_COUT__ <<
"Value: " << value << __E__;
1018 __GEN_COUT__ <<
"Status: " << status << __E__;
1019 __GEN_COUT__ <<
"Severity: " << severity << __E__;
1034 std::array<std::string, 4> currentValues = {time, value, status, severity};
1036 return currentValues;
1040 __GEN_COUT__ << pvName <<
" was not found!" << __E__;
1041 __GEN_COUT__ <<
"Trying to resubscribe to " << pvName << __E__;
1045 std::array<std::string, 4> currentValues = {
"PV Not Found",
"NF",
"N/a",
"N/a"};
1047 return currentValues;
1051 std::array<std::string, 9> EpicsInterface::getSettings(
const std::string& pvName)
1053 __GEN_COUT__ <<
"EpicsInterface::getPVSettings() reached" << __E__;
1055 if(mapOfPVInfo_.find(pvName) != mapOfPVInfo_.end())
1057 std::string units =
"DC'd", upperDisplayLimit =
"DC'd", lowerDisplayLimit =
"DC'd", upperAlarmLimit =
"DC'd", upperWarningLimit =
"DC'd",
1058 lowerWarningLimit =
"DC'd", lowerAlarmLimit =
"DC'd", upperControlLimit =
"DC'd", lowerControlLimit =
"DC'd";
1059 if(mapOfPVInfo_.find(pvName)->second != NULL)
1062 if(mapOfPVInfo_.find(pvName)->second->channelID != NULL)
1066 dbr_ctrl_double* set = &mapOfPVInfo_.find(pvName)->second->settings;
1070 upperDisplayLimit = std::to_string(set->upper_disp_limit);
1071 lowerDisplayLimit = std::to_string(set->lower_disp_limit);
1072 upperWarningLimit = std::to_string(set->upper_warning_limit);
1073 lowerWarningLimit = std::to_string(set->lower_warning_limit);
1074 upperAlarmLimit = std::to_string(set->upper_alarm_limit);
1075 lowerAlarmLimit = std::to_string(set->lower_alarm_limit);
1076 upperControlLimit = std::to_string(set->upper_ctrl_limit);
1077 lowerControlLimit = std::to_string(set->lower_ctrl_limit);
1079 __GEN_COUT__ <<
"Units : " << units << __E__;
1080 __GEN_COUT__ <<
"Upper Display Limit: " << upperDisplayLimit << __E__;
1081 __GEN_COUT__ <<
"Lower Display Limit: " << lowerDisplayLimit << __E__;
1082 __GEN_COUT__ <<
"Upper Alarm Limit : " << upperAlarmLimit << __E__;
1083 __GEN_COUT__ <<
"Upper Warning Limit: " << upperWarningLimit << __E__;
1084 __GEN_COUT__ <<
"Lower Warning Limit: " << lowerWarningLimit << __E__;
1085 __GEN_COUT__ <<
"Lower Alarm Limit : " << lowerAlarmLimit << __E__;
1086 __GEN_COUT__ <<
"Upper Control Limit: " << upperControlLimit << __E__;
1087 __GEN_COUT__ <<
"Lower Control Limit: " << lowerControlLimit << __E__;
1090 std::array<std::string, 9> s = {units,
1104 __GEN_COUT__ << pvName <<
" was not found!" << __E__;
1105 __GEN_COUT__ <<
"Trying to resubscribe to " << pvName << __E__;
1108 std::array<std::string, 9> s = {
"DC'd",
"DC'd",
"DC'd",
"DC'd",
"DC'd",
"DC'd",
"DC'd",
"DC'd",
"DC'd"};
1113 void EpicsInterface::dbSystemLogin()
1115 dcsArchiveDbConnStatus_ = 0;
1116 dcsAlarmDbConnStatus_ = 0;
1117 dcsLogDbConnStatus_ = 0;
1120 dcsArchiveDbConn = PQconnectdb(
1124 "dbname=dcs_archive host=mu2edaq15 port=5434 "
1125 "user=dcs_writer password=Write4Dcs");
1127 if(PQstatus(dcsArchiveDbConn) == CONNECTION_BAD)
1129 __GEN_COUT__ <<
"Unable to connect to the dcs_archive database!\n" << __E__;
1130 PQfinish(dcsArchiveDbConn);
1134 __GEN_COUT__ <<
"Connected to the dcs_archive database!\n" << __E__;
1135 dcsArchiveDbConnStatus_ = 1;
1139 dcsAlarmDbConn = PQconnectdb(
1143 "dbname=dcs_alarm host=mu2edaq15 port=5434 "
1144 "user=dcs_reader password=Read4Dcs");
1146 if(PQstatus(dcsAlarmDbConn) == CONNECTION_BAD)
1148 __GEN_COUT__ <<
"Unable to connect to the dcs_alarm database!\n" << __E__;
1149 PQfinish(dcsAlarmDbConn);
1153 __GEN_COUT__ <<
"Connected to the dcs_alarm database!\n" << __E__;
1154 dcsAlarmDbConnStatus_ = 1;
1158 dcsLogDbConn = PQconnectdb(
1162 "dbname=dcs_log host=mu2edaq15 port=5434 "
1163 "user=dcs_reader password=Read4Dcs");
1165 if(PQstatus(dcsLogDbConn) == CONNECTION_BAD)
1167 __GEN_COUT__ <<
"Unable to connect to the dcs_log database!\n" << __E__;
1168 PQfinish(dcsLogDbConn);
1172 __GEN_COUT__ <<
"Connected to the dcs_log database!\n" << __E__;
1173 dcsLogDbConnStatus_ = 1;
1178 void EpicsInterface::dbSystemLogout()
1180 if(PQstatus(dcsArchiveDbConn) == CONNECTION_OK)
1182 PQfinish(dcsArchiveDbConn);
1183 __GEN_COUT__ <<
"DCS_ARCHIVE DB CONNECTION CLOSED\n" << __E__;
1185 if(PQstatus(dcsAlarmDbConn) == CONNECTION_OK)
1187 PQfinish(dcsAlarmDbConn);
1188 __GEN_COUT__ <<
"DCS_ALARM DB CONNECTION CLOSED\n" << __E__;
1190 if(PQstatus(dcsLogDbConn) == CONNECTION_OK)
1192 PQfinish(dcsLogDbConn);
1193 __GEN_COUT__ <<
"DCS_LOG DB CONNECTION CLOSED\n" << __E__;
1198 std::vector<std::vector<std::string>> EpicsInterface::getChannelHistory(
const std::string& pvName)
1200 __GEN_COUT__ <<
"getChannelHistory() reached" << __E__;
1201 std::vector<std::vector<std::string>> history;
1203 if(mapOfPVInfo_.find(pvName) != mapOfPVInfo_.end())
1205 if(dcsArchiveDbConnStatus_ == 1)
1207 PGresult* res =
nullptr;
1216 "SELECT FLOOR(EXTRACT(EPOCH FROM smpl_time)), float_val, status.name, "
1217 "severity.name, smpl_per FROM channel, sample, status, severity WHERE "
1218 "channel.channel_id = sample.channel_id AND sample.severity_id = "
1219 "severity.severity_id AND sample.status_id = status.status_id AND "
1220 "channel.name = \'%s\' ORDER BY smpl_time desc LIMIT 10",
1223 res = PQexec(dcsArchiveDbConn, buffer);
1225 if(PQresultStatus(res) != PGRES_TUPLES_OK)
1227 __SS__ <<
"getChannelHistory(): SELECT FROM ARCHIVER DATABASE FAILED!!! PQ ERROR: "
1228 << PQresultErrorMessage(res) << __E__;
1233 if(PQntuples(res) > 0)
1236 int nFields = PQnfields(res);
1237 history.resize(PQntuples(res));
1240 for(
int i = 0; i < PQntuples(res); i++)
1242 history[i].resize(nFields);
1243 for(
int j = 0; j < nFields; j++)
1245 history[i][j] = PQgetvalue(res, i, j);
1246 row.append(PQgetvalue(res, i, j));
1251 __GEN_COUT__ << row << __E__;
1257 __SS__ <<
"getChannelHistory(): FAILING GETTING DATA FROM ARCHIVER DATABASE!!! PQ ERROR: "
1258 << PQresultErrorMessage(res) << __E__;
1264 __SS__ <<
"getChannelHistory(): ARCHIVER DATABASE CONNECTION FAILED!!! " << __E__;
1271 history[0] = {
"PV Not Found",
"NF",
"N/a",
"N/a"};
1272 __GEN_COUT__ <<
"getChannelHistory() pvName " << pvName <<
" was not found!" << __E__;
1273 __GEN_COUT__ <<
"Trying to resubscribe to " << pvName << __E__;
1281 std::vector<std::vector<std::string>> EpicsInterface::getLastAlarms(
const std::string& pvName)
1283 __GEN_COUT__ <<
"EpicsInterface::getLastAlarms() reached" << __E__;
1284 std::vector<std::vector<std::string>> alarms;
1286 if(dcsAlarmDbConnStatus_ == 1)
1288 PGresult* res =
nullptr;
1295 snprintf(buffer,
sizeof(buffer),
1296 "SELECT pv.component_id \
1300 , status.name as status \
1301 , severity.name as severity \
1304 , pv.annunciate_ind \
1309 , pv.act_global_alarm_ind \
1310 FROM alarm_tree, pv, status, severity \
1311 WHERE pv.component_id = alarm_tree.component_id \
1312 AND pv.status_id = status.status_id \
1313 AND pv.severity_id = severity.severity_id \
1314 AND alarm_tree.name LIKE \'%%%s%%\' \
1315 ORDER BY pv.severity_id DESC;", pvName.c_str());
1317 res = PQexec(dcsAlarmDbConn, buffer);
1318 __COUT__ <<
"getLastAlarms(): SELECT pv table PQntuples(res): " << PQntuples(res) << __E__;
1320 if(PQresultStatus(res) != PGRES_TUPLES_OK)
1322 __SS__ <<
"getLastAlarms(): SELECT FROM ALARM DATABASE FAILED!!! PQ ERROR: "
1323 << PQresultErrorMessage(res) << __E__;
1328 if(PQntuples(res) > 0)
1331 int nFields = PQnfields(res);
1332 alarms.resize(PQntuples(res));
1335 for(
int i = 0; i < PQntuples(res); i++)
1337 alarms[i].resize(nFields);
1338 for(
int j = 0; j < nFields; j++)
1340 alarms[i][j] = PQgetvalue(res, i, j);
1341 row.append(PQgetvalue(res, i, j));
1353 "Alarms List Not Found",
1373 __SS__ <<
"getLastAlarms(): FAILING GETTING DATA FROM ARCHIVER DATABASE!!! PQ ERROR: "
1374 << PQresultErrorMessage(res) << __E__;
1380 __SS__ <<
"getLastAlarms(): ALARM DATABASE CONNECTION FAILED!!! " << __E__;
1387 std::vector<std::vector<std::string>> EpicsInterface::getAlarmsLog(
const std::string& pvName)
1389 __GEN_COUT__ <<
"EpicsInterface::getAlarmsLog() reached" << __E__;
1390 std::vector<std::vector<std::string>> alarmsHistory;
1392 if(dcsLogDbConnStatus_ == 1)
1394 PGresult* res =
nullptr;
1401 snprintf(buffer,
sizeof(buffer),
1405 , message_content.value \
1406 , msg_property_type.name as \"status\" \
1407 , message.severity \
1408 , message.datum as \"time\" \
1409 FROM message, message_content, msg_property_type \
1410 WHERE message.id = message_content.message_id \
1411 AND message_content.msg_property_type_id = msg_property_type.id \
1412 AND message.type = 'alarm' \
1413 AND message.severity != 'OK' \
1414 AND message.datum >= current_date -20 \
1415 AND message.name LIKE '%%%s%%' \
1416 ORDER BY message.datum DESC;", pvName.c_str());
1418 res = PQexec(dcsLogDbConn, buffer);
1419 __COUT__ <<
"getAlarmsLog(): SELECT message table PQntuples(res): " << PQntuples(res) << __E__;
1421 if(PQresultStatus(res) != PGRES_TUPLES_OK)
1423 __SS__ <<
"getAlarmsLog(): SELECT FROM ALARM LOG DATABASE FAILED!!! PQ ERROR: " << PQresultErrorMessage(res) << __E__;
1428 if(PQntuples(res) > 0)
1431 int nFields = PQnfields(res);
1432 alarmsHistory.resize(PQntuples(res));
1435 for(
int i = 0; i < PQntuples(res); i++)
1437 alarmsHistory[i].resize(nFields);
1438 for(
int j = 0; j < nFields; j++)
1440 alarmsHistory[i][j] = PQgetvalue(res, i, j);
1441 row.append(PQgetvalue(res, i, j));
1450 alarmsHistory.resize(1);
1451 alarmsHistory[0] = {
1453 "Alarms List Not Found",
1465 __SS__ <<
"getAlarmsLog(): FAILING GETTING DATA FROM ARCHIVER DATABASE!!! PQ ERROR: "
1466 << PQresultErrorMessage(res) << __E__;
1472 __SS__ <<
"getAlarmsLog(): ALARM LOG DATABASE CONNECTION FAILED!!! " << __E__;
1475 return alarmsHistory;
1485 std::vector<std::string> EpicsInterface::checkAlarm(
const std::string& pvName,
bool ignoreMinor )
1487 __COUT__ <<
"checkAlarm()" << __E__;
1489 auto pvIt = mapOfPVInfo_.find(pvName);
1490 if(pvIt == mapOfPVInfo_.end())
1492 __SS__ <<
"While checking for alarm status, PV name '" << pvName <<
"' was not found in PV list!" << __E__;
1496 auto valueArray = getCurrentValue(pvIt->first);
1498 std::string& time = valueArray[0];
1499 std::string& value = valueArray[1];
1500 std::string& status = valueArray[2];
1501 std::string& severity = valueArray[3];
1506 __COUTV__(severity);
1507 if(severity == EPICS_NO_ALARM || (ignoreMinor && severity == EPICS_MINOR_ALARM))
1508 return std::vector<std::string>();
1511 return std::vector<std::string>({pvIt->first, time, value, status, severity});
1516 std::vector<std::vector<std::string>> EpicsInterface::checkAlarmNotifications()
1518 std::vector<std::vector<std::string>> alarmReturn;
1519 std::vector<std::string> alarmRow;
1520 auto linkToAlarmsToNotify = getSelfNode().getNode(
"LinkToAlarmAlertNotificationsTable");
1522 if(!linkToAlarmsToNotify.isDisconnected())
1524 auto alarmsToNotifyGroups = linkToAlarmsToNotify.getChildren();
1526 for(
const auto& alarmsToNotifyGroup : alarmsToNotifyGroups)
1528 __COUT__ <<
"checkAlarmNotifications() alarmsToNotifyGroup: " << alarmsToNotifyGroup.first << __E__;
1530 auto alarmsToNotify = alarmsToNotifyGroup.second.getNode(
"LinkToAlarmsToMonitorTable");
1531 if(!alarmsToNotify.isDisconnected())
1533 for(
const auto& alarmToNotify : alarmsToNotify.getChildren())
1535 __COUT__ <<
"checkAlarmNotifications() alarmToNotify: " << alarmToNotify.first << __E__;
1537 alarmRow = checkAlarm(alarmToNotify.second.getNode(
"AlarmChannelName").getValue<std::string>(),
1538 alarmToNotify.second.getNode(
"IgnoreMinorSeverity").getValue<
bool>());
1539 alarmRow.push_back(alarmToNotify.first);
1540 alarmRow.push_back(alarmsToNotifyGroup.second.getNode(
"WhoToNotify").getValue<std::string>());
1541 alarmRow.push_back(alarmsToNotifyGroup.second.getNode(
"DoSendEmail").getValue<std::string>());
1542 alarmRow.push_back(alarmsToNotifyGroup.first);
1543 alarmReturn.push_back(alarmRow);
1562 void EpicsInterface::handleAlarmsForFSM(
const std::string& fsmTransitionName, ConfigurationTree linkToAlarmsToMonitor)
1564 if(!linkToAlarmsToMonitor.isDisconnected())
1566 auto alarmsToMonitor = linkToAlarmsToMonitor.getChildren();
1570 ss <<
"During '" << fsmTransitionName <<
"'... Alarms monitoring (count=" << alarmsToMonitor.size() <<
"):" << __E__;
1571 for(
const auto& alarmToMonitor : alarmsToMonitor)
1572 ss <<
"\t" << alarmToMonitor.first << __E__;
1575 unsigned foundCount = 0;
1576 for(
const auto& alarmToMonitor : alarmsToMonitor)
1578 std::vector<std::string> alarmReturn = checkAlarm(alarmToMonitor.second.getNode(
"AlarmChannelName").getValue<std::string>(),
1579 alarmToMonitor.second.getNode(
"IgnoreMinorSeverity").getValue<
bool>());
1581 if(alarmReturn.size())
1583 ss <<
"Found alarm for channel '" << alarmReturn[0] <<
"' = {"
1584 <<
"time=" << alarmReturn[1] <<
", value=" << alarmReturn[2] <<
", status=" << alarmReturn[3] <<
", severity=" << alarmReturn[4] <<
"}!"
1591 ss << __E__ <<
"Total alarms found = " << foundCount << __E__;
1594 __COUT__ << ss.str();
1597 __COUT__ <<
"Disconnected alarms to monitor!" << __E__;
1603 void EpicsInterface::configure()
1605 handleAlarmsForFSM(
"configure", getSelfNode().getNode(
"LinkToConfigureAlarmsToMonitorTable"));
1607 __COUT__ <<
"configure(): Preparing EPICS for PVs..." << __E__;
1615 std::string slowControlsChannelsSourceTablesString =
1616 getSelfNode().getNode(
"SlowControlsChannelSourceTableList").getValueWithDefault<std::string>(
"");
1618 __COUTV__(slowControlsChannelsSourceTablesString);
1620 std::vector<std::string> slowControlsChannelsSourceTables =
1621 StringMacros::getVectorFromString(slowControlsChannelsSourceTablesString);
1622 __COUTV__(StringMacros::vectorToString(slowControlsChannelsSourceTables));
1624 for(
const auto& slowControlsChannelsSourceTable:slowControlsChannelsSourceTables)
1626 __COUTV__(slowControlsChannelsSourceTable);
1628 const SlowControlsTableBase* slowControlsTable =
1629 getConfigurationManager()->getTable<SlowControlsTableBase>(slowControlsChannelsSourceTable);
1631 if(slowControlsTable->slowControlsChannelListHasChanged())
1633 __COUT__ <<
"configure(): Handling channel list change!" << __E__;
1635 std::vector<std::pair<std::string, std::vector<std::string>>> channels;
1636 slowControlsTable->getSlowControlsChannelList(channels);
1638 for(
const auto& channel : channels)
1640 std::string pvName = channel.first;
1641 std::string descr = channel.second.at(0);
1643 int smpl_mode_id = 1;
1644 double smpl_val = 0.;
1645 double smpl_per = 60.;
1646 int retent_id = 9999;
1647 double retent_val = 9999.;
1649 double low_disp_rng = 0.;
1650 double high_disp_rng = 0.;
1651 double low_warn_lmt = atof(channel.second.at(1).c_str());
1652 double high_warn_lmt = atof(channel.second.at(2).c_str());
1653 double low_alarm_lmt = atof(channel.second.at(3).c_str());
1654 double high_alarm_lmt = atof(channel.second.at(4).c_str());
1655 int prec = atoi(channel.second.at(5).c_str());
1656 std::string unit = channel.second.at(6);
1658 if(!checkIfPVExists(pvName))
1660 mapOfPVInfo_[pvName] =
new PVInfo(DBR_STRING);
1661 __COUT__ <<
"configure(): new PV '" << pvName <<
"' found! Now subscribing" << __E__;
1665 if(dcsArchiveDbConnStatus_ == 1)
1672 snprintf(buffer,
sizeof(buffer),
1673 "SELECT name FROM channel WHERE name = '%s';", pvName.c_str());
1675 res = PQexec(dcsArchiveDbConn, buffer);
1676 __COUT__ <<
"configure(): SELECT channel table PQntuples(res): " << PQntuples(res) << __E__;
1678 if(PQresultStatus(res) != PGRES_TUPLES_OK)
1680 __SS__ <<
"configure(): SELECT FOR DATABASE CHANNEL TABLE FAILED!!! PV Name: "
1681 << pvName <<
" PQ ERROR: " << PQresultErrorMessage(res) << __E__;
1686 if(PQntuples(res) > 0)
1690 __COUT__ <<
"configure(): Updating PV: " << pvName <<
" in the Archiver Database channel table" << __E__;
1691 snprintf(buffer,
sizeof(buffer),
1692 "UPDATE channel SET \
1700 , grp_id, smpl_mode_id, smpl_val, smpl_per, retent_id, retent_val, pvName.c_str());
1703 res = PQexec(dcsArchiveDbConn, buffer);
1705 if(PQresultStatus(res) != PGRES_COMMAND_OK)
1707 __SS__ <<
"configure(): CHANNEL UPDATE INTO DATABASE CHANNEL TABLE FAILED!!! PV Name: "
1708 << pvName <<
" PQ ERROR: " << PQresultErrorMessage(res) << __E__;
1718 __COUT__ <<
"configure(): Writing new PV in the Archiver Database channel table" << __E__;
1719 snprintf(buffer,
sizeof(buffer),
1720 "INSERT INTO channel( \
1729 VALUES ('%s', '%s', %d, %d, %f, %f, %d, %f);", pvName.c_str() ,descr.c_str(), grp_id, smpl_mode_id, smpl_val, smpl_per, retent_id, retent_val);
1731 res = PQexec(dcsArchiveDbConn, buffer);
1732 if(PQresultStatus(res) != PGRES_COMMAND_OK)
1734 __SS__ <<
"configure(): CHANNEL INSERT INTO DATABASE CHANNEL TABLE FAILED!!! PV Name: "
1735 << pvName <<
" PQ ERROR: " << PQresultErrorMessage(res) << __E__;
1743 snprintf(buffer,
sizeof(buffer),
1744 "SELECT channel.channel_id FROM channel, num_metadata WHERE channel.channel_id = num_metadata.channel_id AND channel.name = '%s';", pvName.c_str());
1746 res = PQexec(dcsArchiveDbConn, buffer);
1747 __COUT__ <<
"configure(): SELECT num_metadata table PQntuples(res): " << PQntuples(res) << __E__;
1749 if(PQresultStatus(res) != PGRES_TUPLES_OK)
1751 __SS__ <<
"configure(): SELECT FOR DATABASE NUM_METADATA TABLE FAILED!!! PV Name: "
1752 << pvName <<
" PQ ERROR: " << PQresultErrorMessage(res) << __E__;
1757 if(PQntuples(res) > 0)
1760 std::string channel_id = PQgetvalue(res, 0, 0);
1761 __COUT__ <<
"configure(): Updating PV: " << pvName
1762 <<
" channel_id: " << channel_id <<
" in the Archiver Database num_metadata table" << __E__;
1764 snprintf(buffer,
sizeof(buffer),
1765 "UPDATE num_metadata SET \
1767 , high_disp_rng=%f \
1769 , high_warn_lmt=%f \
1770 , low_alarm_lmt=%f \
1771 , high_alarm_lmt=%f \
1774 WHERE channel_id='%s';",low_disp_rng, high_disp_rng, low_warn_lmt, high_warn_lmt, low_alarm_lmt, high_alarm_lmt, prec, unit.c_str(), channel_id.c_str());
1776 res = PQexec(dcsArchiveDbConn, buffer);
1777 if(PQresultStatus(res) != PGRES_COMMAND_OK)
1779 __SS__ <<
"configure(): CHANNEL UPDATE INTO DATABASE NUM_METADATA TABLE FAILED!!! PV Name(channel_id): "
1780 << pvName <<
" " << channel_id
1781 <<
" PQ ERROR: " << PQresultErrorMessage(res) << __E__;
1790 snprintf(buffer,
sizeof(buffer),
"SELECT channel_id FROM channel WHERE name = '%s';", pvName.c_str());
1792 res = PQexec(dcsArchiveDbConn, buffer);
1793 __COUT__ <<
"configure(): SELECT channel table to check channel_id for num_metadata table. PQntuples(res): " << PQntuples(res) << __E__;
1795 if(PQresultStatus(res) != PGRES_TUPLES_OK)
1797 __SS__ <<
"configure(): SELECT TO DATABASE CHANNEL TABLE FOR NUM_MATADATA TABLE FAILED!!! PV Name: " << pvName
1798 <<
" PQ ERROR: " << PQresultErrorMessage(res) << __E__;
1803 if(PQntuples(res) > 0)
1805 std::string channel_id = PQgetvalue(res, 0, 0);
1806 __COUT__ <<
"configure(): Writing new PV in the Archiver Database num_metadata table" << __E__;
1809 snprintf(buffer,
sizeof(buffer),
1810 "INSERT INTO num_metadata( \
1820 VALUES ('%s',%f,%f,%f,%f,%f,%f,%d,'%s');",
1821 channel_id.c_str(), low_disp_rng, high_disp_rng, low_warn_lmt
1822 , high_warn_lmt, low_alarm_lmt, high_alarm_lmt, prec, unit.c_str());
1824 res = PQexec(dcsArchiveDbConn, buffer);
1825 if(PQresultStatus(res) != PGRES_COMMAND_OK)
1827 __SS__ <<
"configure(): CHANNEL INSERT INTO DATABASE NUM_METADATA TABLE FAILED!!! PV Name: " << pvName
1828 <<
" PQ ERROR: " << PQresultErrorMessage(res) << __E__;
1836 __SS__ <<
"configure(): CHANNEL INSERT INTO DATABASE NUM_METADATA TABLE FAILED!!! PV Name: " << pvName
1837 <<
" NOT RECOGNIZED IN CHANNEL TABLE" << __E__;
1845 __SS__ <<
"configure(): CHANNEL INSERT OR UPDATE INTO DATABASE FAILED!!! "
1846 <<
" PQ ERROR: " << PQresultErrorMessage(res) <<__E__;
1852 __SS__ <<
"configure(): ARCHIVER DATABASE CONNECTION FAILED!!! " << __E__;