#30 modbus comms changes
This commit is contained in:
@@ -88,7 +88,7 @@ function scada_packet()
|
|||||||
-- public accessors --
|
-- public accessors --
|
||||||
|
|
||||||
local modem_event = function () return self.modem_msg_in end
|
local modem_event = function () return self.modem_msg_in end
|
||||||
local raw = function () return self.raw end
|
local raw_sendable = function () return self.raw end
|
||||||
|
|
||||||
local sender = function () return self.s_port end
|
local sender = function () return self.s_port end
|
||||||
local receiver = function () return self.r_port end
|
local receiver = function () return self.r_port end
|
||||||
@@ -106,7 +106,7 @@ function scada_packet()
|
|||||||
receive = receive,
|
receive = receive,
|
||||||
-- raw access
|
-- raw access
|
||||||
modem_event = modem_event,
|
modem_event = modem_event,
|
||||||
raw = raw,
|
raw_sendable = raw_sendable,
|
||||||
-- sender/receiver
|
-- sender/receiver
|
||||||
sender = sender,
|
sender = sender,
|
||||||
receiver = receiver,
|
receiver = receiver,
|
||||||
@@ -121,13 +121,12 @@ function scada_packet()
|
|||||||
end
|
end
|
||||||
|
|
||||||
-- MODBUS packet
|
-- MODBUS packet
|
||||||
-- modeled after MODBUS TCP packet, but length is not transmitted since these are tables (#data = length, easy)
|
-- modeled after MODBUS TCP packet
|
||||||
function modbus_packet()
|
function modbus_packet()
|
||||||
local self = {
|
local self = {
|
||||||
frame = nil,
|
frame = nil,
|
||||||
raw = nil,
|
raw = nil,
|
||||||
txn_id = txn_id,
|
txn_id = txn_id,
|
||||||
protocol = protocol,
|
|
||||||
length = length,
|
length = length,
|
||||||
unit_id = unit_id,
|
unit_id = unit_id,
|
||||||
func_code = func_code,
|
func_code = func_code,
|
||||||
@@ -135,16 +134,15 @@ function modbus_packet()
|
|||||||
}
|
}
|
||||||
|
|
||||||
-- make a MODBUS packet
|
-- make a MODBUS packet
|
||||||
local make = function (txn_id, protocol, unit_id, func_code, data)
|
local make = function (txn_id, unit_id, func_code, data)
|
||||||
self.txn_id = txn_id
|
self.txn_id = txn_id
|
||||||
self.protocol = protocol
|
|
||||||
self.length = #data
|
self.length = #data
|
||||||
self.unit_id = unit_id
|
self.unit_id = unit_id
|
||||||
self.func_code = func_code
|
self.func_code = func_code
|
||||||
self.data = data
|
self.data = data
|
||||||
|
|
||||||
-- populate raw array
|
-- populate raw array
|
||||||
self.raw = { self.txn_id, self.protocol, self.unit_id, self.func_code }
|
self.raw = { self.txn_id, self.unit_id, self.func_code }
|
||||||
for i = 1, self.length do
|
for i = 1, self.length do
|
||||||
table.insert(self.raw, data[i])
|
table.insert(self.raw, data[i])
|
||||||
end
|
end
|
||||||
@@ -156,11 +154,11 @@ function modbus_packet()
|
|||||||
self.frame = frame
|
self.frame = frame
|
||||||
|
|
||||||
if frame.protocol() == PROTOCOLS.MODBUS_TCP then
|
if frame.protocol() == PROTOCOLS.MODBUS_TCP then
|
||||||
local size_ok = frame.length() >= 4
|
local size_ok = frame.length() >= 3
|
||||||
|
|
||||||
if size_ok then
|
if size_ok then
|
||||||
local data = frame.data()
|
local data = frame.data()
|
||||||
make(data[1], data[2], data[3], data[4], { table.unpack(data, 5, #data) })
|
make(data[1], data[2], data[3], { table.unpack(data, 4, #data) })
|
||||||
end
|
end
|
||||||
|
|
||||||
return size_ok
|
return size_ok
|
||||||
@@ -182,7 +180,6 @@ function modbus_packet()
|
|||||||
return {
|
return {
|
||||||
scada_frame = self.frame,
|
scada_frame = self.frame,
|
||||||
txn_id = self.txn_id,
|
txn_id = self.txn_id,
|
||||||
protocol = self.protocol,
|
|
||||||
length = self.length,
|
length = self.length,
|
||||||
unit_id = self.unit_id,
|
unit_id = self.unit_id,
|
||||||
func_code = self.func_code,
|
func_code = self.func_code,
|
||||||
|
|||||||
@@ -203,10 +203,10 @@ function new(rtu_dev)
|
|||||||
return return_ok, response
|
return return_ok, response
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- handle a MODBUS TCP packet and generate a reply
|
||||||
local handle_packet = function (packet)
|
local handle_packet = function (packet)
|
||||||
local return_code = true
|
local return_code = true
|
||||||
local response = nil
|
local response = nil
|
||||||
local reply = packet
|
|
||||||
|
|
||||||
if #packet.data == 2 then
|
if #packet.data == 2 then
|
||||||
-- handle by function code
|
-- handle by function code
|
||||||
@@ -236,32 +236,51 @@ function new(rtu_dev)
|
|||||||
return_code = false
|
return_code = false
|
||||||
end
|
end
|
||||||
|
|
||||||
if return_code then
|
|
||||||
-- default is to echo back
|
-- default is to echo back
|
||||||
if type(response) == "table" then
|
local func_code = packet.func_code
|
||||||
reply.length = #response
|
if not return_code then
|
||||||
reply.data = response
|
|
||||||
end
|
|
||||||
else
|
|
||||||
-- echo back with error flag
|
-- echo back with error flag
|
||||||
reply.func_code = bit.bor(packet.func_code, MODBUS_FCODE.ERROR_FLAG)
|
func_code = bit.bor(packet.func_code, MODBUS_FCODE.ERROR_FLAG)
|
||||||
|
|
||||||
if type(response) == "nil" then
|
if type(response) == "nil" then
|
||||||
reply.length = 0
|
response = { }
|
||||||
reply.data = {}
|
|
||||||
elseif type(response) == "number" then
|
elseif type(response) == "number" then
|
||||||
reply.length = 1
|
response = { response }
|
||||||
reply.data = { response }
|
|
||||||
elseif type(response) == "table" then
|
elseif type(response) == "table" then
|
||||||
reply.length = #response
|
response = response
|
||||||
reply.data = response
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- create reply
|
||||||
|
local reply = comms.modbus_packet()
|
||||||
|
reply.make(packet.txn_id, packet.unit_id, func_code, response)
|
||||||
|
|
||||||
return return_code, reply
|
return return_code, reply
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- return a NEG_ACKNOWLEDGE error reply
|
||||||
|
local reply__neg_ack = function (packet)
|
||||||
|
-- reply back with error flag and exception code
|
||||||
|
local reply = comms.modbus_packet()
|
||||||
|
local fcode = bit.bor(packet.func_code, MODBUS_FCODE.ERROR_FLAG)
|
||||||
|
local data = { MODBUS_EXCODE.NEG_ACKNOWLEDGE }
|
||||||
|
reply.make(packet.txn_id, packet.unit_id, fcode, data)
|
||||||
|
return reply
|
||||||
|
end
|
||||||
|
|
||||||
|
-- return a GATEWAY_PATH_UNAVAILABLE error reply
|
||||||
|
local reply__gw_unavailable = function (packet)
|
||||||
|
-- reply back with error flag and exception code
|
||||||
|
local reply = comms.modbus_packet()
|
||||||
|
local fcode = bit.bor(packet.func_code, MODBUS_FCODE.ERROR_FLAG)
|
||||||
|
local data = { MODBUS_EXCODE.GATEWAY_PATH_UNAVAILABLE }
|
||||||
|
reply.make(packet.txn_id, packet.unit_id, fcode, data)
|
||||||
|
return reply
|
||||||
|
end
|
||||||
|
|
||||||
return {
|
return {
|
||||||
handle_packet = handle_packet
|
handle_packet = handle_packet,
|
||||||
|
reply__neg_ack = reply__neg_ack,
|
||||||
|
reply__gw_unavailable = reply__gw_unavailable
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|||||||
Reference in New Issue
Block a user