THM1176InstrumentManager  1.0
Qt Object abstraction for Metrolab THM1176
SCPIParsing.h
Go to the documentation of this file.
1 // Copyright (c) 2020 Metrolab Technology S.A., Geneva, Switzerland (www.metrolab.com)
2 // See the included file LICENSE.txt for the licensing conditions.
3 
7 
8 #pragma once
9 
10 // Standard includes
11 #include <cstdlib>
12 #include <string>
13 #include <vector>
14 #include <regex>
15 #include <stdexcept>
16 
17 // Personal includes
18 
19 namespace MTL {
20  namespace SCPI {
21 
22 // Utilities
23 #define SCPIParsing_UNUSED_VAR(x) (void)x; // Prevents from unereferenced variable when compiling in release
24 
25  //----------------------------------------------------------------------//
26  // Type Definitions //
27  //----------------------------------------------------------------------//
28  typedef std::vector<unsigned char> tChannel;
29  typedef std::vector<tChannel> tChannelList;
30 
31  //----------------------------------------------------------------------//
32  // Conversion Utilities //
33  //----------------------------------------------------------------------//
41  template <class iterator_type>
42  bool IsArbitraryBlock(const iterator_type first, const iterator_type last, size_t & rStartOffset, size_t & rLength);
43 
48  void ToArbitraryBlock(const std::string & rStr, std::string & rArbitraryBlock, bool InfiniteFormat = false);
49 
55  template <class iterator_type>
56  void FromStringChannelList(iterator_type first, iterator_type last, tChannelList & rChannelList);
57 
61  void ToStringChannelList(const tChannelList & rChannelList, std::string & rStr);
62 
67  void FromBinaryChannelList(const char * pBinaryChanList, size_t Len, tChannelList & rChannelList);
68 
72  void ToBinaryChannelList(const tChannelList & rChannelList, std::vector<char> & rBinaryChanList);
73 
78  void SplitString(const std::string & rStr, std::vector<std::string> & rStrings, char Sep);
79 
80 
81  //----------------------------------------------------------------------//
82  // Conversion Utilities Definitions //
83  //----------------------------------------------------------------------//
84  // Template definitions must be located in the header file to avoid
85  // linking errors.
86  template <class iterator_type>
87  bool IsArbitraryBlock(const iterator_type first, const iterator_type last, size_t & rStartOffset, size_t & rLength)
88  {
89  try
90  {
91  // Check arbitrary format
92  if (*first != '#')
93  throw false;
94 
95  // "Indefinite format": #0...
96  if (*(first+1) == '0')
97  {
98  rStartOffset = 2;
99  rLength = last - first - rStartOffset;
100  }
101 
102  // "Definite length format": #nmmm...
103  else
104  {
105  // Get mmm
106  size_t l_PrefixLen = std::stoul(std::string(&*(first+1), 1));
107  rStartOffset = 2 + l_PrefixLen;
108  rLength = std::stoul(std::string(&*(first+2), l_PrefixLen));
109 
110  // Check mmm
111  size_t l_BufferLength = last - first - rStartOffset;
112  if (rLength > l_BufferLength)
113  throw false; // String contains less data that indicated by the prefix
114  }
115  }
116  catch (bool & rE)
117  {
119  rStartOffset = 0;
120  rLength = 0;
121  return false;
122  }
123  // Possible exception thrown by stoul()
124  catch (std::invalid_argument & rE)
125  {
127  rStartOffset = 0;
128  rLength = 0;
129  return false;
130  }
131  // Possible exception thrown by stoul()
132  catch (std::out_of_range & rE)
133  {
135  rStartOffset = 0;
136  rLength = 0;
137  return false;
138  }
139 
140  return true;
141  }
142  inline void ToArbitraryBlock(const std::string & rStr, std::string & rArbitraryBlock, bool InfiniteFormat)
143  {
144  if (InfiniteFormat)
145  // Infinite format: #0...
146  rArbitraryBlock = "#0" + rStr;
147  else
148  {
149  // Definite length format: #nmmm...
150  std::string l_mmm = std::to_string(rStr.length());
151  rArbitraryBlock = "#" + std::to_string(l_mmm.length()) + l_mmm + rStr;
152  }
153  }
154  template <class iterator_type>
155  void FromStringChannelList(iterator_type first, iterator_type last, tChannelList & rChannelList)
156  {
157  rChannelList.clear();
158  // Check channel list format
159  if (std::regex_match(first, last, std::regex("^\\(@[0-9!,:]*\\)[^]*$")))
160  {
161  // Check empty channel
162  if (std::regex_match(first, last, std::regex("^\\(@\\)[^]*$")))
163  return;
164 
165  tChannel l_Chan;
166  for (size_t l_Index = 2, PortStart = 2; l_Index < (size_t)(last - first); l_Index++)
167  {
168  char c = *(first + l_Index);
169  if (c >= '0' && c <= '9') // In port definition
170  {
171  }
172  else if (c == '!') // End of port
173  {
174  l_Chan.push_back(atoi(std::string(first + PortStart, first + l_Index).c_str()));
175  PortStart = l_Index + 1;
176  }
177  else if (c == ',') // End of channel
178  {
179  // Close port
180  l_Chan.push_back(atoi(std::string(first + PortStart, first + l_Index).c_str()));
181  // Add channel
182  rChannelList.push_back(l_Chan);
183  l_Chan.clear();
184  PortStart = l_Index + 1;
185  }
186  else if (c == ')') // End of channel list
187  {
188  // Close port
189  l_Chan.push_back(atoi(std::string(first + PortStart, first + l_Index).c_str()));
190  // Add channel
191  rChannelList.push_back(l_Chan);
192  // Exit
193  l_Index = last - first;
194  }
195  else
196  {
197  }
198  }
199  }
200  }
201  inline void ToStringChannelList(const tChannelList & rChannelList, std::string & rStr)
202  {
203  // Open channel list string
204  rStr = "(@";
205  // Loop over channels
206  for (tChannelList::const_iterator l_it = rChannelList.begin(); l_it != rChannelList.end(); l_it++)
207  {
208  // Loop over ports
209  for (tChannel::const_iterator portit = l_it->begin(); portit != l_it->end(); portit++)
210  {
211  rStr += std::to_string(*portit);
212  if (portit + 1 != l_it->end())
213  rStr += '!';
214  }
215  if (l_it + 1 != rChannelList.end())
216  rStr += ',';
217  }
218  // Close channel list string
219  rStr += ")";
220  }
221  inline void FromBinaryChannelList(const char * pBinaryChanList, size_t Len, tChannelList & rChannelList)
222  {
223  rChannelList.clear();
224  tChannel l_Chan;
225  for (size_t l_Index = 0; l_Index < Len; l_Index++)
226  {
227  if (pBinaryChanList[l_Index] != 0)
228  l_Chan.push_back(pBinaryChanList[l_Index]);
229  else
230  {
231  rChannelList.push_back(l_Chan);
232  l_Chan.clear();
233  }
234  }
235  if (!l_Chan.empty())
236  rChannelList.push_back(l_Chan);
237  }
238  inline void ToBinaryChannelList(const tChannelList & rChannelList, std::vector<char> & rBinaryChanList)
239  {
240  rBinaryChanList.clear();
241  // Loop over channels
242  for (tChannelList::const_iterator l_it = rChannelList.begin(); l_it != rChannelList.end(); l_it++)
243  {
244  // Loop over ports
245  for (tChannel::const_iterator portit = l_it->begin(); portit != l_it->end(); portit++)
246  {
247  rBinaryChanList.push_back(*portit);
248  }
249  if (l_it + 1 != rChannelList.end())
250  rBinaryChanList.push_back(0);
251  }
252  }
253  inline void SplitString(const std::string & rStr, std::vector<std::string> & rStrings, char Sep)
254  {
255  rStrings.clear();
256 
257  // Check if there is data to split
258  if (rStr.empty())
259  return;
260 
261  // Find first separator (if any)
262  size_t l_Start = 0;
263  size_t l_Next = rStr.find_first_of(Sep);
264  rStrings.push_back(rStr.substr(l_Start, l_Next - l_Start));
265 
266  // Find all separators
267  for (l_Start = l_Next + 1;
268  l_Next != std::string::npos;
269  l_Start = l_Next + 1)
270  {
271  l_Next = rStr.find_first_of(Sep, l_Start);
272  rStrings.push_back(rStr.substr(l_Start, l_Next - l_Start));
273  }
274  }
275 
276 #undef SCPIParsing_UNUSED_VAR
277 
278 }} // namespace MTL::SCPI
MTL::SCPI::ToArbitraryBlock
void ToArbitraryBlock(const std::string &rStr, std::string &rArbitraryBlock, bool InfiniteFormat=false)
Package data as an arbitrary block.
Definition: SCPIParsing.h:142
MTL::SCPI::tChannelList
std::vector< tChannel > tChannelList
SCPI channel list
Definition: SCPIParsing.h:29
SCPIParsing_UNUSED_VAR
#define SCPIParsing_UNUSED_VAR(x)
Definition: SCPIParsing.h:23
MTL::SCPI::ToBinaryChannelList
void ToBinaryChannelList(const tChannelList &rChannelList, std::vector< char > &rBinaryChanList)
Encode binary channel list.
Definition: SCPIParsing.h:238
MTL::SCPI::FromBinaryChannelList
void FromBinaryChannelList(const char *pBinaryChanList, size_t Len, tChannelList &rChannelList)
Decode binary channel list.
Definition: SCPIParsing.h:221
MTL::SCPI::tChannel
std::vector< unsigned char > tChannel
SCPI channel
Definition: SCPIParsing.h:28
MTL::SCPI::IsArbitraryBlock
bool IsArbitraryBlock(const iterator_type first, const iterator_type last, size_t &rStartOffset, size_t &rLength)
Find arbitrary-block data within a buffer.
Definition: SCPIParsing.h:87
MTL
Definition: CTHM1176InstrumentManager.h:179
MTL::SCPI::SplitString
void SplitString(const std::string &rStr, std::vector< std::string > &rStrings, char Sep)
Split a string into substrings separated by a given character.
Definition: SCPIParsing.h:253
MTL::SCPI::ToStringChannelList
void ToStringChannelList(const tChannelList &rChannelList, std::string &rStr)
Encode channel list string.
Definition: SCPIParsing.h:201
MTL::SCPI::FromStringChannelList
void FromStringChannelList(iterator_type first, iterator_type last, tChannelList &rChannelList)
Decode channel list string.
Definition: SCPIParsing.h:155