modbus_rtu_custom
Differences
This shows you the differences between two versions of the page.
Both sides previous revisionPrevious revision | |||
modbus_rtu_custom [2022/10/21 12:01] – Float mode for 32 bit (DW) read and write atolstov | modbus_rtu_custom [2023/11/30 10:01] (current) – emozolyak | ||
---|---|---|---|
Line 434: | Line 434: | ||
return float_number | return float_number | ||
end | end | ||
+ | |||
+ | </ | ||
+ | |||
+ | ==== Version 2 ==== | ||
+ | <code lua> | ||
+ | -- MODBUS RTU Driver | ||
+ | |||
+ | function createDevices () | ||
+ | -- read FC write FC | ||
+ | addDevice({name = " | ||
+ | addDevice({name = " | ||
+ | addDevice({name = " | ||
+ | addDevice({name = " | ||
+ | addDevice({name = " | ||
+ | | ||
+ | end | ||
+ | |||
+ | local errorCount = 0 | ||
+ | |||
+ | -- template | ||
+ | local request = {1, 2, -- slaveId FC | ||
+ | | ||
+ | | ||
+ | | ||
+ | } | ||
+ | | ||
+ | local requestM = {1, 2, -- Адрес устройства, | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | 10, 11, -- Значение2 Hi, Lo | ||
+ | | ||
+ | | ||
+ | } | ||
+ | |||
+ | EXCEPTIONS = {" | ||
+ | " | ||
+ | " | ||
+ | " | ||
+ | " | ||
+ | } | ||
+ | |||
+ | 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, | ||
+ | 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(" | ||
+ | return false | ||
+ | end | ||
+ | -- RECEIVING REPLY --- | ||
+ | local respHead, respData, respCRC = {}, {}, {} | ||
+ | | ||
+ | -- read Header with length | ||
+ | respHead = readBytes(3) | ||
+ | if (respHead == false) then | ||
+ | DEBUG(" | ||
+ | return false | ||
+ | end | ||
+ | | ||
+ | if (respHead[1] ~= request[1]) then | ||
+ | ERROR(" | ||
+ | return false | ||
+ | end | ||
+ | | ||
+ | if (respHead[2] ~= request[2]) then | ||
+ | if (respHead[2] >= 0x81) then | ||
+ | ERROR(" | ||
+ | readBytes(2) -- read till the end | ||
+ | else | ||
+ | ERROR(" | ||
+ | end | ||
+ | | ||
+ | end | ||
+ | | ||
+ | local resp_Lentgh = respHead[3]; | ||
+ | respData = readBytes(resp_Lentgh) | ||
+ | if (respData == false) then | ||
+ | DEBUG(" | ||
+ | return false; | ||
+ | end | ||
+ | -- check CRC in reply | ||
+ | local tmpResponseTab = {} | ||
+ | for i,v in ipairs(respHead) do | ||
+ | table.insert(tmpResponseTab, | ||
+ | end | ||
+ | for i,v in ipairs(respData) do | ||
+ | table.insert(tmpResponseTab, | ||
+ | end | ||
+ | | ||
+ | crc = GetCRC(tmpResponseTab, | ||
+ | crcLo = GetLoByte(crc) | ||
+ | crcHi = GetHiByte(crc) | ||
+ | | ||
+ | respCRC = readBytes(2) | ||
+ | if (respCRC == false) then | ||
+ | DEBUG(" | ||
+ | return false; | ||
+ | end | ||
+ | if (respCRC[1] ~= crcLo) or (respCRC[2] ~= crcHi) then | ||
+ | DEBUG(" | ||
+ | return false; | ||
+ | end | ||
+ | | ||
+ | if (device.name == " | ||
+ | if (resp_Lentgh ~= count) then | ||
+ | ERROR(" | ||
+ | return false; | ||
+ | end | ||
+ | else | ||
+ | if (resp_Lentgh ~= count*2) then | ||
+ | ERROR(" | ||
+ | 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(" | ||
+ | if device.name == " | ||
+ | | ||
+ | return true | ||
+ | end | ||
+ | if 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, | ||
+ | | ||
+ | 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, | ||
+ | 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(" | ||
+ | local res = sendBytes(wrRequest); | ||
+ | if (res == false) then | ||
+ | DEBUG(" | ||
+ | return false; | ||
+ | end | ||
+ | | ||
+ | -- читаем ответ | ||
+ | res = readBytes(8) | ||
+ | | ||
+ | if (res == false) then | ||
+ | DEBUG(" | ||
+ | return false | ||
+ | end | ||
+ | | ||
+ | -- проверяем записалось или нет по количеству записанных регистров | ||
+ | if ( res[6] ~= (kol/2)) then | ||
+ | DEBUG(" | ||
+ | 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, | ||
+ | | ||
+ | local coilsTmp = 0 | ||
+ | if (device.name == " | ||
+ | coilsTmp = dataTable[2] * 0xFF | ||
+ | dataTable[2] = dataTable[1] | ||
+ | dataTable[1] = coilsTmp | ||
+ | end | ||
+ | DEBUG("# | ||
+ | | ||
+ | wrRequest[5] = dataTable[1] | ||
+ | wrRequest[6] = dataTable[2] | ||
+ | | ||
+ | -- CRC | ||
+ | local crc, crcLo, crcHi = 0,0,0 | ||
+ | crc = GetCRC(wrRequest, | ||
+ | crcLo = GetLoByte(crc) | ||
+ | crcHi = GetHiByte(crc) | ||
+ | wrRequest[7] = crcLo | ||
+ | wrRequest[8] = crcHi | ||
+ | | ||
+ | DEBUG(" | ||
+ | local res = sendBytes(wrRequest); | ||
+ | if (res == false) then | ||
+ | DEBUG(" | ||
+ | return false; | ||
+ | end | ||
+ | | ||
+ | -- читаем ответ | ||
+ | res = readBytes(8) | ||
+ | | ||
+ | if (res == false) then | ||
+ | DEBUG(" | ||
+ | return false | ||
+ | end | ||
+ | | ||
+ | if (table.concat(res) ~= table.concat(wrRequest)) then | ||
+ | DEBUG(" | ||
+ | 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, | ||
+ | crcLo = GetLoByte(crc) | ||
+ | crcHi = GetHiByte(crc) | ||
+ | wrRequest[7] = crcLo | ||
+ | wrRequest[8] = crcHi | ||
+ | | ||
+ | DEBUG(" | ||
+ | res = sendBytes(wrRequest); | ||
+ | if (res == false) then | ||
+ | DEBUG(" | ||
+ | return false; | ||
+ | end | ||
+ | | ||
+ | -- читаем ответ | ||
+ | res = readBytes(8) | ||
+ | | ||
+ | if (res == false) then | ||
+ | DEBUG(" | ||
+ | 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,# | ||
+ | crc = bit.bxor(crc, | ||
+ | -- iterate bits in byte | ||
+ | for j=1,8 do | ||
+ | mask = bit.band(crc, | ||
+ | if mask == 0x0001 then | ||
+ | crc = bit.rshift(crc, | ||
+ | crc = bit.bxor(crc, | ||
+ | else | ||
+ | crc = bit.rshift(crc, | ||
+ | end | ||
+ | | ||
+ | end | ||
+ | end | ||
+ | | ||
+ | end | ||
+ | |||
+ | function GetHiByte(c) | ||
+ | | ||
+ | | ||
+ | end | ||
+ | |||
+ | function GetLoByte(input_val) | ||
+ | DEBUG(" | ||
+ | return bit.band(input_val, | ||
+ | end | ||
+ | |||
+ | function GetHexFromTable(inputTab) | ||
+ | -- get hex and concat it to number via string operatoin | ||
+ | DEBUG(" | ||
+ | local numberAs_String = "" | ||
+ | local tmpStr = "" | ||
+ | | ||
+ | for i,v in pairs(inputTab) do | ||
+ | tmpStr = string.format(" | ||
+ | if (#tmpStr == 1) then | ||
+ | tmpStr = " | ||
+ | end | ||
+ | numberAs_String = numberAs_String..tmpStr | ||
+ | end | ||
+ | DEBUG(" | ||
+ | return tonumber(numberAs_String, | ||
+ | end | ||
+ | |||
+ | function GetDataAsTable(value, | ||
+ | |||
+ | local highWord, lowWord, tmpTable = 0, 0, {} | ||
+ | | ||
+ | if (datatype ~= 3) then | ||
+ | DEBUG(" | ||
+ | tmpTable[1] = GetHiByte(value) ; DEBUG(tmpTable[1]) | ||
+ | tmpTable[2] = GetLoByte(value) ; DEBUG(tmpTable[2]) | ||
+ | else | ||
+ | highWord = bit.rshift(value, | ||
+ | lowWord = bit.band(value, | ||
+ | | ||
+ | tmpTable[1] = GetHiByte(highWord) | ||
+ | tmpTable[2] = GetLoByte(highWord) | ||
+ | tmpTable[3] = GetHiByte(lowWord) | ||
+ | tmpTable[4] = GetLoByte(lowWord) | ||
+ | end | ||
+ | return tmpTable | ||
+ | end | ||
+ | |||
</ | </ | ||
modbus_rtu_custom.1666353683.txt.gz · Last modified: 2022/10/21 12:01 by atolstov