pva2pva  1.4.1
 All Classes Functions Variables Pages
dbf_copy.cpp
1 
2 #include <epicsStdio.h>
3 #include <dbAccess.h>
4 #include <dbChannel.h>
5 #include <dbStaticLib.h>
6 #include <dbLock.h>
7 #include <dbEvent.h>
8 #include <epicsString.h>
9 #include <epicsVersion.h>
10 
11 #include <pv/status.h>
12 #include <pv/bitSet.h>
13 #include <pv/pvData.h>
14 #include <pv/anyscalar.h>
15 
16 #include "pvif.h"
17 
18 namespace pvd = epics::pvData;
19 
20 // note that we handle DBF_ENUM differently than in pvif.cpp
21 static
22 pvd::ScalarType DBR2PVD(short dbr)
23 {
24  switch(dbr) {
25 #define CASE(BASETYPE, PVATYPE, DBFTYPE, PVACODE) case DBR_##DBFTYPE: return pvd::pv##PVACODE;
26 #define CASE_SKIP_BOOL
27 #define CASE_REAL_INT64
28 #include "pv/typemap.h"
29 #undef CASE_SKIP_BOOL
30 #undef CASE_REAL_INT64
31 #undef CASE
32  case DBF_ENUM: return pvd::pvUShort;
33  case DBF_STRING: return pvd::pvString;
34  }
35  throw std::invalid_argument("Unsupported DBR code");
36 }
37 
38 long copyPVD2DBF(const pvd::PVField::const_shared_pointer& inraw,
39  void *outbuf, short outdbf, long *outnReq)
40 {
41  long nreq = outnReq ? *outnReq : 1;
42  if(!inraw || nreq <= 0 || INVALID_DB_REQ(outdbf)) return S_db_errArg;
43 
44  pvd::ScalarType outpvd = DBR2PVD(outdbf);
45 
46  pvd::PVField::const_shared_pointer in(inraw);
47 
48  if(outdbf != DBF_STRING && in->getField()->getType() == pvd::structure) {
49  // assume NTEnum.
50  // index to string not requested, so attempt to treat .index as plain integer
51  in = static_cast<const pvd::PVStructure*>(in.get())->getSubField("index");
52  if(!in) return S_db_errArg;
53  }
54 
55  if(in->getField()->getType() == pvd::structure) {
56  assert(outdbf == DBF_STRING);
57  char *outsbuf = (char*)outbuf;
58 
59  // maybe NTEnum
60  // try index -> string
61  const pvd::PVStructure* sin = static_cast<const pvd::PVStructure*>(in.get());
62 
63  pvd::PVScalar::const_shared_pointer index(sin->getSubField<pvd::PVScalar>("index"));
64  if(!index) return S_db_badField; // Not NTEnum, don't know how to handle...
65 
66  // we will have an answer.
67  if(outnReq)
68  *outnReq = 1;
69 
70  pvd::uint16 ival = index->getAs<pvd::uint16>();
71 
72 
73  pvd::PVStringArray::const_shared_pointer choices(sin->getSubField<pvd::PVStringArray>("choices"));
74 
75  if(choices) {
76  pvd::PVStringArray::const_svector strs(choices->view());
77 
78  if(ival < strs.size()) {
79  // found it!
80 
81  const std::string& sval = strs[ival];
82  size_t slen = std::min(sval.size(), size_t(MAX_STRING_SIZE-1));
83  memcpy(outbuf, sval.c_str(), slen);
84  outsbuf[slen] = '\0';
85  return 0;
86  }
87  }
88  // didn't find it. either no choices or index is out of range
89 
90  // print numeric index
91  epicsSnprintf(outsbuf, MAX_STRING_SIZE, "%u", ival);
92  return 0;
93 
94  } else if(in->getField()->getType() == pvd::scalarArray) {
95  const pvd::PVScalarArray* sarr = static_cast<const pvd::PVScalarArray*>(in.get());
96  pvd::shared_vector<const void> arr;
97  sarr->getAs(arr);
98  size_t elemsize = pvd::ScalarTypeFunc::elementSize(arr.original_type());
99 
100  arr.slice(0, nreq*elemsize);
101  nreq = arr.size()/elemsize;
102 
103  if(outdbf == DBF_STRING) {
104  char *outsbuf = (char*)outbuf;
105 
106  // allocate a temp buffer of string[], ick...
107  pvd::shared_vector<std::string> strs(nreq); // alloc
108 
109  pvd::castUnsafeV(nreq, pvd::pvString, strs.data(), arr.original_type(), arr.data());
110 
111  for(long i =0; i<nreq; i++, outsbuf += MAX_STRING_SIZE) {
112  size_t slen = std::min(strs[i].size(), size_t(MAX_STRING_SIZE-1));
113  memcpy(outsbuf, strs[i].c_str(), slen);
114  outsbuf[slen] = '\0';
115  }
116 
117  } else {
118  pvd::castUnsafeV(nreq, outpvd, outbuf, arr.original_type(), arr.data());
119  }
120 
121  if(outnReq)
122  *outnReq = nreq;
123  return 0;
124 
125  } else if(in->getField()->getType() == pvd::scalar) {
126  char *outsbuf = (char*)outbuf;
127  const pvd::PVScalar* sval = static_cast<const pvd::PVScalar*>(in.get());
128  pvd::AnyScalar val;
129  sval->getAs(val);
130 
131  if(outdbf == DBF_STRING && val.type()==pvd::pvString) {
132  // std::string to char*
133  size_t len = std::min(val.as<std::string>().size(), size_t(MAX_STRING_SIZE-1));
134 
135  memcpy(outbuf, val.as<std::string>().c_str(), len);
136  outsbuf[len] = '\0';
137 
138  } else if(outdbf == DBF_STRING) {
139  // non-string to char*
140  std::string temp;
141 
142  pvd::castUnsafeV(1, pvd::pvString, &temp, val.type(), val.unsafe());
143 
144  size_t len = std::min(temp.size(), size_t(MAX_STRING_SIZE-1));
145 
146  memcpy(outbuf, temp.c_str(), len);
147  outsbuf[len] = '\0';
148 
149  } else {
150  // non-string to any
151  pvd::castUnsafeV(1, outpvd, outbuf, val.type(), val.unsafe());
152  }
153 
154  if(outnReq)
155  *outnReq = 1;
156  return 0;
157 
158  } else {
159  // struct array or other strangeness which I don't know how to handle
160  return S_dbLib_badField;
161  }
162 }
163 
164 long copyDBF2PVD(const pvd::shared_vector<const void> &inbuf,
165  const pvd::PVField::shared_pointer& outraw,
166  pvd::BitSet& changed,
167  const pvd::PVStringArray::const_svector &choices)
168 {
169 
170  pvd::ScalarType inpvd = inbuf.original_type();
171  size_t incnt = inbuf.size()/pvd::ScalarTypeFunc::elementSize(inpvd);
172 
173  if(!outraw) return S_db_errArg;
174 
175  pvd::PVField::shared_pointer out(outraw);
176 
177  if(inpvd != pvd::pvString && out->getField()->getType() == pvd::structure) {
178  // assume NTEnum.
179  // string to index not requested, so attempt to treat .index as plain integer
180  out = static_cast<pvd::PVStructure*>(out.get())->getSubField("index");
181  if(!out) return S_db_errArg;
182  }
183 
184  if(out->getField()->getType() == pvd::structure) {
185  assert(inpvd == pvd::pvString);
186 
187  if(incnt==0)
188  return S_db_errArg; // Need at least one string
189 
190  const pvd::shared_vector<const std::string> insbuf(pvd::static_shared_vector_cast<const std::string>(inbuf));
191  const std::string& instr(insbuf[0]);
192 
193  // assume NTEnum
194  // try string to index, then parse
195  pvd::PVStructure* sout = static_cast<pvd::PVStructure*>(out.get());
196 
197  pvd::PVScalar::shared_pointer index(sout->getSubField<pvd::PVScalar>("index"));
198  if(!index) return S_db_badField; // Not NTEnum, don't know how to handle...
199 
200  pvd::uint16 result = pvd::uint16(-1);
201  bool match = false;
202 
203  for(size_t i=0, N=std::min(size_t(0xffff), choices.size()); i<N; i++) {
204  if(choices[i] == instr) {
205  match = true;
206  result = pvd::uint16(i);
207  }
208  }
209 
210  if(!match) {
211  // no choice string matched, so try to parse as integer
212 
213  try{
214  result = pvd::castUnsafe<pvd::uint16>(instr);
215  }catch(std::exception&){
216  return S_db_errArg;
217  }
218  }
219 
220  index->putFrom(result);
221 
222  out = index;
223 
224  } else if(out->getField()->getType() == pvd::scalarArray) {
225  pvd::PVScalarArray* sarr = static_cast<pvd::PVScalarArray*>(out.get());
226 
227  sarr->putFrom(inbuf);
228 
229  } else if(out->getField()->getType() == pvd::scalar) {
230  pvd::PVScalar* sval = static_cast<pvd::PVScalar*>(out.get());
231 
232  if(incnt==0) return S_db_errArg;
233 
234  pvd::AnyScalar val(inpvd, inbuf.data());
235 
236  sval->putFrom(val);
237 
238  } else {
239  // struct array or other strangeness which I don't know how to handle
240  return S_db_badField;
241  }
242 
243  changed.set(out->getFieldOffset());
244  return 0;
245 }