User Tools

Site Tools


Differences

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

Link to this comparison view

modbus_ascii_custom [2019/01/09 12:21] (current)
emozolyak created
Line 1: Line 1:
 +====== An example of custom protocol for Modbus ASCII ======
 +
 +  ***Type**: Serial port
 +  ***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 ASCII Demo Driver
 +
 +function parseAddress ()
 +  -- do something here
 +end
 +
 +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 errorCount = 0;
 +
 +function intToPair(val,​ count) ​
 +    local str = string.upper(string.format("​%0"​ .. count .. "​x",​ val));
 +    local res = {};
 +    for i = 1, count do
 +        res[i] = string.byte(string.sub(str,​ i, i));
 +    end
 +    return res;
 +end
 +
 +function pairToInt(a,​ b)
 +    local str = string.char(a) .. string.char(b);​
 +    local n = tonumber(str,​ 16);
 +    return n;
 +end
 +
 +function LRC(table, start, count)
 +    local lrc = 0;
 +    local i = start;
 +    while (i < (start+count)) do
 +        local str = string.char(table[i]) .. string.char(table[i + 1]);
 +        local n = tonumber(str,​ 16);
 +        lrc = lrc + n;
 +        i = i + 2;
 +    end
 +    lrc = bit.band(lrc,​ 255);
 +    return 256 - lrc;
 +end
 +    ​
 +
 +function readRegister (reg, device, unitId)
 +  local request = {};
 +  ​
 +  -- ASCII header
 +  request[1] = 58;
 +  ​
 +  -- slave address
 +  local addr = intToPair(unitId,​ 2);
 +  request[2] = addr[1];
 +  request[3] = addr[2];
 +
 +  -- function code
 +  local fnCode = intToPair(device.xtraFields[1],​ 2);
 +  request[4] = fnCode[1];
 +  request[5] = fnCode[2];
 +
 +  -- address of register
 +  local intAddr = intToPair(reg.internalAddr,​ 4);
 +  request[6] = intAddr[1];
 +  request[7] = intAddr[2];
 +  request[8] = intAddr[3];
 +  request[9] = intAddr[4];
 +
 +  -- count of registers
 +  local count = 1;
 +  if (reg.dataType == 3) then -- double word
 +    count = 2;
 +  end
 +  count = intToPair(count,​ 4);
 +  request[10] = count[1];
 +  request[11] = count[2];
 +  request[12] = count[3];
 +  request[13] = count[4];
 +
 +  -- LRC
 +  local lrc = LRC(request,​ 2, 12);
 +  lrc = intToPair(lrc,​ 2);
 +
 +  request[14] = lrc[1];
 +  request[15] = lrc[2];
 +  ​
 +  -- CR LF
 +  request[16] = 13;
 +  request[17] = 10;
 +
 +  local res = sendBytes(request);​
 +  ​
 +  if (res == false) then
 +      DEBUG("​Can'​t send bytes"​);​
 +      return false;
 +  end
 +
 +
 +  local response = {};
 +
 +  -- read 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 header"​);​
 +      return false;
 +  end
 +
 +
 +  if (response[1] ~= request[1]) then
 +      ERROR("​Wrong protocol"​);​
 +      return false;
 +  end
 +
 +  if (response[2] ~= request[2] or response[3] ~= request[3]) then
 +      ERROR("​Wrong UnitID in response"​);​
 +      return false;
 +  end
 +
 +  if (response[4] ~= request[4] or response[5] ~= request[5]) then
 +      ERROR("​Wrong function code in response"​);​
 +      return false;
 +  end
 +
 +  local length = pairToInt(response[6],​ response[7]);​
 +  if (length < 1) then
 +      ERROR("​Wrong length in response"​);​
 +      return false;
 +  end
 +  ​
 +  local response2 = {};
 +
 +  response2 = readBytes(length * 2 + 4);
 +  if (response2 == false) then
 +      DEBUG("​Can'​t read response2"​);​
 +      return false;
 +  end
 +  res = #response2;
 +
 +  local result = {};
 +  ​
 +  local resp = {};
 +  for i=1,#​response do 
 +      resp[i] = response[i];​
 +  end
 +  local c = #response;
 +  for i=1,#​response2 do 
 +      resp[c+i] = response2[i];​
 +  end
 +  ​
 +  local lrc_resp = LRC(resp, 2, 6 + length * 2);
 +  local lrc_actual = pairToInt(response2[length*2 + 1], response2[length*2 + 2]);
 +  ​
 +  if (lrc_resp ~= lrc_actual) then
 +      ERROR("​Wrong LRC in response"​);​
 +      return false;
 +  end
 +
 +  if (length >= 1) then
 +      for i = 1, length do
 +          result[i] = pairToInt(response2[i*2 - 1], response2[i*2]);​
 +      end
 +  end
 +
 +  return result;
 +end
 +
 +
 +
 +function writeRegister (reg, device, unitId, newValue)
 +    local request = {};
 +    ​
 +    -- ASCII header
 +    request[1] = 58;
 +    ​
 +    -- slave address
 +    local addr = intToPair(unitId,​ 2);
 +    request[2] = addr[1];
 +    request[3] = addr[2];
 +    ​
 +  ​
 +    if (reg.dataType == 3) then -- double word should be handled in a special way
 +
 +        if (device.xtraFields[3] == 0) then
 +            ERROR("​Can'​t write these type of registers (" .. device.name .. "​)"​);​
 +            return false;
 +        end
 +        ​
 +        -- function code
 +        local fnCode = intToPair(device.xtraFields[3],​ 2);
 +        request[4] = fnCode[1];
 +        request[5] = fnCode[2];
 +    ​
 +        -- address of register
 +        local intAddr = intToPair(reg.internalAddr,​ 4);
 +        request[6] = intAddr[1];
 +        request[7] = intAddr[2];
 +        request[8] = intAddr[3];
 +        request[9] = intAddr[4];
 +
 +        local count = intToPair(2,​ 4);
 +        request[10] = count[1];
 +        request[11] = count[2];
 +        request[12] = count[3];
 +        request[13] = count[4];
 +
 +        -- message length
 +        local dataLen = intToPair(4,​ 2);
 +        request[14] = dataLen[1];
 +        request[15] = dataLen[2];
 +        ​
 +        local valpairs = intToPair(newValue,​ 8);
 +        for i=1,8 do 
 +            request[15+i] = valpairs[i];​
 +        end
 +        ​
 +        -- LRC
 +        local lrc = LRC(request,​ 2, 22);
 +        lrc = intToPair(lrc,​ 2);
 +        request[24] = lrc[1];
 +        request[25] = lrc[2];
 +    ​
 +        -- CR LF
 +        request[26] = 13;
 +        request[27] = 10;
 +        ​
 +        local res = sendBytes(request);​
 +        if (res == false) then
 +            DEBUG("​Can'​t send request"​);​
 +            return false;
 +        end
 +
 +
 +        local response = {};
 +
 +        response = readBytes(17);​
 +        if (response == false) then
 +            DEBUG("​Can'​t read response"​);​
 +            return false;
 +        end
 +        res = #response;
 +        ​
 +        if (res ~= 17) then
 +          DEBUG("​Wrong response length"​);​
 +          return false;
 +        end
 +        ​
 +
 +        if (response[1] ~= request[1]) then
 +          ERROR("​Wrong protocol"​);​
 +          return false;
 +        end
 +        ​
 +        local lrc_resp = LRC(response,​ 2, 12);
 +        local lrc_actual = pairToInt(response[14],​ response[15]);​
 +        if (lrc_resp ~= lrc_actual) then
 +          ERROR("​Wrong LRC in response"​);​
 +          return false;
 +        end
 +        ​
 +        if (response[2] ~= request[2] or response[3] ~= request[3]) then
 +          ERROR("​Wrong UnitID in response"​);​
 +          return false;
 +        end
 +        ​
 +        if (response[4] ~= request[4] or response[5] ~= request[5]) then
 +          ERROR("​Wrong function in response"​);​
 +          return false;
 +        end
 +        ​
 +        if (response[6] ~= request[6] or response[7] ~= request[7] or response[8] ~= request[8] or response[9] ~= request[9]) then
 +          ERROR("​Wrong register address in response"​);​
 +          return false;
 +        end
 +
 +        if (response[10] ~= request[10] or response[11] ~= request[11] or response[12] ~= request[12] or response[13] ~= request[13]) then
 +          ERROR("​Wrong register count"​);​
 +          return false;
 +        end
 +        ​
 +        if (response[16] ~= request[16] or response[17] ~= request[17]) then
 +          ERROR("​Wrong footer 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
 +        ​
 +        -- function code
 +        local fnCode = intToPair(device.xtraFields[2],​ 2);
 +        request[4] = fnCode[1];
 +        request[5] = fnCode[2];
 +    ​
 +        -- address of register
 +        local intAddr = intToPair(reg.internalAddr,​ 4);
 +        request[6] = intAddr[1];
 +        request[7] = intAddr[2];
 +        request[8] = intAddr[3];
 +        request[9] = intAddr[4];
 +
 +        -- data
 +        local val = newValue;
 +        if (reg.dataType == 0) then
 +            if (val > 0) then
 +                val = 255*256;
 +            else
 +                val = 0;
 +            end
 +        end
 +        local valpairs = intToPair(val,​ 4);
 +        request[10] = valpairs[1];​
 +        request[11] = valpairs[2];​
 +        request[12] = valpairs[3];​
 +        request[13] = valpairs[4];​
 +    ​
 +        -- LRC
 +        local lrc = LRC(request,​ 2, 12);
 +        lrc = intToPair(lrc,​ 2);
 +        request[14] = lrc[1];
 +        request[15] = lrc[2];
 +    ​
 +        -- CR LF
 +        request[16] = 13;
 +        request[17] = 10;
 +  ​
 +  ​
 +  ​
 +        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