Пример протокола ModBus TCP — различия между версиями
Материал из WebHMI Wiki
Строка 7: | Строка 7: | ||
<syntaxhighlight lang="lua"> | <syntaxhighlight lang="lua"> | ||
-- MODBUS TCP Demo Driver | -- MODBUS TCP Demo Driver | ||
− | + | ||
function createDevices () | function createDevices () | ||
addDevice({name = "C", shift = 0, base = 10, xtraFields = {1, 5}}); | addDevice({name = "C", shift = 0, base = 10, xtraFields = {1, 5}}); | ||
Строка 14: | Строка 14: | ||
addDevice({name = "IR", shift = 0, base = 10, xtraFields = {4, 0}}); | addDevice({name = "IR", shift = 0, base = 10, xtraFields = {4, 0}}); | ||
end | end | ||
− | + | ||
local transId = 0; | local transId = 0; | ||
local errorCount = 0; | local errorCount = 0; | ||
− | + | ||
function readRegister (reg, device, unitId) | function readRegister (reg, device, unitId) | ||
− | + | ||
local request = {}; | local request = {}; | ||
− | + | ||
-- transaction ID | -- transaction ID | ||
transId = transId + 1; | transId = transId + 1; | ||
− | + | ||
request[1] = bit.band(bit.rshift(transId, 8), 255); | request[1] = bit.band(bit.rshift(transId, 8), 255); | ||
request[2] = bit.band(transId, 255); | request[2] = bit.band(transId, 255); | ||
− | + | ||
-- protocol ID | -- protocol ID | ||
request[3] = 0; | request[3] = 0; | ||
request[4] = 0; | request[4] = 0; | ||
− | + | ||
-- message length | -- message length | ||
request[5] = 0; | request[5] = 0; | ||
request[6] = 6; | request[6] = 6; | ||
− | + | ||
-- unit ID | -- unit ID | ||
request[7] = unitId; | request[7] = unitId; | ||
− | + | ||
-- function code | -- function code | ||
request[8] = device.xtraFields[1]; | request[8] = device.xtraFields[1]; | ||
− | + | ||
-- address of register | -- address of register | ||
request[9] = bit.band(bit.rshift(reg.internalAddr, 8), 255); | request[9] = bit.band(bit.rshift(reg.internalAddr, 8), 255); | ||
request[10] = bit.band(reg.internalAddr, 255); | request[10] = bit.band(reg.internalAddr, 255); | ||
− | + | ||
-- count of registers | -- count of registers | ||
request[11] = 0; | request[11] = 0; | ||
request[12] = 1; | request[12] = 1; | ||
− | + | ||
if (reg.dataType == 3) then -- double word | if (reg.dataType == 3) then -- double word | ||
request[12] = 2; | request[12] = 2; | ||
end | end | ||
− | + | ||
local res = sendBytes(request); | local res = sendBytes(request); | ||
− | + | ||
if (res == false) then | if (res == false) then | ||
DEBUG("Can't send bytes"); | DEBUG("Can't send bytes"); | ||
return false; | return false; | ||
end | end | ||
− | + | ||
− | + | ||
− | + | ||
local response = {}; | local response = {}; | ||
-- read MBAP Header | -- read MBAP Header | ||
Строка 70: | Строка 70: | ||
return false; | return false; | ||
end | end | ||
− | + | ||
res = #response; | res = #response; | ||
if (res ~= 7) then | if (res ~= 7) then | ||
Строка 81: | Строка 81: | ||
return false; | return false; | ||
end | end | ||
− | + | ||
if (response[1] ~= request[1] or response[2] ~= request[2]) then | if (response[1] ~= request[1] or response[2] ~= request[2]) then | ||
ERROR("Wrong transaction ID. Got #" .. (response[1] * 256 + response[2]) .. " but expected #" .. (request[1] * 256 + request[2])); | ERROR("Wrong transaction ID. Got #" .. (response[1] * 256 + response[2]) .. " but expected #" .. (request[1] * 256 + request[2])); | ||
return false; | return false; | ||
end | end | ||
− | + | ||
if (response[3] ~= request[3] or response[4] ~= request[4]) then | if (response[3] ~= request[3] or response[4] ~= request[4]) then | ||
ERROR("Wrong protocol"); | ERROR("Wrong protocol"); | ||
return false; | return false; | ||
end | end | ||
− | + | ||
if (response[7] ~= request[7]) then | if (response[7] ~= request[7]) then | ||
ERROR("Wrong UnitID in response"); | ERROR("Wrong UnitID in response"); | ||
return false; | return false; | ||
end | end | ||
− | + | ||
local length = response[5] * 256 + response[6]; | local length = response[5] * 256 + response[6]; | ||
− | + | ||
if (length < 1) then | if (length < 1) then | ||
ERROR("Wrong length in response"); | ERROR("Wrong length in response"); | ||
return false; | return false; | ||
end | end | ||
− | + | ||
local responsePDU = {}; | local responsePDU = {}; | ||
-- read MBAP Header | -- read MBAP Header | ||
− | + | ||
responsePDU = readBytes(length - 1); | responsePDU = readBytes(length - 1); | ||
if (responsePDU == false) then | if (responsePDU == false) then | ||
Строка 112: | Строка 112: | ||
return false; | return false; | ||
end | end | ||
− | + | ||
res = #responsePDU; | res = #responsePDU; | ||
− | + | ||
if (responsePDU[1] ~= request[8]) then | if (responsePDU[1] ~= request[8]) then | ||
ERROR("Wrong function in response"); | ERROR("Wrong function in response"); | ||
return false; | return false; | ||
end | end | ||
− | + | ||
local dataLength = responsePDU[2]; | local dataLength = responsePDU[2]; | ||
if (dataLength ~= length - 3) then | if (dataLength ~= length - 3) then | ||
Строка 125: | Строка 125: | ||
return false; | return false; | ||
end | end | ||
− | + | ||
local result = {}; | local result = {}; | ||
− | + | ||
if (dataLength >= 1) then | if (dataLength >= 1) then | ||
for i = 1, dataLength do | for i = 1, dataLength do | ||
Строка 133: | Строка 133: | ||
end | end | ||
end | end | ||
− | + | ||
return result; | return result; | ||
end | end | ||
− | + | ||
function writeRegister (reg, device, unitId, newValue) | function writeRegister (reg, device, unitId, newValue) | ||
local request = {}; | local request = {}; | ||
− | + | ||
transId = transId + 1; | transId = transId + 1; | ||
-- transaction ID | -- transaction ID | ||
request[1] = bit.band(bit.rshift(transId, 8), 255); | request[1] = bit.band(bit.rshift(transId, 8), 255); | ||
request[2] = bit.band(transId, 255); | request[2] = bit.band(transId, 255); | ||
− | + | ||
-- protocol ID | -- protocol ID | ||
request[3] = 0; | request[3] = 0; | ||
request[4] = 0; | request[4] = 0; | ||
− | + | ||
if (reg.dataType == 3) then -- double word | if (reg.dataType == 3) then -- double word | ||
-- message length | -- message length | ||
request[5] = 0; | request[5] = 0; | ||
request[6] = 11; | request[6] = 11; | ||
− | + | ||
-- unit ID | -- unit ID | ||
request[7] = unitId; | request[7] = unitId; | ||
− | + | ||
-- function code | -- function code | ||
request[8] = device.xtraFields[3]; | request[8] = device.xtraFields[3]; | ||
− | + | ||
-- address of register | -- address of register | ||
request[9] = bit.band(bit.rshift(reg.internalAddr, 8), 255); | request[9] = bit.band(bit.rshift(reg.internalAddr, 8), 255); | ||
request[10] = bit.band(reg.internalAddr, 255); | request[10] = bit.band(reg.internalAddr, 255); | ||
− | + | ||
-- count of registers | -- count of registers | ||
request[11] = 0; | request[11] = 0; | ||
request[12] = 2; | request[12] = 2; | ||
− | + | ||
-- bytes with data | -- bytes with data | ||
request[13] = 4; | request[13] = 4; | ||
− | + | ||
-- value of registers | -- value of registers | ||
request[14] = bit.band(bit.rshift(newValue, 24), 255); | request[14] = bit.band(bit.rshift(newValue, 24), 255); | ||
Строка 176: | Строка 176: | ||
request[16] = bit.band(bit.rshift(newValue, 8), 255); | request[16] = bit.band(bit.rshift(newValue, 8), 255); | ||
request[17] = bit.band(newValue, 255); | request[17] = bit.band(newValue, 255); | ||
− | + | ||
local res = sendBytes(request); | local res = sendBytes(request); | ||
− | + | ||
if (res == false) then | if (res == false) then | ||
DEBUG("Can't send bytes"); | DEBUG("Can't send bytes"); | ||
return false; | return false; | ||
end | end | ||
− | + | ||
local response = {}; | local response = {}; | ||
− | + | ||
response = readBytes(7); | response = readBytes(7); | ||
if (response == false) then | if (response == false) then | ||
Строка 192: | Строка 192: | ||
end | end | ||
res = #response; | res = #response; | ||
− | + | ||
if (res ~= 7) then | if (res ~= 7) then | ||
DEBUG("Wrong response length"); | DEBUG("Wrong response length"); | ||
return false; | return false; | ||
end | end | ||
− | + | ||
if (response[1] ~= request[1] or response[2] ~= request[2]) then | if (response[1] ~= request[1] or response[2] ~= request[2]) then | ||
ERROR("Wrong transaction ID. Got #" .. (response[1] * 256 + response[2]) .. " but expected #" .. (request[1] * 256 + request[2])); | ERROR("Wrong transaction ID. Got #" .. (response[1] * 256 + response[2]) .. " but expected #" .. (request[1] * 256 + request[2])); | ||
return false; | return false; | ||
end | end | ||
− | + | ||
if (response[3] ~= request[3] or response[4] ~= request[4]) then | if (response[3] ~= request[3] or response[4] ~= request[4]) then | ||
ERROR("Wrong protocol"); | ERROR("Wrong protocol"); | ||
return false; | return false; | ||
end | end | ||
− | + | ||
if (response[7] ~= request[7]) then | if (response[7] ~= request[7]) then | ||
ERROR("Wrong UnitID in response"); | ERROR("Wrong UnitID in response"); | ||
return false; | return false; | ||
end | end | ||
− | + | ||
local length = response[5] * 256 + response[6]; | local length = response[5] * 256 + response[6]; | ||
− | + | ||
if (length < 1) then | if (length < 1) then | ||
ERROR("Wrong length in response"); | ERROR("Wrong length in response"); | ||
return false; | return false; | ||
end | end | ||
− | + | ||
local responsePDU = {}; | local responsePDU = {}; | ||
− | + | ||
responsePDU = readBytes(length - 1); | responsePDU = readBytes(length - 1); | ||
if (responsePDU == false) then | if (responsePDU == false) then | ||
Строка 228: | Строка 228: | ||
end | end | ||
res = #responsePDU; | res = #responsePDU; | ||
− | + | ||
if (responsePDU[1] ~= request[8]) then | if (responsePDU[1] ~= request[8]) then | ||
ERROR("Wrong function in response"); | ERROR("Wrong function in response"); | ||
return false; | return false; | ||
end | end | ||
− | + | ||
if (responsePDU[2] ~= request[9] or responsePDU[3] ~= request[10]) then | if (responsePDU[2] ~= request[9] or responsePDU[3] ~= request[10]) then | ||
ERROR("Wrong register address in response"); | ERROR("Wrong register address in response"); | ||
return false; | return false; | ||
end | end | ||
− | + | ||
if (responsePDU[4] ~= 0 or responsePDU[5] ~= 2) then | if (responsePDU[4] ~= 0 or responsePDU[5] ~= 2) then | ||
ERROR("Wrong register count in response"); | ERROR("Wrong register count in response"); | ||
Строка 251: | Строка 251: | ||
request[5] = 0; | request[5] = 0; | ||
request[6] = 6; | request[6] = 6; | ||
− | + | ||
-- unit ID | -- unit ID | ||
request[7] = unitId; | request[7] = unitId; | ||
request[8] = device.xtraFields[2]; | request[8] = device.xtraFields[2]; | ||
− | + | ||
-- address of register | -- address of register | ||
request[9] = bit.band(bit.rshift(reg.internalAddr, 8), 255); | request[9] = bit.band(bit.rshift(reg.internalAddr, 8), 255); | ||
request[10] = bit.band(reg.internalAddr, 255); | request[10] = bit.band(reg.internalAddr, 255); | ||
− | + | ||
local val = newValue; | local val = newValue; | ||
if (reg.dataType == 0) then | if (reg.dataType == 0) then | ||
Строка 268: | Строка 268: | ||
end | end | ||
end | end | ||
− | + | ||
-- value of registers | -- value of registers | ||
request[11] = bit.band(bit.rshift(val, 8), 255); | request[11] = bit.band(bit.rshift(val, 8), 255); | ||
request[12] = bit.band(val, 255); | request[12] = bit.band(val, 255); | ||
− | + | ||
− | + | ||
local res = sendBytes(request); | local res = sendBytes(request); | ||
− | + | ||
if (res == false) then | if (res == false) then | ||
DEBUG("Can't send bytes"); | DEBUG("Can't send bytes"); | ||
return false; | return false; | ||
end | end | ||
− | + | ||
local response = {}; | local response = {}; | ||
local requestLen = #request; | local requestLen = #request; | ||
− | + | ||
response = readBytes(requestLen); | response = readBytes(requestLen); | ||
if (response == false) then | if (response == false) then | ||
Строка 294: | Строка 294: | ||
return false; | return false; | ||
end | end | ||
− | + | ||
for i = 1,res do | for i = 1,res do | ||
if (response[i] ~= request[i]) then | if (response[i] ~= request[i]) then | ||
Строка 301: | Строка 301: | ||
end | end | ||
end | end | ||
− | + | ||
end | end | ||
− | + | ||
return true; | return true; | ||
end | end | ||
</syntaxhighlight> | </syntaxhighlight> |
Версия 10:14, 1 февраля 2016
Type: TCP
Default TCP port: 502
Address validation: ^(C[0-9]+)$|^(DI[0-9]+)$|^(HR[0-9]+)$|^(IR[0-9]+)$
Validation error message: Invalid register address. Valid ModBus addresses are Cxxx, DIxxx, IRxxx, HRxxx.
Code:
-- MODBUS TCP Demo Driver
function createDevices ()
addDevice({name = "C", shift = 0, base = 10, xtraFields = {1, 5}});
addDevice({name = "DI", shift = 0, base = 10, xtraFields = {2, 0}});
addDevice({name = "HR", shift = 0, base = 10, xtraFields = {3, 6, 16}});
addDevice({name = "IR", shift = 0, base = 10, xtraFields = {4, 0}});
end
local transId = 0;
local errorCount = 0;
function readRegister (reg, device, unitId)
local request = {};
-- transaction ID
transId = transId + 1;
request[1] = bit.band(bit.rshift(transId, 8), 255);
request[2] = bit.band(transId, 255);
-- protocol ID
request[3] = 0;
request[4] = 0;
-- message length
request[5] = 0;
request[6] = 6;
-- unit ID
request[7] = unitId;
-- function code
request[8] = device.xtraFields[1];
-- address of register
request[9] = bit.band(bit.rshift(reg.internalAddr, 8), 255);
request[10] = bit.band(reg.internalAddr, 255);
-- count of registers
request[11] = 0;
request[12] = 1;
if (reg.dataType == 3) then -- double word
request[12] = 2;
end
local res = sendBytes(request);
if (res == false) then
DEBUG("Can't send bytes");
return false;
end
local response = {};
-- read MBAP Header
response = readBytes(7);
if (response == false) then
DEBUG("Can't read response");
return false;
end
res = #response;
if (res ~= 7) then
errorCount = errorCount + 1;
if (errorCount > 3) then
closeConnection();
errorCount = 0;
end
DEBUG("Can't read MBAP");
return false;
end
if (response[1] ~= request[1] or response[2] ~= request[2]) then
ERROR("Wrong transaction ID. Got #" .. (response[1] * 256 + response[2]) .. " but expected #" .. (request[1] * 256 + request[2]));
return false;
end
if (response[3] ~= request[3] or response[4] ~= request[4]) then
ERROR("Wrong protocol");
return false;
end
if (response[7] ~= request[7]) then
ERROR("Wrong UnitID in response");
return false;
end
local length = response[5] * 256 + response[6];
if (length < 1) then
ERROR("Wrong length in response");
return false;
end
local responsePDU = {};
-- read MBAP Header
responsePDU = readBytes(length - 1);
if (responsePDU == false) then
DEBUG("Can't read responsePDU");
return false;
end
res = #responsePDU;
if (responsePDU[1] ~= request[8]) then
ERROR("Wrong function in response");
return false;
end
local dataLength = responsePDU[2];
if (dataLength ~= length - 3) then
ERROR("Wrong length in PDU");
return false;
end
local result = {};
if (dataLength >= 1) then
for i = 1, dataLength do
result[i] = responsePDU[2 + i];
end
end
return result;
end
function writeRegister (reg, device, unitId, newValue)
local request = {};
transId = transId + 1;
-- transaction ID
request[1] = bit.band(bit.rshift(transId, 8), 255);
request[2] = bit.band(transId, 255);
-- protocol ID
request[3] = 0;
request[4] = 0;
if (reg.dataType == 3) then -- double word
-- message length
request[5] = 0;
request[6] = 11;
-- unit ID
request[7] = unitId;
-- function code
request[8] = device.xtraFields[3];
-- address of register
request[9] = bit.band(bit.rshift(reg.internalAddr, 8), 255);
request[10] = bit.band(reg.internalAddr, 255);
-- count of registers
request[11] = 0;
request[12] = 2;
-- bytes with data
request[13] = 4;
-- value of registers
request[14] = bit.band(bit.rshift(newValue, 24), 255);
request[15] = bit.band(bit.rshift(newValue, 16), 255);
request[16] = bit.band(bit.rshift(newValue, 8), 255);
request[17] = bit.band(newValue, 255);
local res = sendBytes(request);
if (res == false) then
DEBUG("Can't send bytes");
return false;
end
local response = {};
response = readBytes(7);
if (response == false) then
DEBUG("Can't read response");
return false;
end
res = #response;
if (res ~= 7) then
DEBUG("Wrong response length");
return false;
end
if (response[1] ~= request[1] or response[2] ~= request[2]) then
ERROR("Wrong transaction ID. Got #" .. (response[1] * 256 + response[2]) .. " but expected #" .. (request[1] * 256 + request[2]));
return false;
end
if (response[3] ~= request[3] or response[4] ~= request[4]) then
ERROR("Wrong protocol");
return false;
end
if (response[7] ~= request[7]) then
ERROR("Wrong UnitID in response");
return false;
end
local length = response[5] * 256 + response[6];
if (length < 1) then
ERROR("Wrong length in response");
return false;
end
local responsePDU = {};
responsePDU = readBytes(length - 1);
if (responsePDU == false) then
DEBUG("Can't read responsePDU");
return false;
end
res = #responsePDU;
if (responsePDU[1] ~= request[8]) then
ERROR("Wrong function in response");
return false;
end
if (responsePDU[2] ~= request[9] or responsePDU[3] ~= request[10]) then
ERROR("Wrong register address in response");
return false;
end
if (responsePDU[4] ~= 0 or responsePDU[5] ~= 2) then
ERROR("Wrong register count in response");
return false;
end
else
if (device.xtraFields[2] == 0) then
ERROR("Can't write these type of registers (" .. device.name .. ")");
return false;
end
-- message length
request[5] = 0;
request[6] = 6;
-- unit ID
request[7] = unitId;
request[8] = device.xtraFields[2];
-- address of register
request[9] = bit.band(bit.rshift(reg.internalAddr, 8), 255);
request[10] = bit.band(reg.internalAddr, 255);
local val = newValue;
if (reg.dataType == 0) then
if (val > 0) then
val = 255*256;
else
val = 0;
end
end
-- value of registers
request[11] = bit.band(bit.rshift(val, 8), 255);
request[12] = bit.band(val, 255);
local res = sendBytes(request);
if (res == false) then
DEBUG("Can't send bytes");
return false;
end
local response = {};
local requestLen = #request;
response = readBytes(requestLen);
if (response == false) then
DEBUG("Can't read response");
return false;
end
res = #response;
if (res ~= requestLen) then
DEBUG("Wrong response length");
return false;
end
for i = 1,res do
if (response[i] ~= request[i]) then
DEBUG("Wrong response");
return false;
end
end
end
return true;
end