rohdeschwarz  0.2.0
TCPIP socket library for Rohde & Schwarz instrument control
block_data.cpp
Go to the documentation of this file.
1 
8 using namespace rohdeschwarz::scpi;
9 
10 
11 // std lib
12 #include <algorithm>
13 #include <cctype>
14 #include <string>
15 
16 
18  _isHeader(false),
19  _headerSize_B (0),
20  _payloadSize_B(0),
21  _blockSize_B (0)
22 {
23  // no operations
24 }
25 
26 
27 BlockData::BlockData(std::vector<unsigned char> data) :
28  _isHeader(false),
29  _headerSize_B (0),
30  _payloadSize_B(0),
31  _blockSize_B (0),
32  _data(data)
33 {
34  processHeader();
35 }
36 
37 
39 {
40  if (isHeader())
41  {
42  // full, valid header
43  return false;
44  }
45 
46  if (_data.empty())
47  {
48  // no data to validate; no error yet...
49  return false;
50  }
51 
52  if (char(_data[0]) != '#')
53  {
54  // missing magic character
55  return true;
56  }
57 
58  if (_data.size() == 1)
59  {
60  // nothing else to check
61  return false;
62  }
63 
64  // check number of size digits
65  if (!std::isdigit(char(_data[1])))
66  {
67  // error: not a number
68  return true;
69  }
70 
71  if (_data.size() == 2)
72  {
73  // nothing else to check
74  return false;
75  }
76 
77  // check available size digits
78  const auto digits = std::min(parseNumberOfSizeDigits(), _data.size() - 2);
79  for (std::size_t digit = 0; digit < digits; digit++)
80  {
81  if (!std::isdigit(_data[2 + digit]))
82  {
83  // error: not a number
84  return true;
85  }
86  }
87 
88  // no errors found
89  return false;
90 }
91 
92 
93 bool BlockData::isHeader() const
94 {
95  return _isHeader;
96 }
97 
98 
100 {
101  if (!isHeader())
102  {
103  return false;
104  }
105  return _data.size() >= _blockSize_B;
106 }
107 
108 
109 void BlockData::push_back(std::vector<unsigned char>::const_iterator begin, std::size_t size)
110 {
111  if (isComplete())
112  {
113  // block needs no more data
114  return;
115  }
116 
117  if (!isHeader())
118  {
119  // copy all
120  auto end = begin + size;
121  _data.insert(_data.end(), begin, end);
122  processHeader();
123  return;
124  }
125 
126  // get number of bytes to read from data
127  const auto read_bytes = std::min(bytesRemaining(), size);
128 
129  // insert data and process
130  auto end = begin + read_bytes;
131  _data.insert(_data.end(), begin, end);
132  processHeader();
133 }
134 
135 
136 std::size_t BlockData::size() const
137 {
138  return _payloadSize_B;
139 }
140 
141 
142 unsigned char* BlockData::data()
143 {
144  if (!isHeader())
145  {
146  // no payload
147  return nullptr;
148  }
149  return _data.data() + _headerSize_B;
150 }
151 
152 
153 std::size_t BlockData::parseNumberOfSizeDigits() const
154 {
155  if (_data.size() < 2)
156  {
157  // not enough data
158  return 0;
159  }
160 
161  // parse
162  using char_p = char*;
163  const char_p begin = char_p(_data.data() + 1);
164  const std::string digit_str(begin, 1);
165  return std::stoul(digit_str);
166 }
167 
168 
169 std::size_t BlockData::parsePayloadSize_B() const
170 {
171  const std::size_t digits = parseNumberOfSizeDigits();
172  if (!digits)
173  {
174  // cannot proceed
175  return 0;
176  }
177  if (_data.size() < 2 + digits)
178  {
179  // not enough data
180  return 0;
181  }
182 
183  // parse
184  using char_p = char*;
185  const char_p begin = char_p(_data.data() + 2);
186  std::string size_str(begin, digits);
187  return std::stoul(size_str);
188 }
189 
190 
191 void BlockData::processHeader()
192 {
193  if (isHeader())
194  {
195  // header already processed
196  return;
197  }
198 
199  if (isHeaderError())
200  {
201  // header is invalid; cannot process
202  return;
203  }
204 
205  // get number of header size digits
206  const auto numberOfSizeDigits = parseNumberOfSizeDigits();
207  if (!numberOfSizeDigits)
208  {
209  // cannot process (yet)
210  return;
211  }
212 
213  // payload size
214  const std::size_t payloadSize_B = parsePayloadSize_B();
215  if (!payloadSize_B)
216  {
217  // cannot process (yet)
218  return;
219  }
220 
221  // success
222  _isHeader = true;
223  _headerSize_B = 2 + numberOfSizeDigits;
224  _payloadSize_B = payloadSize_B;
225  _blockSize_B = _headerSize_B + _payloadSize_B;
226  _data.reserve(_blockSize_B);
227 }
228 
229 
230 std::size_t BlockData::bytesRemaining() const
231 {
232  if (isComplete())
233  {
234  return 0;
235  }
236 
237  return _blockSize_B - _data.size();
238 }
rohdeschwarz::scpi::BlockData definition
char * char_p
Definition: bus.cpp:21
bool isHeaderError() const
Checks the header for errors.
Definition: block_data.cpp:38
bool isComplete() const
Checks for complete Block Data header and payload.
Definition: block_data.cpp:99
BlockData()
Default Constructor.
Definition: block_data.cpp:17
std::size_t size() const
Gets payload size, in bytes, from a complete header.
Definition: block_data.cpp:136
unsigned char * data()
Gets a pointer to the payload data.
Definition: block_data.cpp:142
bool isHeader() const
Checks for a valid and complete Block Data header.
Definition: block_data.cpp:93
void push_back(std::vector< unsigned char >::const_iterator begin, std::size_t size)
Copies data to block.
Definition: block_data.cpp:109