Пример протокола ModBus ASCII — различия между версиями

Материал из WebHMI Wiki
Перейти к: навигация, поиск
(Новая страница: «'''Type:''' Serial port<br/> '''Address validation:''' /^(C[0-9]+)$|^(DI[0-9]+)$|^(HR[0-9]+)$|^(IR[0-9]+)$/g<br/> '''Validation error message:''' Invalid register…»)
 
 
(не показано 9 промежуточных версий 2 участников)
Строка 1: Строка 1:
 +
<languages/>
 +
<translate>
 +
<!--T:1-->
 
'''Type:''' Serial port<br/>
 
'''Type:''' Serial port<br/>
'''Address validation:''' /^(C[0-9]+)$|^(DI[0-9]+)$|^(HR[0-9]+)$|^(IR[0-9]+)$/g<br/>
+
'''Address validation:''' ^(C[0-9]+)$|^(DI[0-9]+)$|^(HR[0-9]+)$|^(IR[0-9]+)$<br/>
 
'''Validation error message:''' Invalid register address. Valid ModBus addresses are Cxxx, DIxxx, IRxxx, HRxxx.<br/>
 
'''Validation error message:''' Invalid register address. Valid ModBus addresses are Cxxx, DIxxx, IRxxx, HRxxx.<br/>
  
 +
<!--T:2-->
 
Code:
 
Code:
<pre>
+
<syntaxhighlight lang="lua">
 
-- MODBUS ASCII Demo Driver
 
-- MODBUS ASCII Demo Driver
  
 +
<!--T:3-->
 
function parseAddress ()
 
function parseAddress ()
 
   -- do something here
 
   -- do something here
 
end
 
end
  
 +
<!--T:4-->
 
function createDevices ()
 
function createDevices ()
 
   addDevice({name = "C",  shift = 0, base = 10, xtraFields = {1, 5}});
 
   addDevice({name = "C",  shift = 0, base = 10, xtraFields = {1, 5}});
Строка 18: Строка 24:
 
end
 
end
  
 +
<!--T:5-->
 
local errorCount = 0;
 
local errorCount = 0;
  
 +
<!--T:6-->
 
function intToPair(val, count)  
 
function intToPair(val, count)  
 
     local str = string.upper(string.format("%0" .. count .. "x", val));
 
     local str = string.upper(string.format("%0" .. count .. "x", val));
Строка 29: Строка 37:
 
end
 
end
  
 +
<!--T:7-->
 
function pairToInt(a, b)
 
function pairToInt(a, b)
 
     local str = string.char(a) .. string.char(b);
 
     local str = string.char(a) .. string.char(b);
Строка 35: Строка 44:
 
end
 
end
  
 +
<!--T:8-->
 
function LRC(table, start, count)
 
function LRC(table, start, count)
 
     local lrc = 0;
 
     local lrc = 0;
Строка 49: Строка 59:
 
      
 
      
  
 +
<!--T:9-->
 
function readRegister (reg, device, unitId)
 
function readRegister (reg, device, unitId)
  -- print("plcId = " .. plcId);
 
  -- print("reg.addr = " .. reg.addr);
 
  -- print("reg.internalAddr = " .. reg.internalAddr);
 
  -- print("reg.dataType = " .. reg.dataType);
 
  -- print("device.xtraFields[1] = " .. device.xtraFields[1]);
 
  -- print("device.xtraFields[2] = " .. device.xtraFields[2]);
 
  -- print("device.xtraFields[3] = " .. device.xtraFields[3]);
 
  -- print("device.xtraFields[4] = " .. device.xtraFields[4]);
 
  -- print("device.xtraFields[5] = " .. device.xtraFields[5]);
 
 
   local request = {};
 
   local request = {};
 
    
 
    
Строка 69: Строка 71:
 
   request[3] = addr[2];
 
   request[3] = addr[2];
  
   -- function code
+
   <!--T:10-->
 +
-- function code
 
   local fnCode = intToPair(device.xtraFields[1], 2);
 
   local fnCode = intToPair(device.xtraFields[1], 2);
 
   request[4] = fnCode[1];
 
   request[4] = fnCode[1];
 
   request[5] = fnCode[2];
 
   request[5] = fnCode[2];
  
   -- address of register
+
   <!--T:11-->
 +
-- address of register
 
   local intAddr = intToPair(reg.internalAddr, 4);
 
   local intAddr = intToPair(reg.internalAddr, 4);
 
   request[6] = intAddr[1];
 
   request[6] = intAddr[1];
Строка 81: Строка 85:
 
   request[9] = intAddr[4];
 
   request[9] = intAddr[4];
  
   -- count of registers
+
   <!--T:12-->
 +
-- count of registers
 
   local count = 1;
 
   local count = 1;
 
   if (reg.dataType == 3) then -- double word
 
   if (reg.dataType == 3) then -- double word
Строка 92: Строка 97:
 
   request[13] = count[4];
 
   request[13] = count[4];
  
   -- LRC
+
   <!--T:13-->
 +
-- LRC
 
   local lrc = LRC(request, 2, 12);
 
   local lrc = LRC(request, 2, 12);
 
   lrc = intToPair(lrc, 2);
 
   lrc = intToPair(lrc, 2);
  
   request[14] = lrc[1];
+
   <!--T:14-->
 +
request[14] = lrc[1];
 
   request[15] = lrc[2];
 
   request[15] = lrc[2];
 
    
 
    
Строка 103: Строка 110:
 
   request[17] = 10;
 
   request[17] = 10;
  
   local res = sendBytes(request);
+
   <!--T:15-->
 +
local res = sendBytes(request);
 
    
 
    
   if (res ~= 0) then
+
   if (res == false) then
 
       DEBUG("Can't send bytes");
 
       DEBUG("Can't send bytes");
       return 0;
+
       return false;
 
   end
 
   end
  
  
   local response = {};
+
   <!--T:16-->
 +
local response = {};
  
   -- read Header
+
   <!--T:17-->
 +
-- read Header
 
   response = readBytes(7);
 
   response = readBytes(7);
 +
  if (response == false) then
 +
      DEBUG("Can't read response");
 +
      return false;
 +
  end
 
   res = #response;
 
   res = #response;
  
   if (res ~= 7) then
+
   <!--T:18-->
 +
if (res ~= 7) then
 
       errorCount = errorCount + 1;
 
       errorCount = errorCount + 1;
 
       if (errorCount > 3) then
 
       if (errorCount > 3) then
Строка 124: Строка 139:
 
       end
 
       end
 
       DEBUG("Can't read header");
 
       DEBUG("Can't read header");
       return 0;
+
       return false;
 
   end
 
   end
  
  
   if (response[1] ~= request[1]) then
+
   <!--T:19-->
 +
if (response[1] ~= request[1]) then
 
       ERROR("Wrong protocol");
 
       ERROR("Wrong protocol");
       return 0;
+
       return false;
 
   end
 
   end
  
   if (response[2] ~= request[2] or response[3] ~= request[3]) then
+
   <!--T:20-->
 +
if (response[2] ~= request[2] or response[3] ~= request[3]) then
 
       ERROR("Wrong UnitID in response");
 
       ERROR("Wrong UnitID in response");
       return 0;
+
       return false;
 
   end
 
   end
  
   if (response[4] ~= request[4] or response[5] ~= request[5]) then
+
   <!--T:21-->
 +
if (response[4] ~= request[4] or response[5] ~= request[5]) then
 
       ERROR("Wrong function code in response");
 
       ERROR("Wrong function code in response");
       return 0;
+
       return false;
 
   end
 
   end
  
   local length = pairToInt(response[6], response[7]);
+
   <!--T:22-->
 +
local length = pairToInt(response[6], response[7]);
 
   if (length < 1) then
 
   if (length < 1) then
 
       ERROR("Wrong length in response");
 
       ERROR("Wrong length in response");
       return 0;
+
       return false;
 
   end
 
   end
 
    
 
    
 
   local response2 = {};
 
   local response2 = {};
  
   response2 = readBytes(length * 2 + 4);
+
   <!--T:23-->
 +
response2 = readBytes(length * 2 + 4);
 +
  if (response2 == false) then
 +
      DEBUG("Can't read response2");
 +
      return false;
 +
  end
 
   res = #response2;
 
   res = #response2;
  
   local result = {};
+
   <!--T:24-->
 +
local result = {};
 
    
 
    
 
   local resp = {};
 
   local resp = {};
Строка 170: Строка 195:
 
   if (lrc_resp ~= lrc_actual) then
 
   if (lrc_resp ~= lrc_actual) then
 
       ERROR("Wrong LRC in response");
 
       ERROR("Wrong LRC in response");
       return 0;
+
       return false;
 
   end
 
   end
  
   if (length >= 1) then
+
   <!--T:25-->
 +
if (length >= 1) then
 
       for i = 1, length do
 
       for i = 1, length do
 
           result[i] = pairToInt(response2[i*2 - 1], response2[i*2]);
 
           result[i] = pairToInt(response2[i*2 - 1], response2[i*2]);
Строка 179: Строка 205:
 
   end
 
   end
  
   return result;
+
   <!--T:26-->
 +
return result;
 
end
 
end
  
  
  
 +
<!--T:27-->
 
function writeRegister (reg, device, unitId, newValue)
 
function writeRegister (reg, device, unitId, newValue)
 
     local request = {};
 
     local request = {};
Строка 196: Строка 224:
 
      
 
      
 
    
 
    
     if (reg.dataType == 3) then -- double word sohuld be handled in a special way
+
     if (reg.dataType == 3) then -- double word should be handled in a special way
  
         if (device.xtraFields[3] == 0) then
+
         <!--T:28-->
 +
if (device.xtraFields[3] == 0) then
 
             ERROR("Can't write these type of registers (" .. device.name .. ")");
 
             ERROR("Can't write these type of registers (" .. device.name .. ")");
             return 0;
+
             return false;
 
         end
 
         end
 
          
 
          
Строка 215: Строка 244:
 
         request[9] = intAddr[4];
 
         request[9] = intAddr[4];
  
         local count = intToPair(2, 4);
+
         <!--T:29-->
 +
local count = intToPair(2, 4);
 
         request[10] = count[1];
 
         request[10] = count[1];
 
         request[11] = count[2];
 
         request[11] = count[2];
Строка 221: Строка 251:
 
         request[13] = count[4];
 
         request[13] = count[4];
  
         -- message length
+
         <!--T:30-->
 +
-- message length
 
         local dataLen = intToPair(4, 2);
 
         local dataLen = intToPair(4, 2);
 
         request[14] = dataLen[1];
 
         request[14] = dataLen[1];
Строка 231: Строка 262:
 
         end
 
         end
 
          
 
          
                -- LRC
+
        -- LRC
 
         local lrc = LRC(request, 2, 22);
 
         local lrc = LRC(request, 2, 22);
 
         lrc = intToPair(lrc, 2);
 
         lrc = intToPair(lrc, 2);
Строка 240: Строка 271:
 
         request[26] = 13;
 
         request[26] = 13;
 
         request[27] = 10;
 
         request[27] = 10;
 
        for i = 1,27 do
 
            print("byte -> [" .. i .. "] = " .. request[i]);
 
        end
 
       
 
 
          
 
          
 
         local res = sendBytes(request);
 
         local res = sendBytes(request);
 
+
         if (res == false) then
         if (res ~= 0) then
+
             DEBUG("Can't send request");
             DEBUG("Can't send bytes");
+
             return false;
             return 0;
+
 
         end
 
         end
  
        local response = {};
 
  
         response = readBytes(17);
+
         <!--T:31-->
 +
local response = {};
 +
 
 +
        <!--T:32-->
 +
response = readBytes(17);
 +
        if (response == false) then
 +
            DEBUG("Can't read response");
 +
            return false;
 +
        end
 
         res = #response;
 
         res = #response;
        print("read " .. res .. " bytes");
 
       
 
        for i = 1,res do
 
          print("byte <- [" .. i .. "] = " .. response[i]);
 
        end
 
 
          
 
          
 
         if (res ~= 17) then
 
         if (res ~= 17) then
Строка 269: Строка 296:
 
          
 
          
  
         if (response[1] ~= request[1]) then
+
         <!--T:33-->
 +
if (response[1] ~= request[1]) then
 
           ERROR("Wrong protocol");
 
           ERROR("Wrong protocol");
 
           return false;
 
           return false;
Строка 296: Строка 324:
 
         end
 
         end
  
         if (response[10] ~= request[10] or response[11] ~= request[11] or response[12] ~= request[12] or response[13] ~= request[13]) then
+
         <!--T:34-->
 +
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");
 
           ERROR("Wrong register count");
 
           return false;
 
           return false;
Строка 306: Строка 335:
 
         end
 
         end
  
 +
    <!--T:35-->
 +
else
  
    else
+
        <!--T:36-->
 
+
if (device.xtraFields[2] == 0) then
        if (device.xtraFields[2] == 0) then
+
 
             ERROR("Can't write these type of registers (" .. device.name .. ")");
 
             ERROR("Can't write these type of registers (" .. device.name .. ")");
             return 0;
+
             return false;
 
         end
 
         end
 
          
 
          
Строка 326: Строка 356:
 
         request[9] = intAddr[4];
 
         request[9] = intAddr[4];
  
         -- data
+
         <!--T:37-->
 +
-- data
 
         local val = newValue;
 
         local val = newValue;
 
         if (reg.dataType == 0) then
 
         if (reg.dataType == 0) then
Строка 355: Строка 386:
 
         local res = sendBytes(request);
 
         local res = sendBytes(request);
 
    
 
    
         if (res ~= 0) then
+
         if (res == false) then
 
             DEBUG("Can't send bytes");
 
             DEBUG("Can't send bytes");
             return 0;
+
             return false;
 
         end
 
         end
 
          
 
          
Строка 364: Строка 395:
 
          
 
          
 
         response = readBytes(requestLen);
 
         response = readBytes(requestLen);
 +
        if (response == false) then
 +
            DEBUG("Can't read response");
 +
            return false;
 +
        end
 
         res = #response;
 
         res = #response;
  
         if (res ~= requestLen) then
+
         <!--T:38-->
 +
if (res ~= requestLen) then
 
           DEBUG("Wrong response length");
 
           DEBUG("Wrong response length");
 
           return false;
 
           return false;
Строка 380: Строка 416:
 
     return true;
 
     return true;
 
end
 
end
</pre>
+
</syntaxhighlight>
 +
</translate>

Текущая версия на 11:27, 1 марта 2018

Другие языки:
English • ‎русский

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:

-- 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