diff --git a/src/nt.cpp b/src/nt.cpp index 27591d7..18ed33a 100644 --- a/src/nt.cpp +++ b/src/nt.cpp @@ -13,7 +13,7 @@ TypeDef NTScalar::build() const { using namespace pvxs::members; - return TypeDef(TypeCode::Struct, + TypeDef def(TypeCode::Struct, value.isarray() ? "epics:nt/NTScalarArray:1.0" : "epics:nt/NTScalar:1.0", { Member(value, "value"), Struct("alarm", "alarm_t", { @@ -28,55 +28,108 @@ TypeDef NTScalar::build() const }), }); -// const bool isnumeric = value.kind()==Kind::Integer || value.kind()==Kind::Real; -// const auto scalar = value.scalarOf(); + const bool isnumeric = value.kind()==Kind::Integer || value.kind()==Kind::Real; + const auto scalar = value.scalarOf(); -// if(display && isnumeric) { -// def.begin() -// .insert("display", TypeCode::Struct).seek("display") -// .insert("limitLow", scalar) -// .insert("limitHigh", scalar) -// .insert("description", TypeCode::String) -// //.insert("format", TypeCode::String) -// .insert("units", TypeCode::String) -// .up() -// ; -// } + if(display && isnumeric) { + def += { + Struct("display", { + Member(scalar, "limitLow"), + Member(scalar, "limitHigh"), + String("description"), + //String("format"), + String("units"), + }), + }; + } -// if(control && isnumeric) { -// def.begin() -// .insert("control", TypeCode::Struct).seek("control") -// .insert("limitLow", scalar) -// .insert("limitHigh", scalar) -// .insert("minStep", scalar) -// .up() -// ; -// } + if(control && isnumeric) { + def += { + Struct("control", { + Member(scalar, "limitLow"), + Member(scalar, "limitHigh"), + Member(scalar, "minStep"), + }), + }; + } -// if(valueAlarm && isnumeric) { -// def.begin() -// .insert("valueAlarm", TypeCode::Struct).seek("valueAlarm") -// .insert("active", TypeCode::Bool) // useless? -// .insert("lowAlarmLimit", scalar) -// .insert("lowWarningLimit", scalar) -// .insert("highWarningLimit", scalar) -// .insert("highAlarmLimit", scalar) -// .insert("lowAlarmSeverity", TypeCode::Int32) -// .insert("lowWarningSeverity", TypeCode::Int32) -// .insert("highWarningSeverity", TypeCode::Int32) -// .insert("highAlarmSeverity", TypeCode::Int32) -// .insert("hysteresis", TypeCode::Float64) -// .up() -// ; -// } + if(valueAlarm && isnumeric) { + def += { + Struct("valueAlarm", { + Bool("active"), + Member(scalar, "lowAlarmLimit"), + Member(scalar, "lowWarningLimit"), + Member(scalar, "highWarningLimit"), + Member(scalar, "highAlarmLimit"), + Int32("lowAlarmSeverity"), + Int32("lowWarningSeverity"), + Int32("highWarningSeverity"), + Int32("highAlarmSeverity"), + Float64("hysteresis"), + }), + }; + } -// return def; + return def; } TypeDef NTNDArray::build() const { - TypeDef def(TypeCode::Struct, "epics:nt/NTNDArray:1.0", {}); + using namespace pvxs::members; + auto time_t = { + Int64("secondsPastEpoch"), + Int32("nanoseconds"), + Int32("userTag"), + }; + auto alarm_t = { + Int32("severity"), + Int32("status"), + String("message"), + }; + + TypeDef def(TypeCode::Struct, "epics:nt/NTNDArray:1.0", { + Union("value", { + BoolA("booleanValue"), + Int8A("byteValue"), + Int16A("shortValue"), + Int32A("intValue"), + Int64A("longValue"), + UInt8A("ubyteValue"), + UInt16A("ushortValue"), + UInt32A("uintValue"), + UInt64A("ulongValue"), + Float32("floatValue"), + Float64("doubleValue"), + }), + Struct("codec", "codec_t", { + String("name"), + Any("parameters"), + }), + Int64("compressedSize"), + Int64("uncompressedSize"), + Int32("uniqueId"), + Struct("dataTimeStamp", "time_t", time_t), + Struct("alarm", "alarm_t", alarm_t), + Struct("timeStamp", "time_t", time_t), + StructA("dimension", "dimension_t", { + Int32("size"), + Int32("offset"), + Int32("fullSize"), + Int32("binning"), + Bool("reverse"), + }), + StructA("attribute", "epics:nt/NTAttribute:1.0", { + String("name"), + Any("value"), + StringA("tags"), + String("descriptor"), + Struct("alarm", "alarm_t", alarm_t), + Struct("timeStamp", "time_t", time_t), + Int32("sourceType"), + String("source"), + }), + }); return def; } diff --git a/src/pvxs/data.h b/src/pvxs/data.h index 6d8a6dc..2bf7b06 100644 --- a/src/pvxs/data.h +++ b/src/pvxs/data.h @@ -279,7 +279,8 @@ public: :TypeDef(code, std::string(), children) {} - //TypeDef& operator+=(const Member& ) + //! append additional children. Only for TypeCode::Struct or TypeCode::Union + TypeDef& operator+=(std::initializer_list children); //! Instanciate this definition Value create() const; diff --git a/src/pvxs/nt.h b/src/pvxs/nt.h index f351ea7..fc58331 100644 --- a/src/pvxs/nt.h +++ b/src/pvxs/nt.h @@ -14,6 +14,11 @@ struct epicsTimeStamp; // epicsTime.h namespace pvxs { namespace nt { +struct TimeStamp { + PVXS_API + TypeDef build(); +}; + struct NTScalar { TypeCode value; bool display; diff --git a/src/type.cpp b/src/type.cpp index eac0791..849c220 100644 --- a/src/type.cpp +++ b/src/type.cpp @@ -89,11 +89,11 @@ static void node_validate(const Member* parent, const std::string& id, TypeCode code) { if(!id.empty() && code!=TypeCode::Struct && code!=TypeCode::Union) - throw std::runtime_error("Only Struct or Union may have an ID"); + throw std::logic_error("Only Struct or Union may have an ID"); if(parent) { auto c = parent->code.scalarOf(); if(c!=TypeCode::Struct && c!=TypeCode::Union) - throw std::runtime_error("Only (array of) Struct or Union may have members"); + throw std::logic_error("Only (array of) Struct or Union may have members"); } } @@ -218,6 +218,52 @@ void build_tree(std::vector& desc, const Member& node) } } +static +void append_tree(Member& node, const Member& adopt) +{ + for(auto& child : node.children) { + if(child.name==adopt.name) { + // update of existing. + + if((child.code.kind()==Kind::Compound) != (adopt.code.kind()==Kind::Compound)) { + throw std::logic_error(SB()<<"May not change member '"< children) +{ + if(!top || (top->code!=TypeCode::Struct && top->code!=TypeCode::Union)) + throw std::logic_error("May only append to Struct or Union"); + + std::shared_ptr edit; + if(top.use_count()==1u) + edit = std::const_pointer_cast(top); + else + edit = std::make_shared(*top); // copy + + for(auto& child : children) { + append_tree(*edit, child); + } + + top = std::move(edit); + + return *this; +} + Value TypeDef::create() const { if(!top)