mirror of
https://github.com/MikaylaFischler/cc-mek-scada.git
synced 2024-08-30 18:22:34 +00:00
This commit is contained in:
@ -11,6 +11,20 @@ local MODBUS_FCODE = {
|
||||
ERROR_FLAG = 0x80
|
||||
}
|
||||
|
||||
-- modbus exception codes
|
||||
local MODBUS_EXCODE = {
|
||||
ILLEGAL_FUNCTION = 0x01,
|
||||
ILLEGAL_DATA_ADDR = 0x02,
|
||||
ILLEGAL_DATA_VALUE = 0x03,
|
||||
SERVER_DEVICE_FAIL = 0x04,
|
||||
ACKNOWLEDGE = 0x05,
|
||||
SERVER_DEVICE_BUSY = 0x06,
|
||||
NEG_ACKNOWLEDGE = 0x07,
|
||||
MEMORY_PARITY_ERROR = 0x08,
|
||||
GATEWAY_PATH_UNAVAILABLE = 0x0A,
|
||||
GATEWAY_TARGET_TIMEOUT = 0x0B
|
||||
}
|
||||
|
||||
-- new modbus comms handler object
|
||||
function modbus_init(rtu_dev)
|
||||
local self = {
|
||||
@ -19,13 +33,22 @@ function modbus_init(rtu_dev)
|
||||
|
||||
local _1_read_coils = function (c_addr_start, count)
|
||||
local readings = {}
|
||||
local access_fault = false
|
||||
local _, coils, _, _ = self.rtu.io_count()
|
||||
local return_ok = (c_addr_start + count) <= coils
|
||||
|
||||
if return_ok then
|
||||
for i = 0, (count - 1) do
|
||||
readings[i] = self.rtu.read_coil(c_addr_start + i)
|
||||
readings[i], access_fault = self.rtu.read_coil(c_addr_start + i)
|
||||
|
||||
if access_fault then
|
||||
return_ok = false
|
||||
readings = MODBUS_EXCODE.SERVER_DEVICE_FAIL
|
||||
break
|
||||
end
|
||||
end
|
||||
else
|
||||
readings = MODBUS_EXCODE.ILLEGAL_DATA_ADDR
|
||||
end
|
||||
|
||||
return return_ok, readings
|
||||
@ -33,13 +56,22 @@ function modbus_init(rtu_dev)
|
||||
|
||||
local _2_read_discrete_inputs = function (di_addr_start, count)
|
||||
local readings = {}
|
||||
local access_fault = false
|
||||
local discrete_inputs, _, _, _ = self.rtu.io_count()
|
||||
local return_ok = (di_addr_start + count) <= discrete_inputs
|
||||
|
||||
if return_ok then
|
||||
for i = 0, (count - 1) do
|
||||
readings[i] = self.rtu.read_di(di_addr_start + i)
|
||||
readings[i], access_fault = self.rtu.read_di(di_addr_start + i)
|
||||
|
||||
if access_fault then
|
||||
return_ok = false
|
||||
readings = MODBUS_EXCODE.SERVER_DEVICE_FAIL
|
||||
break
|
||||
end
|
||||
end
|
||||
else
|
||||
readings = MODBUS_EXCODE.ILLEGAL_DATA_ADDR
|
||||
end
|
||||
|
||||
return return_ok, readings
|
||||
@ -47,13 +79,22 @@ function modbus_init(rtu_dev)
|
||||
|
||||
local _3_read_multiple_holding_registers = function (hr_addr_start, count)
|
||||
local readings = {}
|
||||
local access_fault = false
|
||||
local _, _, _, hold_regs = self.rtu.io_count()
|
||||
local return_ok = (hr_addr_start + count) <= hold_regs
|
||||
|
||||
if return_ok then
|
||||
for i = 0, (count - 1) do
|
||||
readings[i] = self.rtu.read_holding_reg(hr_addr_start + i)
|
||||
readings[i], access_fault = self.rtu.read_holding_reg(hr_addr_start + i)
|
||||
|
||||
if access_fault then
|
||||
return_ok = false
|
||||
readings = MODBUS_EXCODE.SERVER_DEVICE_FAIL
|
||||
break
|
||||
end
|
||||
end
|
||||
else
|
||||
readings = MODBUS_EXCODE.ILLEGAL_DATA_ADDR
|
||||
end
|
||||
|
||||
return return_ok, readings
|
||||
@ -61,93 +102,132 @@ function modbus_init(rtu_dev)
|
||||
|
||||
local _4_read_input_registers = function (ir_addr_start, count)
|
||||
local readings = {}
|
||||
local access_fault = false
|
||||
local _, _, input_regs, _ = self.rtu.io_count()
|
||||
local return_ok = (ir_addr_start + count) <= input_regs
|
||||
|
||||
if return_ok then
|
||||
for i = 0, (count - 1) do
|
||||
readings[i] = self.rtu.read_input_reg(ir_addr_start + i)
|
||||
readings[i], access_fault = self.rtu.read_input_reg(ir_addr_start + i)
|
||||
|
||||
if access_fault then
|
||||
return_ok = false
|
||||
readings = MODBUS_EXCODE.SERVER_DEVICE_FAIL
|
||||
break
|
||||
end
|
||||
end
|
||||
else
|
||||
readings = MODBUS_EXCODE.ILLEGAL_DATA_ADDR
|
||||
end
|
||||
|
||||
return return_ok, readings
|
||||
end
|
||||
|
||||
local _5_write_single_coil = function (c_addr, value)
|
||||
local response = nil
|
||||
local _, coils, _, _ = self.rtu.io_count()
|
||||
local return_ok = c_addr <= coils
|
||||
|
||||
|
||||
if return_ok then
|
||||
self.rtu.write_coil(c_addr, value)
|
||||
local access_fault = self.rtu.write_coil(c_addr, value)
|
||||
|
||||
if access_fault then
|
||||
return_ok = false
|
||||
readings = MODBUS_EXCODE.SERVER_DEVICE_FAIL
|
||||
end
|
||||
else
|
||||
response = MODBUS_EXCODE.ILLEGAL_DATA_ADDR
|
||||
end
|
||||
|
||||
return return_ok
|
||||
return return_ok, response
|
||||
end
|
||||
|
||||
local _6_write_single_holding_register = function (hr_addr, value)
|
||||
local response = nil
|
||||
local _, _, _, hold_regs = self.rtu.io_count()
|
||||
local return_ok = hr_addr <= hold_regs
|
||||
|
||||
if return_ok then
|
||||
self.rtu.write_holding_reg(hr_addr, value)
|
||||
local access_fault = self.rtu.write_holding_reg(hr_addr, value)
|
||||
|
||||
if access_fault then
|
||||
return_ok = false
|
||||
readings = MODBUS_EXCODE.SERVER_DEVICE_FAIL
|
||||
end
|
||||
end
|
||||
|
||||
return return_ok
|
||||
end
|
||||
|
||||
local _15_write_multiple_coils = function (c_addr_start, values)
|
||||
local response = nil
|
||||
local _, coils, _, _ = self.rtu.io_count()
|
||||
local count = #values
|
||||
local return_ok = (c_addr_start + count) <= coils
|
||||
|
||||
if return_ok then
|
||||
for i = 0, (count - 1) do
|
||||
self.rtu.write_coil(c_addr_start + i, values[i + 1])
|
||||
local access_fault = self.rtu.write_coil(c_addr_start + i, values[i + 1])
|
||||
|
||||
if access_fault then
|
||||
return_ok = false
|
||||
readings = MODBUS_EXCODE.SERVER_DEVICE_FAIL
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return return_ok
|
||||
return return_ok, response
|
||||
end
|
||||
|
||||
local _16_write_multiple_holding_registers = function (hr_addr_start, values)
|
||||
local response = nil
|
||||
local _, _, _, hold_regs = self.rtu.io_count()
|
||||
local count = #values
|
||||
local return_ok = (hr_addr_start + count) <= hold_regs
|
||||
|
||||
if return_ok then
|
||||
for i = 0, (count - 1) do
|
||||
self.rtu.write_coil(hr_addr_start + i, values[i + 1])
|
||||
local access_fault = self.rtu.write_coil(hr_addr_start + i, values[i + 1])
|
||||
|
||||
if access_fault then
|
||||
return_ok = false
|
||||
readings = MODBUS_EXCODE.SERVER_DEVICE_FAIL
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return return_ok
|
||||
return return_ok, response
|
||||
end
|
||||
|
||||
local handle_packet = function (packet)
|
||||
local return_code = true
|
||||
local readings = nil
|
||||
local response = nil
|
||||
local reply = packet
|
||||
|
||||
if #packet.data == 2 then
|
||||
-- handle by function code
|
||||
if packet.func_code == MODBUS_FCODE.READ_COILS then
|
||||
return_code, readings = _1_read_coils(packet.data[1], packet.data[2])
|
||||
return_code, response = _1_read_coils(packet.data[1], packet.data[2])
|
||||
elseif packet.func_code == MODBUS_FCODE.READ_DISCRETE_INPUTS then
|
||||
return_code, readings = _2_read_discrete_inputs(packet.data[1], packet.data[2])
|
||||
return_code, response = _2_read_discrete_inputs(packet.data[1], packet.data[2])
|
||||
elseif packet.func_code == MODBUS_FCODE.READ_MUL_HOLD_REGS then
|
||||
return_code, readings = _3_read_multiple_holding_registers(packet.data[1], packet.data[2])
|
||||
return_code, response = _3_read_multiple_holding_registers(packet.data[1], packet.data[2])
|
||||
elseif packet.func_code == MODBUS_FCODE.READ_INPUT_REGISTERS then
|
||||
return_code, readings = _4_read_input_registers(packet.data[1], packet.data[2])
|
||||
return_code, response = _4_read_input_registers(packet.data[1], packet.data[2])
|
||||
elseif packet.func_code == MODBUS_FCODE.WRITE_SINGLE_COIL then
|
||||
return_code = _5_write_single_coil(packet.data[1], packet.data[2])
|
||||
return_code, response = _5_write_single_coil(packet.data[1], packet.data[2])
|
||||
elseif packet.func_code == MODBUS_FCODE.WRITE_SINGLE_HOLD_REG then
|
||||
return_code = _6_write_single_holding_register(packet.data[1], packet.data[2])
|
||||
return_code, response = _6_write_single_holding_register(packet.data[1], packet.data[2])
|
||||
elseif packet.func_code == MODBUS_FCODE.WRITE_MUL_COILS then
|
||||
return_code = _15_write_multiple_coils(packet.data[1], packet.data[2])
|
||||
return_code, response = _15_write_multiple_coils(packet.data[1], packet.data[2])
|
||||
elseif packet.func_code == MODBUS_FCODE.WRITE_MUL_HOLD_REGS then
|
||||
return_code = _16_write_multiple_holding_registers(packet.data[1], packet.data[2])
|
||||
return_code, response = _16_write_multiple_holding_registers(packet.data[1], packet.data[2])
|
||||
else
|
||||
-- unknown function
|
||||
return_code = false
|
||||
response = MODBUS_EXCODE.ILLEGAL_FUNCTION
|
||||
end
|
||||
else
|
||||
-- invalid length
|
||||
@ -155,19 +235,28 @@ function modbus_init(rtu_dev)
|
||||
end
|
||||
|
||||
if return_code then
|
||||
-- response (default is to echo back)
|
||||
response = packet
|
||||
if readings ~= nil then
|
||||
response.length = #readings
|
||||
response.data = readings
|
||||
-- default is to echo back
|
||||
if type(response) == "table" then
|
||||
reply.length = #response
|
||||
reply.data = response
|
||||
end
|
||||
else
|
||||
-- echo back with error flag
|
||||
response = packet
|
||||
response.func_code = bit.bor(packet.func_code, ERROR_FLAG)
|
||||
reply.func_code = bit.bor(packet.func_code, MODBUS_FCODE.ERROR_FLAG)
|
||||
|
||||
if type(response) == "nil" then
|
||||
reply.length = 0
|
||||
reply.data = {}
|
||||
elseif type(response) == "number" then
|
||||
reply.length = 1
|
||||
reply.data = { response }
|
||||
elseif type(response) == "table" then
|
||||
reply.length = #response
|
||||
reply.data = response
|
||||
end
|
||||
end
|
||||
|
||||
return return_code, response
|
||||
return return_code, reply
|
||||
end
|
||||
|
||||
return {
|
||||
|
@ -4,12 +4,17 @@
|
||||
-- Protected Peripheral Manager
|
||||
--
|
||||
|
||||
ACCESS_OK = true
|
||||
ACCESS_FAULT = nil
|
||||
|
||||
----------------------------
|
||||
-- PRIVATE DATA/FUNCTIONS --
|
||||
----------------------------
|
||||
|
||||
local self = {
|
||||
mounts = {},
|
||||
auto_cf = false,
|
||||
faulted = false,
|
||||
mute = false
|
||||
}
|
||||
|
||||
@ -21,18 +26,22 @@ local peri_init = function (device)
|
||||
local status, result = pcall(func, ...)
|
||||
|
||||
if status then
|
||||
-- auto fault clear
|
||||
if self.auto_cf then self.faulted = false end
|
||||
|
||||
-- assume nil is only for functions with no return, so return status
|
||||
if result == nil then
|
||||
return true
|
||||
return ACCESS_OK
|
||||
else
|
||||
return result
|
||||
end
|
||||
else
|
||||
-- function failed
|
||||
self.faulted = true
|
||||
if not mute then
|
||||
log._error("PPM: protected " .. key .. "() -> " .. result)
|
||||
end
|
||||
return nil
|
||||
return ACCESS_FAULT
|
||||
end
|
||||
end
|
||||
end
|
||||
@ -54,6 +63,28 @@ function enable_reporting()
|
||||
self.mute = false
|
||||
end
|
||||
|
||||
-- FAULT MEMORY --
|
||||
|
||||
-- enable automatically clearing fault flag
|
||||
function enable_afc()
|
||||
self.auto_cf = true
|
||||
end
|
||||
|
||||
-- disable automatically clearing fault flag
|
||||
function disable_afc()
|
||||
self.auto_cf = false
|
||||
end
|
||||
|
||||
-- check fault flag
|
||||
function is_faulted()
|
||||
return self.faulted
|
||||
end
|
||||
|
||||
-- clear fault flag
|
||||
function clear_fault()
|
||||
self.faulted = false
|
||||
end
|
||||
|
||||
-- MOUNTING --
|
||||
|
||||
-- mount all available peripherals (clears mounts first)
|
||||
|
Reference in New Issue
Block a user