Commit a0150fff authored by Jonathan Hanks's avatar Jonathan Hanks
Browse files

Captures some test work of useing EPICS v4

This was an exploration in 2017 of using EPICS v4 to
stream data from the FE to the daqd.

This code used a customized build of epics v4 (using
cmake to build instead of the epics build system).

There is a fundimental issue, in that if each change in
the data set is not received, EPICS combines/overwrites
changes.

This checkin is to keep some of the structure and code used
in the tests.


git-svn-id: https://redoubt.ligo-wa.caltech.edu/svn/advLigoRTS/branches/experiment-on-epics-v4-streaming@4954 6dcd42c9-f523-4c6d-aada-af552506706e
parent 33007c7b
......@@ -16,6 +16,7 @@ INCLUDE(Sanitizers)
INCLUDE(Cpp11)
FIND_PACKAGE(PkgConfig)
FIND_PACKAGE(EPICSBase REQUIRED)
FIND_PACKAGE(EPICSv4)
FIND_PACKAGE(FrameCPP REQUIRED)
FIND_PACKAGE(MX)
FIND_PACKAGE(OpenMX)
......
# use pkgconfig to find EPICS Base
if (find_epics_base_included)
return()
endif(find_epics_base_included)
set(find_epics_base_included TRUE)
pkg_check_modules(EPICS_BASE REQUIRED epics-base)
if (EPICS_BASE_FOUND)
......@@ -7,31 +13,63 @@ if (EPICS_BASE_FOUND)
set (_epics_calibs_libs_intl "")
set (_epics_caslibs_libs_intl "")
set (_epics_Comlibs_libs_intl "")
else (${EPICS_BASE_VERSION} VERSION_LESS "3.15")
set (_epics_calibs_libs_intl "ca;Com")
set (_epics_caslibs_libs_intl "cas")
set (_epics_Comlibs_libs_intl "Com")
endif (${EPICS_BASE_VERSION} VERSION_LESS "3.15")
function(_epicsbase_add_library libname)
# message("Searching for ${libname} in ${EPICS4_DIR}/${libname}/lib/linux-x86_64")
find_library(_epicsbase_${libname}_lib name ${libname}
PATHS ${EPICS_BASE_LIBRARY_DIRS})
add_library(_epicsbase_${libname}_bin SHARED IMPORTED)
set_target_properties(_epicsbase_${libname}_bin PROPERTIES
IMPORTED_LOCATION ${_epicsbase_${libname}_lib})
# message("Found binary for ${libname} at ${_epicsbase_${libname}_lib}")
endfunction()
_epicsbase_add_library(ca)
_epicsbase_add_library(Com)
_epicsbase_add_library(cas)
add_library(_epics_base_ca_intl INTERFACE)
target_include_directories(_epics_base_ca_intl INTERFACE
${EPICS_BASE_INCLUDE_DIRS})
target_compile_options(_epics_base_ca_intl INTERFACE
${EPICS_BASE_CFLAGS_OTHER})
target_link_libraries(_epics_base_ca_intl INTERFACE
_epicsbase_Com_bin
_epicsbase_ca_bin)
add_library(_epics_base_cas_intl INTERFACE)
target_include_directories(_epics_base_cas_intl INTERFACE
${EPICS_BASE_INCLUDE_DIRS})
target_compile_options(_epics_base_cas_intl INTERFACE
${EPICS_BASE_CFLAGS_OTHER})
target_link_libraries(_epics_base_cas_intl INTERFACE
_epicsbase_cas_bin)
add_library(_epics_base_Com_intl INTERFACE)
target_include_directories(_epics_base_Com_intl INTERFACE
${EPICS_BASE_INCLUDE_DIRS})
target_compile_options(_epics_base_Com_intl INTERFACE
${EPICS_BASE_CFLAGS_OTHER})
target_link_libraries(_epics_base_Com_intl INTERFACE
_epicsbase_Com_bin
)
set (EPICS_BASE_CAS_LIBS ${_epics_caslibs_libs_intl})
set (EPICS_BASE_CA_LIBS ${_epics_calibs_libs_intl})
set (EPICS_BASE_COM_LIBS ${_epics_Comlibs_libs_intl})
add_library(epics::ca ALIAS _epics_base_ca_intl)
add_library(epics::cas ALIAS _epics_base_cas_intl)
add_library(epics::Com ALIAS _epics_base_Com_intl)
message("Found epics-base")
message("version ${EPICS_BASE_VERSION}")
......
FIND_PACKAGE(PkgConfig)
FIND_PACKAGE(EPICSBase REQUIRED)
if (find_epics_v4_cpp_included)
return()
endif(find_epics_v4_cpp_included)
set(find_epics_v4_cpp_included TRUE)
if (USE_EPICS4_CMAKE)
set (EPICSv4_FOUND 1)
add_subdirectory(${USE_EPICS4_CMAKE} ${PROJECT_BINARY_DIR}/EPICSv4_CMAKE_BUILD)
return()
endif(USE_EPICS4_CMAKE)
if (EPICS4_DIR)
set (EPICSv4_FOUND 1)
function(_epicsv4_add_library libname libbinname deps)
# message("Searching for ${libname} in ${EPICS4_DIR}/${libname}/lib/linux-x86_64")
find_library(_epicsv4_${libname}_lib name ${libbinname}
PATHS ${EPICS4_DIR}/${libname}/lib/linux-x86_64)
add_library(_epicsv4_${libname}_bin SHARED IMPORTED)
set_target_properties(_epicsv4_${libname}_bin PROPERTIES
IMPORTED_LOCATION ${_epicsv4_${libname}_lib})
# message("Found binary for ${libname} at ${_epicsv4_${libname}_lib}")
add_library(_epicsv4_${libname}_intr INTERFACE)
target_include_directories(_epicsv4_${libname}_intr INTERFACE
${EPICS4_DIR}/${libname}/include)
target_link_libraries(_epicsv4_${libname}_intr INTERFACE
_epicsv4_${libname}_bin ${deps})
# message("link deps for ${libname} is _epicsv4_${libname}_bin and ${deps}")
add_library(EPICSv4::${libname} ALIAS _epicsv4_${libname}_intr)
endfunction()
_epicsv4_add_library(pvDataCPP pvData "epics::ca")
_epicsv4_add_library(pvAccessCPP pvAccess EPICSv4::pvDataCPP)
_epicsv4_add_library(normativeTypesCPP nt EPICSv4::pvDataCPP)
_epicsv4_add_library(pvDatabaseCPP pvDatabase EPICSv4::pvAccessCPP)
_epicsv4_add_library(pvaSrvCPP pvaSrv EPICSv4::pvAccessCPP)
_epicsv4_add_library(pvaClientCPP pvaClient "EPICSv4::pvAccessCPP;EPICSv4::normativeTypesCPP")
endif (EPICS4_DIR)
\ No newline at end of file
......@@ -5,3 +5,7 @@ add_subdirectory(nds)
add_subdirectory(mx_stream)
add_subdirectory(run_number)
add_subdirectory(zmq_stream)
if (${EPICSv4_FOUND})
add_subdirectory(epicsv4_stream)
endif (${EPICSv4_FOUND})
cmake_minimum_required(VERSION 3.8)
project(transfer)
set(CMAKE_CXX_STANDARD 11)
SET( CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${PROJECT_SOURCE_DIR}/config" )
FIND_PACKAGE(EPICSv4 REQUIRED)
add_executable(epicsv4_stream
epicsv4_stream.cc
)
target_compile_options(epicsv4_stream PUBLIC
-Wno-deprecated-declarations
-O0
-g3
)
target_include_directories(epicsv4_stream PUBLIC
${CMAKE_CURRENT_SOURCE_DIR}
)
target_link_libraries(epicsv4_stream PUBLIC
EPICSv4::pvDatabaseCPP
EPICSv4::normativeTypesCPP
epics::ca
m
readline
pthread
)
/*
* Copyright information and license terms for this software can be
* found in the file LICENSE that is included with the distribution
*/
/**
* Heavily based on exampleCPP work by Mary Kraimer
*/
#include <algorithm>
#include <cstddef>
#include <cstdlib>
#include <cstddef>
#include <string>
#include <cstdio>
#include <memory>
#include <iostream>
#include <sstream>
#include <vector>
#include <unistd.h>
#include <time.h>
#include <pthread.h>
#include "gps.hh"
#include <pv/channelProviderLocal.h>
#include <pv/serverContext.h>
using namespace std;
using std::tr1::static_pointer_cast;
using namespace epics::pvData;
using namespace epics::pvAccess;
using namespace epics::pvDatabase;
volatile bool done = false;
struct MainLoopArgs
{
PVRecord* record;
size_t data_rate;
};
// Helper function to make sure PVRecord::endGroupPut is called
class EndGroupPut
{
private:
PVRecord& rec_;
public:
EndGroupPut(PVRecord& rec): rec_(rec) {}
~EndGroupPut()
{
rec_.endGroupPut();
}
};
// Create a PVRecord with a GPS timestamp of the given name and add it to the specified database
PVRecordPtr create_transfer_array(PVDatabasePtr master, const std::string& recordName)
{
StructureConstPtr top = getFieldCreate()->createFieldBuilder()->
addNestedStructure("data")->
add("gps", pvLong)->
add("nano", pvLong)->
addArray("blob", pvUByte )->
endNested()->
createStructure();
PVStructurePtr pvStructure = getPVDataCreate()->createPVStructure(top);
PVRecordPtr dest = PVRecord::create(recordName, pvStructure);
bool result = master->addRecord(dest);
if(!result)
throw std::runtime_error("Unable to add array record to the database");
return dest;
}
// Main loop, this tests updating the given record at 16Hz.
void* update_loop(void *arg)
{
const int HERTZ = 16;
MainLoopArgs* args = (MainLoopArgs*)arg;
std::vector<epicsUInt8> source(args->data_rate/HERTZ);
GPS::gps_clock clock;
PVRecord *rec = args->record;
PVStructurePtr structPtr = rec->getPVStructure();
PVLongPtr gpsPtr = structPtr->getSubField<PVLong>("data.gps");
PVLongPtr gpsNanoPtr = structPtr->getSubField<PVLong>("data.nano");
PVScalarArrayPtr arrayPtr = structPtr->getSubField<PVScalarArray>("data.blob");
GPS::gps_time time_step = GPS::gps_time(0, 1000000000/HERTZ);
GPS::gps_time transmit_time = clock.now();
++transmit_time.sec;
transmit_time.nanosec = 0;
for (int i = 0; !done; ++i)
{
GPS::gps_time now = clock.now();
while (now < transmit_time)
{
usleep(1);
now = clock.now();
}
std::fill(source.begin(), source.end(), i % 256);
shared_vector<epicsUInt8> sh_vec(source.size());
std::copy(source.begin(), source.end(), sh_vec.begin());
{
rec->beginGroupPut();
EndGroupPut eput(*rec);
arrayPtr->putFrom(freeze(sh_vec));
gpsPtr->put(transmit_time.sec);
gpsNanoPtr->put(transmit_time.nanosec);
}
transmit_time = transmit_time + time_step;
//std::cout << transmit_time.sec << ":" << transmit_time.nanosec << std::endl;
}
return NULL;
}
int main(int argc,char *argv[])
{
MainLoopArgs args;
string record_name("transfer_array");
args.data_rate = 100 * 1024 * 1024;
if (argc > 1)
record_name = argv[1];
if (argc > 2)
{
istringstream stream(argv[2]);
stream >> args.data_rate;
}
PVDatabasePtr master = PVDatabase::getMaster();
ChannelProviderLocalPtr channelProvider = getChannelProviderLocal();
PVRecordPtr transfer_array = create_transfer_array(master, record_name);
args.record = transfer_array.get();
ServerContext::shared_pointer ctx =
startPVAServer("local",0,true,true);
pthread_t th;
if (pthread_create(&th, NULL, update_loop, (void*)&args) != 0)
{
throw std::runtime_error("Unable to start update thread");
}
master.reset();
cout << "transfer test server\n";
string str;
while(true) {
cout << "Type exit to stop: \n";
getline(cin,str);
if(str.compare("exit")==0) break;
}
done = true;
sleep(2);
ctx->destroy();
return 0;
}
//
// Created by jonathan.hanks on 10/20/17.
//
#ifndef TRANSFER_GPS_H
#define TRANSFER_GPS_H
#include <time.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <unistd.h>
/**
* Operations on GPS time.
* Note for purposes of this testing, this does not return GPS time but system time.
*/
namespace GPS {
struct gps_time
{
long sec;
long nanosec;
gps_time(): sec(0), nanosec(0) {}
explicit gps_time(long s): sec(s), nanosec(0) {}
gps_time(long s, long ns): sec(s), nanosec(ns) {}
gps_time(const gps_time& other): sec(other.sec), nanosec(other.nanosec) {}
gps_time operator-(const gps_time& other) const
{
gps_time result(sec - other.sec, nanosec - other.nanosec);
while (result.nanosec < 0) {
result.nanosec += 1000000000;
--result.sec;
}
return result;
}
gps_time operator+(const gps_time& other) const
{
gps_time result(sec + other.sec, nanosec + other.nanosec);
while (result.nanosec >= 1000000000) {
result.nanosec -= 1000000000;
++result.sec;
}
return result;
}
bool operator==(const gps_time& other) const
{
return (sec == other.sec && nanosec == other.nanosec);
}
bool operator!=(const gps_time& other) const
{
return !(*this == other);
}
bool operator<(const gps_time& other) const
{
if (sec < other.sec) return true;
if (sec > other.sec) return false;
return (nanosec < other.nanosec);
}
};
std::ostream& operator<<(std::ostream& os, const gps_time& gps)
{
os << gps.sec << ":" << gps.nanosec;
return os;
}
class gps_clock
{
public:
gps_time now() const
{
gps_time result;
struct timespec ts;
clock_gettime(CLOCK_REALTIME, &ts);
result.sec = ts.tv_sec;
result.nanosec = ts.tv_nsec;
return result;
}
};
}
#endif //TRANSFER_GPS_H
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment