C++ Instrument Catalog
SCPIParsing.h
Go to the documentation of this file.
1 
5 #pragma once
6 
7 // Standard includes
8 #include <cstdlib>
9 #include <string>
10 #include <vector>
11 #include <regex>
12 #include <stdexcept>
13 
14 // Personal includes
15 
16 namespace MTL {
17  namespace SCPI {
18 
19 // Utilities
20 #define SCPIParsing_UNUSED_VAR(x) (void)x; // Prevents from unereferenced variable when compiling in release
21 
22  //----------------------------------------------------------------------//
23  // Type Definitions //
24  //----------------------------------------------------------------------//
25  typedef std::vector<unsigned char> tChannel;
26  typedef std::vector<tChannel> tChannelList;
27 
28  //----------------------------------------------------------------------//
29  // Conversion Utilities //
30  //----------------------------------------------------------------------//
38  template <class iterator_type>
39  bool IsArbitraryBlock(const iterator_type first, const iterator_type last, size_t & rStartOffset, size_t & rLength);
40 
45  void ToArbitraryBlock(const std::string & rStr, std::string & rArbitraryBlock, bool InfiniteFormat = false);
46 
52  template <class iterator_type>
53  void FromStringChannelList(iterator_type first, iterator_type last, tChannelList & rChannelList);
54 
58  void ToStringChannelList(const tChannelList & rChannelList, std::string & rStr);
59 
64  void FromBinaryChannelList(const char * pBinaryChanList, size_t Len, tChannelList & rChannelList);
65 
69  void ToBinaryChannelList(const tChannelList & rChannelList, std::vector<char> & rBinaryChanList);
70 
75  void SplitString(const std::string & rStr, std::vector<std::string> & rStrings, char Sep);
76 
77 
78  //----------------------------------------------------------------------//
79  // Conversion Utilities Definitions //
80  //----------------------------------------------------------------------//
81  // Template definitions must be located in the header file to avoid
82  // linking errors.
83  template <class iterator_type>
84  bool IsArbitraryBlock(const iterator_type first, const iterator_type last, size_t & rStartOffset, size_t & rLength)
85  {
86  bool l_IsArbitraryBlock = false;
87  rStartOffset = 0;
88  rLength = 0;
89 
90  try
91  {
92  if ( last > first && // Check that data is given
93  *first == '#') // Check arbitrary block format
94  {
95  l_IsArbitraryBlock = true;
96 
97  // "Indefinite format": #0...
98  if (*(first + 1) == '0')
99  {
100  rStartOffset = 2;
101  rLength = last - first - rStartOffset;
102  }
103 
104  // "Definite length format": #nmmm...
105  else
106  {
107  // Get mmm
108  size_t l_PrefixLen = std::stoul(std::string(&*(first + 1), 1));
109  rStartOffset = 2 + l_PrefixLen;
110  rLength = std::stoul(std::string(&*(first + 2), l_PrefixLen));
111 
112  // Check mmm
113  size_t l_BufferLength = last - first - rStartOffset;
114  if (rLength > l_BufferLength)
115  throw false; // String contains less data than indicated by the prefix
116  }
117  }
118  }
119  // Possible exceptions :
120  // bool from local code
121  // std::invalid_argument from stoul()
122  // std::out_of_range from stoul()
123  catch (...)
124  {
125  rStartOffset = 0;
126  rLength = 0;
127  l_IsArbitraryBlock = false;
128  }
129 
130  return l_IsArbitraryBlock;
131  }
132  inline void ToArbitraryBlock(const std::string & rStr, std::string & rArbitraryBlock, bool InfiniteFormat)
133  {
134  if (InfiniteFormat)
135  {
136  // Infinite format: #0...
137  rArbitraryBlock = "#0" + rStr;
138  }
139  else
140  {
141  // Definite length format: #nmmm...
142  std::string l_mmm = std::to_string(rStr.length());
143  rArbitraryBlock = "#" + std::to_string(l_mmm.length()) + l_mmm + rStr;
144  }
145  }
146  template <class iterator_type>
147  void FromStringChannelList(iterator_type first, iterator_type last, tChannelList & rChannelList)
148  {
149  rChannelList.clear();
150  // Check channel list format
151  if (std::regex_match(first, last, std::regex("^\\(@[0-9!,:]*\\)[^]*$")))
152  {
153  // Check empty channel
154  if (std::regex_match(first, last, std::regex("^\\(@\\)[^]*$")))
155  return;
156 
157  tChannel l_Chan;
158  for (size_t l_Index = 2, PortStart = 2; l_Index < (size_t)(last - first); l_Index++)
159  {
160  char c = *(first + l_Index);
161  if (c >= '0' && c <= '9') // In port definition
162  {
163  }
164  else if (c == '!') // End of port
165  {
166  l_Chan.push_back(atoi(std::string(first + PortStart, first + l_Index).c_str()));
167  PortStart = l_Index + 1;
168  }
169  else if (c == ',') // End of channel
170  {
171  // Close port
172  l_Chan.push_back(atoi(std::string(first + PortStart, first + l_Index).c_str()));
173  // Add channel
174  rChannelList.push_back(l_Chan);
175  l_Chan.clear();
176  PortStart = l_Index + 1;
177  }
178  else if (c == ')') // End of channel list
179  {
180  // Close port
181  l_Chan.push_back(atoi(std::string(first + PortStart, first + l_Index).c_str()));
182  // Add channel
183  rChannelList.push_back(l_Chan);
184  // Exit
185  l_Index = last - first;
186  }
187  else
188  {
189  }
190  }
191  }
192  }
193  inline void ToStringChannelList(const tChannelList & rChannelList, std::string & rStr)
194  {
195  // Open channel list string
196  rStr = "(@";
197  // Loop over channels
198  for (tChannelList::const_iterator l_it = rChannelList.begin(); l_it != rChannelList.end(); l_it++)
199  {
200  // Loop over ports
201  for (tChannel::const_iterator portit = l_it->begin(); portit != l_it->end(); portit++)
202  {
203  rStr += std::to_string(*portit);
204  if (portit + 1 != l_it->end())
205  rStr += '!';
206  }
207  if (l_it + 1 != rChannelList.end())
208  rStr += ',';
209  }
210  // Close channel list string
211  rStr += ")";
212  }
213  inline void FromBinaryChannelList(const char * pBinaryChanList, size_t Len, tChannelList & rChannelList)
214  {
215  rChannelList.clear();
216  tChannel l_Chan;
217  for (size_t l_Index = 0; l_Index < Len; l_Index++)
218  {
219  if (pBinaryChanList[l_Index] != 0)
220  l_Chan.push_back(pBinaryChanList[l_Index]);
221  else
222  {
223  rChannelList.push_back(l_Chan);
224  l_Chan.clear();
225  }
226  }
227  if (!l_Chan.empty())
228  rChannelList.push_back(l_Chan);
229  }
230  inline void ToBinaryChannelList(const tChannelList & rChannelList, std::vector<char> & rBinaryChanList)
231  {
232  rBinaryChanList.clear();
233  // Loop over channels
234  for (tChannelList::const_iterator l_it = rChannelList.begin(); l_it != rChannelList.end(); l_it++)
235  {
236  // Loop over ports
237  for (tChannel::const_iterator portit = l_it->begin(); portit != l_it->end(); portit++)
238  {
239  rBinaryChanList.push_back(*portit);
240  }
241  if (l_it + 1 != rChannelList.end())
242  rBinaryChanList.push_back(0);
243  }
244  }
245  inline void SplitString(const std::string & rStr, std::vector<std::string> & rStrings, char Sep)
246  {
247  rStrings.clear();
248 
249  // Check if there is data to split
250  if (rStr.empty())
251  return;
252 
253  // Find first separator (if any)
254  size_t l_Start = 0;
255  size_t l_Next = rStr.find_first_of(Sep);
256  rStrings.push_back(rStr.substr(l_Start, l_Next - l_Start));
257 
258  // Find all separators
259  for (l_Start = l_Next + 1;
260  l_Next != std::string::npos;
261  l_Start = l_Next + 1)
262  {
263  l_Next = rStr.find_first_of(Sep, l_Start);
264  rStrings.push_back(rStr.substr(l_Start, l_Next - l_Start));
265  }
266  }
267 
268 #undef SCPIParsing_UNUSED_VAR
269 
270 }} // 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:132
MTL::SCPI::tChannelList
std::vector< tChannel > tChannelList
SCPI channel list
Definition: SCPIParsing.h:26
MTL::SCPI::ToBinaryChannelList
void ToBinaryChannelList(const tChannelList &rChannelList, std::vector< char > &rBinaryChanList)
Encode binary channel list.
Definition: SCPIParsing.h:230
MTL::SCPI::FromBinaryChannelList
void FromBinaryChannelList(const char *pBinaryChanList, size_t Len, tChannelList &rChannelList)
Decode binary channel list.
Definition: SCPIParsing.h:213
MTL::SCPI::tChannel
std::vector< unsigned char > tChannel
SCPI channel
Definition: SCPIParsing.h:25
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:84
MTL
Definition: CPT2026PeripheralROM.h:19
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:245
date::literals::last
CONSTDATA date::last_spec last
Definition: date.h:1890
MTL::SCPI::ToStringChannelList
void ToStringChannelList(const tChannelList &rChannelList, std::string &rStr)
Encode channel list string.
Definition: SCPIParsing.h:193
MTL::SCPI::FromStringChannelList
void FromStringChannelList(iterator_type first, iterator_type last, tChannelList &rChannelList)
Decode channel list string.
Definition: SCPIParsing.h:147