1 #include "modbusrtuinterface.h"
3 std::deque<weak_ptr<XModbusRTUInterface::PortWrapper>> XModbusRTUInterface::s_openedPorts;
4 XMutex XModbusRTUInterface::s_globalMutex;
6 XModbusRTUInterface::XModbusRTUInterface(
const char *name,
bool runtime,
const shared_ptr<XDriver> &driver) :
10 setSerialBaudRate(9600);
14 XModbusRTUInterface::~XModbusRTUInterface() {
17 XModbusRTUInterface::open() throw (XInterfaceError &) {
22 for(
auto it = s_openedPorts.begin(); it != s_openedPorts.end();) {
23 if(
auto pt = it->lock()) {
24 if(pt->port->portString() == shot[ *
port()].to_str()) {
38 it = s_openedPorts.erase(it);
41 XCharInterface::open();
42 m_openedPort = std::make_shared<PortWrapper>();
43 m_openedPort->port = openedPort();
44 m_openedPort->lastTimeStamp = XTime::now();
45 s_openedPorts.push_back(m_openedPort);
56 XModbusRTUInterface::crc16(
const unsigned char *bytes, uint32_t count) {
58 for(uint32_t i = 0; i < count; ++i) {
59 uint16_t x = bytes[i];
61 for(
int shifts = 0; shifts < 8; ++shifts) {
68 return (z % 0x100u) * 0x100u + z / 0x100u;
71 XModbusRTUInterface::query_unicast(
unsigned int func_code,
72 const std::vector<unsigned char> &bytes, std::vector<unsigned char> &ret_buf) {
73 auto port = m_openedPort;
75 double msec_per_char = 1e3 / serialBaudRate() * 12;
76 double silent = 1e-3 * std::max(3.0, 3.5 * msec_per_char);
77 for(;; msecsleep(silent * 1e3 / 2 + 1)) {
81 if(XTime::now() -
port->lastTimeStamp < silent)
84 port->lastTimeStamp = XTime::now();
85 port->lastTimeStamp += 0.1;
87 unsigned int slave_addr = ***
address();
88 std::vector<unsigned char> buf(bytes.size() + 4);
89 buf[0] =
static_cast<unsigned char>(slave_addr);
90 buf[1] =
static_cast<unsigned char>(func_code);
91 std::copy(bytes.begin(), bytes.end(), &buf[2]);
92 uint16_t crc = crc16( &buf[0], buf.size() - 2);
93 set_word( &buf[buf.size() - 2], crc);
95 port->port->write( reinterpret_cast<char*>(&buf[0]), buf.size());
98 buf.resize(ret_buf.size() + 4);
99 port->port->receive(2);
100 std::copy(
port->port->buffer().begin(),
port->port->buffer().end(), buf.begin());
102 if(buf[0] != slave_addr) {
103 if(buf[1] == slave_addr) {
105 port->port->receive(1);
106 buf[1] =
port->port->buffer()[0];
108 else if((buf[1] & 0x7fu) == func_code) {
112 throw XInterfaceError(formatString(
"Modbus RTU Address Error, got %u instead of %u, and func. = %u.", buf[0], slave_addr, buf[1]), __FILE__, __LINE__);
114 gWarnPrint(formatString(
"Modbus RTU, ignores spurious start bit before a response for slave %u.", slave_addr));
116 if((buf[1] & 0x7fu) != func_code)
117 throw XInterfaceError(
"Modbus RTU Format Error.", __FILE__, __LINE__);
118 if(buf[1] != func_code) {
119 port->port->receive(3);
120 switch(
port->port->buffer()[0]) {
122 throw XInterfaceError(
"Modbus RTU Ill Function.", __FILE__, __LINE__);
124 throw XInterfaceError(
"Modbus RTU Wrong Data Address.", __FILE__, __LINE__);
126 throw XInterfaceError(
"Modbus RTU Wrong Data.", __FILE__, __LINE__);
128 throw XInterfaceError(
"Modbus RTU Slave Error.", __FILE__, __LINE__);
130 throw XInterfaceError(
"Modbus RTU Format Error.", __FILE__, __LINE__);
134 port->port->receive( ret_buf.size() + 2);
135 std::copy(
port->port->buffer().begin(),
port->port->buffer().end(), buf.begin() + 2);
136 crc = crc16( &buf[0], buf.size() - 2);
137 if(crc != get_word( &buf[buf.size() - 2]))
138 throw XInterfaceError(
"Modbus RTU CRC Error.", __FILE__, __LINE__);
139 std::copy(
port->port->buffer().begin(),
port->port->buffer().end() - 2, ret_buf.begin());
141 port->lastTimeStamp = XTime::now();
147 XModbusRTUInterface::readHoldingResistors(uint16_t res_addr,
int count, std::vector<uint16_t> &data) {
148 std::vector<unsigned char> wrbuf(4);
149 set_word( &wrbuf[0], res_addr);
150 set_word( &wrbuf[2], count);
151 std::vector<unsigned char> rdbuf(2 * count + 1);
152 query_unicast(0x03, wrbuf, rdbuf);
154 if(rdbuf[0] != 2 * count)
155 throw XInterfaceError(
"Modbus RTU Format Error.", __FILE__, __LINE__);
156 for(
unsigned int i = 0; i < count; ++i) {
157 data[i] = get_word( &rdbuf[2 * i + 1]);
161 XModbusRTUInterface::presetSingleResistor(uint16_t res_addr, uint16_t data) {
162 std::vector<unsigned char> wrbuf(4);
163 set_word( &wrbuf[0], res_addr);
164 set_word( &wrbuf[2], data);
165 std::vector<unsigned char> rdbuf(4);
166 query_unicast(0x06, wrbuf, rdbuf);
167 if(rdbuf.back() != wrbuf.back())
168 throw XInterfaceError(
"Modbus Format Error.", __FILE__, __LINE__);
171 XModbusRTUInterface::presetMultipleResistors(uint16_t res_no,
int count,
const std::vector<uint16_t> &data) {
172 std::vector<unsigned char> wrbuf(5 + 2 * count);
173 set_word( &wrbuf[0], res_no);
174 set_word( &wrbuf[2], count);
175 wrbuf[4] = count * 2;
177 for(
auto it = data.begin(); it != data.end(); ++it) {
178 set_word( &wrbuf[idx], *it);
181 std::vector<unsigned char> rdbuf(4);
182 query_unicast(0x10, wrbuf, rdbuf);
185 XModbusRTUInterface::diagnostics() {
186 std::vector<unsigned char> wrbuf(4);
187 set_word( &wrbuf[0], 0);
188 set_word( &wrbuf[2], 0x1234);
189 std::vector<unsigned char> rdbuf(4);
190 query_unicast(0x08, wrbuf, rdbuf);