-
Notifications
You must be signed in to change notification settings - Fork 2.2k
P183 modbus RTU #5390
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: mega
Are you sure you want to change the base?
P183 modbus RTU #5390
Changes from 1 commit
38c20bc
46f2a50
7d0e802
cc31b10
53ec930
a715544
5f8868a
aa34ac3
02f46b3
11cf754
e7aabda
1ee2b35
18e8b86
bd7661e
8c66411
fc27c88
8f5e5f9
a4dfca1
7795cc1
6e201fb
280e8bf
4515c8c
21b427e
8d5ce4d
5ba2f9f
b432092
c182cea
67134da
3495afe
abe1a67
e93b4c3
ef31d27
c322798
da1e31d
0098e3c
7e01a41
934b595
610c3e9
33e4439
6b774aa
7efc42d
68bba7f
2e2ab34
bb28e71
470d3c2
884deb3
c66aee9
79ffeb4
afa1b6a
0f9c1dd
d254ae4
9111e0d
30d2b12
115cb39
6f2cb43
e5583da
a2dc9e0
01985f9
c117ebd
298517c
c723180
8517192
90c3a19
305d41e
c8abfef
49e803b
67bdaf7
281d0e6
485c46b
a741bee
e7eac10
d68d88b
1af346c
41d11b5
3a873c5
e90a72f
afa7ca5
7b7649b
e831f0f
98effa0
814016c
eb3327d
a68f5eb
55c6ccd
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -16,13 +16,12 @@ ModbusDEVICE_struct::~ModbusDEVICE_struct() { | |
| /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ||
| void ModbusDEVICE_struct::reset() { | ||
| if (_modbus_link != nullptr) { | ||
| _modbus_link->freeTransactions(this); | ||
| ModbusMGR_singleton.disconnect(_deviceID); | ||
| _modbus_link = nullptr; | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why not use some (weak) |
||
| } | ||
| _deviceID = 0; | ||
| _queueID = 0; | ||
| _sendframe_size = 0; | ||
| _recv_buf_used = 0; | ||
| _deviceID = 0; | ||
|
|
||
| _modbus_address = MODBUS_BROADCAST_ADDRESS; | ||
| } | ||
|
|
||
|
|
@@ -48,6 +47,16 @@ bool ModbusDEVICE_struct::init(uint8_t slaveAddress, | |
|
|
||
| _modbus_address = slaveAddress; | ||
|
|
||
| if (loglevelActiveFor(LOG_LEVEL_INFO)) { | ||
| String log = F("---> ModbusDevice Init: Slave address = "); | ||
| log += slaveAddress; | ||
| log += F(", This = "); | ||
| log += (ulong)this; | ||
|
flashmark marked this conversation as resolved.
Outdated
|
||
| log += F(", deviceID = "); | ||
| log += _deviceID; | ||
| addLogMove(LOG_LEVEL_INFO, log); | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. More |
||
| } | ||
|
|
||
| // TODO: further implementation needed | ||
| return success; | ||
| } | ||
|
|
@@ -74,17 +83,29 @@ uint16_t ModbusDEVICE_struct::getModbusTimeout() const | |
| /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ||
| bool ModbusDEVICE_struct::readHoldingRegister(uint16_t address, | ||
| uint16_t *valuePtr, | ||
| ModbusQueueState_t *statePtr) { | ||
| buildFrame(_modbus_address, MODBUS_READ_HOLDING_REGISTERS, address, 1); | ||
| uint16_t crc = CalculateCRC(_sendframe, _sendframe_size); | ||
| _sendframe[_sendframe_size++] = lowByte(crc); // CRC low byte | ||
| _sendframe[_sendframe_size++] = highByte(crc); // CRC high byte | ||
| _queueID = queueFrame(); | ||
| *statePtr = ModbusQueueState_t::QUEUED; | ||
| _statePtr = statePtr; | ||
| _resultPtr = valuePtr; | ||
| _state = ModbusQueueState_t::QUEUED; | ||
| _messageType = ModbusMessageType::READ_HOLDING_REGISTERS; | ||
| ModbusQueueState_t *statePtr) | ||
| { | ||
| if (_modbus_link == nullptr) { | ||
| return false; | ||
| } | ||
| Modbus_RequestQueueElement *request = _modbus_link->newTransaction(this); | ||
|
|
||
| request->_messageType = ModbusMessageType::READ_HOLDING_REGISTERS; | ||
| request->_userData = valuePtr; | ||
| request->_sendframe[0] = _modbus_address; | ||
| request->_sendframe[1] = MODBUS_READ_HOLDING_REGISTERS; | ||
| request->_sendframe[2] = highByte(address); | ||
| request->_sendframe[3] = lowByte(address); | ||
| request->_sendframe[4] = 0; | ||
| request->_sendframe[5] = 1; // Read 1 register | ||
| uint16_t crc = CalculateCRC(request->_sendframe, 6); | ||
| request->_sendframe[6] = lowByte(crc); // CRC low byte | ||
| request->_sendframe[7] = highByte(crc); // CRC high byte | ||
| request->_sendframe_length = 8; // Size with CRC | ||
| request->_rcvframe_length = 7; // Expect 8 bytes in response | ||
| dump_buffer(request->_sendframe, request->_sendframe_length); | ||
| uint16_t queueID = _modbus_link->queueRequest(request); | ||
| *statePtr = ModbusQueueState_t::QUEUED; | ||
|
|
||
| // Don't touch *valueptr here, it might contain a previous valid result. | ||
| return false; // TODO: implement | ||
|
|
@@ -95,17 +116,22 @@ bool ModbusDEVICE_struct::writeSingleRegister(uint16_t address, | |
| uint16_t value, | ||
| ModbusQueueState_t *statePtr) | ||
| { | ||
| buildFrame(_modbus_address, MODBUS_WRITE_SINGLE_REGISTER, address, 1); | ||
| _sendframe[4] = highByte(value); | ||
| _sendframe[5] = lowByte(value); | ||
| uint16_t crc = CalculateCRC(_sendframe, _sendframe_size); | ||
| _sendframe[_sendframe_size++] = lowByte(crc); // CRC low byte | ||
| _sendframe[_sendframe_size++] = highByte(crc); // CRC high byte | ||
| _queueID = queueFrame(); | ||
| *statePtr = ModbusQueueState_t::QUEUED; | ||
| _statePtr = statePtr; | ||
| _state = ModbusQueueState_t::QUEUED; | ||
| _messageType = ModbusMessageType::WRITE_SINGLE_REGISTER; | ||
| Modbus_RequestQueueElement *request = _modbus_link->newTransaction(this); | ||
|
|
||
| request->_sendframe[0] = _modbus_address; | ||
| request->_sendframe[1] = MODBUS_WRITE_SINGLE_REGISTER; | ||
| request->_sendframe[2] = highByte(address); | ||
| request->_sendframe[3] = lowByte(address); | ||
| request->_sendframe[4] = highByte(value); | ||
| request->_sendframe[5] = lowByte(value); | ||
| uint16_t crc = CalculateCRC(request->_sendframe, 6); | ||
| request->_sendframe[6] = lowByte(crc); // CRC low byte | ||
| request->_sendframe[7] = highByte(crc); // CRC high byte | ||
| request->_sendframe_length = 8; // Size with CRC | ||
| request->_rcvframe_length = 8; // Expect 8 bytes in response | ||
| uint16_t queueID = _modbus_link->queueRequest(request); | ||
| *statePtr = ModbusQueueState_t::QUEUED; | ||
| request->_messageType = ModbusMessageType::WRITE_SINGLE_REGISTER; | ||
| return false; | ||
| } | ||
|
|
||
|
|
@@ -114,104 +140,74 @@ void ModbusDEVICE_struct::processCommand() { | |
| if (_modbus_link != nullptr) { | ||
| _modbus_link->processCommand(); // Trigger processing of the command queue on the link | ||
| } | ||
| else { | ||
| _state = ModbusQueueState_t::ERROR; | ||
| } | ||
| } | ||
|
|
||
| /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ||
| // Callback function called by the Modbus link when a response is received for a queued request. | ||
| // Note that the response might be an invalid response or a timeout | ||
| // The queueID identifies the request. | ||
| /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ||
| void ModbusDEVICE_struct::linkCallback(uint16_t queueID) | ||
| void ModbusDEVICE_struct::linkCallback(Modbus_RequestQueueElement *req) | ||
| { | ||
| if (queueID != _queueID) { | ||
| return; // Not for us | ||
| } | ||
| bool response = _modbus_link->getResponse(_queueID, _recv_buf, _recv_buf_used); | ||
|
|
||
| if (response) { | ||
| switch (_messageType) { | ||
| case ModbusMessageType::READ_HOLDING_REGISTERS: | ||
| { | ||
| if ((_recv_buf[0] == _modbus_address) && (_recv_buf[1] == MODBUS_READ_HOLDING_REGISTERS) && (_recv_buf[2] == 2)) { | ||
| uint16_t crc = CalculateCRC(_recv_buf, 5); | ||
|
|
||
| if ((_recv_buf[5] == lowByte(crc)) && (_recv_buf[6] == highByte(crc))) { | ||
| // Valid response | ||
| if (_resultPtr != nullptr) { | ||
| *_resultPtr = (_recv_buf[3] << 8) | _recv_buf[4]; // Combine high and low byte | ||
| } | ||
| _state = ModbusQueueState_t::AVAILABLE; | ||
| } else { | ||
| // Invalid CRC | ||
| _state = ModbusQueueState_t::ERROR; | ||
| String log = F("---> Device callback: "); | ||
|
flashmark marked this conversation as resolved.
Outdated
|
||
|
|
||
| log += req->_id; | ||
| log += F(", Message = "); | ||
| log += (uint8_t)req->_messageType; | ||
|
flashmark marked this conversation as resolved.
Outdated
|
||
|
|
||
|
|
||
| switch (req->_messageType) { | ||
| case ModbusMessageType::READ_HOLDING_REGISTERS: | ||
| { | ||
| if ((req->_rcvframe[0] == _modbus_address) && (req->_rcvframe[1] == MODBUS_READ_HOLDING_REGISTERS) && (req->_rcvframe[2] == 2)) { | ||
| uint16_t crc = CalculateCRC(req->_rcvframe, 5); | ||
|
|
||
| if ((req->_rcvframe[5] == lowByte(crc)) && (req->_rcvframe[6] == highByte(crc))) { | ||
| // Valid response | ||
| if (req->_userData != nullptr) { | ||
| *((uint16_t *)req->_userData) = (req->_rcvframe[3] << 8) | req->_rcvframe[4]; // Combine high and low byte | ||
| } | ||
| } else { | ||
| // Invalid response | ||
| _state = ModbusQueueState_t::ERROR; | ||
| // Invalid CRC | ||
| } | ||
| return; | ||
| break; | ||
| } else { | ||
| // Invalid response | ||
| } | ||
| case ModbusMessageType::WRITE_SINGLE_REGISTER: | ||
| { | ||
| if ((_recv_buf[0] == _modbus_address) && (_recv_buf[1] == MODBUS_READ_HOLDING_REGISTERS) && (_recv_buf[2] == 2)) { | ||
| uint16_t crc = CalculateCRC(_recv_buf, 5); | ||
|
|
||
| if ((_recv_buf[5] == lowByte(crc)) && (_recv_buf[6] == highByte(crc))) { | ||
| // Valid response | ||
| _state = ModbusQueueState_t::AVAILABLE; | ||
| } | ||
| else { | ||
| // Invalid CRC | ||
| _state = ModbusQueueState_t::ERROR; | ||
| } | ||
| } else { | ||
| // Invalid response | ||
| _state = ModbusQueueState_t::ERROR; | ||
| break; | ||
| } | ||
|
|
||
| case ModbusMessageType::WRITE_SINGLE_REGISTER: | ||
| { | ||
| if ((req->_rcvframe[0] == _modbus_address) && (req->_rcvframe[1] == MODBUS_READ_HOLDING_REGISTERS) && (req->_rcvframe[2] == 2)) { | ||
| uint16_t crc = CalculateCRC(req->_rcvframe, 5); | ||
|
|
||
| if ((req->_rcvframe[5] == lowByte(crc)) && (req->_rcvframe[6] == highByte(crc))) { | ||
| // Valid response | ||
| } | ||
| break; | ||
| } | ||
| case ModbusMessageType::NONE: | ||
| { | ||
| // Should not happen | ||
| _state = ModbusQueueState_t::ERROR; | ||
| break; | ||
| else { | ||
| // Invalid CRC | ||
| } | ||
| } else { | ||
| // Invalid response | ||
| } | ||
| break; | ||
| } | ||
|
|
||
| default: | ||
| { | ||
| // Unknown message type | ||
| _state = ModbusQueueState_t::ERROR; | ||
| break; | ||
| } | ||
| case ModbusMessageType::NONE: | ||
| { | ||
| // Should not happen | ||
| break; | ||
| } | ||
| } | ||
|
|
||
| // Update the state as seen by the client | ||
| if (_statePtr != nullptr) { | ||
| *_statePtr = _state; | ||
| default: | ||
| { | ||
| // Unknown message type | ||
| break; | ||
| } | ||
| } | ||
| } | ||
|
|
||
| /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ||
| // Build a Modbus RTU frame filling in the standard fields. | ||
| // Note that thsi does not include the CRC. | ||
| // The frame is stored in the _sendframe buffer and the size is stored in _sendframe_size. | ||
| /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ||
| void ModbusDEVICE_struct::buildFrame(uint8_t slaveAddress, | ||
| uint8_t functionCode, | ||
| uint16_t startAddress, | ||
| uint8_t byteCount) { | ||
| _sendframe[0] = slaveAddress; | ||
| _sendframe[1] = functionCode; | ||
| _sendframe[2] = highByte(startAddress); | ||
| _sendframe[3] = lowByte(startAddress); | ||
| _sendframe[4] = highByte(byteCount); | ||
| _sendframe[5] = lowByte(byteCount); | ||
| _sendframe_size = 6; // Size without the CRC | ||
| _modbus_link->freeTransaction(req); | ||
| addLogMove(LOG_LEVEL_INFO, log); | ||
| } | ||
|
|
||
| /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ||
|
|
@@ -236,15 +232,19 @@ uint16_t ModbusDEVICE_struct::CalculateCRC(uint8_t *buf, int len) { | |
| } | ||
|
|
||
| /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ||
| // Queue the assembled Modbus frame for transmission over the link using the ModbusLink object. | ||
| // The function returns the queue ID assigned to the request, or 0 if queuing failed | ||
| /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ||
| uint16_t ModbusDEVICE_struct::queueFrame() { | ||
| if (_modbus_link == nullptr) { | ||
| return false; | ||
| void ModbusDEVICE_struct::dump_buffer(const uint8_t *buffer, size_t length) { | ||
| if (loglevelActiveFor(LOG_LEVEL_INFO)) { | ||
| String log = F("---> Modbus: Dumping buffer: "); | ||
|
|
||
| for (size_t i = 0; i < length; ++i) { | ||
| log += String(buffer[i], HEX); | ||
|
|
||
| if (i < length - 1) { | ||
| log += F(", "); | ||
| } | ||
| } | ||
| addLogMove(LOG_LEVEL_INFO, log); | ||
| } | ||
| _queueID = _modbus_link->queueRequest(this, _sendframe, _sendframe_size, MODBUS_RECEIVE_BUFFER, _timeout); | ||
| return _queueID; | ||
| } | ||
|
|
||
| #endif // if FEATURE_MODBUS | ||
Uh oh!
There was an error while loading. Please reload this page.