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