KaCanOpen
 All Classes Functions Variables Typedefs Enumerations Pages
value.cpp
1 /*
2  * Copyright (c) 2015, Thomas Keh
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are met:
7  *
8  * 1. Redistributions of source code must retain the above copyright
9  * notice, this list of conditions and the following disclaimer.
10  *
11  * 2. Redistributions in binary form must reproduce the above copyright
12  * notice, this list of conditions and the following disclaimer in the
13  * documentation and/or other materials provided with the distribution.
14  *
15  * 3. Neither the name of the copyright holder nor the names of its
16  * contributors may be used to endorse or promote products derived from
17  * this software without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
23  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29  * POSSIBILITY OF SUCH DAMAGE.
30  */
31 
32 #include "value.h"
33 #include "logger.h"
34 #include "canopen_error.h"
35 
36 #include <sstream>
37 #include <string>
38 
39 namespace kaco {
40 
42  DEBUG_LOG("Creating empty value");
43  type = Type::invalid;
44 }
45 
46 Value::Value(uint8_t value) {
47  DEBUG_LOG("Creating uint8 value");
48  type = Type::uint8;
49  uint8 = value;
50 }
51 
52 Value::Value(uint16_t value) {
53  DEBUG_LOG("Creating uint16 value");
54  type = Type::uint16;
55  uint16 = value;
56 }
57 
58 Value::Value(uint32_t value) {
59  DEBUG_LOG("Creating uint32 value");
60  type = Type::uint32;
61  uint32 = value;
62 }
63 
64 Value::Value(uint64_t value) {
65  DEBUG_LOG("Creating uint64 value");
66  type = Type::uint64;
67  uint64 = value;
68 }
69 
70 Value::Value(int8_t value) {
71  DEBUG_LOG("Creating int8 value");
72  type = Type::int8;
73  int8 = value;
74 }
75 
76 Value::Value(int16_t value) {
77  DEBUG_LOG("Creating int16 value");
78  type = Type::int16;
79  int16 = value;
80 }
81 
82 Value::Value(int32_t value) {
83  DEBUG_LOG("Creating int32 value");
84  type = Type::int32;
85  int32 = value;
86 }
87 
88 Value::Value(int64_t value) {
89  DEBUG_LOG("Creating int64 value");
90  type = Type::int64;
91  int64 = value;
92 }
93 
94 Value::Value(float value) {
95  DEBUG_LOG("Creating real32 value");
96  type = Type::real32;
97  real32 = value;
98 }
99 
100 Value::Value(double value) {
101  DEBUG_LOG("Creating real64 value");
102  type = Type::real64;
103  real64 = value;
104 }
105 
106 Value::Value(bool value) {
107  DEBUG_LOG("Creating boolean value");
108  type = Type::boolean;
109  boolean = value;
110 }
111 
112 Value::Value(const std::string& value) : string(value) {
113  DEBUG_LOG("Creating string value");
114  type = Type::string;
115 }
116 
117 Value::Value(const char* value) : string(value) {
118  DEBUG_LOG("Creating string value");
119  type = Type::string;
120 }
121 
122 Value::Value(const std::vector<uint8_t>& value) : octet_string(value) {
123  DEBUG_LOG("Creating octet string value");
124  type = Type::octet_string;
125 }
126 
127 Value::Value(Type type_, const std::vector<uint8_t>& data) {
128 
129  type = type_;
130 
131  if (type != Type::string && type != Type::octet_string) {
132  // strings and octet strings have variable size
133  const uint8_t type_size = Utils::get_type_size(type);
134  if (data.size() != type_size) {
135  throw canopen_error("[Value constructor] Wrong byte vector size: data.size()="+std::to_string(data.size())
136  +" type_size="+std::to_string(type_size)+" type="+Utils::type_to_string(type));
137  }
138  }
139 
140  switch(type) {
141 
142  case Type::uint8: {
143  uint8 = data[0];
144  break;
145  }
146 
147  case Type::int8: {
148  int8 = data[0];
149  break;
150  }
151 
152  case Type::uint16: {
153  uint16 = (uint16_t)data[0] + ((uint16_t)data[1] << 8);
154  break;
155  }
156 
157  case Type::int16: {
158  int16 = (int16_t)data[0] + ((int16_t)data[1] << 8);
159  break;
160  }
161 
162  case Type::uint32: {
163  uint32 = (uint32_t)data[0] + ((uint32_t)data[1] << 8) + ((uint32_t)data[2] << 16) + ((uint32_t)data[3] << 24);
164  break;
165  }
166 
167  case Type::int32: {
168  int32 = (int32_t)data[0] + ((int32_t)data[1] << 8) + ((int32_t)data[2] << 16) + ((int32_t)data[3] << 24);
169  break;
170  }
171 
172  case Type::uint64: {
173  uint64 = (uint64_t)data[0] + ((uint64_t)data[1] << 8) + ((uint64_t)data[2] << 16) + ((uint64_t)data[3] << 24)
174  + ((uint64_t)data[4] << 32) + ((uint64_t)data[5] << 40) + ((uint64_t)data[6] << 48) + ((uint64_t)data[7] << 56);
175  break;
176  }
177 
178  case Type::int64: {
179  int64 = (int64_t)data[0] + ((int64_t)data[1] << 8) + ((int64_t)data[2] << 16) + ((int64_t)data[3] << 24)
180  + ((int64_t)data[4] << 32) + ((int64_t)data[5] << 40) + ((int64_t)data[6] << 48) + ((int64_t)data[7] << 56);
181  break;
182  }
183 
184  case Type::real32: {
185  // TODO: test this
186  const uint32_t val = (uint32_t)data[0] + ((uint32_t)data[1] << 8) + ((uint32_t)data[2] << 16) + ((uint32_t)data[3] << 24);
187  real32 = reinterpret_cast<const float&>(val);
188  break;
189  }
190 
191  case Type::real64: {
192  // TODO: test this
193  const uint64_t val = (uint64_t)data[0] + ((uint64_t)data[1] << 8) + ((uint64_t)data[2] << 16) + ((uint64_t)data[3] << 24)
194  + ((uint64_t)data[4] << 32) + ((uint64_t)data[5] << 40) + ((uint64_t)data[6] << 48) + ((uint64_t)data[7] << 56);
195  real64 = reinterpret_cast<const double&>(val);
196  break;
197  }
198 
199  case Type::string: {
200  string = std::string(reinterpret_cast<char const*>(data.data()), data.size());
201  break;
202  }
203 
204  case Type::octet_string: {
205  octet_string = data;
206  break;
207  }
208 
209  case Type::boolean: {
210  boolean = (data[0]>0);
211  break;
212  }
213 
214  case Type::invalid: {
215  throw canopen_error("[Value constructor] Can't construct invalid value with this constructor.");
216  }
217 
218  }
219 
220 }
221 
222 std::vector<uint8_t> Value::get_bytes() const {
223 
224  std::vector<uint8_t> result;
225 
226  switch(type) {
227 
228  case Type::uint8: {
229  result.push_back(uint8);
230  break;
231  }
232 
233  case Type::uint16: {
234  result.push_back(uint16 & 0xFF);
235  result.push_back((uint16>>8) & 0xFF);
236  break;
237  }
238 
239  case Type::uint32: {
240  result.push_back(uint32 & 0xFF);
241  result.push_back((uint32>>8) & 0xFF);
242  result.push_back((uint32>>16) & 0xFF);
243  result.push_back((uint32>>24) & 0xFF);
244  break;
245  }
246 
247  case Type::uint64: {
248  result.push_back(uint64 & 0xFF);
249  result.push_back((uint64>>8) & 0xFF);
250  result.push_back((uint64>>16) & 0xFF);
251  result.push_back((uint64>>24) & 0xFF);
252  result.push_back((uint64>>32) & 0xFF);
253  result.push_back((uint64>>40) & 0xFF);
254  result.push_back((uint64>>48) & 0xFF);
255  result.push_back((uint64>>56) & 0xFF);
256  break;
257  }
258 
259  case Type::int8: {
260  result.push_back(int8);
261  break;
262  }
263 
264  case Type::int16: {
265  result.push_back(int16 & 0xFF);
266  result.push_back((int16>>8) & 0xFF);
267  break;
268  }
269 
270  case Type::int32: {
271  result.push_back(int32 & 0xFF);
272  result.push_back((int32>>8) & 0xFF);
273  result.push_back((int32>>16) & 0xFF);
274  result.push_back((int32>>24) & 0xFF);
275  break;
276  }
277 
278  case Type::int64: {
279  result.push_back(int64 & 0xFF);
280  result.push_back((int64>>8) & 0xFF);
281  result.push_back((int64>>16) & 0xFF);
282  result.push_back((int64>>24) & 0xFF);
283  result.push_back((int64>>32) & 0xFF);
284  result.push_back((int64>>40) & 0xFF);
285  result.push_back((int64>>48) & 0xFF);
286  result.push_back((int64>>56) & 0xFF);
287  break;
288  }
289 
290  case Type::real32: {
291  // TODO: test this
292  const uint32_t val = reinterpret_cast<const uint32_t&>(real32);
293  result.push_back(val & 0xFF);
294  result.push_back((val>>8) & 0xFF);
295  result.push_back((val>>16) & 0xFF);
296  result.push_back((val>>24) & 0xFF);
297  break;
298  }
299 
300  case Type::real64: {
301  // TODO: test this
302  const uint64_t val = reinterpret_cast<const uint64_t&>(real64);
303  result.push_back(val & 0xFF);
304  result.push_back((val>>8) & 0xFF);
305  result.push_back((val>>16) & 0xFF);
306  result.push_back((val>>24) & 0xFF);
307  result.push_back((val>>32) & 0xFF);
308  result.push_back((val>>40) & 0xFF);
309  result.push_back((val>>48) & 0xFF);
310  result.push_back((val>>56) & 0xFF);
311  break;
312  }
313 
314  case Type::boolean: {
315  result.push_back(boolean?0x01:0x00);
316  break;
317  }
318 
319  case Type::string: {
320  for (size_t i=0; i<string.length(); ++i) {
321  result.push_back((uint8_t)string[i]);
322  }
323  break;
324  }
325 
326  case Type::octet_string: {
327  result = octet_string;
328  break;
329  }
330 
331  case Type::invalid: {
332  throw canopen_error("[Value::get_bytes] Can't get bytes of invalid type.");
333  }
334 
335  }
336 
337  return result;
338 
339 }
340 
341 bool Value::operator==(const Value& other) const {
342 
343  DEBUG(
344 
345  if (type != other.type) {
346  throw canopen_error("[Value::operator==] Comparing values of different type: "+Utils::type_to_string(type)+" != "+Utils::type_to_string(other.type)+".");
347  }
348 
349  )
350 
351  switch(type) {
352 
353  case Type::uint8: {
354  return uint8 == (uint8_t) other;
355  }
356 
357  case Type::uint16: {
358  return uint16 == (uint16_t) other;
359  }
360 
361  case Type::uint32: {
362  return uint32 == (uint32_t) other;
363  }
364 
365  case Type::uint64: {
366  return uint64 == (uint64_t) other;
367  }
368 
369  case Type::int8: {
370  return int8 == (int8_t) other;
371  }
372 
373  case Type::int16: {
374  return int16 == (int16_t) other;
375  }
376 
377  case Type::int32: {
378  return int32 == (int32_t) other;
379  }
380 
381  case Type::int64: {
382  return int64 == (int64_t) other;
383  }
384 
385  case Type::real32: {
386  return real32 == (float) real32;
387  }
388 
389  case Type::real64: {
390  return real64 == (double) real64;
391  }
392 
393  case Type::boolean: {
394  return boolean == (bool) boolean;
395  }
396 
397  case Type::string: {
398  return string == (std::string) other;
399  }
400 
401  case Type::octet_string: {
402  // reusing code from value_printer...
403  return to_string() == other.to_string();
404  }
405 
406  case Type::invalid: {
407  throw canopen_error("[Value::operator==] Comparing invalid type.");
408  }
409 
410  }
411  return false;
412 }
413 
414 bool Value::operator!=(const Value& other) const {
415  return !(operator==(other));
416 }
417 
418 std::string Value::to_string() const {
419  using namespace value_printer;
420  std::ostringstream stream;
421  stream << std::dec << *this;
422  return stream.str();
423 }
424 
425 //----------------//
426 // Cast operators //
427 //----------------//
428 
431 #define CO_VALUE_TYPE_CAST_OP(mtypeout, mtypein) \
432  Value::operator mtypeout() const { \
433  if (type != Type::mtypein ) { \
434  throw canopen_error("[Value cast operator] Illegal conversion from "+Utils::type_to_string(type)+" to " #mtypein "."); \
435  } \
436  return mtypein; \
437  }
438 
441 #define CO_VALUE_TYPE_CAST_OP_INT(mtype) CO_VALUE_TYPE_CAST_OP(mtype##_t, mtype)
442 
443 CO_VALUE_TYPE_CAST_OP_INT(uint8);
444 CO_VALUE_TYPE_CAST_OP_INT(uint16);
445 CO_VALUE_TYPE_CAST_OP_INT(uint32);
446 CO_VALUE_TYPE_CAST_OP_INT(uint64);
447 CO_VALUE_TYPE_CAST_OP_INT(int8);
448 CO_VALUE_TYPE_CAST_OP_INT(int16);
449 CO_VALUE_TYPE_CAST_OP_INT(int32);
450 CO_VALUE_TYPE_CAST_OP_INT(int64);
451 CO_VALUE_TYPE_CAST_OP(bool, boolean);
452 CO_VALUE_TYPE_CAST_OP(float, real32);
453 CO_VALUE_TYPE_CAST_OP(double, real64);
454 CO_VALUE_TYPE_CAST_OP(std::string, string);
455 CO_VALUE_TYPE_CAST_OP(std::vector<uint8_t>, octet_string);
456 
457 //-------------------//
458 // std::cout Printer //
459 //-------------------//
460 
461 namespace value_printer {
462  std::ostream &operator<<(std::ostream &os, Value val) {
463  switch(val.type) {
464 
465  case Type::uint8: {
466  // 1-byte types are printed as char by default -> double casting.
467  return os << static_cast<uint32_t>(static_cast<uint8_t>(val));
468  }
469 
470  case Type::uint16: {
471  return os << static_cast<uint16_t>(val);
472  }
473 
474  case Type::uint32: {
475  return os << static_cast<uint32_t>(val);
476  }
477 
478  case Type::uint64: {
479  return os << static_cast<uint64_t>(val);
480  }
481 
482  case Type::int8: {
483  // 1-byte types are printed as char by default -> double casting.
484  return os << static_cast<uint32_t>(static_cast<int8_t>(val));
485  }
486 
487  case Type::int16: {
488  return os << static_cast<int16_t>(val);
489  }
490 
491  case Type::int32: {
492  return os << static_cast<int32_t>(val);
493  }
494 
495  case Type::int64: {
496  return os << static_cast<int64_t>(val);
497  }
498 
499  case Type::real32: {
500  return os << static_cast<float>(val);
501  }
502 
503  case Type::real64: {
504  return os << static_cast<double>(val);
505  }
506 
507  case Type::boolean: {
508  return os << (static_cast<bool>(val)?"TRUE":"FALSE");
509  }
510 
511  case Type::string: {
512  return os << static_cast<std::string>(val);
513  }
514 
515  case Type::octet_string: {
516  const auto& octet_string = val.get_bytes();
517  os << "[";
518  for (size_t i=0; i<octet_string.size(); ++i) {
519  // 1-byte types are printed as char by default -> casting.
520  os << static_cast<uint32_t>(octet_string[i]);
521  if (i+1<octet_string.size()) {
522  os << ",";
523  }
524  }
525  return os << "]";
526  }
527 
528  default: {
529  return os << "[Unknown value type]";
530  }
531 
532  }
533  }
534 }
535 
536 } // end namespace kaco
bool operator!=(const Value &other) const
Compares not equal.
Definition: value.cpp:414
std::vector< uint8_t > get_bytes() const
Returns the byte representation (little-endian) as a vector.
Definition: value.cpp:222
std::string to_string() const
Returns the value as a printable string.
Definition: value.cpp:418
This is the base class of all types of exceptions thrown by the KaCanOpen library. It can be used directly like std::runtime_error if there isn't any more specific error class.
Definition: canopen_error.h:43
static std::string type_to_string(Type type)
Converts data types to a string.
Definition: utils.cpp:42
Value()
Constructs an invalid value.
Definition: value.cpp:41
Type type
Tyoe of the value.
Definition: value.h:56
bool operator==(const Value &other) const
Compares equal.
Definition: value.cpp:341
static uint8_t get_type_size(Type type)
Returns the size of a data type in bytes.
Definition: utils.cpp:112
This class contains a value to be stored in the object dictionary. The value can have one of the type...
Definition: value.h:53
std::vector< uint8_t > octet_string
The value if type==Type::octet_string It's seperate because std::vector is non-trivial and should not...
Definition: value.h:69