User Tools

Site Tools


Differences

This shows you the differences between two versions of the page.

Link to this comparison view

modbus_tcp_custom [2019/01/09 12:23] (current)
emozolyak created
Line 1: Line 1:
 +====== An example of custom protocol for ModBus TCP ======
  
 +  ***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:
 +
 +<code lua>
 +-- 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
 +</​code>​

Page Tools