Skip to content
Snippets Groups Projects
Commit 3f70bd24 authored by Jonathan Hanks's avatar Jonathan Hanks
Browse files

Adding support for double values in simple_pv.

parent 19f31885
No related branches found
No related tags found
1 merge request!176Adding support for double values in simple_pv.
......@@ -23,9 +23,10 @@ namespace simple_epics
"Duplicate key insertion to the epics db" );
}
std::string name{ attr.name( ) };
pvs_.insert( std::make_pair( std::move( name ),
detail::make_unique_ptr< detail::simpleIntPV >(
*this, std::move( attr ) ) ) );
pvs_.insert(
std::make_pair( std::move( name ),
detail::make_unique_ptr< detail::simpleIntPV >(
*this, std::move( attr ) ) ) );
}
void
......@@ -40,9 +41,28 @@ namespace simple_epics
"Duplicate key insertion to the epics db" );
}
std::string name{ attr.name( ) };
pvs_.insert( std::make_pair( std::move( name ),
detail::make_unique_ptr< detail::simpleStringPV >(
*this, std::move( attr ) ) ) );
pvs_.insert(
std::make_pair( std::move( name ),
detail::make_unique_ptr< detail::simpleStringPV >(
*this, std::move( attr ) ) ) );
}
void
Server::addPV( pvDoubleAttributes attr )
{
std::lock_guard< std::mutex > l_( m_ );
auto it = pvs_.find( attr.name( ) );
if ( it != pvs_.end( ) )
{
throw std::runtime_error(
"Duplicate key insertion to the epics db" );
}
std::string name{ attr.name( ) };
pvs_.insert(
std::make_pair( std::move( name ),
detail::make_unique_ptr< detail::simpleDoublePV >(
*this, std::move( attr ) ) ) );
}
void
......
......@@ -131,6 +131,70 @@ namespace simple_epics
const char* src_;
};
/*!
* @brief A description of a PV, used to describe a double PV to the server.
* @note this is given a pointer to the data. This value is only read
* when a Server object is told to update its data.
*/
class pvDoubleAttributes
{
public:
pvDoubleAttributes( std::string pv_name,
double* value,
std::pair< double, double > alarm_range,
std::pair< double, double > warn_range )
: name_{ std::move( pv_name ) },
alarm_low_{ alarm_range.first },
alarm_high_{ alarm_range.second }, warn_low_{ warn_range.first },
warn_high_{ warn_range.second }, src_{ value }
{
}
const std::string&
name( ) const
{
return name_;
}
double
alarm_high( ) const
{
return alarm_high_;
}
double
alarm_low( ) const
{
return alarm_low_;
}
double
warn_high( ) const
{
return warn_high_;
}
double
warn_low( ) const
{
return warn_low_;
}
const double*
src( ) const
{
return src_;
}
private:
std::string name_;
double alarm_high_;
double alarm_low_;
double warn_high_;
double warn_low_;
double* src_;
};
/*!
* @brief An R/O implementation of the Portable CA Server.
*/
......@@ -147,6 +211,7 @@ namespace simple_epics
*/
void addPV( pvIntAttributes attr );
void addPV( pvStringAttributes attr );
void addPV( pvDoubleAttributes attr );
/*!
* @brief Reflect all changes in the data for each PV into the server
......
......@@ -30,6 +30,21 @@ namespace simple_epics
setup_string_pv_table pv_string_table_setup_;
class setup_double_pv_table
{
public:
setup_double_pv_table( )
{
simpleDoublePV::setup_func_table( );
}
};
setup_double_pv_table pv_double_table_setup_;
/*
* Start of int PV
*/
gddAppFuncTable< simpleIntPV >&
simpleIntPV::get_func_table( )
{
......@@ -226,6 +241,10 @@ namespace simple_epics
}
}
/*
* Start of string PV
*/
gddAppFuncTable< simpleStringPV >&
simpleStringPV::get_func_table( )
{
......@@ -367,6 +386,206 @@ namespace simple_epics
}
}
/*
* Start of double PV
*/
gddAppFuncTable< simpleDoublePV >&
simpleDoublePV::get_func_table( )
{
static gddAppFuncTable< simpleDoublePV > func_table;
return func_table;
}
simpleDoublePV::~simpleDoublePV( ) = default;
gddAppFuncTableStatus
simpleDoublePV::read_status( gdd& g )
{
g.putConvert( val_->getStat( ) );
return S_casApp_success;
}
gddAppFuncTableStatus
simpleDoublePV::read_severity( gdd& g )
{
g.putConvert( val_->getSevr( ) );
return S_casApp_success;
}
gddAppFuncTableStatus
simpleDoublePV::read_precision( gdd& g )
{
g.putConvert( 0 );
return S_casApp_success;
}
gddAppFuncTableStatus
simpleDoublePV::read_alarm_high( gdd& g )
{
g.putConvert( attr_.alarm_high( ) );
return S_casApp_success;
}
gddAppFuncTableStatus
simpleDoublePV::read_alarm_low( gdd& g )
{
g.putConvert( attr_.alarm_low( ) );
return S_casApp_success;
}
gddAppFuncTableStatus
simpleDoublePV::read_warn_high( gdd& g )
{
g.putConvert( attr_.warn_high( ) );
return S_casApp_success;
}
gddAppFuncTableStatus
simpleDoublePV::read_warn_low( gdd& g )
{
g.putConvert( attr_.warn_low( ) );
return S_casApp_success;
}
gddAppFuncTableStatus
simpleDoublePV::read_value( gdd& g )
{
auto status =
gddApplicationTypeTable::app_table.smartCopy( &g, val_.get( ) );
return ( status ? S_cas_noConvert : S_casApp_success );
}
void
simpleDoublePV::setup_func_table( )
{
auto install = []( const char* name,
gddAppFuncTableStatus (
simpleDoublePV::*handler )( gdd& ) ) {
gddAppFuncTableStatus status;
// char error_string[100];
status = get_func_table( ).installReadFunc( name, handler );
if ( status != S_gddAppFuncTable_Success )
{
// errSymLookup(status, error_string,
// sizeof(error_string));
// throw std::runtime_error(error_string);
throw std::runtime_error(
"Unable to initialize pv lookup table" );
}
};
install( "units", &simpleDoublePV::read_attr_not_handled );
install( "status", &simpleDoublePV::read_status );
install( "severity", &simpleDoublePV::read_severity );
install( "maxElements", &simpleDoublePV::read_attr_not_handled );
install( "precision", &simpleDoublePV::read_precision );
install( "alarmHigh", &simpleDoublePV::read_alarm_high );
install( "alarmLow", &simpleDoublePV::read_alarm_low );
install( "alarmHighWarning", &simpleDoublePV::read_warn_high );
install( "alarmLowWarning", &simpleDoublePV::read_warn_low );
install( "maxElements", &simpleDoublePV::read_attr_not_handled );
install( "graphicHigh", &simpleDoublePV::read_attr_not_handled );
install( "graphicLow", &simpleDoublePV::read_attr_not_handled );
install( "controlHigh", &simpleDoublePV::read_attr_not_handled );
install( "controlLow", &simpleDoublePV::read_attr_not_handled );
install( "enums", &simpleDoublePV::read_attr_not_handled );
install( "menuitem", &simpleDoublePV::read_attr_not_handled );
install( "timestamp", &simpleDoublePV::read_attr_not_handled );
install( "value", &simpleDoublePV::read_value );
}
caStatus
simpleDoublePV::read( const casCtx& ctx, gdd& prototype )
{
return get_func_table( ).read( *this, prototype );
}
caStatus
simpleDoublePV::write( const casCtx& ctx, const gdd& value )
{
return S_casApp_noSupport;
}
aitEnum
simpleDoublePV::bestExternalType( ) const
{
return val_->primitiveType( );
}
caStatus
simpleDoublePV::interestRegister( )
{
monitored_ = true;
return S_casApp_success;
}
void
simpleDoublePV::interestDelete( )
{
monitored_ = false;
}
void
simpleDoublePV::update( )
{
set_value( *attr_.src( ) );
}
void
simpleDoublePV::set_value( double value )
{
double current_value = 0;
val_->getConvert( current_value );
if ( current_value == value )
{
return;
}
val_->putConvert( value );
aitTimeStamp ts = aitTimeStamp( epicsTime::getCurrent( ) );
val_->setTimeStamp( &ts );
aitUint16 stat = epicsAlarmNone;
aitUint16 sevr = epicsSevNone;
if ( value >= attr_.alarm_high( ) )
{
stat = epicsAlarmHiHi;
sevr = epicsSevMajor;
}
else if ( value <= attr_.alarm_low( ) )
{
stat = epicsAlarmLoLo;
sevr = epicsSevMajor;
}
else if ( value >= attr_.warn_high( ) )
{
stat = epicsAlarmHigh;
sevr = epicsSevMinor;
}
else if ( value <= attr_.warn_low( ) )
{
stat = epicsAlarmLow;
sevr = epicsSevMinor;
}
val_->setSevr( sevr );
val_->setStat( stat );
if ( monitored_ )
{
casEventMask mask = casEventMask( server_.valueEventMask( ) );
bool alarm_changed =
( stat != val_->getStat( ) || sevr != val_->getSevr( ) );
if ( alarm_changed )
{
mask |= server_.alarmEventMask( );
}
postEvent( mask, *val_ );
}
}
} // namespace detail
} // namespace simple_epics
\ No newline at end of file
......@@ -32,7 +32,8 @@ namespace simple_epics
std::unique_ptr< T >
make_unique_ptr( Ts&&... params )
{
return std::unique_ptr< T >( new T( std::forward< Ts >( params )... ) );
return std::unique_ptr< T >(
new T( std::forward< Ts >( params )... ) );
}
class setup_int_pv_table;
......@@ -174,6 +175,80 @@ namespace simple_epics
bool monitored_;
};
class setup_double_pv_table;
/*!
* @brief A representation of a R/O double in a PV
*/
class simpleDoublePV : public simplePVBase
{
friend class setup_double_pv_table;
public:
simpleDoublePV( caServer& server, pvDoubleAttributes attr )
: simplePVBase( ), server_{ server }, attr_{ std::move(
attr ) },
val_( ), monitored_{ false }
{
val_ = new gddScalar( gddAppType_value, aitEnumFloat64 );
val_->unreference( );
set_value( *attr_.src( ) );
}
~simpleDoublePV( ) override;
caStatus read( const casCtx& ctx, gdd& prototype ) override;
caStatus write( const casCtx& ctx, const gdd& value ) override;
void destroy( ) override{};
aitEnum bestExternalType( ) const override;
const char*
getName( ) const override
{
return attr_.name( ).c_str( );
}
caStatus interestRegister( ) override;
void interestDelete( ) override;
void update( ) override;
private:
void set_value( double value );
static void setup_func_table( );
static gddAppFuncTable< simpleDoublePV >& get_func_table( );
gddAppFuncTableStatus
read_attr_not_handled( gdd& g )
{
return S_casApp_success;
}
gddAppFuncTableStatus read_status( gdd& g );
gddAppFuncTableStatus read_severity( gdd& g );
gddAppFuncTableStatus read_precision( gdd& g );
gddAppFuncTableStatus read_alarm_high( gdd& g );
gddAppFuncTableStatus read_alarm_low( gdd& g );
gddAppFuncTableStatus read_warn_high( gdd& g );
gddAppFuncTableStatus read_warn_low( gdd& g );
gddAppFuncTableStatus read_value( gdd& g );
caServer& server_;
pvDoubleAttributes attr_;
smartGDDPointer val_;
bool monitored_;
};
} // namespace detail
} // namespace simple_epics
......
......@@ -25,7 +25,7 @@ simple_pv_server_create( const char* prefix, SimplePV* pvs, int pv_count )
const std::string prefix_ = ( prefix ? prefix : "" );
auto pv_server = server.get();
auto pv_server = server.get( );
std::for_each(
pvs,
pvs + pv_count,
......@@ -41,8 +41,8 @@ simple_pv_server_create( const char* prefix, SimplePV* pvs, int pv_count )
pv_server->addPV( simple_epics::pvIntAttributes(
prefix_ + pv.name,
reinterpret_cast< int* >( pv.data ),
std::make_pair( pv.alarm_low, pv.alarm_high ),
std::make_pair( pv.warn_low, pv.warn_high ) ) );
std::make_pair< int, int >( pv.alarm_low, pv.alarm_high ),
std::make_pair< int, int >( pv.warn_low, pv.warn_high ) ) );
}
break;
case SIMPLE_PV_STRING:
......@@ -51,6 +51,15 @@ simple_pv_server_create( const char* prefix, SimplePV* pvs, int pv_count )
prefix_ + pv.name, reinterpret_cast< char* >( pv.data ) ) );
}
break;
case SIMPLE_PV_DOUBLE:
{
pv_server->addPV( simple_epics::pvDoubleAttributes(
prefix_ + pv.name,
reinterpret_cast< double* >( pv.data ),
std::make_pair( pv.alarm_low, pv.alarm_high ),
std::make_pair( pv.warn_low, pv.warn_high ) ) );
}
break;
}
} );
......
......@@ -7,6 +7,7 @@ extern "C" {
#define SIMPLE_PV_INT 0
#define SIMPLE_PV_STRING 1
#define SIMPLE_PV_DOUBLE 2
/*!
* @brief A Simple structure representing a read-only PV
......@@ -17,11 +18,12 @@ typedef struct SimplePV
int pv_type; /// SIMPLE_PV_INT or SIMPLE_PV_STRING
void* data;
// These values are only used for an int pv
int alarm_high;
int alarm_low;
int warn_high;
int warn_low;
// These values are only used for an int or double pv
// they will be cased to the appropriate type
double alarm_high;
double alarm_low;
double warn_high;
double warn_low;
} SimplePV;
typedef void* simple_pv_handle;
......
......@@ -14,11 +14,13 @@ main( int argc, char** argv )
{
const double pi = std::acos( -1 );
int sin_val = 0;
int cos_val = 100;
int delay_ms = 0;
char buffer1[ 1024 ] = "Hello World!";
char buffer2[ 1024 ] = "0";
int sin_val = 0;
int cos_val = 100;
double sin_val_d = 0.0;
double cos_val_d = 100.0;
int delay_ms = 0;
char buffer1[ 1024 ] = "Hello World!";
char buffer2[ 1024 ] = "0";
int i = 0;
bool done = false;
......@@ -33,6 +35,16 @@ main( int argc, char** argv )
&cos_val,
std::make_pair( -200, 200 ),
std::make_pair( -198, 198 ) ) );
server.addPV(
simple_epics::pvDoubleAttributes( "TEST_SIN_D",
&sin_val_d,
std::make_pair( -98.5, 98.5 ),
std::make_pair( -85.5, 85.5 ) ) );
server.addPV(
simple_epics::pvDoubleAttributes( "TEST_COS_D",
&cos_val_d,
std::make_pair( -98.5, 98.5 ),
std::make_pair( -85.5, 85.5 ) ) );
server.addPV( simple_epics::pvIntAttributes( "TEST_DELAY",
&delay_ms,
std::make_pair( -1, 200 ),
......@@ -43,7 +55,7 @@ main( int argc, char** argv )
while ( !done )
{
auto now = std::chrono::system_clock::now( );
auto end_by = now + std::chrono::milliseconds( 1000 / 4 );
auto end_by = now + std::chrono::milliseconds( 1000 / 8 );
fileDescriptorManager.process( 1 );
......@@ -52,6 +64,9 @@ main( int argc, char** argv )
sin_val = static_cast< int >( 100 * std::sin( rad ) );
cos_val = static_cast< int >( 100 * std::cos( rad ) );
sin_val_d = 100 * std::sin( rad );
cos_val_d = 100 * std::cos( rad );
i = ( i + 5 ) % 360;
std::snprintf( buffer2, 1024, "%d", i );
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment