|
1 | | -/* Copyright © 2018 Pascal JEAN, All rights reserved. |
| 1 | +/* Copyright © 2018-2019 Pascal JEAN, All rights reserved. |
2 | 2 | * This file is part of the libmodbuspp Library. |
3 | 3 | * |
4 | 4 | * The libmodbuspp Library is free software; you can redistribute it and/or |
|
18 | 18 | #ifndef MODBUSPP_DATA_H |
19 | 19 | #define MODBUSPP_DATA_H |
20 | 20 |
|
21 | | -#include <string> |
22 | | -#include <modbus.h> |
23 | | -#include "global.h" |
| 21 | +#include <cstdio> // printf |
| 22 | +#include <cstring> // mencpy ... |
| 23 | +#include <array> |
| 24 | +#include <type_traits> |
| 25 | +#include "modbuspp-swap.h" |
| 26 | + |
| 27 | +#ifndef __DOXYGEN__ |
| 28 | +#endif /* __DOXYGEN__ not defined */ |
24 | 29 |
|
25 | 30 | /** |
26 | 31 | * |
27 | 32 | */ |
28 | 33 | namespace Modbus { |
29 | 34 |
|
| 35 | + enum Endian { // network number ABCD |
| 36 | + EndianBigBig = 0x00, // bytes in big endian order, word in big endian order : ABCD |
| 37 | + EndianBig = EndianBigBig, // big endian order : ABCD |
| 38 | + EndianBigLittle = 0x01, // bytes in big endian order, word in little endian order : CDAB |
| 39 | + EndianLittleBig = 0x02, // bytes in little endian order, word in big endian order : BADC |
| 40 | + EndianLittleLittle = 0x03, // bytes in little endian order, word in little endian order : DCBA |
| 41 | + EndianLittle = EndianLittleLittle // little endian order : DCBA |
| 42 | + }; |
| 43 | + |
| 44 | + |
| 45 | + class Device; |
| 46 | + class Master; |
| 47 | + |
30 | 48 | /** |
31 | 49 | * @class Data |
32 | | - * @brief |
| 50 | + * @author Pascal JEAN, aka epsilonrt |
| 51 | + * @copyright GNU Lesser General Public License |
| 52 | + * @brief |
33 | 53 | */ |
| 54 | + template <typename T, Endian e = EndianBigBig> |
34 | 55 | class Data { |
35 | 56 | public: |
36 | | - enum Type { |
37 | | - Byte, // 2 Bytes (nothing is smaller than the word on MODBUS) |
38 | | - Word, // 2 Bytes - 1 MODBUS register |
39 | | - LongWord, // 4 Bytes - 2 MODBUS registers |
40 | | - LongLongWord, // 8 Bytes - 4 MODBUS registers |
41 | | - Float, // 4 Bytes - 2 MODBUS registers |
42 | | - Double, // 8 Bytes - 4 MODBUS registers |
43 | | - Void = -1 |
44 | | - }; |
45 | | - |
46 | | - enum Endian { // network number ABCD |
47 | | - EndianBigBig = 0x00, // bytes in big endian order, word in big endian order : ABCD |
48 | | - EndianBig = EndianBigBig, // big endian order : ABCD |
49 | | - EndianBigLittle = 0x01, // bytes in big endian order, word in little endian order : CDAB |
50 | | - EndianLittleBig = 0x02, // bytes in little endian order, word in big endian order : BADC |
51 | | - EndianLittleLittle = 0x03, // bytes in little endian order, word in little endian order : DCBA |
52 | | - EndianLittle = EndianLittleLittle // little endian order : DCBA |
53 | | - }; |
54 | | - |
55 | | - Data (Type type = Void, Endian endian = EndianBig); // default constructor |
56 | | - Data (const Data & other); |
57 | | - virtual ~Data(); |
58 | | - |
59 | | - Data (uint8_t v, Endian endian = EndianBig); |
60 | | - Data (uint16_t v, Endian endian = EndianBig); |
61 | | - Data (uint32_t v, Endian endian = EndianBig); |
62 | | - Data (uint64_t v, Endian endian = EndianBig); |
63 | | - Data (char v, Endian endian = EndianBig); |
64 | | - Data (int v, Endian endian = EndianBig); |
65 | | - Data (long v, Endian endian = EndianBig); |
66 | | - Data (long long v, Endian endian = EndianBig); |
67 | | - Data (float v, Endian endian = EndianBig); |
68 | | - Data (double v, Endian endian = EndianBig); |
69 | | - |
70 | | - void swap (Data &other); |
71 | | - Data& operator= (const Data &other); |
72 | | - |
73 | | - void set (uint8_t v); |
74 | | - void set (uint16_t v); |
75 | | - void set (uint32_t v); |
76 | | - void set (uint64_t v); |
77 | | - |
78 | | - void set (char v); |
79 | | - void set (int v); |
80 | | - void set (long v); |
81 | | - void set (long long v); |
82 | | - void set (float v); |
83 | | - void set (double v); |
84 | | - |
85 | | - void get (uint8_t & v) const; |
86 | | - void get (uint16_t & v) const; |
87 | | - void get (uint32_t & v) const; |
88 | | - void get (uint64_t & v) const; |
89 | | - |
90 | | - void get (char & v) const; |
91 | | - void get (int & v) const; |
92 | | - void get (long & v) const; |
93 | | - void get (long long & v) const; |
94 | | - void get (float & v) const; |
95 | | - void get (double & v) const; |
96 | | - |
97 | | - Endian endianness() const; |
98 | | - Type type() const; |
99 | | - void setType (Type t); |
100 | | - size_t size() const; |
101 | | - uint16_t * ptr(); |
102 | | - const uint16_t * ptr() const; |
| 57 | + static_assert ( (sizeof (T) >= 2 && (sizeof (T) % 2) == 0), "Bad Data typename !"); |
| 58 | + static_assert (std::is_arithmetic<T>::value, "Arithmetic type required."); |
| 59 | + |
| 60 | + Data() : m_endian (e) { |
| 61 | + m_value = 0; |
| 62 | + updateRegisters(); |
| 63 | + } |
| 64 | + |
| 65 | + Data (const T& t) : m_value (t), m_endian (e) { |
| 66 | + updateRegisters(); |
| 67 | + } |
| 68 | + |
| 69 | + operator T&() { |
| 70 | + return m_value; |
| 71 | + } |
| 72 | + |
| 73 | + operator T&() const { |
| 74 | + return m_value; |
| 75 | + } |
| 76 | + |
| 77 | + T& value() { |
| 78 | + return m_value; |
| 79 | + } |
| 80 | + |
| 81 | + const T& value() const { |
| 82 | + return m_value; |
| 83 | + } |
| 84 | + |
| 85 | + T* operator&() { |
| 86 | + return & m_value; |
| 87 | + } |
| 88 | + |
| 89 | + const T* operator&() const { |
| 90 | + return & m_value; |
| 91 | + } |
| 92 | + |
| 93 | + T& operator= (const T& t) { |
| 94 | + m_value = t; |
| 95 | + updateRegisters(); |
| 96 | + return m_value; |
| 97 | + } |
| 98 | + |
| 99 | + Endian endianness() const { |
| 100 | + return m_endian; |
| 101 | + } |
| 102 | + |
| 103 | + std::size_t size() const { |
| 104 | + return sizeof (m_value); |
| 105 | + } |
| 106 | + |
| 107 | + std::array < uint16_t, sizeof (T) / 2 > & registers() { |
| 108 | + return m_registers; |
| 109 | + } |
| 110 | + |
| 111 | + const std::array < uint16_t, sizeof (T) / 2 > & registers() const { |
| 112 | + return m_registers; |
| 113 | + } |
| 114 | + |
| 115 | + |
| 116 | + void swap (T & v) { |
| 117 | + |
| 118 | + switch (m_endian) { // net value: ABCDEFGH |
| 119 | + case EndianBigBig: // ABCDEFGH: bytes Big, word Big : no swap |
| 120 | + break; |
| 121 | + case EndianBigLittle: // GHEFCDAB: bytes Big, word Little : swap words |
| 122 | + v = swapWords (v); |
| 123 | + break; |
| 124 | + case EndianLittleBig: // BADCFEHG: bytes Little, word Big : swap bytes of words |
| 125 | + v = swapBytesInWords (v); |
| 126 | + break; |
| 127 | + case EndianLittleLittle: // HGFEDCBA: bytes Little, word Little: swap all |
| 128 | + v = swapBytes (v); |
| 129 | + break; |
| 130 | + } |
| 131 | + } |
103 | 132 |
|
104 | 133 | // debug purpose |
105 | | - void print () const; |
106 | | - static void print (const uint8_t * p, const size_t s); |
107 | | - static void print (const uint8_t & v); |
108 | | - static void print (const uint16_t & v); |
109 | | - static void print (const uint32_t & v); |
110 | | - static void print (const uint64_t & v); |
111 | | - static void print (const char & v); |
112 | | - static void print (const int & v); |
113 | | - static void print (const long & v); |
114 | | - static void print (const long long & v); |
115 | | - static void print (const float & v); |
116 | | - static void print (const double & v); |
| 134 | + static void print (const uint8_t * p, const size_t s) { |
| 135 | + std::printf ("0x"); |
| 136 | + for (std::size_t i = 0; i < s; i++) { |
| 137 | + std::printf ("%02X", p[i]); |
| 138 | + } |
| 139 | + std::printf ("\n"); |
| 140 | + } |
| 141 | + |
| 142 | + static void print (const T & v) { |
| 143 | + print ( (const uint8_t *) &v, sizeof (v)); |
| 144 | + } |
| 145 | + |
| 146 | + void print () { |
| 147 | + updateRegisters(); |
| 148 | + print ( (const uint8_t *) m_registers.data(), size()); |
| 149 | + } |
| 150 | + |
| 151 | + friend class Device; |
| 152 | + friend class Master; |
117 | 153 |
|
118 | 154 | protected: |
119 | | - class Private; |
120 | | - Data (Private &dd); |
121 | | - std::unique_ptr<Private> d_ptr; |
| 155 | + |
| 156 | + // update MODBUS registers from data value |
| 157 | + // to call before writing in the MODBUS registers |
| 158 | + void updateRegisters() { |
| 159 | + T v; |
| 160 | + |
| 161 | + v = hton (m_value); |
| 162 | + swap (v); |
| 163 | + std::memcpy (m_registers.data(), &v, sizeof (T)); |
| 164 | + for (auto & r : m_registers) { |
| 165 | + r = ntoh (r); |
| 166 | + } |
| 167 | + } |
| 168 | + |
| 169 | + // update data value from MODBUS registers |
| 170 | + // to call after reading the modbus registers |
| 171 | + void updateValue() { |
| 172 | + T v; |
| 173 | + |
| 174 | + for (auto & r : m_registers) { |
| 175 | + r = hton (r); |
| 176 | + } |
| 177 | + std::memcpy (&v, m_registers.data(), sizeof (T)); |
| 178 | + swap (v); |
| 179 | + m_value = ntoh (v); |
| 180 | + } |
122 | 181 |
|
123 | 182 | private: |
124 | | - PIMP_DECLARE_PRIVATE (Data) |
| 183 | + T m_value; |
| 184 | + Endian m_endian; |
| 185 | + std::array < uint16_t, sizeof (T) / 2 > m_registers; |
125 | 186 | }; |
126 | 187 | } |
127 | 188 | /** |
|
0 commit comments