User Tools

Site Tools


modbus_rtu_custom

Differences

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

Link to this comparison view

Both sides previous revisionPrevious revision
modbus_rtu_custom [2022/10/21 12:01] – Float mode for 32 bit (DW) read and write atolstovmodbus_rtu_custom [2023/11/30 10:01] (current) emozolyak
Line 434: Line 434:
  return float_number  return float_number
 end end
 +
 +</code>
 +
 +==== Version 2 ====
 +<code lua>
 +-- MODBUS RTU Driver
 +
 +function createDevices ()
 +                                                     -- read FC write FC
 +  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}})
 +  addDevice({name = "IR", shift = 0, base = 10, xtraFields = {4, 0}})
 +  addDevice({name = "MHR",shift = 0, base = 10, xtraFields = {3, 16}})
 +  
 +end
 +
 +local errorCount = 0
 +
 +-- template 
 +local request = {1, 2,      -- slaveId FC
 +                 3,  4,     -- addr high lo 
 +                 5,  6,     -- count hi lo 
 +                 0,  0      -- crc high lo 
 +                }
 +                
 +local requestM = {1, 2,     -- Адрес устройства, Функциональный код
 +                 3,  4,     -- Адрес первого регистра Hi, Lo
 +                 5,  6,     -- Количество регистров Hi, Lo
 +                 7,         -- Количество байт далее
 +                 8,  9,     -- Значение1 Hi, Lo
 +                 10, 11,    -- Значение2 Hi, Lo
 +                 -------------------------------
 +                 0,  0      -- Контрольная сумма CRC Hi, Lo
 +                }  
 +
 +EXCEPTIONS = {"Illegal Function",     "Illegal Data Address",
 +               "Illegal Data Value",  "Slave Device Failure",
 +               "Acknowledge",         "Slave Device Busy",
 +               "Negative Acknowledge", "Memory Parity Error",
 +               "Gateway Path Unavailable", "Gateway Target Device Failed to Respond"
 +              }
 +
 +function readRegister (reg, device, unitId)
 +                             --- FORMING REQUEST ----------- 
 +      -- slave address
 +  request[1] = unitId;
 +  
 +  -- function code
 +  request[2] = device.xtraFields[1]
 +  
 +  -- address of register
 +  request[3] = GetHiByte(reg.internalAddr)
 +  request[4] = GetLoByte(reg.internalAddr)
 +  
 +  -- count of registers
 +  local count = 1
 +      if (reg.dataType == 3) then -- double word
 +        count = 2
 +      end
 +  request[5] = GetHiByte(count)
 +  request[6] = GetLoByte(count)
 +  
 +   -- CRC
 +  local crc = GetCRC(request, 2)
 +  local crcLo,crcHi = 0,0 -- will be used below too 
 +  crcLo = GetLoByte(crc) ; request[7] = crcLo
 +  crcHi = GetHiByte(crc) ; request[8] = crcHi
 +
 +                           -- SENDING REQUEST 
 +  if not (sendBytes(request)) then
 +      DEBUG("Can't send bytes")
 +      return false
 +  end
 +                           -- RECEIVING REPLY --- 
 +  local respHead, respData, respCRC = {}, {}, {}
 +  
 +    -- read Header with length 
 +  respHead = readBytes(3)
 +  if (respHead == false) then
 +      DEBUG("Can't read response")
 +      return false
 +  end
 +  
 +  if (respHead[1] ~= request[1]) then
 +      ERROR("Wrong slaveID in response!")
 +      return false
 +  end
 +  
 +  if (respHead[2] ~= request[2]) then
 +      if (respHead[2] >= 0x81) then 
 +          ERROR("EXCEPTION: "..EXCEPTIONS[bit.band(respHead[2], 0x0F)])
 +          readBytes(2) -- read till the end 
 +      else       
 +          ERROR("Wrong Func Code in response")
 +      end 
 +   return false;
 +  end
 +  
 +  local resp_Lentgh = respHead[3]; 
 +        respData = readBytes(resp_Lentgh)
 +  if (respData == false) then
 +      DEBUG("Can't read response");
 +      return false;
 +  end
 +  -- check CRC in reply 
 +  local tmpResponseTab = {}
 +    for i,v in ipairs(respHead) do 
 +        table.insert(tmpResponseTab, v) 
 +    end 
 +    for i,v in ipairs(respData) do 
 +        table.insert(tmpResponseTab, v) 
 +    end 
 +  
 +  crc = GetCRC(tmpResponseTab, 0)
 +  crcLo = GetLoByte(crc)
 +  crcHi = GetHiByte(crc)
 +    
 +  respCRC = readBytes(2)
 +  if (respCRC == false) then
 +      DEBUG("Can't read response");
 +      return false;
 +  end
 +  if (respCRC[1] ~= crcLo) or (respCRC[2] ~= crcHi) then 
 +      DEBUG("Wrong CRC in reply! "..string.format("%X", crcLo).." "..string.format("%X", crcHi));
 +      return false;
 +  end 
 +  
 +  if (device.name == "DI") or (device.name == "C" then 
 +      if (resp_Lentgh ~= count) then
 +          ERROR("Wrong length in response");
 +          return false;
 +      end
 +  else 
 +      if (resp_Lentgh ~= count*2) then
 +          ERROR("Wrong length in response");
 +          return false;
 +      end
 +  end 
 +                                  -- RETURN DATA --  
 +    --return GetHexFromTable(respData)
 +    return respData
 +
 +end -- readRegister
 +
 +
 +
 +function writeRegister (reg, device, unitId, newValue)
 +    -- for read-only don't write 
 +                                    DEBUG("Going to write this value "..newValue)
 +    if device.name == "IR" or device.name == "DI" then 
 +         ERROR("Can't write these type of registers (" .. device.name .. ")")
 +        return true 
 +    end 
 +    if device.name == "MHR" then 
 +         ERROR("Can't write these type of registers (" .. device.name .. ")")
 +         
 +        -------------------------------------- My Write MHR --------------------------------------
 +        local wrRequest = {};
 +        local n_byte =1;
 +        
 +        -- Адрес устройства
 +        wrRequest[n_byte] = unitId;   
 +        
 +        -- Функциональный код
 +        n_byte = n_byte +1;
 +        wrRequest[n_byte] = device.xtraFields[2]
 +        
 +        -- Адрес первого регистра Hi, Lo
 +        n_byte = n_byte +1;
 +        wrRequest[n_byte] = GetHiByte(reg.internalAddr)
 +        n_byte = n_byte +1;
 +        wrRequest[n_byte] = GetLoByte(reg.internalAddr)
 +        
 +        -- копируем в dataTable байты которые нужно записать
 +        local dataTable = GetDataAsTable(newValue, reg.dataType)
 +        
 +        local kol = #dataTable; -- количество байт которые нужно записать
 +        -- Количество регистров Hi, Lo
 +        n_byte = n_byte +1;
 +        wrRequest[n_byte] = 0;
 +        n_byte = n_byte +1;
 +        wrRequest[n_byte] = kol/2;
 +        
 +        -- Количество байт далее
 +        n_byte = n_byte +1;
 +        wrRequest[n_byte] = kol;
 +        
 +        -- Значение 1,2,3... Hi, Lo
 +        for i = 1, kol do 
 +            n_byte = n_byte +1;
 +            wrRequest[n_byte] = dataTable[i]
 +        end
 +        
 +        -- CRC
 +        local crc, crcLo, crcHi = 0,0,0
 +        crc = GetCRC(wrRequest, 0)
 +        crcLo = GetLoByte(crc)
 +        crcHi = GetHiByte(crc) 
 +        n_byte = n_byte +1;
 +        wrRequest[n_byte] = crcLo
 +        n_byte = n_byte +1;
 +        wrRequest[n_byte] = crcHi 
 +        
 +
 +        DEBUG("Going to send this packet "..table.concat(wrRequest))    
 +        local res = sendBytes(wrRequest);
 +        if (res == false) then
 +            DEBUG("Can't send request");
 +            return false;
 +        end
 +        
 +        -- читаем ответ 
 +        res = readBytes(8) 
 +        
 +        if (res == false) then
 +            DEBUG("Can't receive reply")
 +            return false
 +        end 
 +        
 +        -- проверяем записалось или нет по количеству записанных регистров
 +        if ( res[6] ~= (kol/2)) then 
 +            DEBUG("Response does not match!")
 +            return false
 +        end
 +        -------------------------------------- My Write MHR --------------------------------------
 +         
 +        return true 
 +    else 
 +    
 +        local wrRequest = {};
 +        
 +        -- slave address
 +        wrRequest[1] = unitId;   
 +        
 +        -- function code
 +        wrRequest[2] = device.xtraFields[2]
 +        
 +        -- address of register
 +        wrRequest[3] = GetHiByte(reg.internalAddr)
 +        wrRequest[4] = GetLoByte(reg.internalAddr)
 +        
 +        local dataTable = GetDataAsTable(newValue, reg.dataType)
 +            
 +            local coilsTmp = 0 
 +            if (device.name == "C") then 
 +                coilsTmp = dataTable[2] * 0xFF 
 +                dataTable[2] = dataTable[1]
 +                dataTable[1] = coilsTmp
 +            end 
 +        DEBUG("#dataTable now "..#dataTable)
 +        
 +        wrRequest[5] = dataTable[1]
 +        wrRequest[6] = dataTable[2]
 +        
 +        -- CRC
 +        local crc, crcLo, crcHi = 0,0,0
 +        crc = GetCRC(wrRequest, 0)
 +        crcLo = GetLoByte(crc)
 +        crcHi = GetHiByte(crc) 
 +        wrRequest[7] = crcLo
 +        wrRequest[8] = crcHi 
 +        
 +        DEBUG("Going to send this packet "..table.concat(wrRequest))    
 +        local res = sendBytes(wrRequest);
 +        if (res == false) then
 +            DEBUG("Can't send request");
 +            return false;
 +        end
 +        
 +        -- читаем ответ 
 +        res = readBytes(8) 
 +        
 +        if (res == false) then
 +            DEBUG("Can't receive reply")
 +            return false
 +        end 
 +        
 +        if (table.concat(res) ~= table.concat(wrRequest)) then 
 +            DEBUG("Response does not match!")
 +            return false
 +        end 
 +        
 +        if (#dataTable == 4) then 
 +            -- если пишем DWORD
 +            -- repeat steps for 2nd Word 
 +            wrRequest[3] = GetHiByte(reg.internalAddr + 1)
 +            wrRequest[4] = GetLoByte(reg.internalAddr + 1)
 +            wrRequest[5] = dataTable[3]
 +            wrRequest[6] = dataTable[4]
 +            
 +            wrRequest[7] = nil -- удаляем ячейку со старым CRC
 +            wrRequest[8] = nil -- удаляем ячейку со старым CRC
 +            
 +            -- CRC
 +            crc = GetCRC(wrRequest, 0)
 +            crcLo = GetLoByte(crc)
 +            crcHi = GetHiByte(crc) 
 +            wrRequest[7] = crcLo
 +            wrRequest[8] = crcHi 
 +            
 +            DEBUG("Going to send this packet "..table.concat(wrRequest)) 
 +            res = sendBytes(wrRequest);
 +            if (res == false) then
 +                DEBUG("Can't send request");
 +                return false;
 +            end
 +            
 +            -- читаем ответ 
 +            res = readBytes(8) 
 +            
 +            if (res == false) then
 +                DEBUG("Can't receive reply")
 +                return false
 +            end 
 +        end 
 +        return true
 +    end
 +end
 +
 +
 +-- Calculating CRC for RTU 
 +function GetCRC(req, offset) 
 +    
 +  local crc = 0xffff
 +  local mask = 0
 +  
 +  -- iterate bytes
 +for i=1,#req-offset do
 +      crc = bit.bxor(crc,req[i])
 +      -- iterate bits in byte 
 +      for j=1,8 do
 +          mask = bit.band(crc,0x0001)
 +          if mask == 0x0001 then
 +              crc = bit.rshift(crc,1)
 +              crc = bit.bxor(crc,0xA001)
 +          else
 +              crc = bit.rshift(crc,1)
 +          end
 +          
 +      end 
 +end 
 +     return crc
 +end
 +
 +function GetHiByte(c)
 +                                   DEBUG("Going to get high byte from "..c)
 +   return bit.rshift(c,8)
 +end
 +
 +function GetLoByte(input_val) 
 +                                    DEBUG("Going to get low byte from "..input_val)
 +    return bit.band(input_val,0xFF)
 +end
 +
 +function GetHexFromTable(inputTab)
 +    -- get hex and concat it to number via string operatoin 
 +                                    DEBUG("entered GetHexFromTable with table - "..table.concat(inputTab))
 +    local numberAs_String = "" 
 +    local tmpStr = "" 
 +    
 +        for i,v in pairs(inputTab) do 
 +            tmpStr = string.format("%X",v)
 +            if (#tmpStr == 1) then 
 +                tmpStr = "0"..tmpStr
 +            end 
 +            numberAs_String = numberAs_String..tmpStr
 +        end 
 +                                DEBUG("number is "..numberAs_String.." decimal = "..numberAs_String)    
 +    return tonumber(numberAs_String, 16)
 +end
 +
 +function GetDataAsTable(value, datatype)
 + 
 +    local highWord, lowWord, tmpTable = 0, 0, {}
 +    
 +    if (datatype ~= 3) then 
 +        DEBUG("getdataastable - going to process value  "..value)
 +        tmpTable[1] = GetHiByte(value) ; DEBUG(tmpTable[1])
 +        tmpTable[2] = GetLoByte(value) ; DEBUG(tmpTable[2])
 +    else 
 +        highWord = bit.rshift(value,16)
 +        lowWord = bit.band(value,0xFFFF)
 +        
 +        tmpTable[1] = GetHiByte(highWord)
 +        tmpTable[2] = GetLoByte(highWord)
 +        tmpTable[3] = GetHiByte(lowWord)
 +        tmpTable[4] = GetLoByte(lowWord)
 +    end 
 +    return tmpTable
 +end
 +
  
 </code> </code>
  
  
modbus_rtu_custom.txt · Last modified: 2023/11/30 10:01 by emozolyak

Donate Powered by PHP Valid HTML5 Valid CSS Driven by DokuWiki