Skip to content

Commit e8382ce

Browse files
committed
Change the Data class to a template
1 parent d9272bf commit e8382ce

File tree

6 files changed

+693
-825
lines changed

6 files changed

+693
-825
lines changed

include/modbuspp-data.h

Lines changed: 149 additions & 88 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
/* Copyright © 2018 Pascal JEAN, All rights reserved.
1+
/* Copyright © 2018-2019 Pascal JEAN, All rights reserved.
22
* This file is part of the libmodbuspp Library.
33
*
44
* The libmodbuspp Library is free software; you can redistribute it and/or
@@ -18,110 +18,171 @@
1818
#ifndef MODBUSPP_DATA_H
1919
#define MODBUSPP_DATA_H
2020

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 */
2429

2530
/**
2631
*
2732
*/
2833
namespace Modbus {
2934

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+
3048
/**
3149
* @class Data
32-
* @brief
50+
* @author Pascal JEAN, aka epsilonrt
51+
* @copyright GNU Lesser General Public License
52+
* @brief
3353
*/
54+
template <typename T, Endian e = EndianBigBig>
3455
class Data {
3556
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+
}
103132

104133
// 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;
117153

118154
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+
}
122181

123182
private:
124-
PIMP_DECLARE_PRIVATE (Data)
183+
T m_value;
184+
Endian m_endian;
185+
std::array < uint16_t, sizeof (T) / 2 > m_registers;
125186
};
126187
}
127188
/**

include/modbuspp-swap.h

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
/* Copyright © 2018-2019 Pascal JEAN, All rights reserved.
2+
* This file is part of the libmodbuspp Library.
3+
*
4+
* The libmodbuspp Library is free software; you can redistribute it and/or
5+
* modify it under the terms of the GNU Lesser General Public
6+
* License as published by the Free Software Foundation; either
7+
* version 3 of the License, or (at your option) any later version.
8+
*
9+
* The libmodbuspp Library is distributed in the hope that it will be useful,
10+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
11+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12+
* Lesser General Public License for more details.
13+
*
14+
* You should have received a copy of the GNU Lesser General Public License
15+
* along with the libmodbuspp Library; if not, see <http://www.gnu.org/licenses/>.
16+
*/
17+
18+
#ifndef MODBUSPP_SWAP_H
19+
#define MODBUSPP_SWAP_H
20+
21+
#ifndef __DOXYGEN__
22+
23+
#include <algorithm> // std::swap until C++11
24+
#include <utility> // std::swap since C++11
25+
26+
/*
27+
* reverse the order of the bytes
28+
*/
29+
template <typename T>
30+
T swapBytes (T input) { // swap bytes
31+
uint8_t * ptr = reinterpret_cast<uint8_t*> (&input);
32+
33+
for (std::size_t i = 0; i < sizeof (T) / 2; ++i) {
34+
35+
std::swap (ptr[i], ptr[ sizeof (T) - 1 - i ]);
36+
}
37+
return input;
38+
}
39+
40+
/*
41+
* reverse the order of the 16-bit words
42+
*/
43+
template <typename T>
44+
T swapWords (T input) { // swap words
45+
uint16_t * ptr = reinterpret_cast<uint16_t*> (&input);
46+
47+
for (std::size_t i = 0; i < sizeof (T) / 4; ++i) {
48+
49+
std::swap (ptr[i], ptr[ (sizeof (T) / 2) - 1 - i ]);
50+
}
51+
return input;
52+
}
53+
54+
/*
55+
* reverse the byte order of each 16-bit word.
56+
*/
57+
template <typename T>
58+
T swapBytesInWords (T input) { // swap bytes in each words
59+
uint16_t * ptr = reinterpret_cast<uint16_t*> (&input);
60+
61+
for (std::size_t i = 0; i < sizeof (T) / 2; ++i) {
62+
63+
ptr[i] = swapBytes (ptr[i]);
64+
}
65+
return input;
66+
}
67+
68+
/*
69+
* converts the input from host byte order to network byte order.
70+
*/
71+
template <typename T>
72+
T hton (T input) {
73+
#if __BYTE_ORDER == __LITTLE_ENDIAN
74+
return swapBytes (input);
75+
#else
76+
return input;
77+
#endif
78+
}
79+
80+
/*
81+
* converts the input from host byte network to host byte order.
82+
*/
83+
template <typename T>
84+
T ntoh (T input) {
85+
#if __BYTE_ORDER == __LITTLE_ENDIAN
86+
return swapBytes (input);
87+
#else
88+
return input;
89+
#endif
90+
}
91+
#endif /* __DOXYGEN__ not defined */
92+
/* ========================================================================== */
93+
#endif /* MODBUSPP_SWAP_H defined */

0 commit comments

Comments
 (0)