Belle II Software  release-08-01-10
NSMData.cc
1 /**************************************************************************
2  * basf2 (Belle II Analysis Software Framework) *
3  * Author: The Belle II Collaboration *
4  * *
5  * See git log for contributors and copyright holders. *
6  * This file is licensed under LGPL-3.0, see LICENSE.md. *
7  **************************************************************************/
8 #include "daq/slc/nsm/NSMData.h"
9 
10 #include "daq/slc/nsm/NSMCommunicator.h"
11 #include "daq/slc/nsm/NSMCallback.h"
12 #include "daq/slc/nsm/NSMHandlerException.h"
13 
14 #include <daq/slc/system/Time.h>
15 
16 #include <daq/slc/base/ConfigFile.h>
17 #include <daq/slc/base/StringUtil.h>
18 #include <daq/slc/base/Writer.h>
19 #include <daq/slc/base/Reader.h>
20 
21 #include <nsm2/belle2nsm.h>
22 extern "C" {
23 #include <nsm2/nsmlib2.h>
24 }
25 
26 #include <cstdio>
27 #include <cstdlib>
28 #include <cstring>
29 #include <unistd.h>
30 
31 using namespace Belle2;
32 
33 NSMData::NSMData(const std::string& dataname,
34  const std::string& format, int revision)
35  : AbstractDBObject(), m_allocated(false),
36  m_pdata(NULL), m_size(0), m_offset(0)
37 {
38  setName(dataname);
39  setFormat(format);
40  setRevision(revision);
41 }
42 
43 NSMData::NSMData()
44  : AbstractDBObject(), m_allocated(false),
45  m_pdata(NULL), m_size(0), m_offset(0)
46 {
47  setRevision(-1);
48 }
49 
50 NSMData::NSMData(const NSMData& data)
51  : AbstractDBObject(data)
52 {
53  m_allocated = data.m_allocated;
54  m_size = data.m_size;
55  setFormat(data.getFormat());
56  setRevision(data.getRevision());
57  setIndex(data.getIndex());
58  setName(data.getName());
59  m_pdata = NULL;
60  if (m_allocated) {
61  m_pdata = malloc(m_size);
62  memcpy(m_pdata, data.m_pdata, m_size);
63  } else {
64  if (data.m_pdata != NULL) m_pdata = data.m_pdata;
65  }
66  const DBField::NameList& name_v(data.getFieldNames());
67  for (DBField::NameList::const_iterator it = name_v.begin();
68  it != name_v.end(); ++it) {
69  const std::string& name(*it);
70  const DBField::Property& pro(data.getProperty(name));
71  add(name, pro);
72  if (pro.getType() == DBField::OBJECT) {
73  NSMDataList data_v(data.getObjects(name));
74  for (size_t i = 0; i < data_v.size(); i++) {
75  NSMData& cdata(data_v[i]);
76  cdata.m_pdata = (void*)((char*)m_pdata +
77  pro.getOffset() + cdata.m_size * i);
78  }
79  m_data_v_m.insert(NSMDataListMap::value_type(name, data_v));
80  }
81  }
82 }
83 
84 NSMData::~NSMData()
85 {
86  reset();
87  if (m_allocated && m_pdata != NULL) {
88  free(m_pdata);
89  m_pdata = NULL;
90  }
91 }
92 
93 const NSMData& NSMData::operator=(const NSMData& data)
94 {
96  m_allocated = data.m_allocated;
97  m_pdata = data.m_pdata;
98  m_size = data.m_size;
99  m_offset = data.m_offset;
100  m_format = data.m_format;
101  m_revision = data.m_revision;
102  m_data_v_m = data.m_data_v_m;
103  m_empty = data.m_empty;
104  m_com = data.m_com;
105  m_tstamp = data.m_tstamp;
106  return *this;
107 }
108 
109 void NSMData::reset()
110 {
111  AbstractDBObject::reset();
112  if (m_allocated && m_pdata != NULL) {
113  free(m_pdata);
114  m_pdata = NULL;
115  }
116 }
117 
118 void NSMData::addValue(const std::string& name, const void* data,
119  DBField::Type type, int length)
120 {
121  DBField::Property pro(type, length, m_offset);
122  if (length == 0) length = 1;
123  int size = pro.getTypeSize() * length;
124  if (size <= 0) return;
125  if (!hasField(name)) {
126  add(name, pro);
127  m_offset += size;
128  }
129  if (data != NULL) {
130  memcpy((char*)m_pdata + pro.getOffset(), data, size);
131  }
132 }
133 
134 void NSMData::setValue(const std::string& name, const void* data,
135  int length)
136 {
137  const DBField::Property& pro(getProperty(name));
138  if (length == 0) length = 1;
139  int size = pro.getTypeSize() * length;
140  if (data != NULL && hasField(name) && size > 0) {
141  memcpy((char*)m_pdata + pro.getOffset(), data, size);
142  }
143 }
144 
145 void* NSMData::open(NSMCommunicator& com)
146 {
147  if (m_pdata == NULL) {
148  b2nsm_context(com.getContext());
149  if (getenv("NSM2_INCDIR") == NULL) {
150  ConfigFile file("slowcontrol");
151  setenv("NSM2_INCDIR", file.get("nsm.data.incpath").c_str(), 0);
152  }
153  if ((m_pdata = b2nsm_openmem(getName().c_str(), getFormat().c_str(),
154  getRevision())) == NULL) {
155  throw (NSMHandlerException("Failed to open data memory %s (%s %s %d)",
156  nsmlib_strerror(com.getContext()), getName().c_str(), getFormat().c_str(),
157  getRevision()));
158  }
159  parse();
160  }
161  return m_pdata;
162 }
163 
164 void* NSMData::allocate(NSMCommunicator& com, int interval)
165 {
166  if (m_pdata == NULL) {
167  b2nsm_context(com.getContext());
168  if (getenv("NSM2_INCDIR") == NULL) {
169  ConfigFile file("slowcontrol");
170  setenv("NSM2_INCDIR", file.get("nsm.data.incpath").c_str(), 0);
171  }
172  if ((m_pdata = b2nsm_allocmem(getName().c_str(), getFormat().c_str(),
173  getRevision(), interval)) == NULL) {
174  throw (NSMHandlerException("Failed to allocate data memory %s",
175  nsmlib_strerror(com.getContext())));
176  }
177  parse();
178  memset(m_pdata, 0, m_size);
179  m_com = &com;
180  m_tstamp = 0;
181  /*
182  com.getCallback().add(new NSMVHandlerText("nsmdata.name", true, false, getName()));
183  com.getCallback().add(new NSMVHandlerText("nsmdata.format", true, false, getFormat()));
184  com.getCallback().add(new NSMVHandlerInt("nsmdata.revision", true, false, getRevision()));
185  com.getCallback().add(new NSMVHandlerInt("nsmdata.tstamp", true, false, m_tstamp));
186  */
187  }
188  return m_pdata;
189 }
190 
191 void* NSMData::parse(const char* incpath, bool malloc_new)
192 {
193 #if NSM_PACKAGE_VERSION >= 1914
194  if (getenv("NSM2_INCDIR") == NULL) {
195  ConfigFile file("slowcontrol");
196  setenv("NSM2_INCDIR", file.get("nsm.data.incpath").c_str(), 0);
197  }
198  NSMparse* ptr = NULL;
199  char fmtstr[256];
200  int revision = 0;
201  if ((ptr = (NSMparse*)nsmlib_parsefile(getFormat().c_str(), getRevision(),
202  incpath, fmtstr, &revision)) == NULL) {
203  throw (NSMHandlerException("Failed to parse header file (%s:%d) : %s",
204  getFormat().c_str(), getRevision(), nsmlib_parseerr(NULL)));
205  }
206  if (getRevision() != revision && revision > 0) {
207  setRevision(revision);
208  }
209  int length;
210  std::string name_in;
211  parse(ptr, length, name_in);
212  if (m_size > 0 && malloc_new) {
213  m_allocated = true;
214  return (m_pdata = malloc(m_size));
215  }
216 #else
217  throw (NSMHandlerException("too old nsmlib (nsmparse) : version = %d", NSM_PACKAGE_VERSION));
218 #endif
219  return NULL;
220 }
221 
222 void NSMData::flush()
223 {
224 #if NSM_PACKAGE_VERSION >= 1914
225  m_tstamp = Time().getSecond();
226  sleep(1);
227  m_com->getCallback().set("nsmdata.tstamp", m_tstamp);
228 #endif
229 }
230 
231 #if NSM_PACKAGE_VERSION >= 1914
232 NSMparse* NSMData::parse(NSMparse* ptr, int& length, std::string& name_in)
233 {
234  m_size = 0;
235  while (ptr != NULL) {
236  length = ptr->size;
237  if (length < 0) length = 0;
238  int type = ptr->type;
239  std::string name = ptr->name;
240  int offset = ptr->offset;
241  m_offset = offset;
242  if (type == 'l') type = DBField::LONG;//INT64;
243  else if (type == 'i') type = DBField::INT;//INT32;
244  else if (type == 's') type = DBField::SHORT;//INT16;
245  else if (type == 'c') type = DBField::CHAR;//CHAR;
246  else if (type == 'L') type = DBField::LONG;//UINT64;
247  else if (type == 'I') type = DBField::INT;//UINT32;
248  else if (type == 'S') type = DBField::SHORT;//UINT16;
249  else if (type == 'C') type = DBField::CHAR;//BYTE8;
250  else if (type == 'd') type = DBField::DOUBLE;
251  else if (type == 'f') type = DBField::FLOAT;
252  else if (type == '(') {
253  NSMData data(getName(), getFormat() + "." + name, getRevision());
254  char* pdata = ((char*)m_pdata + offset);
255  data.m_pdata = pdata;
256  ptr = data.parse(ptr->next, length, name);
257  data.setFormat(getFormat() + "." + name);
258  int len = (length == 0) ? 1 : length;
259  NSMDataList data_v;
260  for (int i = 0; i < len; i++) {
261  data.setIndex(i);
262  data.m_pdata = (void*)(pdata + i * data.getSize());
263  data_v.push_back(data);
264  }
265  m_data_v_m.insert(NSMDataListMap::value_type(name, data_v));
266  type = DBField::OBJECT;
267  m_size += data.m_size * length;
268  } else if (type == ')') {
269  name_in = name;
270  return ptr;
271  }
272  DBField::Property pro((DBField::Type)type, length, offset);
273  add(name, pro);
274  int len = (length == 0) ? 1 : length;
275  m_size += pro.getTypeSize() * len;
276  if (ptr == NULL) break;
277  ptr = ptr->next;
278  }
279  return 0;
280 }
281 #endif
282 
283 void* NSMData::getValue(const std::string& name)
284 {
285  if (!hasValue(name)) return NULL;
286  char* data = (char*)get();
287  return (data + getProperty(name).getOffset());
288 }
289 
290 const void* NSMData::getValue(const std::string& name)
291 const
292 {
293  if (!hasValue(name)) return NULL;
294  char* data = (char*)get();
295  return (data + getProperty(name).getOffset());
296 }
297 
298 void NSMData::readObject(Reader& reader)
299 {
300  setName(reader.readString());
301  setFormat(reader.readString());
302  setRevision(reader.readInt());
303  int size = reader.readInt();
304  if (m_size > 0 && m_size < size) {
305  m_allocated = true;
306  free(m_pdata);
307  m_pdata = malloc(size);
308  }
309  setSize(size);
310  int npars = reader.readInt();
311  for (int n = 0; n < npars; n++) {
312  std::string name = reader.readString();
313  DBField::Type type = (DBField::Type)reader.readInt();
314  size_t length = reader.readInt();
315  size_t offset = reader.readInt();
316  if (!hasValue(name)) add(name, DBField::Property(type, length, offset));
317  void* buf = getValue(name);
318  if (length == 0) length = 1;
319  if (type == DBField::OBJECT) {
320  NSMDataList data_v;
321  for (size_t i = 0; i < length; i++) {
322  NSMData data;
323  data.m_pdata = (char*)getValue(name) + length * i;
324  reader.readObject(data);
325  data_v.push_back(data);
326  }
327  m_data_v_m.insert(NSMDataListMap::value_type(name, data_v));
328  } else {
329  for (size_t i = 0; i < length; i++) {
330  switch (type) {
331  case DBField::CHAR: ((char*)buf)[i] = reader.readChar(); break;
332  case DBField::SHORT: ((int16*)buf)[i] = reader.readShort(); break;
333  case DBField::INT: ((int32*)buf)[i] = reader.readInt(); break;
334  case DBField::LONG: ((int64*)buf)[i] = reader.readLong(); break;
335  case DBField::FLOAT: ((float*)buf)[i] = reader.readFloat(); break;
336  case DBField::DOUBLE: ((double*)buf)[i] = reader.readDouble(); break;
337  default: break;
338  }
339  }
340  }
341  }
342 }
343 
344 void NSMData::writeObject(Writer& writer) const
345 {
346  writer.writeString(getName());
347  writer.writeString(getFormat());
348  writer.writeInt(getRevision());
349  writer.writeInt(getSize());
350  const DBField::NameList& name_v(getFieldNames());
351  writer.writeInt(name_v.size());
352  for (DBField::NameList::const_iterator it = name_v.begin();
353  it != name_v.end(); ++it) {
354  const std::string& name(*it);
355  writer.writeString(name);
356  const DBField::Property& pro(getProperty(name));
357  writer.writeInt(pro.getType());
358  writer.writeInt(pro.getLength());
359  writer.writeInt(pro.getOffset());
360  size_t length = pro.getLength();
361  const void* buf = getValue(name);
362  if (length == 0) length = 1;
363  if (pro.getType() == DBField::OBJECT) {
364  const NSMDataList& data_v(getObjects(name));
365  for (size_t i = 0; i < length; i++) {
366  writer.writeObject(data_v[i]);
367  }
368  } else {
369  for (size_t i = 0; i < length; i++) {
370  switch (pro.getType()) {
371  case DBField::CHAR: writer.writeChar(((char*)buf)[i]); break;
372  case DBField::SHORT: writer.writeShort(((int16*)buf)[i]); break;
373  case DBField::INT: writer.writeInt(((int64*)buf)[i]); break;
374  case DBField::LONG: writer.writeLong(((int32*)buf)[i]); break;
375  case DBField::FLOAT: writer.writeFloat(((float*)buf)[i]); break;
376  case DBField::DOUBLE: writer.writeDouble(((double*)buf)[i]); break;
377  default : break;
378  }
379  }
380  }
381  }
382 }
383 
384 void NSMData::print(const std::string& name_in) const
385 {
386  NameValueList map;
387  search(map, name_in);
388  size_t length = 0;
389  for (NameValueList::iterator it = map.begin();
390  it != map.end(); ++it) {
391  if (it->name.size() > length) length = it->name.size();
392  }
393  for (NameValueList::iterator it = map.begin();
394  it != map.end(); ++it) {
395  printf(StringUtil::form("%%-%ds : %%s\n", length).c_str(),
396  it->name.c_str(), it->value.c_str());
397  }
398 }
399 
400 void NSMData::search(NSMData::NameValueList& map,
401  const std::string& name_in) const
402 {
403  const DBField::NameList& name_v(getFieldNames());
404  for (DBField::NameList::const_iterator it = name_v.begin();
405  it != name_v.end(); ++it) {
406  const std::string& name(*it);
407  const DBField::Property& pro(getProperty(name));
408  size_t length = pro.getLength();
409  std::string name_out = name_in;
410  if (name_in.size() > 0) name_out += ".";
411  name_out += name;
412  if (length > 0) {
413  if (pro.getType() == DBField::OBJECT) {
414  const NSMDataList& data_v(getObjects(name));
415  for (size_t i = 0; i < length; i++) {
416  data_v[i].search(map, StringUtil::form("%s[%d]", name_out.c_str(), i));
417  }
418  } else {
419  const void* buf = getValue(name);
420  if (pro.getType() == DBField::CHAR) {
421  NameValue nv;
422  nv.name = name_out;
423  nv.value = (char*)buf;
424  map.push_back(nv);
425  } else {
426  const char* name_c = name_out.c_str();
427  for (int i = 0; i < (int)length; i++) {
428  std::string vname = StringUtil::form("%s[%d]", name_c, i);
429  std::string val;
430  switch (pro.getType()) {
431  case DBField::SHORT:
432  val = StringUtil::form("%d", ((int16*)buf)[i]); break;
433  case DBField::INT:
434  val = StringUtil::form("%d", ((int32*)buf)[i]); break;
435  case DBField::LONG:
436  val = StringUtil::form("%ld", ((int64*)buf)[i]); break;
437  case DBField::FLOAT:
438  val = StringUtil::form("%f", ((float*)buf)[i]); break;
439  case DBField::DOUBLE:
440  val = StringUtil::form("%d", ((double*)buf)[i]); break;
441  default : break;
442  }
443  NameValue nv;
444  nv.name = vname;
445  nv.value = val;
446  map.push_back(nv);
447  }
448  }
449  }
450  } else {
451  if (pro.getType() == DBField::OBJECT) {
452  const NSMDataList& data_v(getObjects(name));
453  data_v[0].search(map, name_out);
454  } else {
455  NameValue nv;
456  nv.name = name_out;
457  nv.value = getValueText(name);
458  map.push_back(nv);
459  }
460  }
461  }
462 }
463 
464 void NSMData::printPV(const std::string& name_in) const
465 {
466  const DBField::NameList& name_v(getFieldNames());
467  for (DBField::NameList::const_iterator it = name_v.begin();
468  it != name_v.end(); ++it) {
469  const std::string& name(*it);
470  const DBField::Property& pro(getProperty(name));
471  size_t length = pro.getLength();
472  std::string name_out = name_in;
473  if (name_in.size() > 0) name_out += ":";
474  else {
475  name_out += (getName() + ":") + (getFormat() + ":");
476  }
477  name_out += name;
478  std::string pvtype;
479  switch (pro.getType()) {
480  case DBField::CHAR:
481  case DBField::SHORT:
482  case DBField::INT:
483  case DBField::LONG: pvtype = "longin"; break;
484  case DBField::FLOAT:
485  case DBField::DOUBLE: pvtype = "ai"; break;
486  default : break;
487  }
488  if (length > 0) {
489  if (pro.getType() == DBField::OBJECT) {
490  const NSMDataList& data_v(getObjects(name));
491  for (size_t i = 0; i < length; i++) {
492  data_v[i].printPV(StringUtil::form("%s[%d]", name_out.c_str(), i));
493  }
494  } else {
495  for (size_t i = 0; i < length; i++) {
496  printf("record(%s, \"B2_nsm:%s[%d]\")\n"
497  "{\n"
498  " field(SCAN, \".1 second\")\n"
499  " field(DTYP, \"nsm2_data_%s\")\n"
500  "}\n\n", pvtype.c_str(), name_out.c_str(), (int)i, pvtype.c_str());
501  }
502  }
503  } else {
504  if (pro.getType() == DBField::OBJECT) {
505  const NSMDataList& data_v(getObjects(name));
506  data_v[0].print(name_out);
507  } else {
508  printf("record(%s, \"B2_nsm2:%s\")\n"
509  "{\n"
510  " field(SCAN, \".1 second\")\n"
511  " field(DTYP, \"nsm2_data_%s\")\n"
512  "}\n\n", pvtype.c_str(), name_out.c_str(), pvtype.c_str());
513  }
514  }
515  }
516 }
517 
518 const void* NSMData::find(const std::string& name_in, DBField::Type& type, int& length) const
519 {
520  size_t pos;
521  std::string name_out = name_in;
522  if ((pos = name_in.find(".")) != std::string::npos) {
523  StringList str = StringUtil::split(name_out, '.');
524  StringList sstr = StringUtil::split(str[0], '[');
525  const NSMDataList& data_v(getObjects(sstr[0]));
526  int index = 0;
527  if (sstr.size() > 1) {
528  index = atoi(sstr[1].c_str());
529  }
530  name_out = name_in.substr(pos + 1);
531  return data_v[index].find(name_out, type, length);
532  }
533  int index = 0;
534  if ((pos = name_out.find("[")) != std::string::npos) {
535  StringList str = StringUtil::split(name_out, '[');
536  name_out = str[0];
537  index = atoi(str[1].c_str());
538  }
539  if (!hasValue(name_out)) return NULL;
540  const DBField::Property& pro(getProperty(name_out));
541  length = pro.getLength();
542  type = pro.getType();
543  const void* buf = getValue(name_out);
544  switch (type) {
545  case DBField::CHAR: return (((const char*)buf) + index);
546  case DBField::SHORT: return (((const int16*)buf) + index);
547  case DBField::INT: return (((const int32*)buf) + index);
548  case DBField::LONG: return (((const int64*)buf) + index);
549  case DBField::FLOAT: return (((const float*)buf) + index);
550  case DBField::DOUBLE: return (((const double*)buf) + index);
551  default: return NULL;
552  }
553  return NULL;
554 }
555 
556 int NSMData::getNObjects(const std::string& name) const
557 {
558  NSMDataListMap::const_iterator it = m_data_v_m.find(name);
559  if (it != m_data_v_m.end()) return it->second.size();
560  return 0;
561 }
562 
563 const NSMData& NSMData::getObject(const std::string& name, int index) const
564 {
565  NSMDataListMap::const_iterator it = m_data_v_m.find(name);
566  if (it != m_data_v_m.end()) return it->second[index];
567  else throw (std::out_of_range(StringUtil::form("%s:%d", __FILE__, __LINE__)));
568 }
569 
570 NSMData& NSMData::getObject(const std::string& name, int index)
571 {
572  NSMDataListMap::iterator it = m_data_v_m.find(name);
573  if (it != m_data_v_m.end()) return it->second[index];
574  else throw (std::out_of_range(StringUtil::form("%s:%d", __FILE__, __LINE__)));
575 }
576 
577 const NSMData::NSMDataList& NSMData::getObjects(const std::string& name) const
578 {
579  NSMDataListMap::const_iterator it = m_data_v_m.find(name);
580  if (it != m_data_v_m.end()) return it->second;
581  else throw (std::out_of_range(StringUtil::form("%s:%d", __FILE__, __LINE__)));
582 }
583 
584 NSMData::NSMDataList& NSMData::getObjects(const std::string& name)
585 {
586  NSMDataListMap::iterator it = m_data_v_m.find(name);
587  if (it != m_data_v_m.end()) return it->second;
588  else throw (std::out_of_range(StringUtil::form("%s:%d", __FILE__, __LINE__)));
589 }
590 
const AbstractDBObject & operator=(const AbstractDBObject &object)
Operator =.
const NSMData & operator=(const NSMData &data)
Operator =.
Definition: NSMData.cc:93
Abstract base class for different kinds of events.