pdb: meta mapping
This commit is contained in:
@ -36,8 +36,7 @@ record(waveform, "$(N):ArrayData") {
|
||||
"$(N):Array":{
|
||||
+id:"epics:nt/NTNDArray:1.0",
|
||||
"value":{+type:"any", +channel:"VAL", +trigger:"*"},
|
||||
"alarm.severity":{+type:"plain", +channel:"SEVR"},
|
||||
"alarm.status":{+type:"plain", +channel:"STAT"}
|
||||
"":{+type:"meta", +channel:"SEVR"}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
@ -21,12 +21,19 @@ typedef std::map<std::string, options_t> config_t;
|
||||
struct context {
|
||||
std::string msg;
|
||||
std::string group, field, key;
|
||||
unsigned depth; // number of '{'s
|
||||
// depth 0 - invalid
|
||||
// depth 1 - top Object
|
||||
// depth 2 - Group
|
||||
// depth 3 - field
|
||||
|
||||
context() :depth(0u) {}
|
||||
|
||||
GroupConfig conf;
|
||||
|
||||
void can_assign()
|
||||
{
|
||||
if(group.empty() || field.empty())
|
||||
if(depth<2 || depth>3)
|
||||
throw std::runtime_error("Can't assign value in this context");
|
||||
}
|
||||
|
||||
@ -34,7 +41,7 @@ struct context {
|
||||
can_assign();
|
||||
GroupConfig::Group& grp = conf.groups[group];
|
||||
|
||||
if(key.empty()) {
|
||||
if(depth==2) {
|
||||
if(field=="+atomic") {
|
||||
grp.atomic = value.as<pvd::boolean>();
|
||||
grp.atomic_set = true;
|
||||
@ -48,7 +55,7 @@ struct context {
|
||||
}
|
||||
field.clear();
|
||||
|
||||
} else {
|
||||
} else if(depth==3) {
|
||||
GroupConfig::Field& fld = grp.fields[field];
|
||||
|
||||
if(key=="+type") {
|
||||
@ -125,8 +132,9 @@ int conf_string(void * ctx, const unsigned char * stringVal,
|
||||
int conf_start_map(void * ctx)
|
||||
{
|
||||
TRY {
|
||||
if(!self->group.empty() && !self->field.empty() && !self->key.empty())
|
||||
throw std::runtime_error("Too deep");
|
||||
self->depth++;
|
||||
if(self->depth>3)
|
||||
throw std::runtime_error("Group field def. can't contain Object (too deep)");
|
||||
return 1;
|
||||
}CATCH()
|
||||
}
|
||||
@ -135,16 +143,16 @@ int conf_map_key(void * ctx, const unsigned char * key,
|
||||
unsigned int stringLen)
|
||||
{
|
||||
TRY {
|
||||
if(stringLen==0)
|
||||
throw std::runtime_error("empty key");
|
||||
if(stringLen==0 && self->depth!=2)
|
||||
throw std::runtime_error("empty group or key name not allowed");
|
||||
|
||||
std::string name((const char*)key, stringLen);
|
||||
|
||||
if(self->group.empty())
|
||||
if(self->depth==1)
|
||||
self->group.swap(name);
|
||||
else if(self->field.empty())
|
||||
else if(self->depth==2)
|
||||
self->field.swap(name);
|
||||
else if(self->key.empty())
|
||||
else if(self->depth==3)
|
||||
self->key.swap(name);
|
||||
else
|
||||
throw std::logic_error("Too deep!!");
|
||||
@ -158,10 +166,15 @@ int conf_end_map(void * ctx)
|
||||
TRY {
|
||||
assert(self->key.empty()); // cleared in assign()
|
||||
|
||||
if(!self->field.empty())
|
||||
if(self->depth==3)
|
||||
self->key.clear();
|
||||
else if(self->depth==2)
|
||||
self->field.clear();
|
||||
else if(!self->group.empty())
|
||||
else if(self->depth==1)
|
||||
self->group.clear();
|
||||
else
|
||||
throw std::logic_error("Invalid depth");
|
||||
self->depth--;
|
||||
|
||||
return 1;
|
||||
}CATCH()
|
||||
|
@ -363,13 +363,14 @@ PDBProvider::PDBProvider(const epics::pvAccess::Configuration::shared_pointer &)
|
||||
|
||||
// parse down attachment point to build/traverse structure
|
||||
FieldName parts(mem.pvfldname);
|
||||
assert(!parts.empty());
|
||||
|
||||
for(size_t j=0; j<parts.size()-1; j++) {
|
||||
if(parts[j].isArray())
|
||||
builder = builder->addNestedStructureArray(parts[j].name);
|
||||
else
|
||||
builder = builder->addNestedStructure(parts[j].name);
|
||||
if(!parts.empty()) {
|
||||
for(size_t j=0; j<parts.size()-1; j++) {
|
||||
if(parts[j].isArray())
|
||||
builder = builder->addNestedStructureArray(parts[j].name);
|
||||
else
|
||||
builder = builder->addNestedStructure(parts[j].name);
|
||||
}
|
||||
}
|
||||
|
||||
if(!mem.structID.empty())
|
||||
@ -381,10 +382,15 @@ PDBProvider::PDBProvider(const epics::pvAccess::Configuration::shared_pointer &)
|
||||
chan.swap(temp);
|
||||
}
|
||||
|
||||
builder = mem.builder->dtype(builder, parts.back().name, chan);
|
||||
if(!parts.empty())
|
||||
builder = mem.builder->dtype(builder, parts.back().name, chan);
|
||||
else
|
||||
builder = mem.builder->dtype(builder, "", chan);
|
||||
|
||||
for(size_t j=0; j<parts.size()-1; j++)
|
||||
builder = builder->endNested();
|
||||
if(!parts.empty()) {
|
||||
for(size_t j=0; j<parts.size()-1; j++)
|
||||
builder = builder->endNested();
|
||||
}
|
||||
|
||||
if(!mem.pvname.empty()) {
|
||||
members_map[mem.pvfldname] = J;
|
||||
@ -611,6 +617,8 @@ PDBProvider::createChannel(std::string const & channelName,
|
||||
|
||||
FieldName::FieldName(const std::string& pv)
|
||||
{
|
||||
if(pv.empty())
|
||||
return;
|
||||
Splitter S(pv.c_str(), '.');
|
||||
std::string part;
|
||||
while(S.snip(part)) {
|
||||
|
@ -400,7 +400,7 @@ void putAll(const PVC &pv, unsigned dbe, db_field_log *pfl)
|
||||
}
|
||||
}
|
||||
|
||||
void findNSMask(pvCommon& pvmeta, dbChannel *chan, const epics::pvData::PVStructurePtr& pvalue)
|
||||
void findNSMask(pvTimeAlarm& pvmeta, dbChannel *chan, const epics::pvData::PVStructurePtr& pvalue)
|
||||
{
|
||||
pdbRecordIterator info(chan);
|
||||
const char *UT = info.info("Q:time:tag");
|
||||
@ -741,7 +741,9 @@ struct PVIFMeta : public PVIF
|
||||
pvd::PVStructurePtr field(std::dynamic_pointer_cast<pvd::PVStructure>(fld));
|
||||
if(!field)
|
||||
throw std::logic_error("PVIFMeta attached type mis-match");
|
||||
meta.chan = channel;
|
||||
attachTime(meta, field);
|
||||
findNSMask(meta, channel, field);
|
||||
if(enclosing) {
|
||||
meta.maskALWAYS.clear();
|
||||
meta.maskALWAYS.set(enclosing->getFieldOffset());
|
||||
@ -788,8 +790,15 @@ struct MetaBuilder : public PVIFBuilder
|
||||
dbChannel *channel)
|
||||
{
|
||||
pvd::StandardFieldPtr std(pvd::getStandardField());
|
||||
return builder->add("alarm", std->alarm())
|
||||
->add("timeStamp", std->timeStamp());
|
||||
if(fld.empty()) {
|
||||
return builder->add("alarm", std->alarm())
|
||||
->add("timeStamp", std->timeStamp());
|
||||
} else {
|
||||
return builder->addNestedStructure(fld)
|
||||
->add("alarm", std->alarm())
|
||||
->add("timeStamp", std->timeStamp())
|
||||
->endNested();
|
||||
}
|
||||
}
|
||||
|
||||
// Attach to a structure instance.
|
||||
@ -800,7 +809,7 @@ struct MetaBuilder : public PVIFBuilder
|
||||
const FieldName& fldname) OVERRIDE FINAL
|
||||
{
|
||||
if(!channel)
|
||||
throw std::runtime_error("+type:\"any\" requires +channel:");
|
||||
throw std::runtime_error("+type:\"meta\" requires +channel:");
|
||||
|
||||
pvd::PVField *enclosing = 0;
|
||||
pvd::PVFieldPtr fld(fldname.lookup(root, &enclosing));
|
||||
|
@ -19,9 +19,12 @@ void test_parse()
|
||||
" \"fld\":{\n"
|
||||
" \"+type\": \"simple\","
|
||||
" \"+putorder\": -4"
|
||||
" },\n"
|
||||
" \"\":{\n"
|
||||
" \"+type\": \"top\""
|
||||
" }\n"
|
||||
" },\n"
|
||||
" \"fld2\":{\n"
|
||||
" \"grpb\":{\n"
|
||||
" }\n"
|
||||
"}";
|
||||
|
||||
@ -36,12 +39,18 @@ void test_parse()
|
||||
testEqual(conf.groups["grpa"].fields["fld"].type, "simple");
|
||||
testEqual(conf.groups["grpa"].fields["fld"].channel, "");
|
||||
testEqual(conf.groups["grpa"].fields["fld"].putorder, -4);
|
||||
|
||||
testEqual(conf.groups["grpa"].fields[""].type, "top");
|
||||
}
|
||||
|
||||
void test_fail()
|
||||
{
|
||||
testDiag("test_fail()");
|
||||
|
||||
{
|
||||
GroupConfig conf;
|
||||
testThrows(std::runtime_error, GroupConfig::parse("{", conf));
|
||||
}
|
||||
{
|
||||
GroupConfig conf;
|
||||
testThrows(std::runtime_error, GroupConfig::parse("{\"G\":{\"F\":{\"K\":{}}}}", conf));
|
||||
@ -56,7 +65,7 @@ void test_fail()
|
||||
|
||||
MAIN(testanyscalar)
|
||||
{
|
||||
testPlan(8);
|
||||
testPlan(10);
|
||||
try {
|
||||
test_parse();
|
||||
test_fail();
|
||||
|
Reference in New Issue
Block a user