Files
ISTTOK/epics/css/sys-mng-opi/CSS/MARTe/Interfaces/EPICSLib/EPICSSignalsTable.cpp
2019-10-21 16:02:55 +01:00

267 lines
8.9 KiB
C++

/*
* Copyright 2011 EFDA | European Fusion Development Agreement
*
* Licensed under the EUPL, Version 1.1 or - as soon they
will be approved by the European Commission - subsequent
versions of the EUPL (the "Licence");
* You may not use this work except in compliance with the
Licence.
* You may obtain a copy of the Licence at:
*
* http://ec.europa.eu/idabc/eupl
*
* Unless required by applicable law or agreed to in
writing, software distributed under the Licence is
distributed on an "AS IS" basis,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
express or implied.
* See the Licence for the specific language governing
permissions and limitations under the Licence.
*
* $Id$
*
**/
#include "EPICSSignalsTable.h"
#include "GlobalObjectDataBase.h"
#include "GCRTemplate.h"
#include "DDBInterface.h"
#include "CDBExtended.h"
#include "SignalInterface.h"
#define DEFAULT_SERVER_SUBSAMPLING 1000
// we do not need to sort the list in any order
// so we remove it (at least for now)
/*
class AlphaSorterClass : public SortFilter {
public:
virtual ~AlphaSorterClass(){};
virtual int32 Compare(LinkedListable *data1,LinkedListable *data2){
const EPICSSignal *p1 = (const EPICSSignal *)data1;
const EPICSSignal *p2 = (const EPICSSignal *)data2;
if (p2 == NULL) return 1;
if (p1 == NULL) return -1;
return strcmp(p2->EPICSName(),p1->EPICSName());
}
} AlphaSorter;
*/
/*
* Initialize has to link signals in the DDB with
* EPICS descriptors (sending messages ?)
* EPICS is message based so doesn't care
*/
bool EPICSSignalsTable::Initialize (const DDBInterface &ddbInterface, ConfigurationDataBase &info) {
// CleanUp
CleanUp();
// check the number of signals
int32 nOfSignals = ddbInterface.NumberOfEntries();
if(nOfSignals == 0)
return False;
CDBExtended cdb(info);
unsigned dataOffset = 0;
int i = 0;
// Find the Signal Server object
FString SignalsServer;
if (!cdb.ReadFString(SignalsServer,"SignalsServer")) {
CStaticAssertErrorCondition(FatalError,
"EPICSSignalsTable::Initialize: SignalsServer not defined in the configuration"
);
return False;
}
GCReference gc = GODBFindByName( SignalsServer.Buffer() );
if ( !gc.IsValid() ) {
CStaticAssertErrorCondition(FatalError,
"EPICSSignalsTable::Initialize cannot find %s in the GlobalObjectDataBase",
SignalsServer.Buffer() );
return False;
}
// GCRTemplate<PubSubInterface> epics_hnd = gc;
// TODO more generic
gcrEPICSHnd = gc;
if ( !gcrEPICSHnd.IsValid() ) {
CStaticAssertErrorCondition(FatalError,
"EPICSSignalsTable::Initialize cannot cast %s as an EPICSHandler",
SignalsServer.Buffer() );
return False;
}
//------------------------------------------------------------------------- end server initialization
// ddbInterface signal list
const DDBSignalDescriptor *descriptor = ddbInterface.SignalsList();
// searching for signals
if(!cdb->Move("Signals")){
CStaticAssertErrorCondition(FatalError,
"EPICSSignalsTable::Initialise: GAM did not specify Signals entry"
);
return False;
}
if ( signalsTable )
delete [] signalsTable;
signalsTable = new EPICSSignal * [nOfSignals];
for(i = 0; ((i < nOfSignals)&&(descriptor != NULL)); i++) {
// move to children
cdb->MoveToChildren(i);
// retrive descriptor description
FString ddbName = descriptor->SignalName();
uint32 ddbSize = descriptor->SignalSize();
BasicTypeDescriptor ddbDesc = descriptor->SignalTypeCode();
// Get the server signal name
FString EPICSSignalName;
if ( !cdb.ReadFString(EPICSSignalName,"ServerName") ) {
CStaticAssertErrorCondition(FatalError,
"EPICSSignalsTable::Initialize: ServerName not specified for DDB signal %s",
ddbName.Buffer());
return False;
}
// Get the server signal subsampling
int32 EPICSSignalSubSample;
if ( !cdb.ReadInt32(EPICSSignalSubSample,"ServerSubSampling", DEFAULT_SERVER_SUBSAMPLING) ) {
CStaticAssertErrorCondition(Information,
"EPICSSignalsTable::Initialize: ServerSubSampling not specified for signal %s assuming %d",
ddbName.Buffer(), EPICSSignalSubSample);
} //------------------------------------------------------------------- end fetching configuration data
// subscribe for service in the server
unsigned EPICSId = -1;
if ( !(gcrEPICSHnd->subscribe(EPICSSignalName.Buffer(), ddbDesc, ddbSize, EPICSId)) ) {
CStaticAssertErrorCondition(FatalError,
"EPICSSignalsTable::Initialize: %s subscribe fails for signal %s (server's signal name %s)",
SignalsServer.Buffer(), ddbName.Buffer(), EPICSSignalName.Buffer() );
return False;
}
// NOTA differently from the JpfSignalTable we are not interested in the calibration data (if needed to be implemented)
// in the previous version (jpf) if you have an array of signals in MARTe than each signals
// will be mapped to a different jpf signal and also EPICSSignal, in this implementation
// EPICS (and also MDSplus) support array of data so we also need to support array of data
// now it is possible to create the Server's signal
EPICSSignal * newSignal = new EPICSSignal(
ddbName, ddbDesc, ddbSize, dataOffset,
EPICSSignalName, EPICSId, EPICSSignalSubSample);
if (newSignal == NULL) {
CStaticAssertErrorCondition(FatalError,
"EPICSSignalsTable::Initialize: Failed allocating space for signal %s (%s)",
ddbName.Buffer(), EPICSSignalName.Buffer());
return False;
}
else
CStaticAssertErrorCondition(Information,
"EPICSSignalsTable::Initialize: Added Signal %s (EPICS: %s)",
ddbName.Buffer(), EPICSSignalName.Buffer());
//ListInsert(newSignal,&AlphaSorter); //previous implementation
ListInsert(newSignal);
// copy the pointer in the table
signalsTable[i] = newSignal;
// Increment offset
dataOffset += newSignal->GetDDBSize();
// return to parent
cdb->MoveToFather();
// move to another signal
descriptor = descriptor->Next();
}
// end "Signals" configuration
cdb->MoveToFather();
if( (ListSize() == 0) || (List() == NULL) ) {
CStaticAssertErrorCondition(FatalError,
"EPICSSignalsTable::Initialize: No signal added to the list"
);
return False;
}
return True;
} //--------------------------------------------------------------------------- ObjectLoadSetup
/* UpdateSignals
* Updates all signals in the list pushing an event message on the queue
*/
bool EPICSSignalsTable::UpdateSignals (char * buffer, int32 timestamp) {
int _ret;
int nOfSignals = this->ListSize(); // get the number of signals from the list
for (int i=0; i<nOfSignals; i++) {
// update the signal on the server only if needed
if ( !(signalsTable[i]->counter % signalsTable[i]->GetEPICSSubSample()) ) {
_ret = gcrEPICSHnd->put( signalsTable[i]->GetEPICSIndex(),
(buffer + signalsTable[i]->GetDDBOffset()), (unsigned) timestamp );
if ( _ret == 0 )
CStaticAssertErrorCondition(FatalError,
"EPICSSignalsTable::UpdateSignals: ->put return CIRCULAR BUFFER OVERFLOW"
);
}
signalsTable[i]->counter++;
}
return True;
} //--------------------------------------------------------------------------- UpdateSignals
// not required
/*
int32 EPICSSignalsTable::FindOffsetAndInitSignalType(const FString &signalName, GCRTemplate<SignalInterface> signal, int32 nOfSamples) {
EPICSSignal *sig = (EPICSSignal *)List();
for(int i = 0; i < ListSize(); i++){
if(strcmp(sig->EPICSName(),signalName.Buffer()) == 0){
signal->CopyData(sig->Type(), nOfSamples);
return sig->Offset();
}
sig = (EPICSSignal *)sig->Next();
}
return -1;
}
*/
bool EPICSSignalsTable::ObjectDescription(StreamInterface &s,bool full,StreamInterface *err) {
EPICSSignal *sig = (EPICSSignal *)List();
if(sig == NULL) return False;
s.Printf("Signals = {\n");
for(int i = 0; i < this->ListSize(); i++){
FString bType;
FString oType;
s.Printf("Signal%d = {\n",i);
sig->GetDDBType().ConvertToString(bType);
s.Printf(" Name = \"%s\" \n" , sig->GetEPICSName());
s.Printf(" DataType = %s \n" , bType.Buffer());
// s.Printf(" Cal0 = %f \n", sortedSignalVector[i]->Cal0());
// s.Printf(" Cal1 = %f \n", sortedSignalVector[i]->Cal1());
s.Printf("}\n");
sig = (EPICSSignal *)sig->Next();
}
s.Printf("}\n");
return True;
}