C++ Instrument Catalog
VISAInstrumentBuffer.h
Go to the documentation of this file.
1 #pragma once
2 
3 #include <iterator>
4 
5 #include "VISAInstrumentTypes.h"
6 #include "Synchronization.h"
7 
8 using namespace MTL::Synchronization;
9 
10 namespace MTL {
11  namespace Instrument {
12 
13  //----------------------------------------------------------------------//
14  // VISA Buffer //
15  //----------------------------------------------------------------------//
16  // This class is intended to provide an efficient way of reading data
17  // through VISA and easy aswer parsing.
18  // VISA Read requires an allocated buffer pointer and its length.
19  // Parsing methods (regex, find etc...) require std::string object or
20  // iterators.
21  // - std::string doesn't ensure to store data contiguously: cannot write
22  // to it through a pointer.
23  // - std::vector ensures contiguous storage and it is allowed to write to
24  // its allocated storage (capacity) through a pointer. But it is
25  // impossible to set its size. It is thus not possible to indicate how
26  // many bytes have been stored into the vector after a read.
27  //
28  // This class holds data into an std::vector. Storage allocation in thus
29  // stored into contiguous memory and memory allocation is auto handled.
30  // A size member is managed by this class itself and can be set by a
31  // method. We must ensure that this class size is always lower or equal
32  // to the contained vector size (the class capacity is equivalent to the
33  // contained vector size).
34  //----------------------------------------------------------------------//
35  //#define MTL_VISA_BUFFER_TYPE ViByte
36  #define MTL_VISA_BUFFER_TYPE char
38  {
39  private:
40  mutable CRecursiveMutex m_Lock;
41  std::vector<MTL_VISA_BUFFER_TYPE> m_Vector; // Used to store the data contiguously
42  size_t m_Size; // Used to handle the real size
43  public:
44  CVISABuffer(size_t InitialCapacity = 2048)
45  : m_Vector(), m_Size(0)
46  {
47  CLockGuard<CRecursiveMutex> Lock(m_Lock);
48 
49  reserve(InitialCapacity);
50  }
51  CVISABuffer(const MTL_VISA_BUFFER_TYPE * pData, size_t DataLen)
52  : m_Vector(), m_Size(0)
53  {
54  CLockGuard<CRecursiveMutex> Lock(m_Lock);
55 
56  assign(pData, pData + DataLen);
57  }
58  virtual ~CVISABuffer()
59  {}
60 
61  void clear()
62  {
63  CLockGuard<CRecursiveMutex> Lock(m_Lock);
64 
65  m_Size = 0;
66  }
67  void reserve(size_t capacity)
68  {
69  CLockGuard<CRecursiveMutex> Lock(m_Lock);
70 
71  if (capacity > m_Vector.size())
72  m_Vector.resize(capacity);
73  }
74  void resize(size_t size)
75  {
76  CLockGuard<CRecursiveMutex> Lock(m_Lock);
77 
78  if (size > m_Vector.size())
79  {
80  // Ensure the vector can contain at least the required size
81  m_Vector.resize(size);
82  }
83  m_Size = size;
84  }
85 
86  size_t size() const
87  {
88  CLockGuard<CRecursiveMutex> Lock(m_Lock);
89 
90  return m_Size;
91  }
92  size_t capacity() const
93  {
94  CLockGuard<CRecursiveMutex> Lock(m_Lock);
95 
96  return m_Vector.size();
97  }
98 
99  std::vector<MTL_VISA_BUFFER_TYPE>::iterator begin()
100  {
101  CLockGuard<CRecursiveMutex> Lock(m_Lock);
102 
103  return m_Vector.begin();
104  }
105  std::vector<MTL_VISA_BUFFER_TYPE>::const_iterator begin() const
106  {
107  CLockGuard<CRecursiveMutex> Lock(m_Lock);
108 
109  return m_Vector.begin();
110  }
111  std::vector<MTL_VISA_BUFFER_TYPE>::iterator end()
112  {
113  CLockGuard<CRecursiveMutex> Lock(m_Lock);
114 
115  return m_Vector.begin() + m_Size;
116  }
117  std::vector<MTL_VISA_BUFFER_TYPE>::const_iterator end() const
118  {
119  CLockGuard<CRecursiveMutex> Lock(m_Lock);
120 
121  return m_Vector.begin() + m_Size;
122  }
123 
125  {
126  CLockGuard<CRecursiveMutex> Lock(m_Lock);
127 
128  return m_Vector.data();
129  }
130  const MTL_VISA_BUFFER_TYPE* data() const noexcept
131  {
132  CLockGuard<CRecursiveMutex> Lock(m_Lock);
133 
134  return m_Vector.data();
135  }
136  MTL_VISA_BUFFER_TYPE& operator[] (size_t n)
137  {
138  CLockGuard<CRecursiveMutex> Lock(m_Lock);
139 
140  return m_Vector[n];
141  }
142  const MTL_VISA_BUFFER_TYPE& operator[] (size_t n) const
143  {
144  CLockGuard<CRecursiveMutex> Lock(m_Lock);
145 
146  return m_Vector[n];
147  }
148  void assign(const MTL_VISA_BUFFER_TYPE* First, const MTL_VISA_BUFFER_TYPE* Last)
149  {
150  CLockGuard<CRecursiveMutex> Lock(m_Lock);
151 
152  if (capacity() < (size_t)(Last - First))
153  reserve(Last - First);
154  std::copy(First, Last, m_Vector.begin());
155  m_Size = Last - First;
156  }
157  void assign(const MTL_VISA_BUFFER_TYPE* pData, size_t n)
158  {
159  CLockGuard<CRecursiveMutex> Lock(m_Lock);
160 
161  if (capacity() < n)
162  reserve(n);
163  std::copy(pData, pData + n, m_Vector.begin());
164  m_Size = n;
165  }
166  };
167 
168  //----------------------------------------------------------------------//
169  // Buffer Parser //
170  //----------------------------------------------------------------------//
172  {
173  private:
174  std::vector<char>::const_iterator m_Bbegin;
175  std::vector<char>::const_iterator m_Bend;
176  std::vector<char>::const_iterator m_SplitOffset;
177  public:
178  struct sToken {
179  std::vector<char>::const_iterator begin;
180  std::vector<char>::const_iterator end;
181  sToken(std::vector<char>::const_iterator b, std::vector<char>::const_iterator e)
182  : begin(b), end(e) {}
183  };
184  typedef std::vector<sToken> tTokens;
185 
186  public:
187  CVISABufferParser(std::vector<char>::const_iterator begin, std::vector<char>::const_iterator end)
188  : m_Bbegin(begin), m_Bend(end), m_SplitOffset(begin) {}
189 
190  std::vector<char>::const_iterator begin()
191  {
192  return m_Bbegin;
193  }
194  std::vector<char>::const_iterator end()
195  {
196  return m_Bend;
197  }
198 
199  const tTokens Tokenize(const char Separator = ';', size_t Offset = 0)
200  {
201  tTokens l_Tokens;
202 
203  // Check if there is data to split
204  if (m_Bbegin == m_Bend)
205  return l_Tokens;
206 
207  // Find first separator (if any).
208  std::vector<char>::const_iterator l_Start = m_Bbegin + Offset;
209  std::vector<char>::const_iterator l_Next = std::find(l_Start, m_Bend, Separator);
210  l_Tokens.push_back(sToken(l_Start, l_Next));
211 
212  // Find all separators
213  while (l_Next != m_Bend)
214  {
215  l_Start = l_Next + 1;
216  l_Next = std::find(l_Start, m_Bend, Separator);
217  l_Tokens.push_back(sToken(l_Start, l_Next));
218  }
219 
220  // Strip white space off front.
221  const std::string l_Whitespace(" \t\n\r");
222  for (auto l_Token : l_Tokens)
223  {
224  while (std::string::npos != l_Whitespace.find(*l_Token.begin))
225  l_Token.begin++;
226  }
227 
228  return l_Tokens;
229  }
230 
231  // /!\ When next token is an arbitrary block, it may contain a ';', which causes rNextEnd to be wrong
232  bool GetNext(std::vector<char>::const_iterator & rNextBegin, std::vector<char>::const_iterator & rNextEnd, const char Separator = ';')
233  {
234  // Strip white space off front.
235  const std::string l_Whitespace(" \t\n\r");
236  while (m_SplitOffset < m_Bend &&
237  std::string::npos != l_Whitespace.find(*m_SplitOffset))
238  m_SplitOffset++;
239 
240  // Did we reach the last token?
241  if (m_SplitOffset == m_Bend)
242  {
243  rNextBegin = m_Bend;
244  rNextEnd = m_Bend;
245  return false;
246  }
247 
248  // Find next
249  rNextBegin = m_SplitOffset;
250  rNextEnd = std::find(m_SplitOffset, m_Bend, Separator);
251 
252  // Did we reach the last token?
253  if (rNextEnd == m_Bend)
254  m_SplitOffset = m_Bend; // Set offset to the ending interator
255  else
256  m_SplitOffset = rNextEnd + 1; // Skip separator for next call
257 
258  return true;
259  }
260 
261  // When parsing arbitrary block, it is necessary to force offset to skip ';' chars that are not separators
262  void SetNextOffset(std::vector<char>::const_iterator Offset)
263  {
264  m_SplitOffset = Offset;
265  // Check bounds
266  if (m_SplitOffset < m_Bbegin)
267  m_SplitOffset = m_Bbegin;
268  if (m_SplitOffset > m_Bend)
269  m_SplitOffset = m_Bbegin;
270  }
271  };
272 
273 }} // namespace MTL::Instrument
MTL::Instrument::CVISABufferParser::sToken::begin
std::vector< char >::const_iterator begin
Definition: VISAInstrumentBuffer.h:179
MTL::Instrument::CVISABuffer::data
const MTL_VISA_BUFFER_TYPE * data() const noexcept
Definition: VISAInstrumentBuffer.h:130
Synchronization.h
Synchronization primitives.
MTL::Instrument::CVISABuffer::end
std::vector< MTL_VISA_BUFFER_TYPE >::const_iterator end() const
Definition: VISAInstrumentBuffer.h:117
MTL::Instrument::CVISABuffer::clear
void clear()
Definition: VISAInstrumentBuffer.h:61
MTL::Instrument::CVISABufferParser::sToken
Definition: VISAInstrumentBuffer.h:178
MTL::Instrument::CVISABufferParser::sToken::sToken
sToken(std::vector< char >::const_iterator b, std::vector< char >::const_iterator e)
Definition: VISAInstrumentBuffer.h:181
MTL::Synchronization
Definition: Synchronization.h:12
MTL::Instrument::CVISABuffer::resize
void resize(size_t size)
Definition: VISAInstrumentBuffer.h:74
MTL::Instrument::CVISABuffer::begin
std::vector< MTL_VISA_BUFFER_TYPE >::iterator begin()
Definition: VISAInstrumentBuffer.h:99
MTL::Instrument::CVISABufferParser::GetNext
bool GetNext(std::vector< char >::const_iterator &rNextBegin, std::vector< char >::const_iterator &rNextEnd, const char Separator=';')
Definition: VISAInstrumentBuffer.h:232
MTL::Instrument::CVISABufferParser::Tokenize
const tTokens Tokenize(const char Separator=';', size_t Offset=0)
Definition: VISAInstrumentBuffer.h:199
MTL_VISA_BUFFER_TYPE
#define MTL_VISA_BUFFER_TYPE
Definition: VISAInstrumentBuffer.h:36
MTL::Instrument::CVISABufferParser::sToken::end
std::vector< char >::const_iterator end
Definition: VISAInstrumentBuffer.h:180
MTL::Instrument::CVISABuffer::capacity
size_t capacity() const
Definition: VISAInstrumentBuffer.h:92
MTL::Instrument::CVISABufferParser::SetNextOffset
void SetNextOffset(std::vector< char >::const_iterator Offset)
Definition: VISAInstrumentBuffer.h:262
MTL
Definition: CPT2026PeripheralROM.h:19
MTL::Instrument::CVISABuffer::assign
void assign(const MTL_VISA_BUFFER_TYPE *First, const MTL_VISA_BUFFER_TYPE *Last)
Definition: VISAInstrumentBuffer.h:148
MTL::Instrument::CVISABuffer::~CVISABuffer
virtual ~CVISABuffer()
Definition: VISAInstrumentBuffer.h:58
MTL::Instrument::CVISABuffer::reserve
void reserve(size_t capacity)
Definition: VISAInstrumentBuffer.h:67
MTL::Instrument::CVISABuffer::end
std::vector< MTL_VISA_BUFFER_TYPE >::iterator end()
Definition: VISAInstrumentBuffer.h:111
MTL::Instrument::CVISABufferParser::begin
std::vector< char >::const_iterator begin()
Definition: VISAInstrumentBuffer.h:190
VISAInstrumentTypes.h
C++ wrapper for NI-VISA: type definitions.
MTL::Instrument::CVISABuffer::CVISABuffer
CVISABuffer(const MTL_VISA_BUFFER_TYPE *pData, size_t DataLen)
Definition: VISAInstrumentBuffer.h:51
MTL::Instrument::CVISABufferParser::tTokens
std::vector< sToken > tTokens
Definition: VISAInstrumentBuffer.h:184
MTL::Instrument::CVISABufferParser
Definition: VISAInstrumentBuffer.h:171
MTL::Instrument::CVISABuffer
Definition: VISAInstrumentBuffer.h:37
MTL::Instrument::CVISABuffer::assign
void assign(const MTL_VISA_BUFFER_TYPE *pData, size_t n)
Definition: VISAInstrumentBuffer.h:157
MTL::Instrument::CVISABuffer::data
MTL_VISA_BUFFER_TYPE * data() noexcept
Definition: VISAInstrumentBuffer.h:124
MTL::Synchronization::CLockGuard
Lock.
Definition: Synchronization.h:62
MTL::Synchronization::CRecursiveMutex
std::recursive_mutex CRecursiveMutex
Recursive Mutex.
Definition: Synchronization.h:20
MTL::Instrument::CVISABufferParser::end
std::vector< char >::const_iterator end()
Definition: VISAInstrumentBuffer.h:194
MTL::Instrument::CVISABufferParser::CVISABufferParser
CVISABufferParser(std::vector< char >::const_iterator begin, std::vector< char >::const_iterator end)
Definition: VISAInstrumentBuffer.h:187
MTL::Instrument::CVISABuffer::size
size_t size() const
Definition: VISAInstrumentBuffer.h:86
MTL::Instrument::CVISABuffer::CVISABuffer
CVISABuffer(size_t InitialCapacity=2048)
Definition: VISAInstrumentBuffer.h:44
MTL::Instrument::CVISABuffer::begin
std::vector< MTL_VISA_BUFFER_TYPE >::const_iterator begin() const
Definition: VISAInstrumentBuffer.h:105