Merge pull request #341 from MikaylaFischler/300-code-footprint-cleanup-tasks

300 code footprint cleanup tasks
This commit is contained in:
Mikayla 2023-09-01 22:52:47 -04:00 committed by GitHub
commit b9073153b3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
70 changed files with 853 additions and 945 deletions

View File

@ -24,6 +24,7 @@
}, },
"Lua.hint.setType": true, "Lua.hint.setType": true,
"Lua.diagnostics.disable": [ "Lua.diagnostics.disable": [
"duplicate-set-field" "duplicate-set-field",
"inject-field"
] ]
} }

View File

@ -17,8 +17,8 @@ local println = util.println
local PROTOCOL = comms.PROTOCOL local PROTOCOL = comms.PROTOCOL
local DEVICE_TYPE = comms.DEVICE_TYPE local DEVICE_TYPE = comms.DEVICE_TYPE
local ESTABLISH_ACK = comms.ESTABLISH_ACK local ESTABLISH_ACK = comms.ESTABLISH_ACK
local SCADA_MGMT_TYPE = comms.SCADA_MGMT_TYPE local MGMT_TYPE = comms.MGMT_TYPE
local SCADA_CRDN_TYPE = comms.SCADA_CRDN_TYPE local CRDN_TYPE = comms.CRDN_TYPE
local UNIT_COMMAND = comms.UNIT_COMMAND local UNIT_COMMAND = comms.UNIT_COMMAND
local FAC_COMMAND = comms.FAC_COMMAND local FAC_COMMAND = comms.FAC_COMMAND
@ -279,7 +279,7 @@ function coordinator.comms(version, nic, num_units, crd_channel, svr_channel, pk
apisessions.init(nic) apisessions.init(nic)
-- send a packet to the supervisor -- send a packet to the supervisor
---@param msg_type SCADA_MGMT_TYPE|SCADA_CRDN_TYPE ---@param msg_type MGMT_TYPE|CRDN_TYPE
---@param msg table ---@param msg table
local function _send_sv(protocol, msg_type, msg) local function _send_sv(protocol, msg_type, msg)
local s_pkt = comms.scada_packet() local s_pkt = comms.scada_packet()
@ -307,7 +307,7 @@ function coordinator.comms(version, nic, num_units, crd_channel, svr_channel, pk
local s_pkt = comms.scada_packet() local s_pkt = comms.scada_packet()
local m_pkt = comms.mgmt_packet() local m_pkt = comms.mgmt_packet()
m_pkt.make(SCADA_MGMT_TYPE.ESTABLISH, { ack }) m_pkt.make(MGMT_TYPE.ESTABLISH, { ack })
s_pkt.make(packet.src_addr(), packet.seq_num() + 1, PROTOCOL.SCADA_MGMT, m_pkt.raw_sendable()) s_pkt.make(packet.src_addr(), packet.seq_num() + 1, PROTOCOL.SCADA_MGMT, m_pkt.raw_sendable())
nic.transmit(pkt_channel, crd_channel, s_pkt) nic.transmit(pkt_channel, crd_channel, s_pkt)
@ -316,13 +316,13 @@ function coordinator.comms(version, nic, num_units, crd_channel, svr_channel, pk
-- attempt connection establishment -- attempt connection establishment
local function _send_establish() local function _send_establish()
_send_sv(PROTOCOL.SCADA_MGMT, SCADA_MGMT_TYPE.ESTABLISH, { comms.version, version, DEVICE_TYPE.CRDN }) _send_sv(PROTOCOL.SCADA_MGMT, MGMT_TYPE.ESTABLISH, { comms.version, version, DEVICE_TYPE.CRD })
end end
-- keep alive ack -- keep alive ack
---@param srv_time integer ---@param srv_time integer
local function _send_keep_alive_ack(srv_time) local function _send_keep_alive_ack(srv_time)
_send_sv(PROTOCOL.SCADA_MGMT, SCADA_MGMT_TYPE.KEEP_ALIVE, { srv_time, util.time() }) _send_sv(PROTOCOL.SCADA_MGMT, MGMT_TYPE.KEEP_ALIVE, { srv_time, util.time() })
end end
-- PUBLIC FUNCTIONS -- -- PUBLIC FUNCTIONS --
@ -394,20 +394,20 @@ function coordinator.comms(version, nic, num_units, crd_channel, svr_channel, pk
self.sv_linked = false self.sv_linked = false
self.sv_r_seq_num = nil self.sv_r_seq_num = nil
iocontrol.fp_link_state(types.PANEL_LINK_STATE.DISCONNECTED) iocontrol.fp_link_state(types.PANEL_LINK_STATE.DISCONNECTED)
_send_sv(PROTOCOL.SCADA_MGMT, SCADA_MGMT_TYPE.CLOSE, {}) _send_sv(PROTOCOL.SCADA_MGMT, MGMT_TYPE.CLOSE, {})
end end
-- send a facility command -- send a facility command
---@param cmd FAC_COMMAND command ---@param cmd FAC_COMMAND command
---@param option any? optional option options for the optional options (like waste mode) ---@param option any? optional option options for the optional options (like waste mode)
function public.send_fac_command(cmd, option) function public.send_fac_command(cmd, option)
_send_sv(PROTOCOL.SCADA_CRDN, SCADA_CRDN_TYPE.FAC_CMD, { cmd, option }) _send_sv(PROTOCOL.SCADA_CRDN, CRDN_TYPE.FAC_CMD, { cmd, option })
end end
-- send the auto process control configuration with a start command -- send the auto process control configuration with a start command
---@param config coord_auto_config configuration ---@param config coord_auto_config configuration
function public.send_auto_start(config) function public.send_auto_start(config)
_send_sv(PROTOCOL.SCADA_CRDN, SCADA_CRDN_TYPE.FAC_CMD, { _send_sv(PROTOCOL.SCADA_CRDN, CRDN_TYPE.FAC_CMD, {
FAC_COMMAND.START, config.mode, config.burn_target, config.charge_target, config.gen_target, config.limits FAC_COMMAND.START, config.mode, config.burn_target, config.charge_target, config.gen_target, config.limits
}) })
end end
@ -417,7 +417,7 @@ function coordinator.comms(version, nic, num_units, crd_channel, svr_channel, pk
---@param unit integer unit ID ---@param unit integer unit ID
---@param option any? optional option options for the optional options (like burn rate) ---@param option any? optional option options for the optional options (like burn rate)
function public.send_unit_command(cmd, unit, option) function public.send_unit_command(cmd, unit, option)
_send_sv(PROTOCOL.SCADA_CRDN, SCADA_CRDN_TYPE.UNIT_CMD, { cmd, unit, option }) _send_sv(PROTOCOL.SCADA_CRDN, CRDN_TYPE.UNIT_CMD, { cmd, unit, option })
end end
-- parse a packet -- parse a packet
@ -426,7 +426,7 @@ function coordinator.comms(version, nic, num_units, crd_channel, svr_channel, pk
---@param reply_to integer ---@param reply_to integer
---@param message any ---@param message any
---@param distance integer ---@param distance integer
---@return mgmt_frame|crdn_frame|capi_frame|nil packet ---@return mgmt_frame|crdn_frame|nil packet
function public.parse_packet(side, sender, reply_to, message, distance) function public.parse_packet(side, sender, reply_to, message, distance)
local s_pkt = nic.receive(side, sender, reply_to, message, distance) local s_pkt = nic.receive(side, sender, reply_to, message, distance)
local pkt = nil local pkt = nil
@ -444,12 +444,6 @@ function coordinator.comms(version, nic, num_units, crd_channel, svr_channel, pk
if crdn_pkt.decode(s_pkt) then if crdn_pkt.decode(s_pkt) then
pkt = crdn_pkt.get() pkt = crdn_pkt.get()
end end
-- get as coordinator API packet
elseif s_pkt.protocol() == PROTOCOL.COORD_API then
local capi_pkt = comms.capi_packet()
if capi_pkt.decode(s_pkt) then
pkt = capi_pkt.get()
end
else else
log.debug("attempted parse of illegal packet type " .. s_pkt.protocol(), true) log.debug("attempted parse of illegal packet type " .. s_pkt.protocol(), true)
end end
@ -459,7 +453,7 @@ function coordinator.comms(version, nic, num_units, crd_channel, svr_channel, pk
end end
-- handle a packet -- handle a packet
---@param packet mgmt_frame|crdn_frame|capi_frame|nil ---@param packet mgmt_frame|crdn_frame|nil
---@return boolean close_ui ---@return boolean close_ui
function public.handle_packet(packet) function public.handle_packet(packet)
local was_linked = self.sv_linked local was_linked = self.sv_linked
@ -475,18 +469,18 @@ function coordinator.comms(version, nic, num_units, crd_channel, svr_channel, pk
elseif r_chan == pkt_channel then elseif r_chan == pkt_channel then
if not self.sv_linked then if not self.sv_linked then
log.debug("discarding pocket API packet before linked to supervisor") log.debug("discarding pocket API packet before linked to supervisor")
elseif protocol == PROTOCOL.COORD_API then elseif protocol == PROTOCOL.SCADA_CRDN then
---@cast packet capi_frame ---@cast packet crdn_frame
-- look for an associated session -- look for an associated session
local session = apisessions.find_session(src_addr) local session = apisessions.find_session(src_addr)
-- API packet -- coordinator packet
if session ~= nil then if session ~= nil then
-- pass the packet onto the session handler -- pass the packet onto the session handler
session.in_queue.push_packet(packet) session.in_queue.push_packet(packet)
else else
-- any other packet should be session related, discard it -- any other packet should be session related, discard it
log.debug("discarding COORD_API packet without a known session") log.debug("discarding SCADA_CRDN packet without a known session")
end end
elseif protocol == PROTOCOL.SCADA_MGMT then elseif protocol == PROTOCOL.SCADA_MGMT then
---@cast packet mgmt_frame ---@cast packet mgmt_frame
@ -497,7 +491,7 @@ function coordinator.comms(version, nic, num_units, crd_channel, svr_channel, pk
if session ~= nil then if session ~= nil then
-- pass the packet onto the session handler -- pass the packet onto the session handler
session.in_queue.push_packet(packet) session.in_queue.push_packet(packet)
elseif packet.type == SCADA_MGMT_TYPE.ESTABLISH then elseif packet.type == MGMT_TYPE.ESTABLISH then
-- establish a new session -- establish a new session
-- validate packet and continue -- validate packet and continue
if packet.length == 3 and type(packet.data[1]) == "string" and type(packet.data[2]) == "string" then if packet.length == 3 and type(packet.data[1]) == "string" and type(packet.data[2]) == "string" then
@ -553,7 +547,7 @@ function coordinator.comms(version, nic, num_units, crd_channel, svr_channel, pk
if protocol == PROTOCOL.SCADA_CRDN then if protocol == PROTOCOL.SCADA_CRDN then
---@cast packet crdn_frame ---@cast packet crdn_frame
if self.sv_linked then if self.sv_linked then
if packet.type == SCADA_CRDN_TYPE.INITIAL_BUILDS then if packet.type == CRDN_TYPE.INITIAL_BUILDS then
if packet.length == 2 then if packet.length == 2 then
-- record builds -- record builds
local fac_builds = iocontrol.record_facility_builds(packet.data[1]) local fac_builds = iocontrol.record_facility_builds(packet.data[1])
@ -561,31 +555,31 @@ function coordinator.comms(version, nic, num_units, crd_channel, svr_channel, pk
if fac_builds and unit_builds then if fac_builds and unit_builds then
-- acknowledge receipt of builds -- acknowledge receipt of builds
_send_sv(PROTOCOL.SCADA_CRDN, SCADA_CRDN_TYPE.INITIAL_BUILDS, {}) _send_sv(PROTOCOL.SCADA_CRDN, CRDN_TYPE.INITIAL_BUILDS, {})
else else
log.debug("received invalid INITIAL_BUILDS packet") log.debug("received invalid INITIAL_BUILDS packet")
end end
else else
log.debug("INITIAL_BUILDS packet length mismatch") log.debug("INITIAL_BUILDS packet length mismatch")
end end
elseif packet.type == SCADA_CRDN_TYPE.FAC_BUILDS then elseif packet.type == CRDN_TYPE.FAC_BUILDS then
if packet.length == 1 then if packet.length == 1 then
-- record facility builds -- record facility builds
if iocontrol.record_facility_builds(packet.data[1]) then if iocontrol.record_facility_builds(packet.data[1]) then
-- acknowledge receipt of builds -- acknowledge receipt of builds
_send_sv(PROTOCOL.SCADA_CRDN, SCADA_CRDN_TYPE.FAC_BUILDS, {}) _send_sv(PROTOCOL.SCADA_CRDN, CRDN_TYPE.FAC_BUILDS, {})
else else
log.debug("received invalid FAC_BUILDS packet") log.debug("received invalid FAC_BUILDS packet")
end end
else else
log.debug("FAC_BUILDS packet length mismatch") log.debug("FAC_BUILDS packet length mismatch")
end end
elseif packet.type == SCADA_CRDN_TYPE.FAC_STATUS then elseif packet.type == CRDN_TYPE.FAC_STATUS then
-- update facility status -- update facility status
if not iocontrol.update_facility_status(packet.data) then if not iocontrol.update_facility_status(packet.data) then
log.debug("received invalid FAC_STATUS packet") log.debug("received invalid FAC_STATUS packet")
end end
elseif packet.type == SCADA_CRDN_TYPE.FAC_CMD then elseif packet.type == CRDN_TYPE.FAC_CMD then
-- facility command acknowledgement -- facility command acknowledgement
if packet.length >= 2 then if packet.length >= 2 then
local cmd = packet.data[1] local cmd = packet.data[1]
@ -613,24 +607,24 @@ function coordinator.comms(version, nic, num_units, crd_channel, svr_channel, pk
else else
log.debug("SCADA_CRDN facility command ack packet length mismatch") log.debug("SCADA_CRDN facility command ack packet length mismatch")
end end
elseif packet.type == SCADA_CRDN_TYPE.UNIT_BUILDS then elseif packet.type == CRDN_TYPE.UNIT_BUILDS then
-- record builds -- record builds
if packet.length == 1 then if packet.length == 1 then
if iocontrol.record_unit_builds(packet.data[1]) then if iocontrol.record_unit_builds(packet.data[1]) then
-- acknowledge receipt of builds -- acknowledge receipt of builds
_send_sv(PROTOCOL.SCADA_CRDN, SCADA_CRDN_TYPE.UNIT_BUILDS, {}) _send_sv(PROTOCOL.SCADA_CRDN, CRDN_TYPE.UNIT_BUILDS, {})
else else
log.debug("received invalid UNIT_BUILDS packet") log.debug("received invalid UNIT_BUILDS packet")
end end
else else
log.debug("UNIT_BUILDS packet length mismatch") log.debug("UNIT_BUILDS packet length mismatch")
end end
elseif packet.type == SCADA_CRDN_TYPE.UNIT_STATUSES then elseif packet.type == CRDN_TYPE.UNIT_STATUSES then
-- update statuses -- update statuses
if not iocontrol.update_unit_statuses(packet.data) then if not iocontrol.update_unit_statuses(packet.data) then
log.debug("received invalid UNIT_STATUSES packet") log.debug("received invalid UNIT_STATUSES packet")
end end
elseif packet.type == SCADA_CRDN_TYPE.UNIT_CMD then elseif packet.type == CRDN_TYPE.UNIT_CMD then
-- unit command acknowledgement -- unit command acknowledgement
if packet.length == 3 then if packet.length == 3 then
local cmd = packet.data[1] local cmd = packet.data[1]
@ -672,7 +666,7 @@ function coordinator.comms(version, nic, num_units, crd_channel, svr_channel, pk
elseif protocol == PROTOCOL.SCADA_MGMT then elseif protocol == PROTOCOL.SCADA_MGMT then
---@cast packet mgmt_frame ---@cast packet mgmt_frame
if self.sv_linked then if self.sv_linked then
if packet.type == SCADA_MGMT_TYPE.KEEP_ALIVE then if packet.type == MGMT_TYPE.KEEP_ALIVE then
-- keep alive request received, echo back -- keep alive request received, echo back
if packet.length == 1 then if packet.length == 1 then
local timestamp = packet.data[1] local timestamp = packet.data[1]
@ -690,7 +684,7 @@ function coordinator.comms(version, nic, num_units, crd_channel, svr_channel, pk
else else
log.debug("SCADA keep alive packet length mismatch") log.debug("SCADA keep alive packet length mismatch")
end end
elseif packet.type == SCADA_MGMT_TYPE.CLOSE then elseif packet.type == MGMT_TYPE.CLOSE then
-- handle session close -- handle session close
sv_watchdog.cancel() sv_watchdog.cancel()
self.sv_addr = comms.BROADCAST self.sv_addr = comms.BROADCAST
@ -701,7 +695,7 @@ function coordinator.comms(version, nic, num_units, crd_channel, svr_channel, pk
else else
log.debug("received unknown SCADA_MGMT packet type " .. packet.type) log.debug("received unknown SCADA_MGMT packet type " .. packet.type)
end end
elseif packet.type == SCADA_MGMT_TYPE.ESTABLISH then elseif packet.type == MGMT_TYPE.ESTABLISH then
-- connection with supervisor established -- connection with supervisor established
if packet.length == 2 then if packet.length == 2 then
local est_ack = packet.data[1] local est_ack = packet.data[1]

View File

@ -8,8 +8,8 @@ local iocontrol = require("coordinator.iocontrol")
local pocket = {} local pocket = {}
local PROTOCOL = comms.PROTOCOL local PROTOCOL = comms.PROTOCOL
-- local CAPI_TYPE = comms.CAPI_TYPE -- local CRDN_TYPE = comms.CRDN_TYPE
local SCADA_MGMT_TYPE = comms.SCADA_MGMT_TYPE local MGMT_TYPE = comms.MGMT_TYPE
-- retry time constants in ms -- retry time constants in ms
-- local INITIAL_WAIT = 1500 -- local INITIAL_WAIT = 1500
@ -72,22 +72,22 @@ function pocket.new_session(id, s_addr, in_queue, out_queue, timeout)
iocontrol.fp_pkt_disconnected(id) iocontrol.fp_pkt_disconnected(id)
end end
-- send a CAPI packet -- send a CRDN packet
-----@param msg_type CAPI_TYPE -----@param msg_type CRDN_TYPE
-----@param msg table -----@param msg table
-- local function _send(msg_type, msg) -- local function _send(msg_type, msg)
-- local s_pkt = comms.scada_packet() -- local s_pkt = comms.scada_packet()
-- local c_pkt = comms.capi_packet() -- local c_pkt = comms.crdn_packet()
-- c_pkt.make(msg_type, msg) -- c_pkt.make(msg_type, msg)
-- s_pkt.make(self.seq_num, PROTOCOL.COORD_API, c_pkt.raw_sendable()) -- s_pkt.make(self.seq_num, PROTOCOL.SCADA_CRDN, c_pkt.raw_sendable())
-- out_queue.push_packet(s_pkt) -- out_queue.push_packet(s_pkt)
-- self.seq_num = self.seq_num + 1 -- self.seq_num = self.seq_num + 1
-- end -- end
-- send a SCADA management packet -- send a SCADA management packet
---@param msg_type SCADA_MGMT_TYPE ---@param msg_type MGMT_TYPE
---@param msg table ---@param msg table
local function _send_mgmt(msg_type, msg) local function _send_mgmt(msg_type, msg)
local s_pkt = comms.scada_packet() local s_pkt = comms.scada_packet()
@ -101,7 +101,7 @@ function pocket.new_session(id, s_addr, in_queue, out_queue, timeout)
end end
-- handle a packet -- handle a packet
---@param pkt mgmt_frame|capi_frame ---@param pkt mgmt_frame|crdn_frame
local function _handle_packet(pkt) local function _handle_packet(pkt)
-- check sequence number -- check sequence number
if self.r_seq_num == nil then if self.r_seq_num == nil then
@ -117,17 +117,17 @@ function pocket.new_session(id, s_addr, in_queue, out_queue, timeout)
self.conn_watchdog.feed() self.conn_watchdog.feed()
-- process packet -- process packet
if pkt.scada_frame.protocol() == PROTOCOL.COORD_API then if pkt.scada_frame.protocol() == PROTOCOL.SCADA_CRDN then
---@cast pkt capi_frame ---@cast pkt crdn_frame
-- handle packet by type -- handle packet by type
if pkt.type == nil then if pkt.type == nil then
else else
log.debug(log_header .. "handler received unsupported CAPI packet type " .. pkt.type) log.debug(log_header .. "handler received unsupported CRDN packet type " .. pkt.type)
end end
elseif pkt.scada_frame.protocol() == PROTOCOL.SCADA_MGMT then elseif pkt.scada_frame.protocol() == PROTOCOL.SCADA_MGMT then
---@cast pkt mgmt_frame ---@cast pkt mgmt_frame
if pkt.type == SCADA_MGMT_TYPE.KEEP_ALIVE then if pkt.type == MGMT_TYPE.KEEP_ALIVE then
-- keep alive reply -- keep alive reply
if pkt.length == 2 then if pkt.length == 2 then
local srv_start = pkt.data[1] local srv_start = pkt.data[1]
@ -146,7 +146,7 @@ function pocket.new_session(id, s_addr, in_queue, out_queue, timeout)
else else
log.debug(log_header .. "SCADA keep alive packet length mismatch") log.debug(log_header .. "SCADA keep alive packet length mismatch")
end end
elseif pkt.type == SCADA_MGMT_TYPE.CLOSE then elseif pkt.type == MGMT_TYPE.CLOSE then
-- close the session -- close the session
_close() _close()
else else
@ -174,7 +174,7 @@ function pocket.new_session(id, s_addr, in_queue, out_queue, timeout)
-- close the connection -- close the connection
function public.close() function public.close()
_close() _close()
_send_mgmt(SCADA_MGMT_TYPE.CLOSE, {}) _send_mgmt(MGMT_TYPE.CLOSE, {})
log.info(log_header .. "session closed by server") log.info(log_header .. "session closed by server")
end end
@ -229,7 +229,7 @@ function pocket.new_session(id, s_addr, in_queue, out_queue, timeout)
periodics.keep_alive = periodics.keep_alive + elapsed periodics.keep_alive = periodics.keep_alive + elapsed
if periodics.keep_alive >= PERIODICS.KEEP_ALIVE then if periodics.keep_alive >= PERIODICS.KEEP_ALIVE then
_send_mgmt(SCADA_MGMT_TYPE.KEEP_ALIVE, { util.time() }) _send_mgmt(MGMT_TYPE.KEEP_ALIVE, { util.time() })
periodics.keep_alive = 0 periodics.keep_alive = 0
end end

View File

@ -22,7 +22,7 @@ local sounder = require("coordinator.sounder")
local apisessions = require("coordinator.session.apisessions") local apisessions = require("coordinator.session.apisessions")
local COORDINATOR_VERSION = "v1.0.9" local COORDINATOR_VERSION = "v1.0.10"
local println = util.println local println = util.println
local println_ts = util.println_ts local println_ts = util.println_ts

View File

@ -12,6 +12,8 @@ local VerticalBar = require("graphics.elements.indicators.vbar")
local cpair = core.cpair local cpair = core.cpair
local border = core.border local border = core.border
local text_fg_bg = style.text_colors
-- new boiler view -- new boiler view
---@param root graphics_element parent ---@param root graphics_element parent
---@param x integer top left x ---@param x integer top left x
@ -20,12 +22,9 @@ local border = core.border
local function new_view(root, x, y, ps) local function new_view(root, x, y, ps)
local boiler = Rectangle{parent=root,border=border(1,colors.gray,true),width=31,height=7,x=x,y=y} local boiler = Rectangle{parent=root,border=border(1,colors.gray,true),width=31,height=7,x=x,y=y}
local text_fg_bg = cpair(colors.black, colors.lightGray)
local lu_col = cpair(colors.gray, colors.gray)
local status = StateIndicator{parent=boiler,x=9,y=1,states=style.boiler.states,value=1,min_width=12} local status = StateIndicator{parent=boiler,x=9,y=1,states=style.boiler.states,value=1,min_width=12}
local temp = DataIndicator{parent=boiler,x=5,y=3,lu_colors=lu_col,label="Temp:",unit="K",format="%10.2f",value=0,width=22,fg_bg=text_fg_bg} local temp = DataIndicator{parent=boiler,x=5,y=3,lu_colors=style.lu_col,label="Temp:",unit="K",format="%10.2f",value=0,width=22,fg_bg=text_fg_bg}
local boil_r = DataIndicator{parent=boiler,x=5,y=4,lu_colors=lu_col,label="Boil:",unit="mB/t",format="%10.0f",value=0,commas=true,width=22,fg_bg=text_fg_bg} local boil_r = DataIndicator{parent=boiler,x=5,y=4,lu_colors=style.lu_col,label="Boil:",unit="mB/t",format="%10.0f",value=0,commas=true,width=22,fg_bg=text_fg_bg}
status.register(ps, "computed_status", status.update) status.register(ps, "computed_status", status.update)
temp.register(ps, "temperature", temp.update) temp.register(ps, "temperature", temp.update)

View File

@ -18,6 +18,9 @@ local border = core.border
local TEXT_ALIGN = core.TEXT_ALIGN local TEXT_ALIGN = core.TEXT_ALIGN
local text_fg_bg = style.text_colors
local lu_col = style.lu_colors
-- new induction matrix view -- new induction matrix view
---@param root graphics_element parent ---@param root graphics_element parent
---@param x integer top left x ---@param x integer top left x
@ -31,14 +34,12 @@ local function new_view(root, x, y, data, ps, id)
local matrix = Div{parent=root,fg_bg=style.root,width=33,height=24,x=x,y=y} local matrix = Div{parent=root,fg_bg=style.root,width=33,height=24,x=x,y=y}
TextBox{parent=matrix,text=" ",width=33,height=1,x=1,y=1,fg_bg=cpair(colors.lightGray,colors.gray)} TextBox{parent=matrix,text=" ",width=33,height=1,x=1,y=1,fg_bg=style.lg_gray}
TextBox{parent=matrix,text=title,alignment=TEXT_ALIGN.CENTER,width=33,height=1,x=1,y=2,fg_bg=cpair(colors.lightGray,colors.gray)} TextBox{parent=matrix,text=title,alignment=TEXT_ALIGN.CENTER,width=33,height=1,x=1,y=2,fg_bg=style.lg_gray}
local rect = Rectangle{parent=matrix,border=border(1,colors.gray,true),width=33,height=22,x=1,y=3} local rect = Rectangle{parent=matrix,border=border(1,colors.gray,true),width=33,height=22,x=1,y=3}
local text_fg_bg = cpair(colors.black, colors.lightGray)
local label_fg_bg = cpair(colors.gray, colors.lightGray) local label_fg_bg = cpair(colors.gray, colors.lightGray)
local lu_col = cpair(colors.gray, colors.gray)
local status = StateIndicator{parent=rect,x=10,y=1,states=style.imatrix.states,value=1,min_width=14} local status = StateIndicator{parent=rect,x=10,y=1,states=style.imatrix.states,value=1,min_width=14}
local energy = PowerIndicator{parent=rect,x=7,y=3,lu_colors=lu_col,label="Energy: ",format="%8.2f",value=0,width=26,fg_bg=text_fg_bg} local energy = PowerIndicator{parent=rect,x=7,y=3,lu_colors=lu_col,label="Energy: ",format="%8.2f",value=0,width=26,fg_bg=text_fg_bg}

View File

@ -4,6 +4,8 @@
local iocontrol = require("coordinator.iocontrol") local iocontrol = require("coordinator.iocontrol")
local style = require("coordinator.ui.style")
local core = require("graphics.core") local core = require("graphics.core")
local Div = require("graphics.elements.div") local Div = require("graphics.elements.div")
@ -15,6 +17,9 @@ local TEXT_ALIGN = core.TEXT_ALIGN
local cpair = core.cpair local cpair = core.cpair
local text_fg_bg = style.text_colors
local lg_wh = style.lg_white
-- create a pocket list entry -- create a pocket list entry
---@param parent graphics_element parent ---@param parent graphics_element parent
---@param id integer PKT session ID ---@param id integer PKT session ID
@ -23,22 +28,22 @@ local function init(parent, id)
-- root div -- root div
local root = Div{parent=parent,x=2,y=2,height=4,width=parent.get_width()-2,hidden=true} local root = Div{parent=parent,x=2,y=2,height=4,width=parent.get_width()-2,hidden=true}
local entry = Div{parent=root,x=2,y=1,height=3,fg_bg=cpair(colors.black,colors.white)} local entry = Div{parent=root,x=2,y=1,height=3,fg_bg=style.bw_fg_bg}
local ps_prefix = "pkt_" .. id .. "_" local ps_prefix = "pkt_" .. id .. "_"
TextBox{parent=entry,x=1,y=1,text="",width=8,height=1,fg_bg=cpair(colors.black,colors.lightGray)} TextBox{parent=entry,x=1,y=1,text="",width=8,height=1,fg_bg=text_fg_bg}
local pkt_addr = TextBox{parent=entry,x=1,y=2,text="@ C ??",alignment=TEXT_ALIGN.CENTER,width=8,height=1,fg_bg=cpair(colors.black,colors.lightGray),nav_active=cpair(colors.gray,colors.black)} local pkt_addr = TextBox{parent=entry,x=1,y=2,text="@ C ??",alignment=TEXT_ALIGN.CENTER,width=8,height=1,fg_bg=text_fg_bg,nav_active=cpair(colors.gray,colors.black)}
TextBox{parent=entry,x=1,y=3,text="",width=8,height=1,fg_bg=cpair(colors.black,colors.lightGray)} TextBox{parent=entry,x=1,y=3,text="",width=8,height=1,fg_bg=text_fg_bg}
pkt_addr.register(ps, ps_prefix .. "addr", pkt_addr.set_value) pkt_addr.register(ps, ps_prefix .. "addr", pkt_addr.set_value)
TextBox{parent=entry,x=10,y=2,text="FW:",width=3,height=1} TextBox{parent=entry,x=10,y=2,text="FW:",width=3,height=1}
local pkt_fw_v = TextBox{parent=entry,x=14,y=2,text=" ------- ",width=20,height=1,fg_bg=cpair(colors.lightGray,colors.white)} local pkt_fw_v = TextBox{parent=entry,x=14,y=2,text=" ------- ",width=20,height=1,fg_bg=lg_wh}
pkt_fw_v.register(ps, ps_prefix .. "fw", pkt_fw_v.set_value) pkt_fw_v.register(ps, ps_prefix .. "fw", pkt_fw_v.set_value)
TextBox{parent=entry,x=35,y=2,text="RTT:",width=4,height=1} TextBox{parent=entry,x=35,y=2,text="RTT:",width=4,height=1}
local pkt_rtt = DataIndicator{parent=entry,x=40,y=2,label="",unit="",format="%5d",value=0,width=5,fg_bg=cpair(colors.lightGray,colors.white)} local pkt_rtt = DataIndicator{parent=entry,x=40,y=2,label="",unit="",format="%5d",value=0,width=5,fg_bg=lg_wh}
TextBox{parent=entry,x=46,y=2,text="ms",width=4,height=1,fg_bg=cpair(colors.lightGray,colors.white)} TextBox{parent=entry,x=46,y=2,text="ms",width=4,height=1,fg_bg=lg_wh}
pkt_rtt.register(ps, ps_prefix .. "rtt", pkt_rtt.update) pkt_rtt.register(ps, ps_prefix .. "rtt", pkt_rtt.update)
pkt_rtt.register(ps, ps_prefix .. "rtt_color", pkt_rtt.recolor) pkt_rtt.register(ps, ps_prefix .. "rtt_color", pkt_rtt.recolor)

View File

@ -33,6 +33,8 @@ local lu_cpair = style.lu_colors
local hzd_fg_bg = style.hzd_fg_bg local hzd_fg_bg = style.hzd_fg_bg
local dis_colors = style.dis_colors local dis_colors = style.dis_colors
local gry_wht = style.gray_white
local ind_grn = style.ind_grn local ind_grn = style.ind_grn
local ind_yel = style.ind_yel local ind_yel = style.ind_yel
local ind_red = style.ind_red local ind_red = style.ind_red
@ -47,6 +49,10 @@ local period = core.flasher.PERIOD
local function new_view(root, x, y) local function new_view(root, x, y)
assert(root.get_height() >= (y + 24), "main display not of sufficient vertical resolution (add an additional row of monitors)") assert(root.get_height() >= (y + 24), "main display not of sufficient vertical resolution (add an additional row of monitors)")
local black = cpair(colors.black, colors.black)
local blk_brn = cpair(colors.black, colors.brown)
local blk_pur = cpair(colors.black, colors.purple)
local facility = iocontrol.get_db().facility local facility = iocontrol.get_db().facility
local units = iocontrol.get_db().units local units = iocontrol.get_db().units
@ -116,35 +122,35 @@ local function new_view(root, x, y)
local targets = Div{parent=proc,width=31,height=24,x=1,y=1} local targets = Div{parent=proc,width=31,height=24,x=1,y=1}
local burn_tag = Div{parent=targets,x=1,y=1,width=8,height=4,fg_bg=cpair(colors.black,colors.purple)} local burn_tag = Div{parent=targets,x=1,y=1,width=8,height=4,fg_bg=blk_pur}
TextBox{parent=burn_tag,x=2,y=2,text="Burn Target",width=7,height=2} TextBox{parent=burn_tag,x=2,y=2,text="Burn Target",width=7,height=2}
local burn_target = Div{parent=targets,x=9,y=1,width=23,height=3,fg_bg=cpair(colors.gray,colors.white)} local burn_target = Div{parent=targets,x=9,y=1,width=23,height=3,fg_bg=gry_wht}
local b_target = SpinboxNumeric{parent=burn_target,x=11,y=1,whole_num_precision=4,fractional_precision=1,min=0.1,arrow_fg_bg=cpair(colors.gray,colors.white),fg_bg=bw_fg_bg} local b_target = SpinboxNumeric{parent=burn_target,x=11,y=1,whole_num_precision=4,fractional_precision=1,min=0.1,arrow_fg_bg=gry_wht,fg_bg=bw_fg_bg}
TextBox{parent=burn_target,x=18,y=2,text="mB/t"} TextBox{parent=burn_target,x=18,y=2,text="mB/t"}
local burn_sum = DataIndicator{parent=targets,x=9,y=4,label="",format="%18.1f",value=0,unit="mB/t",commas=true,lu_colors=cpair(colors.black,colors.black),width=23,fg_bg=cpair(colors.black,colors.brown)} local burn_sum = DataIndicator{parent=targets,x=9,y=4,label="",format="%18.1f",value=0,unit="mB/t",commas=true,lu_colors=black,width=23,fg_bg=blk_brn}
b_target.register(facility.ps, "process_burn_target", b_target.set_value) b_target.register(facility.ps, "process_burn_target", b_target.set_value)
burn_sum.register(facility.ps, "burn_sum", burn_sum.update) burn_sum.register(facility.ps, "burn_sum", burn_sum.update)
local chg_tag = Div{parent=targets,x=1,y=6,width=8,height=4,fg_bg=cpair(colors.black,colors.purple)} local chg_tag = Div{parent=targets,x=1,y=6,width=8,height=4,fg_bg=blk_pur}
TextBox{parent=chg_tag,x=2,y=2,text="Charge Target",width=7,height=2} TextBox{parent=chg_tag,x=2,y=2,text="Charge Target",width=7,height=2}
local chg_target = Div{parent=targets,x=9,y=6,width=23,height=3,fg_bg=cpair(colors.gray,colors.white)} local chg_target = Div{parent=targets,x=9,y=6,width=23,height=3,fg_bg=gry_wht}
local c_target = SpinboxNumeric{parent=chg_target,x=2,y=1,whole_num_precision=15,fractional_precision=0,min=0,arrow_fg_bg=cpair(colors.gray,colors.white),fg_bg=bw_fg_bg} local c_target = SpinboxNumeric{parent=chg_target,x=2,y=1,whole_num_precision=15,fractional_precision=0,min=0,arrow_fg_bg=gry_wht,fg_bg=bw_fg_bg}
TextBox{parent=chg_target,x=18,y=2,text="MFE"} TextBox{parent=chg_target,x=18,y=2,text="MFE"}
local cur_charge = DataIndicator{parent=targets,x=9,y=9,label="",format="%19d",value=0,unit="MFE",commas=true,lu_colors=cpair(colors.black,colors.black),width=23,fg_bg=cpair(colors.black,colors.brown)} local cur_charge = DataIndicator{parent=targets,x=9,y=9,label="",format="%19d",value=0,unit="MFE",commas=true,lu_colors=black,width=23,fg_bg=blk_brn}
c_target.register(facility.ps, "process_charge_target", c_target.set_value) c_target.register(facility.ps, "process_charge_target", c_target.set_value)
cur_charge.register(facility.induction_ps_tbl[1], "energy", function (j) cur_charge.update(util.joules_to_fe(j) / 1000000) end) cur_charge.register(facility.induction_ps_tbl[1], "energy", function (j) cur_charge.update(util.joules_to_fe(j) / 1000000) end)
local gen_tag = Div{parent=targets,x=1,y=11,width=8,height=4,fg_bg=cpair(colors.black,colors.purple)} local gen_tag = Div{parent=targets,x=1,y=11,width=8,height=4,fg_bg=blk_pur}
TextBox{parent=gen_tag,x=2,y=2,text="Gen. Target",width=7,height=2} TextBox{parent=gen_tag,x=2,y=2,text="Gen. Target",width=7,height=2}
local gen_target = Div{parent=targets,x=9,y=11,width=23,height=3,fg_bg=cpair(colors.gray,colors.white)} local gen_target = Div{parent=targets,x=9,y=11,width=23,height=3,fg_bg=gry_wht}
local g_target = SpinboxNumeric{parent=gen_target,x=8,y=1,whole_num_precision=9,fractional_precision=0,min=0,arrow_fg_bg=cpair(colors.gray,colors.white),fg_bg=bw_fg_bg} local g_target = SpinboxNumeric{parent=gen_target,x=8,y=1,whole_num_precision=9,fractional_precision=0,min=0,arrow_fg_bg=gry_wht,fg_bg=bw_fg_bg}
TextBox{parent=gen_target,x=18,y=2,text="kFE/t"} TextBox{parent=gen_target,x=18,y=2,text="kFE/t"}
local cur_gen = DataIndicator{parent=targets,x=9,y=14,label="",format="%17d",value=0,unit="kFE/t",commas=true,lu_colors=cpair(colors.black,colors.black),width=23,fg_bg=cpair(colors.black,colors.brown)} local cur_gen = DataIndicator{parent=targets,x=9,y=14,label="",format="%17d",value=0,unit="kFE/t",commas=true,lu_colors=black,width=23,fg_bg=blk_brn}
g_target.register(facility.ps, "process_gen_target", g_target.set_value) g_target.register(facility.ps, "process_gen_target", g_target.set_value)
cur_gen.register(facility.induction_ps_tbl[1], "last_input", function (j) cur_gen.update(util.round(util.joules_to_fe(j) / 1000)) end) cur_gen.register(facility.induction_ps_tbl[1], "last_input", function (j) cur_gen.update(util.round(util.joules_to_fe(j) / 1000)) end)
@ -159,10 +165,10 @@ local function new_view(root, x, y)
for i = 1, 4 do for i = 1, 4 do
local unit local unit
local tag_fg_bg = cpair(colors.gray,colors.white) local tag_fg_bg = gry_wht
local lim_fg_bg = cpair(colors.lightGray,colors.white) local lim_fg_bg = style.lg_white
local ctl_fg = colors.lightGray local ctl_fg = colors.lightGray
local cur_fg_bg = cpair(colors.lightGray,colors.white) local cur_fg_bg = style.lg_white
local cur_lu = colors.lightGray local cur_lu = colors.lightGray
if i <= facility.num_units then if i <= facility.num_units then
@ -170,7 +176,7 @@ local function new_view(root, x, y)
tag_fg_bg = cpair(colors.black,colors.lightBlue) tag_fg_bg = cpair(colors.black,colors.lightBlue)
lim_fg_bg = bw_fg_bg lim_fg_bg = bw_fg_bg
ctl_fg = colors.gray ctl_fg = colors.gray
cur_fg_bg = cpair(colors.black,colors.brown) cur_fg_bg = blk_brn
cur_lu = colors.black cur_lu = colors.black
end end
@ -180,7 +186,7 @@ local function new_view(root, x, y)
TextBox{parent=unit_tag,x=2,y=2,text="Unit "..i.." Limit",width=7,height=2} TextBox{parent=unit_tag,x=2,y=2,text="Unit "..i.." Limit",width=7,height=2}
local lim_ctl = Div{parent=limit_div,x=9,y=_y,width=14,height=3,fg_bg=cpair(ctl_fg,colors.white)} local lim_ctl = Div{parent=limit_div,x=9,y=_y,width=14,height=3,fg_bg=cpair(ctl_fg,colors.white)}
local lim = SpinboxNumeric{parent=lim_ctl,x=2,y=1,whole_num_precision=4,fractional_precision=1,min=0.1,arrow_fg_bg=cpair(colors.gray,colors.white),fg_bg=lim_fg_bg} local lim = SpinboxNumeric{parent=lim_ctl,x=2,y=1,whole_num_precision=4,fractional_precision=1,min=0.1,arrow_fg_bg=gry_wht,fg_bg=lim_fg_bg}
TextBox{parent=lim_ctl,x=9,y=2,text="mB/t",width=4,height=1} TextBox{parent=lim_ctl,x=9,y=2,text="mB/t",width=4,height=1}
local cur_burn = DataIndicator{parent=limit_div,x=9,y=_y+3,label="",format="%7.1f",value=0,unit="mB/t",commas=false,lu_colors=cpair(cur_lu,cur_lu),width=14,fg_bg=cur_fg_bg} local cur_burn = DataIndicator{parent=limit_div,x=9,y=_y+3,label="",format="%7.1f",value=0,unit="mB/t",commas=false,lu_colors=cpair(cur_lu,cur_lu),width=14,fg_bg=cur_fg_bg}
@ -203,8 +209,8 @@ local function new_view(root, x, y)
local stat_div = Div{parent=proc,width=22,height=24,x=57,y=6} local stat_div = Div{parent=proc,width=22,height=24,x=57,y=6}
for i = 1, 4 do for i = 1, 4 do
local tag_fg_bg = cpair(colors.gray, colors.white) local tag_fg_bg = gry_wht
local ind_fg_bg = cpair(colors.lightGray, colors.white) local ind_fg_bg = style.lg_white
local ind_off = colors.lightGray local ind_off = colors.lightGray
if i <= facility.num_units then if i <= facility.num_units then
@ -241,12 +247,12 @@ local function new_view(root, x, y)
local u_stat = Rectangle{parent=proc,border=border(1,colors.gray,true),thin=true,width=31,height=4,x=1,y=16,fg_bg=bw_fg_bg} local u_stat = Rectangle{parent=proc,border=border(1,colors.gray,true),thin=true,width=31,height=4,x=1,y=16,fg_bg=bw_fg_bg}
local stat_line_1 = TextBox{parent=u_stat,x=1,y=1,text="UNKNOWN",width=31,height=1,alignment=TEXT_ALIGN.CENTER,fg_bg=bw_fg_bg} local stat_line_1 = TextBox{parent=u_stat,x=1,y=1,text="UNKNOWN",width=31,height=1,alignment=TEXT_ALIGN.CENTER,fg_bg=bw_fg_bg}
local stat_line_2 = TextBox{parent=u_stat,x=1,y=2,text="awaiting data...",width=31,height=1,alignment=TEXT_ALIGN.CENTER,fg_bg=cpair(colors.gray, colors.white)} local stat_line_2 = TextBox{parent=u_stat,x=1,y=2,text="awaiting data...",width=31,height=1,alignment=TEXT_ALIGN.CENTER,fg_bg=gry_wht}
stat_line_1.register(facility.ps, "status_line_1", stat_line_1.set_value) stat_line_1.register(facility.ps, "status_line_1", stat_line_1.set_value)
stat_line_2.register(facility.ps, "status_line_2", stat_line_2.set_value) stat_line_2.register(facility.ps, "status_line_2", stat_line_2.set_value)
local auto_controls = Div{parent=proc,x=1,y=20,width=31,height=5,fg_bg=cpair(colors.gray,colors.white)} local auto_controls = Div{parent=proc,x=1,y=20,width=31,height=5,fg_bg=gry_wht}
-- save the automatic process control configuration without starting -- save the automatic process control configuration without starting
local function _save_cfg() local function _save_cfg()
@ -321,7 +327,7 @@ local function new_view(root, x, y)
local waste_sel = Div{parent=proc,width=21,height=24,x=81,y=1} local waste_sel = Div{parent=proc,width=21,height=24,x=81,y=1}
TextBox{parent=waste_sel,text=" ",width=21,height=1,x=1,y=1,fg_bg=cpair(colors.black,colors.brown)} TextBox{parent=waste_sel,text=" ",width=21,height=1,x=1,y=1,fg_bg=blk_brn}
TextBox{parent=waste_sel,text="WASTE PRODUCTION",alignment=TEXT_ALIGN.CENTER,width=21,height=1,x=1,y=2,fg_bg=cpair(colors.lightGray,colors.brown)} TextBox{parent=waste_sel,text="WASTE PRODUCTION",alignment=TEXT_ALIGN.CENTER,width=21,height=1,x=1,y=2,fg_bg=cpair(colors.lightGray,colors.brown)}
local rect = Rectangle{parent=waste_sel,border=border(1,colors.brown,true),width=21,height=22,x=1,y=3} local rect = Rectangle{parent=waste_sel,border=border(1,colors.brown,true),width=21,height=22,x=1,y=3}

View File

@ -14,6 +14,9 @@ local StateIndicator = require("graphics.elements.indicators.state")
local cpair = core.cpair local cpair = core.cpair
local border = core.border local border = core.border
local text_fg_bg = style.text_colors
local lu_col = style.lu_colors
-- create new reactor view -- create new reactor view
---@param root graphics_element parent ---@param root graphics_element parent
---@param x integer top left x ---@param x integer top left x
@ -22,9 +25,6 @@ local border = core.border
local function new_view(root, x, y, ps) local function new_view(root, x, y, ps)
local reactor = Rectangle{parent=root,border=border(1, colors.gray, true),width=30,height=7,x=x,y=y} local reactor = Rectangle{parent=root,border=border(1, colors.gray, true),width=30,height=7,x=x,y=y}
local text_fg_bg = cpair(colors.black, colors.lightGray)
local lu_col = cpair(colors.gray, colors.gray)
local status = StateIndicator{parent=reactor,x=6,y=1,states=style.reactor.states,value=1,min_width=16} local status = StateIndicator{parent=reactor,x=6,y=1,states=style.reactor.states,value=1,min_width=16}
local core_temp = DataIndicator{parent=reactor,x=2,y=3,lu_colors=lu_col,label="Core Temp:",unit="K",format="%10.2f",value=0,width=26,fg_bg=text_fg_bg} local core_temp = DataIndicator{parent=reactor,x=2,y=3,lu_colors=lu_col,label="Core Temp:",unit="K",format="%10.2f",value=0,width=26,fg_bg=text_fg_bg}
local burn_r = DataIndicator{parent=reactor,x=2,y=4,lu_colors=lu_col,label="Burn Rate:",unit="mB/t",format="%10.2f",value=0,width=26,fg_bg=text_fg_bg} local burn_r = DataIndicator{parent=reactor,x=2,y=4,lu_colors=lu_col,label="Burn Rate:",unit="mB/t",format="%10.2f",value=0,width=26,fg_bg=text_fg_bg}

View File

@ -15,6 +15,9 @@ local VerticalBar = require("graphics.elements.indicators.vbar")
local cpair = core.cpair local cpair = core.cpair
local border = core.border local border = core.border
local text_fg_bg = style.text_colors
local lu_col = style.lu_colors
-- new turbine view -- new turbine view
---@param root graphics_element parent ---@param root graphics_element parent
---@param x integer top left x ---@param x integer top left x
@ -23,9 +26,6 @@ local border = core.border
local function new_view(root, x, y, ps) local function new_view(root, x, y, ps)
local turbine = Rectangle{parent=root,border=border(1,colors.gray,true),width=23,height=7,x=x,y=y} local turbine = Rectangle{parent=root,border=border(1,colors.gray,true),width=23,height=7,x=x,y=y}
local text_fg_bg = cpair(colors.black, colors.lightGray)
local lu_col = cpair(colors.gray, colors.gray)
local status = StateIndicator{parent=turbine,x=7,y=1,states=style.turbine.states,value=1,min_width=12} local status = StateIndicator{parent=turbine,x=7,y=1,states=style.turbine.states,value=1,min_width=12}
local prod_rate = PowerIndicator{parent=turbine,x=5,y=3,lu_colors=lu_col,label="",format="%10.2f",value=0,rate=true,width=16,fg_bg=text_fg_bg} local prod_rate = PowerIndicator{parent=turbine,x=5,y=3,lu_colors=lu_col,label="",format="%10.2f",value=0,rate=true,width=16,fg_bg=text_fg_bg}
local flow_rate = DataIndicator{parent=turbine,x=5,y=4,lu_colors=lu_col,label="",unit="mB/t",format="%10.0f",value=0,commas=true,width=16,fg_bg=text_fg_bg} local flow_rate = DataIndicator{parent=turbine,x=5,y=4,lu_colors=lu_col,label="",unit="mB/t",format="%10.0f",value=0,commas=true,width=16,fg_bg=text_fg_bg}

View File

@ -2,6 +2,8 @@
-- Reactor Unit SCADA Coordinator GUI -- Reactor Unit SCADA Coordinator GUI
-- --
local types = require("scada-common.types")
local iocontrol = require("coordinator.iocontrol") local iocontrol = require("coordinator.iocontrol")
local style = require("coordinator.ui.style") local style = require("coordinator.ui.style")
@ -34,6 +36,9 @@ local border = core.border
local bw_fg_bg = style.bw_fg_bg local bw_fg_bg = style.bw_fg_bg
local lu_cpair = style.lu_colors local lu_cpair = style.lu_colors
local hzd_fg_bg = style.hzd_fg_bg local hzd_fg_bg = style.hzd_fg_bg
local dis_colors = style.dis_colors
local gry_wht = style.gray_white
local ind_grn = style.ind_grn local ind_grn = style.ind_grn
local ind_yel = style.ind_yel local ind_yel = style.ind_yel
@ -93,7 +98,7 @@ local function init(parent, id)
waste.register(u_ps, "waste_fill", waste.update) waste.register(u_ps, "waste_fill", waste.update)
ccool.register(u_ps, "ccool_type", function (type) ccool.register(u_ps, "ccool_type", function (type)
if type == "mekanism:sodium" then if type == types.FLUID.SODIUM then
ccool.recolor(cpair(colors.lightBlue, colors.gray)) ccool.recolor(cpair(colors.lightBlue, colors.gray))
else else
ccool.recolor(cpair(colors.blue, colors.gray)) ccool.recolor(cpair(colors.blue, colors.gray))
@ -101,7 +106,7 @@ local function init(parent, id)
end) end)
hcool.register(u_ps, "hcool_type", function (type) hcool.register(u_ps, "hcool_type", function (type)
if type == "mekanism:superheated_sodium" then if type == types.FLUID.SUPERHEATED_SODIUM then
hcool.recolor(cpair(colors.orange, colors.gray)) hcool.recolor(cpair(colors.orange, colors.gray))
else else
hcool.recolor(cpair(colors.white, colors.gray)) hcool.recolor(cpair(colors.white, colors.gray))
@ -130,7 +135,7 @@ local function init(parent, id)
local u_stat = Rectangle{parent=main,border=border(1,colors.gray,true),thin=true,width=33,height=4,x=46,y=3,fg_bg=bw_fg_bg} local u_stat = Rectangle{parent=main,border=border(1,colors.gray,true),thin=true,width=33,height=4,x=46,y=3,fg_bg=bw_fg_bg}
local stat_line_1 = TextBox{parent=u_stat,x=1,y=1,text="UNKNOWN",width=33,height=1,alignment=TEXT_ALIGN.CENTER,fg_bg=bw_fg_bg} local stat_line_1 = TextBox{parent=u_stat,x=1,y=1,text="UNKNOWN",width=33,height=1,alignment=TEXT_ALIGN.CENTER,fg_bg=bw_fg_bg}
local stat_line_2 = TextBox{parent=u_stat,x=1,y=2,text="awaiting data...",width=33,height=1,alignment=TEXT_ALIGN.CENTER,fg_bg=cpair(colors.gray, colors.white)} local stat_line_2 = TextBox{parent=u_stat,x=1,y=2,text="awaiting data...",width=33,height=1,alignment=TEXT_ALIGN.CENTER,fg_bg=gry_wht}
stat_line_1.register(u_ps, "U_StatusLine1", stat_line_1.set_value) stat_line_1.register(u_ps, "U_StatusLine1", stat_line_1.set_value)
stat_line_2.register(u_ps, "U_StatusLine2", stat_line_2.set_value) stat_line_2.register(u_ps, "U_StatusLine2", stat_line_2.set_value)
@ -341,10 +346,8 @@ local function init(parent, id)
-- reactor controls -- -- reactor controls --
---------------------- ----------------------
local dis_colors = cpair(colors.white, colors.lightGray) local burn_control = Div{parent=main,x=12,y=28,width=19,height=3,fg_bg=gry_wht}
local burn_rate = SpinboxNumeric{parent=burn_control,x=2,y=1,whole_num_precision=4,fractional_precision=1,min=0.1,arrow_fg_bg=gry_wht,fg_bg=bw_fg_bg}
local burn_control = Div{parent=main,x=12,y=28,width=19,height=3,fg_bg=cpair(colors.gray,colors.white)}
local burn_rate = SpinboxNumeric{parent=burn_control,x=2,y=1,whole_num_precision=4,fractional_precision=1,min=0.1,arrow_fg_bg=cpair(colors.gray,colors.white),fg_bg=bw_fg_bg}
TextBox{parent=burn_control,x=9,y=2,text="mB/t"} TextBox{parent=burn_control,x=9,y=2,text="mB/t"}
local set_burn = function () unit.set_burn(burn_rate.get_value()) end local set_burn = function () unit.set_burn(burn_rate.get_value()) end
@ -480,7 +483,7 @@ local function init(parent, id)
auto_div.line_break() auto_div.line_break()
local function set_group() unit.set_group(group.get_value() - 1) end local function set_group() unit.set_group(group.get_value() - 1) end
local set_grp_btn = PushButton{parent=auto_div,text="SET",x=4,min_width=5,fg_bg=cpair(colors.black,colors.yellow),active_fg_bg=style.wh_gray,dis_fg_bg=cpair(colors.gray,colors.white),callback=set_group} local set_grp_btn = PushButton{parent=auto_div,text="SET",x=4,min_width=5,fg_bg=cpair(colors.black,colors.yellow),active_fg_bg=style.wh_gray,dis_fg_bg=gry_wht,callback=set_group}
auto_div.line_break() auto_div.line_break()

View File

@ -23,7 +23,6 @@ local TEXT_ALIGN = core.TEXT_ALIGN
local sprintf = util.sprintf local sprintf = util.sprintf
local cpair = core.cpair
local border = core.border local border = core.border
local pipe = core.pipe local pipe = core.pipe
@ -31,6 +30,7 @@ local wh_gray = style.wh_gray
local bw_fg_bg = style.bw_fg_bg local bw_fg_bg = style.bw_fg_bg
local text_c = style.text_colors local text_c = style.text_colors
local lu_c = style.lu_colors local lu_c = style.lu_colors
local lg_gray = style.lg_gray
local ind_grn = style.ind_grn local ind_grn = style.ind_grn
local ind_wht = style.ind_wht local ind_wht = style.ind_wht
@ -64,8 +64,6 @@ local function make(parent, x, y, wide, unit)
-- bounding box div -- bounding box div
local root = Div{parent=parent,x=x,y=y,width=_wide(136, 114),height=height} local root = Div{parent=parent,x=x,y=y,width=_wide(136, 114),height=height}
local lg_gray = cpair(colors.lightGray, colors.gray)
------------------ ------------------
-- COOLING LOOP -- -- COOLING LOOP --
------------------ ------------------

View File

@ -261,7 +261,7 @@ local function init(main)
if tank_defs[i] > 0 then if tank_defs[i] > 0 then
local vy = 3 + y_ofs(i) local vy = 3 + y_ofs(i)
TextBox{parent=main,x=12,y=vy,text="\x10\x11",fg_bg=cpair(colors.black,colors.lightGray),width=2,height=1} TextBox{parent=main,x=12,y=vy,text="\x10\x11",fg_bg=text_col,width=2,height=1}
local conn = IndicatorLight{parent=main,x=9,y=vy+1,label=util.sprintf("PV%02d-EMC", i * 5),colors=style.ind_grn} local conn = IndicatorLight{parent=main,x=9,y=vy+1,label=util.sprintf("PV%02d-EMC", i * 5),colors=style.ind_grn}
local open = IndicatorLight{parent=main,x=9,y=vy+2,label="OPEN",colors=style.ind_wht} local open = IndicatorLight{parent=main,x=9,y=vy+2,label="OPEN",colors=style.ind_wht}
@ -288,7 +288,7 @@ local function init(main)
local tank = Div{parent=main,x=3,y=7+y_offset,width=20,height=14} local tank = Div{parent=main,x=3,y=7+y_offset,width=20,height=14}
TextBox{parent=tank,text=" ",height=1,x=1,y=1,fg_bg=cpair(colors.lightGray,colors.gray)} TextBox{parent=tank,text=" ",height=1,x=1,y=1,fg_bg=style.lg_gray}
TextBox{parent=tank,text="DYNAMIC TANK "..id,alignment=TEXT_ALIGN.CENTER,height=1,fg_bg=style.wh_gray} TextBox{parent=tank,text="DYNAMIC TANK "..id,alignment=TEXT_ALIGN.CENTER,height=1,fg_bg=style.wh_gray}
local tank_box = Rectangle{parent=tank,border=border(1,colors.gray,true),width=20,height=12} local tank_box = Rectangle{parent=tank,border=border(1,colors.gray,true),width=20,height=12}
@ -338,7 +338,7 @@ local function init(main)
local sps = Div{parent=main,x=140,y=3,height=12} local sps = Div{parent=main,x=140,y=3,height=12}
TextBox{parent=sps,text=" ",width=24,height=1,x=1,y=1,fg_bg=cpair(colors.lightGray,colors.gray)} TextBox{parent=sps,text=" ",width=24,height=1,x=1,y=1,fg_bg=style.lg_gray}
TextBox{parent=sps,text="SPS",alignment=TEXT_ALIGN.CENTER,width=24,height=1,fg_bg=wh_gray} TextBox{parent=sps,text="SPS",alignment=TEXT_ALIGN.CENTER,width=24,height=1,fg_bg=wh_gray}
local sps_box = Rectangle{parent=sps,border=border(1,colors.gray,true),width=24,height=10} local sps_box = Rectangle{parent=sps,border=border(1,colors.gray,true),width=24,height=10}

View File

@ -28,6 +28,8 @@ local TEXT_ALIGN = core.TEXT_ALIGN
local cpair = core.cpair local cpair = core.cpair
local led_grn = style.led_grn
-- create new front panel view -- create new front panel view
---@param panel graphics_element main displaybox ---@param panel graphics_element main displaybox
---@param num_units integer number of units (number of unit monitors) ---@param num_units integer number of units (number of unit monitors)
@ -47,13 +49,13 @@ local function init(panel, num_units)
local system = Div{parent=main_page,width=14,height=17,x=2,y=2} local system = Div{parent=main_page,width=14,height=17,x=2,y=2}
local status = LED{parent=system,label="STATUS",colors=cpair(colors.green,colors.red)} local status = LED{parent=system,label="STATUS",colors=cpair(colors.green,colors.red)}
local heartbeat = LED{parent=system,label="HEARTBEAT",colors=cpair(colors.green,colors.green_off)} local heartbeat = LED{parent=system,label="HEARTBEAT",colors=led_grn}
status.update(true) status.update(true)
system.line_break() system.line_break()
heartbeat.register(ps, "heartbeat", heartbeat.update) heartbeat.register(ps, "heartbeat", heartbeat.update)
local modem = LED{parent=system,label="MODEM",colors=cpair(colors.green,colors.green_off)} local modem = LED{parent=system,label="MODEM",colors=led_grn}
local network = RGBLED{parent=system,label="NETWORK",colors={colors.green,colors.red,colors.orange,colors.yellow,colors.gray}} local network = RGBLED{parent=system,label="NETWORK",colors={colors.green,colors.red,colors.orange,colors.yellow,colors.gray}}
network.update(types.PANEL_LINK_STATE.DISCONNECTED) network.update(types.PANEL_LINK_STATE.DISCONNECTED)
system.line_break() system.line_break()
@ -61,25 +63,25 @@ local function init(panel, num_units)
modem.register(ps, "has_modem", modem.update) modem.register(ps, "has_modem", modem.update)
network.register(ps, "link_state", network.update) network.register(ps, "link_state", network.update)
local speaker = LED{parent=system,label="SPEAKER",colors=cpair(colors.green,colors.green_off)} local speaker = LED{parent=system,label="SPEAKER",colors=led_grn}
speaker.register(ps, "has_speaker", speaker.update) speaker.register(ps, "has_speaker", speaker.update)
---@diagnostic disable-next-line: undefined-field ---@diagnostic disable-next-line: undefined-field
local comp_id = util.sprintf("(%d)", os.getComputerID()) local comp_id = util.sprintf("(%d)", os.getComputerID())
TextBox{parent=system,x=9,y=4,width=6,height=1,text=comp_id,fg_bg=cpair(colors.lightGray,colors.ivory)} TextBox{parent=system,x=9,y=4,width=6,height=1,text=comp_id,fg_bg=style.fp_label}
local monitors = Div{parent=main_page,width=16,height=17,x=18,y=2} local monitors = Div{parent=main_page,width=16,height=17,x=18,y=2}
local main_monitor = LED{parent=monitors,label="MAIN MONITOR",colors=cpair(colors.green,colors.green_off)} local main_monitor = LED{parent=monitors,label="MAIN MONITOR",colors=led_grn}
main_monitor.register(ps, "main_monitor", main_monitor.update) main_monitor.register(ps, "main_monitor", main_monitor.update)
local flow_monitor = LED{parent=monitors,label="FLOW MONITOR",colors=cpair(colors.green,colors.green_off)} local flow_monitor = LED{parent=monitors,label="FLOW MONITOR",colors=led_grn}
flow_monitor.register(ps, "flow_monitor", flow_monitor.update) flow_monitor.register(ps, "flow_monitor", flow_monitor.update)
monitors.line_break() monitors.line_break()
for i = 1, num_units do for i = 1, num_units do
local unit_monitor = LED{parent=monitors,label="UNIT "..i.." MONITOR",colors=cpair(colors.green,colors.green_off)} local unit_monitor = LED{parent=monitors,label="UNIT "..i.." MONITOR",colors=led_grn}
unit_monitor.register(ps, "unit_monitor_" .. i, unit_monitor.update) unit_monitor.register(ps, "unit_monitor_" .. i, unit_monitor.update)
end end
@ -87,7 +89,7 @@ local function init(panel, num_units)
-- about footer -- about footer
-- --
local about = Div{parent=main_page,width=15,height=3,x=1,y=16,fg_bg=cpair(colors.lightGray,colors.ivory)} local about = Div{parent=main_page,width=15,height=3,x=1,y=16,fg_bg=style.fp_label}
local fw_v = TextBox{parent=about,x=1,y=1,text="FW: v00.00.00",alignment=TEXT_ALIGN.LEFT,height=1} local fw_v = TextBox{parent=about,x=1,y=1,text="FW: v00.00.00",alignment=TEXT_ALIGN.LEFT,height=1}
local comms_v = TextBox{parent=about,x=1,y=2,text="NT: v00.00.00",alignment=TEXT_ALIGN.LEFT,height=1} local comms_v = TextBox{parent=about,x=1,y=2,text="NT: v00.00.00",alignment=TEXT_ALIGN.LEFT,height=1}
@ -101,7 +103,7 @@ local function init(panel, num_units)
-- API page -- API page
local api_page = Div{parent=page_div,x=1,y=1,hidden=true} local api_page = Div{parent=page_div,x=1,y=1,hidden=true}
local api_list = ListBox{parent=api_page,x=1,y=1,height=17,width=51,scroll_height=1000,fg_bg=cpair(colors.black,colors.ivory),nav_fg_bg=cpair(colors.gray,colors.lightGray),nav_active=cpair(colors.black,colors.gray)} local api_list = ListBox{parent=api_page,x=1,y=1,height=17,width=51,scroll_height=1000,fg_bg=style.fp_text,nav_fg_bg=cpair(colors.gray,colors.lightGray),nav_active=cpair(colors.black,colors.gray)}
local _ = Div{parent=api_list,height=1,hidden=true} -- padding local _ = Div{parent=api_list,height=1,hidden=true} -- padding
-- assemble page panes -- assemble page panes
@ -111,11 +113,11 @@ local function init(panel, num_units)
local page_pane = MultiPane{parent=page_div,x=1,y=1,panes=panes} local page_pane = MultiPane{parent=page_div,x=1,y=1,panes=panes}
local tabs = { local tabs = {
{ name = "CRD", color = cpair(colors.black, colors.ivory) }, { name = "CRD", color = style.fp_text },
{ name = "API", color = cpair(colors.black, colors.ivory) }, { name = "API", color = style.fp_text },
} }
TabBar{parent=panel,y=2,tabs=tabs,min_width=9,callback=page_pane.set_value,fg_bg=cpair(colors.black,colors.white)} TabBar{parent=panel,y=2,tabs=tabs,min_width=9,callback=page_pane.set_value,fg_bg=style.bw_fg_bg}
-- link pocket API list management to PGI -- link pocket API list management to PGI
pgi.link_elements(api_list, pkt_entry) pgi.link_elements(api_list, pkt_entry)

View File

@ -2,8 +2,6 @@
-- Main SCADA Coordinator GUI -- Main SCADA Coordinator GUI
-- --
local util = require("scada-common.util")
local iocontrol = require("coordinator.iocontrol") local iocontrol = require("coordinator.iocontrol")
local style = require("coordinator.ui.style") local style = require("coordinator.ui.style")
@ -20,8 +18,6 @@ local DataIndicator = require("graphics.elements.indicators.data")
local TEXT_ALIGN = core.TEXT_ALIGN local TEXT_ALIGN = core.TEXT_ALIGN
local cpair = core.cpair
-- create new main view -- create new main view
---@param main graphics_element main displaybox ---@param main graphics_element main displaybox
local function init(main) local function init(main)
@ -30,7 +26,7 @@ local function init(main)
-- window header message -- window header message
local header = TextBox{parent=main,y=1,text="Nuclear Generation Facility SCADA Coordinator",alignment=TEXT_ALIGN.CENTER,height=1,fg_bg=style.header} local header = TextBox{parent=main,y=1,text="Nuclear Generation Facility SCADA Coordinator",alignment=TEXT_ALIGN.CENTER,height=1,fg_bg=style.header}
local ping = DataIndicator{parent=main,x=1,y=1,label="SVTT",format="%d",value=0,unit="ms",lu_colors=cpair(colors.lightGray, colors.white),width=12,fg_bg=style.header} local ping = DataIndicator{parent=main,x=1,y=1,label="SVTT",format="%d",value=0,unit="ms",lu_colors=style.lg_white,width=12,fg_bg=style.header}
-- max length example: "01:23:45 AM - Wednesday, September 28 2022" -- max length example: "01:23:45 AM - Wednesday, September 28 2022"
local datetime = TextBox{parent=main,x=(header.get_width()-42),y=1,text="",alignment=TEXT_ALIGN.RIGHT,width=42,height=1,fg_bg=style.header} local datetime = TextBox{parent=main,x=(header.get_width()-42),y=1,text="",alignment=TEXT_ALIGN.RIGHT,width=42,height=1,fg_bg=style.header}
@ -77,7 +73,7 @@ local function init(main)
assert(cnc_bottom_align_start >= cnc_y_start, "main display not of sufficient vertical resolution (add an additional row of monitors)") assert(cnc_bottom_align_start >= cnc_y_start, "main display not of sufficient vertical resolution (add an additional row of monitors)")
TextBox{parent=main,y=cnc_bottom_align_start,text=util.strrep("\x8c", header.get_width()),alignment=TEXT_ALIGN.CENTER,height=1,fg_bg=cpair(colors.lightGray,colors.gray)} TextBox{parent=main,y=cnc_bottom_align_start,text=string.rep("\x8c", header.get_width()),alignment=TEXT_ALIGN.CENTER,height=1,fg_bg=style.lg_gray}
cnc_bottom_align_start = cnc_bottom_align_start + 2 cnc_bottom_align_start = cnc_bottom_align_start + 2

View File

@ -78,11 +78,19 @@ style.lu_colors = cpair(colors.gray, colors.gray)
style.hzd_fg_bg = style.wh_gray style.hzd_fg_bg = style.wh_gray
style.dis_colors = cpair(colors.white, colors.lightGray) style.dis_colors = cpair(colors.white, colors.lightGray)
style.lg_gray = cpair(colors.lightGray, colors.gray)
style.lg_white = cpair(colors.lightGray, colors.white)
style.gray_white = cpair(colors.gray, colors.white)
style.ind_grn = cpair(colors.green, colors.gray) style.ind_grn = cpair(colors.green, colors.gray)
style.ind_yel = cpair(colors.yellow, colors.gray) style.ind_yel = cpair(colors.yellow, colors.gray)
style.ind_red = cpair(colors.red, colors.gray) style.ind_red = cpair(colors.red, colors.gray)
style.ind_wht = style.wh_gray style.ind_wht = style.wh_gray
style.fp_text = cpair(colors.black, colors.ivory)
style.fp_label = cpair(colors.lightGray, colors.ivory)
style.led_grn = cpair(colors.green, colors.green_off)
-- UI COMPONENTS -- -- UI COMPONENTS --
style.reactor = { style.reactor = {

View File

@ -7,7 +7,7 @@ local flasher = require("graphics.flasher")
local core = {} local core = {}
core.version = "1.1.1" core.version = "1.1.2"
core.flasher = flasher core.flasher = flasher
core.events = events core.events = events
@ -35,11 +35,7 @@ core.TEXT_ALIGN = {
---@param even? boolean whether to pad width extra to account for rectangular pixels, defaults to false ---@param even? boolean whether to pad width extra to account for rectangular pixels, defaults to false
---@return graphics_border ---@return graphics_border
function core.border(width, color, even) function core.border(width, color, even)
return { return { width = width, color = color, even = even or false }
width = width,
color = color,
even = even or false -- convert nil to false
}
end end
---@class graphics_frame ---@class graphics_frame
@ -56,12 +52,7 @@ end
---@param h integer ---@param h integer
---@return graphics_frame ---@return graphics_frame
function core.gframe(x, y, w, h) function core.gframe(x, y, w, h)
return { return { x = x, y = y, w = w, h = h }
x = x,
y = y,
w = w,
h = h
}
end end
---@class cpair ---@class cpair

View File

@ -166,6 +166,31 @@ function element.new(args, child_offset_x, child_offset_y)
self.bounds.x2 = self.position.x + f.w - 1 self.bounds.x2 = self.position.x + f.w - 1
self.bounds.y1 = self.position.y self.bounds.y1 = self.position.y
self.bounds.y2 = self.position.y + f.h - 1 self.bounds.y2 = self.position.y + f.h - 1
-- alias functions
-- window set cursor position
---@param x integer
---@param y integer
function protected.w_set_cur(x, y) protected.window.setCursorPos(x, y) end
-- set background color
---@param c color
function protected.w_set_bkg(c) protected.window.setBackgroundColor(c) end
-- set foreground (text) color
---@param c color
function protected.w_set_fgd(c) protected.window.setTextColor(c) end
-- write text
---@param str string
function protected.w_write(str) protected.window.write(str) end
-- blit text
---@param str string
---@param fg string
---@param bg string
function protected.w_blit(str, fg, bg) protected.window.blit(str, fg, bg) end
end end
-- check if a coordinate relative to the parent is within the bounds of this element -- check if a coordinate relative to the parent is within the bounds of this element

View File

@ -36,49 +36,49 @@ local function waiting(args)
if state >= 0 and state < 7 then if state >= 0 and state < 7 then
-- top -- top
e.window.setCursorPos(1 + math.floor(state / 2), 1) e.w_set_cur(1 + math.floor(state / 2), 1)
if state % 2 == 0 then if state % 2 == 0 then
e.window.blit("\x8f", blit_fg, blit_bg) e.w_blit("\x8f", blit_fg, blit_bg)
else else
e.window.blit("\x8a\x85", blit_fg_2x, blit_bg_2x) e.w_blit("\x8a\x85", blit_fg_2x, blit_bg_2x)
end end
-- bottom -- bottom
e.window.setCursorPos(4 - math.ceil(state / 2), 3) e.w_set_cur(4 - math.ceil(state / 2), 3)
if state % 2 == 0 then if state % 2 == 0 then
e.window.blit("\x8f", blit_fg, blit_bg) e.w_blit("\x8f", blit_fg, blit_bg)
else else
e.window.blit("\x8a\x85", blit_fg_2x, blit_bg_2x) e.w_blit("\x8a\x85", blit_fg_2x, blit_bg_2x)
end end
else else
local st = state - 7 local st = state - 7
-- right -- right
if st % 3 == 0 then if st % 3 == 0 then
e.window.setCursorPos(4, 1 + math.floor(st / 3)) e.w_set_cur(4, 1 + math.floor(st / 3))
e.window.blit("\x83", blit_bg, blit_fg) e.w_blit("\x83", blit_bg, blit_fg)
elseif st % 3 == 1 then elseif st % 3 == 1 then
e.window.setCursorPos(4, 1 + math.floor(st / 3)) e.w_set_cur(4, 1 + math.floor(st / 3))
e.window.blit("\x8f", blit_bg, blit_fg) e.w_blit("\x8f", blit_bg, blit_fg)
e.window.setCursorPos(4, 2 + math.floor(st / 3)) e.w_set_cur(4, 2 + math.floor(st / 3))
e.window.blit("\x83", blit_fg, blit_bg) e.w_blit("\x83", blit_fg, blit_bg)
else else
e.window.setCursorPos(4, 2 + math.floor(st / 3)) e.w_set_cur(4, 2 + math.floor(st / 3))
e.window.blit("\x8f", blit_fg, blit_bg) e.w_blit("\x8f", blit_fg, blit_bg)
end end
-- left -- left
if st % 3 == 0 then if st % 3 == 0 then
e.window.setCursorPos(1, 3 - math.floor(st / 3)) e.w_set_cur(1, 3 - math.floor(st / 3))
e.window.blit("\x83", blit_fg, blit_bg) e.w_blit("\x83", blit_fg, blit_bg)
e.window.setCursorPos(1, 2 - math.floor(st / 3)) e.w_set_cur(1, 2 - math.floor(st / 3))
e.window.blit("\x8f", blit_bg, blit_fg) e.w_blit("\x8f", blit_bg, blit_fg)
elseif st % 3 == 1 then elseif st % 3 == 1 then
e.window.setCursorPos(1, 2 - math.floor(st / 3)) e.w_set_cur(1, 2 - math.floor(st / 3))
e.window.blit("\x83", blit_bg, blit_fg) e.w_blit("\x83", blit_bg, blit_fg)
else else
e.window.setCursorPos(1, 2 - math.floor(st / 3)) e.w_set_cur(1, 2 - math.floor(st / 3))
e.window.blit("\x8f", blit_fg, blit_bg) e.w_blit("\x8f", blit_fg, blit_bg)
end end
end end

View File

@ -25,8 +25,8 @@ local function colormap(args)
local e = element.new(args) local e = element.new(args)
-- draw color map -- draw color map
e.window.setCursorPos(1, 1) e.w_set_cur(1, 1)
e.window.blit(spaces, bkg, bkg) e.w_blit(spaces, bkg, bkg)
return e.complete() return e.complete()
end end

View File

@ -36,9 +36,8 @@ local function app_button(args)
local e = element.new(args) local e = element.new(args)
-- write app title, centered -- write app title, centered
e.window.setCursorPos(1, 4) e.w_set_cur(math.floor((e.frame.w - string.len(args.title)) / 2) + 1, 4)
e.window.setCursorPos(math.floor((e.frame.w - string.len(args.title)) / 2) + 1, 4) e.w_write(args.title)
e.window.write(args.title)
-- draw the app button -- draw the app button
local function draw() local function draw()
@ -51,36 +50,36 @@ local function app_button(args)
end end
-- draw icon -- draw icon
e.window.setCursorPos(1, 1) e.w_set_cur(1, 1)
e.window.setTextColor(fgd) e.w_set_fgd(fgd)
e.window.setBackgroundColor(bkg) e.w_set_bkg(bkg)
e.window.write("\x9f\x83\x83\x83") e.w_write("\x9f\x83\x83\x83")
e.window.setTextColor(bkg) e.w_set_fgd(bkg)
e.window.setBackgroundColor(fgd) e.w_set_bkg(fgd)
e.window.write("\x90") e.w_write("\x90")
e.window.setTextColor(fgd) e.w_set_fgd(fgd)
e.window.setBackgroundColor(bkg) e.w_set_bkg(bkg)
e.window.setCursorPos(1, 2) e.w_set_cur(1, 2)
e.window.write("\x95 ") e.w_write("\x95 ")
e.window.setTextColor(bkg) e.w_set_fgd(bkg)
e.window.setBackgroundColor(fgd) e.w_set_bkg(fgd)
e.window.write("\x95") e.w_write("\x95")
e.window.setCursorPos(1, 3) e.w_set_cur(1, 3)
e.window.write("\x82\x8f\x8f\x8f\x81") e.w_write("\x82\x8f\x8f\x8f\x81")
-- write the icon text -- write the icon text
e.window.setCursorPos(3, 2) e.w_set_cur(3, 2)
e.window.setTextColor(fgd) e.w_set_fgd(fgd)
e.window.setBackgroundColor(bkg) e.w_set_bkg(bkg)
e.window.write(args.text) e.w_write(args.text)
end end
-- draw the app button as pressed (if active_fg_bg set) -- draw the app button as pressed (if active_fg_bg set)
local function show_pressed() local function show_pressed()
if e.enabled and args.active_fg_bg ~= nil then if e.enabled and args.active_fg_bg ~= nil then
e.value = true e.value = true
e.window.setTextColor(args.active_fg_bg.fgd) e.w_set_fgd(args.active_fg_bg.fgd)
e.window.setBackgroundColor(args.active_fg_bg.bkg) e.w_set_bkg(args.active_fg_bg.bkg)
draw() draw()
end end
end end
@ -89,8 +88,8 @@ local function app_button(args)
local function show_unpressed() local function show_unpressed()
if e.enabled and args.active_fg_bg ~= nil then if e.enabled and args.active_fg_bg ~= nil then
e.value = false e.value = false
e.window.setTextColor(e.fg_bg.fgd) e.w_set_fgd(e.fg_bg.fgd)
e.window.setBackgroundColor(e.fg_bg.bkg) e.w_set_bkg(e.fg_bg.bkg)
draw() draw()
end end
end end

View File

@ -32,24 +32,24 @@ local function checkbox(args)
-- show the button state -- show the button state
local function draw() local function draw()
e.window.setCursorPos(1, 1) e.w_set_cur(1, 1)
if e.value then if e.value then
-- show as selected -- show as selected
e.window.setTextColor(args.box_fg_bg.bkg) e.w_set_fgd(args.box_fg_bg.bkg)
e.window.setBackgroundColor(args.box_fg_bg.fgd) e.w_set_bkg(args.box_fg_bg.fgd)
e.window.write("\x88") e.w_write("\x88")
e.window.setTextColor(args.box_fg_bg.fgd) e.w_set_fgd(args.box_fg_bg.fgd)
e.window.setBackgroundColor(e.fg_bg.bkg) e.w_set_bkg(e.fg_bg.bkg)
e.window.write("\x95") e.w_write("\x95")
else else
-- show as unselected -- show as unselected
e.window.setTextColor(e.fg_bg.bkg) e.w_set_fgd(e.fg_bg.bkg)
e.window.setBackgroundColor(args.box_fg_bg.bkg) e.w_set_bkg(args.box_fg_bg.bkg)
e.window.write("\x88") e.w_write("\x88")
e.window.setTextColor(args.box_fg_bg.bkg) e.w_set_fgd(args.box_fg_bg.bkg)
e.window.setBackgroundColor(e.fg_bg.bkg) e.w_set_bkg(e.fg_bg.bkg)
e.window.write("\x95") e.w_write("\x95")
end end
end end
@ -71,10 +71,10 @@ local function checkbox(args)
end end
-- write label text -- write label text
e.window.setCursorPos(3, 1) e.w_set_cur(3, 1)
e.window.setTextColor(e.fg_bg.fgd) e.w_set_fgd(e.fg_bg.fgd)
e.window.setBackgroundColor(e.fg_bg.bkg) e.w_set_bkg(e.fg_bg.bkg)
e.window.write(args.label) e.w_write(args.label)
-- initial draw -- initial draw
draw() draw()

View File

@ -1,7 +1,6 @@
-- Hazard-bordered Button Graphics Element -- Hazard-bordered Button Graphics Element
local tcd = require("scada-common.tcd") local tcd = require("scada-common.tcd")
local util = require("scada-common.util")
local core = require("graphics.core") local core = require("graphics.core")
local element = require("graphics.element") local element = require("graphics.element")
@ -34,35 +33,35 @@ local function hazard_button(args)
local e = element.new(args) local e = element.new(args)
-- write the button text -- write the button text
e.window.setCursorPos(3, 2) e.w_set_cur(3, 2)
e.window.write(args.text) e.w_write(args.text)
-- draw border -- draw border
---@param accent color accent color ---@param accent color accent color
local function draw_border(accent) local function draw_border(accent)
-- top -- top
e.window.setTextColor(accent) e.w_set_fgd(accent)
e.window.setBackgroundColor(args.fg_bg.bkg) e.w_set_bkg(args.fg_bg.bkg)
e.window.setCursorPos(1, 1) e.w_set_cur(1, 1)
e.window.write("\x99" .. util.strrep("\x89", args.width - 2) .. "\x99") e.w_write("\x99" .. string.rep("\x89", args.width - 2) .. "\x99")
-- center left -- center left
e.window.setCursorPos(1, 2) e.w_set_cur(1, 2)
e.window.setTextColor(args.fg_bg.bkg) e.w_set_fgd(args.fg_bg.bkg)
e.window.setBackgroundColor(accent) e.w_set_bkg(accent)
e.window.write("\x99") e.w_write("\x99")
-- center right -- center right
e.window.setTextColor(args.fg_bg.bkg) e.w_set_fgd(args.fg_bg.bkg)
e.window.setBackgroundColor(accent) e.w_set_bkg(accent)
e.window.setCursorPos(args.width, 2) e.w_set_cur(args.width, 2)
e.window.write("\x99") e.w_write("\x99")
-- bottom -- bottom
e.window.setTextColor(accent) e.w_set_fgd(accent)
e.window.setBackgroundColor(args.fg_bg.bkg) e.w_set_bkg(args.fg_bg.bkg)
e.window.setCursorPos(1, 3) e.w_set_cur(1, 3)
e.window.write("\x99" .. util.strrep("\x98", args.width - 2) .. "\x99") e.w_write("\x99" .. string.rep("\x98", args.width - 2) .. "\x99")
end end
-- on request timeout: recursively calls itself to double flash button text -- on request timeout: recursively calls itself to double flash button text
@ -73,9 +72,9 @@ local function hazard_button(args)
if n == 0 then if n == 0 then
-- go back off -- go back off
e.window.setTextColor(args.fg_bg.fgd) e.w_set_fgd(args.fg_bg.fgd)
e.window.setCursorPos(3, 2) e.w_set_cur(3, 2)
e.window.write(args.text) e.w_write(args.text)
end end
if n >= 4 then if n >= 4 then
@ -83,18 +82,18 @@ local function hazard_button(args)
elseif n % 2 == 0 then elseif n % 2 == 0 then
-- toggle text color on after 0.25 seconds -- toggle text color on after 0.25 seconds
tcd.dispatch(0.25, function () tcd.dispatch(0.25, function ()
e.window.setTextColor(args.accent) e.w_set_fgd(args.accent)
e.window.setCursorPos(3, 2) e.w_set_cur(3, 2)
e.window.write(args.text) e.w_write(args.text)
on_timeout(n + 1) on_timeout(n + 1)
on_timeout(n + 1) on_timeout(n + 1)
end) end)
elseif n % 1 then elseif n % 1 then
-- toggle text color off after 0.25 seconds -- toggle text color off after 0.25 seconds
tcd.dispatch(0.25, function () tcd.dispatch(0.25, function ()
e.window.setTextColor(args.fg_bg.fgd) e.w_set_fgd(args.fg_bg.fgd)
e.window.setCursorPos(3, 2) e.w_set_cur(3, 2)
e.window.write(args.text) e.w_write(args.text)
on_timeout(n + 1) on_timeout(n + 1)
end) end)
end end
@ -102,9 +101,9 @@ local function hazard_button(args)
-- blink routine for success indication -- blink routine for success indication
local function on_success() local function on_success()
e.window.setTextColor(args.fg_bg.fgd) e.w_set_fgd(args.fg_bg.fgd)
e.window.setCursorPos(3, 2) e.w_set_cur(3, 2)
e.window.write(args.text) e.w_write(args.text)
end end
-- blink routine for failure indication -- blink routine for failure indication
@ -115,9 +114,9 @@ local function hazard_button(args)
if n == 0 then if n == 0 then
-- go back off -- go back off
e.window.setTextColor(args.fg_bg.fgd) e.w_set_fgd(args.fg_bg.fgd)
e.window.setCursorPos(3, 2) e.w_set_cur(3, 2)
e.window.write(args.text) e.w_write(args.text)
end end
if n >= 2 then if n >= 2 then
@ -125,17 +124,17 @@ local function hazard_button(args)
elseif n % 2 == 0 then elseif n % 2 == 0 then
-- toggle text color on after 0.5 seconds -- toggle text color on after 0.5 seconds
tcd.dispatch(0.5, function () tcd.dispatch(0.5, function ()
e.window.setTextColor(args.accent) e.w_set_fgd(args.accent)
e.window.setCursorPos(3, 2) e.w_set_cur(3, 2)
e.window.write(args.text) e.w_write(args.text)
on_failure(n + 1) on_failure(n + 1)
end) end)
elseif n % 1 then elseif n % 1 then
-- toggle text color off after 0.25 seconds -- toggle text color off after 0.25 seconds
tcd.dispatch(0.25, function () tcd.dispatch(0.25, function ()
e.window.setTextColor(args.fg_bg.fgd) e.w_set_fgd(args.fg_bg.fgd)
e.window.setCursorPos(3, 2) e.w_set_cur(3, 2)
e.window.write(args.text) e.w_write(args.text)
on_failure(n + 1) on_failure(n + 1)
end) end)
end end
@ -147,9 +146,9 @@ local function hazard_button(args)
if e.enabled then if e.enabled then
if core.events.was_clicked(event.type) then if core.events.was_clicked(event.type) then
-- change text color to indicate clicked -- change text color to indicate clicked
e.window.setTextColor(args.accent) e.w_set_fgd(args.accent)
e.window.setCursorPos(3, 2) e.w_set_cur(3, 2)
e.window.write(args.text) e.w_write(args.text)
-- abort any other callbacks -- abort any other callbacks
tcd.abort(on_timeout) tcd.abort(on_timeout)
@ -182,18 +181,18 @@ local function hazard_button(args)
function e.disable() function e.disable()
if args.dis_colors then if args.dis_colors then
draw_border(args.dis_colors.color_a) draw_border(args.dis_colors.color_a)
e.window.setTextColor(args.dis_colors.color_b) e.w_set_fgd(args.dis_colors.color_b)
e.window.setCursorPos(3, 2) e.w_set_cur(3, 2)
e.window.write(args.text) e.w_write(args.text)
end end
end end
-- show the button as enabled -- show the button as enabled
function e.enable() function e.enable()
draw_border(args.accent) draw_border(args.accent)
e.window.setTextColor(args.fg_bg.fgd) e.w_set_fgd(args.fg_bg.fgd)
e.window.setCursorPos(3, 2) e.w_set_cur(3, 2)
e.window.write(args.text) e.w_write(args.text)
end end
-- initial draw of border -- initial draw of border

View File

@ -75,19 +75,19 @@ local function multi_button(args)
for i = 1, #args.options do for i = 1, #args.options do
local opt = args.options[i] ---@type button_option local opt = args.options[i] ---@type button_option
e.window.setCursorPos(opt._start_x, 1) e.w_set_cur(opt._start_x, 1)
if e.value == i then if e.value == i then
-- show as pressed -- show as pressed
e.window.setTextColor(opt.active_fg_bg.fgd) e.w_set_fgd(opt.active_fg_bg.fgd)
e.window.setBackgroundColor(opt.active_fg_bg.bkg) e.w_set_bkg(opt.active_fg_bg.bkg)
else else
-- show as unpressed -- show as unpressed
e.window.setTextColor(opt.fg_bg.fgd) e.w_set_fgd(opt.fg_bg.fgd)
e.window.setBackgroundColor(opt.fg_bg.bkg) e.w_set_bkg(opt.fg_bg.bkg)
end end
e.window.write(util.pad(opt.text, button_width)) e.w_write(util.pad(opt.text, button_width))
end end
end end

View File

@ -48,16 +48,16 @@ local function push_button(args)
e.window.clear() e.window.clear()
-- write the button text -- write the button text
e.window.setCursorPos(h_pad, v_pad) e.w_set_cur(h_pad, v_pad)
e.window.write(args.text) e.w_write(args.text)
end end
-- draw the button as pressed (if active_fg_bg set) -- draw the button as pressed (if active_fg_bg set)
local function show_pressed() local function show_pressed()
if e.enabled and args.active_fg_bg ~= nil then if e.enabled and args.active_fg_bg ~= nil then
e.value = true e.value = true
e.window.setTextColor(args.active_fg_bg.fgd) e.w_set_fgd(args.active_fg_bg.fgd)
e.window.setBackgroundColor(args.active_fg_bg.bkg) e.w_set_bkg(args.active_fg_bg.bkg)
draw() draw()
end end
end end
@ -66,8 +66,8 @@ local function push_button(args)
local function show_unpressed() local function show_unpressed()
if e.enabled and args.active_fg_bg ~= nil then if e.enabled and args.active_fg_bg ~= nil then
e.value = false e.value = false
e.window.setTextColor(e.fg_bg.fgd) e.w_set_fgd(e.fg_bg.fgd)
e.window.setBackgroundColor(e.fg_bg.bkg) e.w_set_bkg(e.fg_bg.bkg)
draw() draw()
end end
end end
@ -102,8 +102,8 @@ local function push_button(args)
function e.enable() function e.enable()
if args.dis_fg_bg ~= nil then if args.dis_fg_bg ~= nil then
e.value = false e.value = false
e.window.setTextColor(e.fg_bg.fgd) e.w_set_fgd(e.fg_bg.fgd)
e.window.setBackgroundColor(e.fg_bg.bkg) e.w_set_bkg(e.fg_bg.bkg)
draw() draw()
end end
end end
@ -112,8 +112,8 @@ local function push_button(args)
function e.disable() function e.disable()
if args.dis_fg_bg ~= nil then if args.dis_fg_bg ~= nil then
e.value = false e.value = false
e.window.setTextColor(args.dis_fg_bg.fgd) e.w_set_fgd(args.dis_fg_bg.fgd)
e.window.setBackgroundColor(args.dis_fg_bg.bkg) e.w_set_bkg(args.dis_fg_bg.bkg)
draw() draw()
end end
end end

View File

@ -56,28 +56,28 @@ local function radio_button(args)
for i = 1, #args.options do for i = 1, #args.options do
local opt = args.options[i] ---@type string local opt = args.options[i] ---@type string
e.window.setCursorPos(1, i) e.w_set_cur(1, i)
if e.value == i then if e.value == i then
-- show as selected -- show as selected
e.window.setTextColor(args.radio_colors.color_a) e.w_set_fgd(args.radio_colors.color_a)
e.window.setBackgroundColor(args.radio_bg) e.w_set_bkg(args.radio_bg)
else else
-- show as unselected -- show as unselected
e.window.setTextColor(args.radio_colors.color_b) e.w_set_fgd(args.radio_colors.color_b)
e.window.setBackgroundColor(args.radio_bg) e.w_set_bkg(args.radio_bg)
end end
e.window.write("\x88") e.w_write("\x88")
e.window.setTextColor(args.radio_bg) e.w_set_fgd(args.radio_bg)
e.window.setBackgroundColor(e.fg_bg.bkg) e.w_set_bkg(e.fg_bg.bkg)
e.window.write("\x95") e.w_write("\x95")
-- write button text -- write button text
e.window.setTextColor(e.fg_bg.fgd) e.w_set_fgd(e.fg_bg.fgd)
e.window.setBackgroundColor(e.fg_bg.bkg) e.w_set_bkg(e.fg_bg.bkg)
e.window.write(opt) e.w_write(opt)
end end
end end

View File

@ -52,27 +52,27 @@ local function sidebar(args)
local y = ((i - 1) * 3) + 1 local y = ((i - 1) * 3) + 1
e.window.setCursorPos(1, y) e.w_set_cur(1, y)
if pressed and i == pressed_idx then if pressed and i == pressed_idx then
e.window.setTextColor(e.fg_bg.fgd) e.w_set_fgd(e.fg_bg.fgd)
e.window.setBackgroundColor(e.fg_bg.bkg) e.w_set_bkg(e.fg_bg.bkg)
else else
e.window.setTextColor(tab.color.fgd) e.w_set_fgd(tab.color.fgd)
e.window.setBackgroundColor(tab.color.bkg) e.w_set_bkg(tab.color.bkg)
end end
e.window.write(" ") e.w_write(" ")
e.window.setCursorPos(1, y + 1) e.w_set_cur(1, y + 1)
if e.value == i then if e.value == i then
-- show as selected -- show as selected
e.window.write(" " .. tab.char .. "\x10") e.w_write(" " .. tab.char .. "\x10")
else else
-- show as unselected -- show as unselected
e.window.write(" " .. tab.char .. " ") e.w_write(" " .. tab.char .. " ")
end end
e.window.setCursorPos(1, y + 2) e.w_set_cur(1, y + 2)
e.window.write(" ") e.w_write(" ")
end end
end end

View File

@ -58,17 +58,17 @@ local function spinbox(args)
-- draw the arrows -- draw the arrows
local function draw_arrows(color) local function draw_arrows(color)
e.window.setBackgroundColor(args.arrow_fg_bg.bkg) e.w_set_bkg(args.arrow_fg_bg.bkg)
e.window.setTextColor(color) e.w_set_fgd(color)
e.window.setCursorPos(1, 1) e.w_set_cur(1, 1)
e.window.write(util.strrep("\x1e", wn_prec)) e.w_write(string.rep("\x1e", wn_prec))
e.window.setCursorPos(1, 3) e.w_set_cur(1, 3)
e.window.write(util.strrep("\x1f", wn_prec)) e.w_write(string.rep("\x1f", wn_prec))
if fr_prec > 0 then if fr_prec > 0 then
e.window.setCursorPos(1 + wn_prec, 1) e.w_set_cur(1 + wn_prec, 1)
e.window.write(" " .. util.strrep("\x1e", fr_prec)) e.w_write(" " .. string.rep("\x1e", fr_prec))
e.window.setCursorPos(1 + wn_prec, 3) e.w_set_cur(1 + wn_prec, 3)
e.window.write(" " .. util.strrep("\x1f", fr_prec)) e.w_write(" " .. string.rep("\x1f", fr_prec))
end end
end end
@ -119,10 +119,10 @@ local function spinbox(args)
end end
-- draw -- draw
e.window.setBackgroundColor(e.fg_bg.bkg) e.w_set_bkg(e.fg_bg.bkg)
e.window.setTextColor(e.fg_bg.fgd) e.w_set_fgd(e.fg_bg.fgd)
e.window.setCursorPos(1, 2) e.w_set_cur(1, 2)
e.window.write(util.sprintf(fmt, e.value)) e.w_write(util.sprintf(fmt, e.value))
end end
-- init with the default value -- init with the default value

View File

@ -47,20 +47,20 @@ local function switch_button(args)
local function draw_state() local function draw_state()
if e.value then if e.value then
-- show as pressed -- show as pressed
e.window.setTextColor(args.active_fg_bg.fgd) e.w_set_fgd(args.active_fg_bg.fgd)
e.window.setBackgroundColor(args.active_fg_bg.bkg) e.w_set_bkg(args.active_fg_bg.bkg)
else else
-- show as unpressed -- show as unpressed
e.window.setTextColor(e.fg_bg.fgd) e.w_set_fgd(e.fg_bg.fgd)
e.window.setBackgroundColor(e.fg_bg.bkg) e.w_set_bkg(e.fg_bg.bkg)
end end
-- clear to redraw background -- clear to redraw background
e.window.clear() e.window.clear()
-- write the button text -- write the button text
e.window.setCursorPos(h_pad, v_pad) e.w_set_cur(h_pad, v_pad)
e.window.write(args.text) e.w_write(args.text)
end end
-- initial draw -- initial draw

View File

@ -71,17 +71,17 @@ local function tabbar(args)
for i = 1, #args.tabs do for i = 1, #args.tabs do
local tab = args.tabs[i] ---@type tabbar_tab local tab = args.tabs[i] ---@type tabbar_tab
e.window.setCursorPos(tab._start_x, 1) e.w_set_cur(tab._start_x, 1)
if e.value == i then if e.value == i then
e.window.setTextColor(tab.color.fgd) e.w_set_fgd(tab.color.fgd)
e.window.setBackgroundColor(tab.color.bkg) e.w_set_bkg(tab.color.bkg)
else else
e.window.setTextColor(e.fg_bg.fgd) e.w_set_fgd(e.fg_bg.fgd)
e.window.setBackgroundColor(e.fg_bg.bkg) e.w_set_bkg(e.fg_bg.bkg)
end end
e.window.write(util.pad(tab.name, button_width)) e.w_write(util.pad(tab.name, button_width))
end end
end end

View File

@ -53,17 +53,17 @@ local function alarm_indicator_light(args)
-- called by flasher when enabled -- called by flasher when enabled
local function flash_callback() local function flash_callback()
e.window.setCursorPos(1, 1) e.w_set_cur(1, 1)
if flash_on then if flash_on then
if e.value == 2 then if e.value == 2 then
e.window.blit(" \x95", "0" .. c2, c2 .. e.fg_bg.blit_bkg) e.w_blit(" \x95", "0" .. c2, c2 .. e.fg_bg.blit_bkg)
end end
else else
if e.value == 3 then if e.value == 3 then
e.window.blit(" \x95", "0" .. c3, c3 .. e.fg_bg.blit_bkg) e.w_blit(" \x95", "0" .. c3, c3 .. e.fg_bg.blit_bkg)
else else
e.window.blit(" \x95", "0" .. c1, c1 .. e.fg_bg.blit_bkg) e.w_blit(" \x95", "0" .. c1, c1 .. e.fg_bg.blit_bkg)
end end
end end
@ -76,7 +76,7 @@ local function alarm_indicator_light(args)
local was_off = e.value ~= 2 local was_off = e.value ~= 2
e.value = new_state e.value = new_state
e.window.setCursorPos(1, 1) e.w_set_cur(1, 1)
if args.flash then if args.flash then
if was_off and (new_state == 2) then if was_off and (new_state == 2) then
@ -87,17 +87,17 @@ local function alarm_indicator_light(args)
flasher.stop(flash_callback) flasher.stop(flash_callback)
if new_state == 3 then if new_state == 3 then
e.window.blit(" \x95", "0" .. c3, c3 .. e.fg_bg.blit_bkg) e.w_blit(" \x95", "0" .. c3, c3 .. e.fg_bg.blit_bkg)
else else
e.window.blit(" \x95", "0" .. c1, c1 .. e.fg_bg.blit_bkg) e.w_blit(" \x95", "0" .. c1, c1 .. e.fg_bg.blit_bkg)
end end
end end
elseif new_state == 2 then elseif new_state == 2 then
e.window.blit(" \x95", "0" .. c2, c2 .. e.fg_bg.blit_bkg) e.w_blit(" \x95", "0" .. c2, c2 .. e.fg_bg.blit_bkg)
elseif new_state == 3 then elseif new_state == 3 then
e.window.blit(" \x95", "0" .. c3, c3 .. e.fg_bg.blit_bkg) e.w_blit(" \x95", "0" .. c3, c3 .. e.fg_bg.blit_bkg)
else else
e.window.blit(" \x95", "0" .. c1, c1 .. e.fg_bg.blit_bkg) e.w_blit(" \x95", "0" .. c1, c1 .. e.fg_bg.blit_bkg)
end end
end end
@ -107,7 +107,7 @@ local function alarm_indicator_light(args)
-- write label and initial indicator light -- write label and initial indicator light
e.on_update(1) e.on_update(1)
e.window.write(args.label) e.w_write(args.label)
return e.complete() return e.complete()
end end

View File

@ -47,25 +47,25 @@ local function core_map(args)
-- create coordinate grid and frame -- create coordinate grid and frame
local function draw_frame() local function draw_frame()
e.window.setTextColor(colors.white) e.w_set_fgd(colors.white)
for x = 0, (inner_width - 1) do for x = 0, (inner_width - 1) do
e.window.setCursorPos(x + start_x, 1) e.w_set_cur(x + start_x, 1)
e.window.write(util.sprintf("%X", x)) e.w_write(util.sprintf("%X", x))
end end
for y = 0, (inner_height - 1) do for y = 0, (inner_height - 1) do
e.window.setCursorPos(1, y + start_y) e.w_set_cur(1, y + start_y)
e.window.write(util.sprintf("%X", y)) e.w_write(util.sprintf("%X", y))
end end
-- even out bottom edge -- even out bottom edge
e.window.setTextColor(e.fg_bg.bkg) e.w_set_fgd(e.fg_bg.bkg)
e.window.setBackgroundColor(args.parent.get_fg_bg().bkg) e.w_set_bkg(args.parent.get_fg_bg().bkg)
e.window.setCursorPos(1, e.frame.h) e.w_set_cur(1, e.frame.h)
e.window.write(util.strrep("\x8f", e.frame.w)) e.w_write(string.rep("\x8f", e.frame.w))
e.window.setTextColor(e.fg_bg.fgd) e.w_set_fgd(e.fg_bg.fgd)
e.window.setBackgroundColor(e.fg_bg.bkg) e.w_set_bkg(e.fg_bg.bkg)
end end
-- draw the core -- draw the core
@ -102,13 +102,13 @@ local function core_map(args)
-- draw pattern -- draw pattern
for y = start_y, inner_height + (start_y - 1) do for y = start_y, inner_height + (start_y - 1) do
e.window.setCursorPos(start_x, y) e.w_set_cur(start_x, y)
for _ = 1, inner_width do for _ = 1, inner_width do
if alternator then if alternator then
i = i + 1 i = i + 1
e.window.blit("\x07", text_c, back_c) e.w_blit("\x07", text_c, back_c)
else else
e.window.blit("\x07", "7", "8") e.w_blit("\x07", "7", "8")
end end
alternator = not alternator alternator = not alternator

View File

@ -37,12 +37,12 @@ local function data(args)
-- label color -- label color
if args.lu_colors ~= nil then if args.lu_colors ~= nil then
e.window.setTextColor(args.lu_colors.color_a) e.w_set_fgd(args.lu_colors.color_a)
end end
-- write label -- write label
e.window.setCursorPos(1, 1) e.w_set_cur(1, 1)
e.window.write(args.label) e.w_write(args.label)
local value_color = e.fg_bg.fgd local value_color = e.fg_bg.fgd
local label_len = string.len(args.label) local label_len = string.len(args.label)
@ -60,25 +60,25 @@ local function data(args)
e.value = value e.value = value
-- clear old data and label -- clear old data and label
e.window.setCursorPos(data_start, 1) e.w_set_cur(data_start, 1)
e.window.write(util.spaces(clear_width)) e.w_write(util.spaces(clear_width))
-- write data -- write data
local data_str = util.sprintf(args.format, value) local data_str = util.sprintf(args.format, value)
e.window.setCursorPos(data_start, 1) e.w_set_cur(data_start, 1)
e.window.setTextColor(value_color) e.w_set_fgd(value_color)
if args.commas then if args.commas then
e.window.write(util.comma_format(data_str)) e.w_write(util.comma_format(data_str))
else else
e.window.write(data_str) e.w_write(data_str)
end end
-- write label -- write label
if args.unit ~= nil then if args.unit ~= nil then
if args.lu_colors ~= nil then if args.lu_colors ~= nil then
e.window.setTextColor(args.lu_colors.color_b) e.w_set_fgd(args.lu_colors.color_b)
end end
e.window.write(" " .. args.unit) e.w_write(" " .. args.unit)
end end
end end

View File

@ -87,16 +87,16 @@ local function hbar(args)
-- draw bar -- draw bar
for y = 1, e.frame.h do for y = 1, e.frame.h do
e.window.setCursorPos(1, y) e.w_set_cur(1, y)
-- intentionally swapped fgd/bkg since we use spaces as fill, but they are the opposite -- intentionally swapped fgd/bkg since we use spaces as fill, but they are the opposite
e.window.blit(spaces, bkg, fgd) e.w_blit(spaces, bkg, fgd)
end end
end end
-- update percentage -- update percentage
if args.show_percent then if args.show_percent then
e.window.setCursorPos(bar_width + 2, math.max(1, math.ceil(e.frame.h / 2))) e.w_set_cur(bar_width + 2, math.max(1, math.ceil(e.frame.h / 2)))
e.window.write(util.sprintf("%3.0f%%", fraction * 100)) e.w_write(util.sprintf("%3.0f%%", fraction * 100))
end end
end end

View File

@ -1,7 +1,5 @@
-- Icon Indicator Graphics Element -- Icon Indicator Graphics Element
local util = require("scada-common.util")
local element = require("graphics.element") local element = require("graphics.element")
---@class icon_sym_color ---@class icon_sym_color
@ -44,22 +42,22 @@ local function icon(args)
table.insert(state_blit_cmds, { table.insert(state_blit_cmds, {
text = " " .. sym_color.symbol .. " ", text = " " .. sym_color.symbol .. " ",
fgd = util.strrep(sym_color.color.blit_fgd, 3), fgd = string.rep(sym_color.color.blit_fgd, 3),
bkg = util.strrep(sym_color.color.blit_bkg, 3) bkg = string.rep(sym_color.color.blit_bkg, 3)
}) })
end end
-- write label and initial indicator light -- write label and initial indicator light
e.window.setCursorPos(5, 1) e.w_set_cur(5, 1)
e.window.write(args.label) e.w_write(args.label)
-- on state change -- on state change
---@param new_state integer indicator state ---@param new_state integer indicator state
function e.on_update(new_state) function e.on_update(new_state)
local blit_cmd = state_blit_cmds[new_state] local blit_cmd = state_blit_cmds[new_state]
e.value = new_state e.value = new_state
e.window.setCursorPos(1, 1) e.w_set_cur(1, 1)
e.window.blit(blit_cmd.text, blit_cmd.fgd, blit_cmd.bkg) e.w_blit(blit_cmd.text, blit_cmd.fgd, blit_cmd.bkg)
end end
-- set indicator state -- set indicator state

View File

@ -44,12 +44,12 @@ local function indicator_led(args)
-- called by flasher when enabled -- called by flasher when enabled
local function flash_callback() local function flash_callback()
e.window.setCursorPos(1, 1) e.w_set_cur(1, 1)
if flash_on then if flash_on then
e.window.blit("\x8c", args.colors.blit_a, e.fg_bg.blit_bkg) e.w_blit("\x8c", args.colors.blit_a, e.fg_bg.blit_bkg)
else else
e.window.blit("\x8c", args.colors.blit_b, e.fg_bg.blit_bkg) e.w_blit("\x8c", args.colors.blit_b, e.fg_bg.blit_bkg)
end end
flash_on = not flash_on flash_on = not flash_on
@ -61,8 +61,8 @@ local function indicator_led(args)
flash_on = true flash_on = true
flasher.start(flash_callback, args.period) flasher.start(flash_callback, args.period)
else else
e.window.setCursorPos(1, 1) e.w_set_cur(1, 1)
e.window.blit("\x8c", args.colors.blit_a, e.fg_bg.blit_bkg) e.w_blit("\x8c", args.colors.blit_a, e.fg_bg.blit_bkg)
end end
end end
@ -73,8 +73,8 @@ local function indicator_led(args)
flasher.stop(flash_callback) flasher.stop(flash_callback)
end end
e.window.setCursorPos(1, 1) e.w_set_cur(1, 1)
e.window.blit("\x8c", args.colors.blit_b, e.fg_bg.blit_bkg) e.w_blit("\x8c", args.colors.blit_b, e.fg_bg.blit_bkg)
end end
-- on state change -- on state change
@ -91,8 +91,8 @@ local function indicator_led(args)
-- write label and initial indicator light -- write label and initial indicator light
e.on_update(false) e.on_update(false)
if string.len(args.label) > 0 then if string.len(args.label) > 0 then
e.window.setCursorPos(3, 1) e.w_set_cur(3, 1)
e.window.write(args.label) e.w_write(args.label)
end end
return e.complete() return e.complete()

View File

@ -56,16 +56,16 @@ local function indicator_led_pair(args)
-- called by flasher when enabled -- called by flasher when enabled
local function flash_callback() local function flash_callback()
e.window.setCursorPos(1, 1) e.w_set_cur(1, 1)
if flash_on then if flash_on then
if e.value == 2 then if e.value == 2 then
e.window.blit("\x8c", c1, e.fg_bg.blit_bkg) e.w_blit("\x8c", c1, e.fg_bg.blit_bkg)
elseif e.value == 3 then elseif e.value == 3 then
e.window.blit("\x8c", c2, e.fg_bg.blit_bkg) e.w_blit("\x8c", c2, e.fg_bg.blit_bkg)
end end
else else
e.window.blit("\x8c", co, e.fg_bg.blit_bkg) e.w_blit("\x8c", co, e.fg_bg.blit_bkg)
end end
flash_on = not flash_on flash_on = not flash_on
@ -77,7 +77,7 @@ local function indicator_led_pair(args)
local was_off = e.value <= 1 local was_off = e.value <= 1
e.value = new_state e.value = new_state
e.window.setCursorPos(1, 1) e.w_set_cur(1, 1)
if args.flash then if args.flash then
if was_off and (new_state > 1) then if was_off and (new_state > 1) then
@ -87,14 +87,14 @@ local function indicator_led_pair(args)
flash_on = false flash_on = false
flasher.stop(flash_callback) flasher.stop(flash_callback)
e.window.blit("\x8c", co, e.fg_bg.blit_bkg) e.w_blit("\x8c", co, e.fg_bg.blit_bkg)
end end
elseif new_state == 2 then elseif new_state == 2 then
e.window.blit("\x8c", c1, e.fg_bg.blit_bkg) e.w_blit("\x8c", c1, e.fg_bg.blit_bkg)
elseif new_state == 3 then elseif new_state == 3 then
e.window.blit("\x8c", c2, e.fg_bg.blit_bkg) e.w_blit("\x8c", c2, e.fg_bg.blit_bkg)
else else
e.window.blit("\x8c", co, e.fg_bg.blit_bkg) e.w_blit("\x8c", co, e.fg_bg.blit_bkg)
end end
end end
@ -105,8 +105,8 @@ local function indicator_led_pair(args)
-- write label and initial indicator light -- write label and initial indicator light
e.on_update(1) e.on_update(1)
if string.len(args.label) > 0 then if string.len(args.label) > 0 then
e.window.setCursorPos(3, 1) e.w_set_cur(3, 1)
e.window.write(args.label) e.w_write(args.label)
end end
return e.complete() return e.complete()

View File

@ -37,9 +37,9 @@ local function indicator_led_rgb(args)
---@param new_state integer indicator state ---@param new_state integer indicator state
function e.on_update(new_state) function e.on_update(new_state)
e.value = new_state e.value = new_state
e.window.setCursorPos(1, 1) e.w_set_cur(1, 1)
if type(args.colors[new_state]) == "number" then if type(args.colors[new_state]) == "number" then
e.window.blit("\x8c", colors.toBlit(args.colors[new_state]), e.fg_bg.blit_bkg) e.w_blit("\x8c", colors.toBlit(args.colors[new_state]), e.fg_bg.blit_bkg)
end end
end end
@ -50,8 +50,8 @@ local function indicator_led_rgb(args)
-- write label and initial indicator light -- write label and initial indicator light
e.on_update(1) e.on_update(1)
if string.len(args.label) > 0 then if string.len(args.label) > 0 then
e.window.setCursorPos(3, 1) e.w_set_cur(3, 1)
e.window.write(args.label) e.w_write(args.label)
end end
return e.complete() return e.complete()

View File

@ -44,12 +44,12 @@ local function indicator_light(args)
-- called by flasher when enabled -- called by flasher when enabled
local function flash_callback() local function flash_callback()
e.window.setCursorPos(1, 1) e.w_set_cur(1, 1)
if flash_on then if flash_on then
e.window.blit(" \x95", "0" .. args.colors.blit_a, args.colors.blit_a .. e.fg_bg.blit_bkg) e.w_blit(" \x95", "0" .. args.colors.blit_a, args.colors.blit_a .. e.fg_bg.blit_bkg)
else else
e.window.blit(" \x95", "0" .. args.colors.blit_b, args.colors.blit_b .. e.fg_bg.blit_bkg) e.w_blit(" \x95", "0" .. args.colors.blit_b, args.colors.blit_b .. e.fg_bg.blit_bkg)
end end
flash_on = not flash_on flash_on = not flash_on
@ -61,8 +61,8 @@ local function indicator_light(args)
flash_on = true flash_on = true
flasher.start(flash_callback, args.period) flasher.start(flash_callback, args.period)
else else
e.window.setCursorPos(1, 1) e.w_set_cur(1, 1)
e.window.blit(" \x95", "0" .. args.colors.blit_a, args.colors.blit_a .. e.fg_bg.blit_bkg) e.w_blit(" \x95", "0" .. args.colors.blit_a, args.colors.blit_a .. e.fg_bg.blit_bkg)
end end
end end
@ -73,8 +73,8 @@ local function indicator_light(args)
flasher.stop(flash_callback) flasher.stop(flash_callback)
end end
e.window.setCursorPos(1, 1) e.w_set_cur(1, 1)
e.window.blit(" \x95", "0" .. args.colors.blit_b, args.colors.blit_b .. e.fg_bg.blit_bkg) e.w_blit(" \x95", "0" .. args.colors.blit_b, args.colors.blit_b .. e.fg_bg.blit_bkg)
end end
-- on state change -- on state change
@ -90,8 +90,8 @@ local function indicator_light(args)
-- write label and initial indicator light -- write label and initial indicator light
e.on_update(false) e.on_update(false)
e.window.setCursorPos(3, 1) e.w_set_cur(3, 1)
e.window.write(args.label) e.w_write(args.label)
return e.complete() return e.complete()
end end

View File

@ -34,12 +34,12 @@ local function power(args)
-- label color -- label color
if args.lu_colors ~= nil then if args.lu_colors ~= nil then
e.window.setTextColor(args.lu_colors.color_a) e.w_set_fgd(args.lu_colors.color_a)
end end
-- write label -- write label
e.window.setCursorPos(1, 1) e.w_set_cur(1, 1)
e.window.write(args.label) e.w_write(args.label)
local data_start = string.len(args.label) + 2 local data_start = string.len(args.label) + 2
if string.len(args.label) == 0 then data_start = 1 end if string.len(args.label) == 0 then data_start = 1 end
@ -52,13 +52,13 @@ local function power(args)
local data_str, unit = util.power_format(value, false, args.format) local data_str, unit = util.power_format(value, false, args.format)
-- write data -- write data
e.window.setCursorPos(data_start, 1) e.w_set_cur(data_start, 1)
e.window.setTextColor(e.fg_bg.fgd) e.w_set_fgd(e.fg_bg.fgd)
e.window.write(util.comma_format(data_str)) e.w_write(util.comma_format(data_str))
-- write unit -- write unit
if args.lu_colors ~= nil then if args.lu_colors ~= nil then
e.window.setTextColor(args.lu_colors.color_b) e.w_set_fgd(args.lu_colors.color_b)
end end
-- append per tick if rate is set -- append per tick if rate is set
@ -70,7 +70,7 @@ local function power(args)
if unit == "FE" then unit = "FE " end if unit == "FE" then unit = "FE " end
end end
e.window.write(" " .. unit) e.w_write(" " .. unit)
end end
-- set the value -- set the value

View File

@ -36,12 +36,12 @@ local function rad(args)
-- label color -- label color
if args.lu_colors ~= nil then if args.lu_colors ~= nil then
e.window.setTextColor(args.lu_colors.color_a) e.w_set_fgd(args.lu_colors.color_a)
end end
-- write label -- write label
e.window.setCursorPos(1, 1) e.w_set_cur(1, 1)
e.window.write(args.label) e.w_write(args.label)
local label_len = string.len(args.label) local label_len = string.len(args.label)
local data_start = 1 local data_start = 1
@ -58,24 +58,24 @@ local function rad(args)
e.value = value.radiation e.value = value.radiation
-- clear old data and label -- clear old data and label
e.window.setCursorPos(data_start, 1) e.w_set_cur(data_start, 1)
e.window.write(util.spaces(clear_width)) e.w_write(util.spaces(clear_width))
-- write data -- write data
local data_str = util.sprintf(args.format, e.value) local data_str = util.sprintf(args.format, e.value)
e.window.setCursorPos(data_start, 1) e.w_set_cur(data_start, 1)
e.window.setTextColor(e.fg_bg.fgd) e.w_set_fgd(e.fg_bg.fgd)
if args.commas then if args.commas then
e.window.write(util.comma_format(data_str)) e.w_write(util.comma_format(data_str))
else else
e.window.write(data_str) e.w_write(data_str)
end end
-- write unit -- write unit
if args.lu_colors ~= nil then if args.lu_colors ~= nil then
e.window.setTextColor(args.lu_colors.color_b) e.w_set_fgd(args.lu_colors.color_b)
end end
e.window.write(" " .. value.unit) e.w_write(" " .. value.unit)
end end
-- set the value -- set the value

View File

@ -51,8 +51,8 @@ local function state_indicator(args)
table.insert(state_blit_cmds, { table.insert(state_blit_cmds, {
text = text, text = text,
fgd = util.strrep(state_def.color.blit_fgd, string.len(text)), fgd = string.rep(state_def.color.blit_fgd, string.len(text)),
bkg = util.strrep(state_def.color.blit_bkg, string.len(text)) bkg = string.rep(state_def.color.blit_bkg, string.len(text))
}) })
end end
@ -64,8 +64,8 @@ local function state_indicator(args)
function e.on_update(new_state) function e.on_update(new_state)
local blit_cmd = state_blit_cmds[new_state] local blit_cmd = state_blit_cmds[new_state]
e.value = new_state e.value = new_state
e.window.setCursorPos(1, 1) e.w_set_cur(1, 1)
e.window.blit(blit_cmd.text, blit_cmd.fgd, blit_cmd.bkg) e.w_blit(blit_cmd.text, blit_cmd.fgd, blit_cmd.bkg)
end end
-- set indicator state -- set indicator state

View File

@ -56,16 +56,16 @@ local function tristate_indicator_light(args)
-- called by flasher when enabled -- called by flasher when enabled
local function flash_callback() local function flash_callback()
e.window.setCursorPos(1, 1) e.w_set_cur(1, 1)
if flash_on then if flash_on then
if e.value == 2 then if e.value == 2 then
e.window.blit(" \x95", "0" .. c2, c2 .. e.fg_bg.blit_bkg) e.w_blit(" \x95", "0" .. c2, c2 .. e.fg_bg.blit_bkg)
elseif e.value == 3 then elseif e.value == 3 then
e.window.blit(" \x95", "0" .. c3, c3 .. e.fg_bg.blit_bkg) e.w_blit(" \x95", "0" .. c3, c3 .. e.fg_bg.blit_bkg)
end end
else else
e.window.blit(" \x95", "0" .. c1, c1 .. e.fg_bg.blit_bkg) e.w_blit(" \x95", "0" .. c1, c1 .. e.fg_bg.blit_bkg)
end end
flash_on = not flash_on flash_on = not flash_on
@ -77,7 +77,7 @@ local function tristate_indicator_light(args)
local was_off = e.value <= 1 local was_off = e.value <= 1
e.value = new_state e.value = new_state
e.window.setCursorPos(1, 1) e.w_set_cur(1, 1)
if args.flash then if args.flash then
if was_off and (new_state > 1) then if was_off and (new_state > 1) then
@ -87,14 +87,14 @@ local function tristate_indicator_light(args)
flash_on = false flash_on = false
flasher.stop(flash_callback) flasher.stop(flash_callback)
e.window.blit(" \x95", "0" .. c1, c1 .. e.fg_bg.blit_bkg) e.w_blit(" \x95", "0" .. c1, c1 .. e.fg_bg.blit_bkg)
end end
elseif new_state == 2 then elseif new_state == 2 then
e.window.blit(" \x95", "0" .. c2, c2 .. e.fg_bg.blit_bkg) e.w_blit(" \x95", "0" .. c2, c2 .. e.fg_bg.blit_bkg)
elseif new_state == 3 then elseif new_state == 3 then
e.window.blit(" \x95", "0" .. c3, c3 .. e.fg_bg.blit_bkg) e.w_blit(" \x95", "0" .. c3, c3 .. e.fg_bg.blit_bkg)
else else
e.window.blit(" \x95", "0" .. c1, c1 .. e.fg_bg.blit_bkg) e.w_blit(" \x95", "0" .. c1, c1 .. e.fg_bg.blit_bkg)
end end
end end
@ -104,7 +104,7 @@ local function tristate_indicator_light(args)
-- write label and initial indicator light -- write label and initial indicator light
e.on_update(1) e.on_update(1)
e.window.write(args.label) e.w_write(args.label)
return e.complete() return e.complete()
end end

View File

@ -27,11 +27,11 @@ local function vbar(args)
local e = element.new(args) local e = element.new(args)
-- blit strings -- blit strings
local fgd = util.strrep(e.fg_bg.blit_fgd, e.frame.w) local fgd = string.rep(e.fg_bg.blit_fgd, e.frame.w)
local bkg = util.strrep(e.fg_bg.blit_bkg, e.frame.w) local bkg = string.rep(e.fg_bg.blit_bkg, e.frame.w)
local spaces = util.spaces(e.frame.w) local spaces = util.spaces(e.frame.w)
local one_third = util.strrep("\x8f", e.frame.w) local one_third = string.rep("\x8f", e.frame.w)
local two_thirds = util.strrep("\x83", e.frame.w) local two_thirds = string.rep("\x83", e.frame.w)
-- handle data changes -- handle data changes
---@param fraction number 0.0 to 1.0 ---@param fraction number 0.0 to 1.0
@ -56,28 +56,28 @@ local function vbar(args)
local y = e.frame.h local y = e.frame.h
-- start at base of vertical bar -- start at base of vertical bar
e.window.setCursorPos(1, y) e.w_set_cur(1, y)
-- fill percentage -- fill percentage
for _ = 1, num_bars / 3 do for _ = 1, num_bars / 3 do
e.window.blit(spaces, bkg, fgd) e.w_blit(spaces, bkg, fgd)
y = y - 1 y = y - 1
e.window.setCursorPos(1, y) e.w_set_cur(1, y)
end end
-- add fractional bar if needed -- add fractional bar if needed
if num_bars % 3 == 1 then if num_bars % 3 == 1 then
e.window.blit(one_third, bkg, fgd) e.w_blit(one_third, bkg, fgd)
y = y - 1 y = y - 1
elseif num_bars % 3 == 2 then elseif num_bars % 3 == 2 then
e.window.blit(two_thirds, bkg, fgd) e.w_blit(two_thirds, bkg, fgd)
y = y - 1 y = y - 1
end end
-- fill the rest blank -- fill the rest blank
while y > 0 do while y > 0 do
e.window.setCursorPos(1, y) e.w_set_cur(1, y)
e.window.blit(spaces, fgd, bkg) e.w_blit(spaces, fgd, bkg)
y = y - 1 y = y - 1
end end
end end
@ -86,8 +86,8 @@ local function vbar(args)
-- change bar color -- change bar color
---@param fg_bg cpair new bar colors ---@param fg_bg cpair new bar colors
function e.recolor(fg_bg) function e.recolor(fg_bg)
fgd = util.strrep(fg_bg.blit_fgd, e.frame.w) fgd = string.rep(fg_bg.blit_fgd, e.frame.w)
bkg = util.strrep(fg_bg.blit_bkg, e.frame.w) bkg = string.rep(fg_bg.blit_bkg, e.frame.w)
-- re-draw -- re-draw
last_num_bars = 0 last_num_bars = 0

View File

@ -63,34 +63,34 @@ local function listbox(args)
-- draw up/down arrows -- draw up/down arrows
if pressed_arrow == 1 then if pressed_arrow == 1 then
e.window.setTextColor(active_fg_bg.fgd) e.w_set_fgd(active_fg_bg.fgd)
e.window.setBackgroundColor(active_fg_bg.bkg) e.w_set_bkg(active_fg_bg.bkg)
e.window.setCursorPos(e.frame.w, 1) e.w_set_cur(e.frame.w, 1)
e.window.write("\x1e") e.w_write("\x1e")
e.window.setTextColor(nav_fg_bg.fgd) e.w_set_fgd(nav_fg_bg.fgd)
e.window.setBackgroundColor(nav_fg_bg.bkg) e.w_set_bkg(nav_fg_bg.bkg)
e.window.setCursorPos(e.frame.w, e.frame.h) e.w_set_cur(e.frame.w, e.frame.h)
e.window.write("\x1f") e.w_write("\x1f")
elseif pressed_arrow == -1 then elseif pressed_arrow == -1 then
e.window.setTextColor(nav_fg_bg.fgd) e.w_set_fgd(nav_fg_bg.fgd)
e.window.setBackgroundColor(nav_fg_bg.bkg) e.w_set_bkg(nav_fg_bg.bkg)
e.window.setCursorPos(e.frame.w, 1) e.w_set_cur(e.frame.w, 1)
e.window.write("\x1e") e.w_write("\x1e")
e.window.setTextColor(active_fg_bg.fgd) e.w_set_fgd(active_fg_bg.fgd)
e.window.setBackgroundColor(active_fg_bg.bkg) e.w_set_bkg(active_fg_bg.bkg)
e.window.setCursorPos(e.frame.w, e.frame.h) e.w_set_cur(e.frame.w, e.frame.h)
e.window.write("\x1f") e.w_write("\x1f")
else else
e.window.setTextColor(nav_fg_bg.fgd) e.w_set_fgd(nav_fg_bg.fgd)
e.window.setBackgroundColor(nav_fg_bg.bkg) e.w_set_bkg(nav_fg_bg.bkg)
e.window.setCursorPos(e.frame.w, 1) e.w_set_cur(e.frame.w, 1)
e.window.write("\x1e") e.w_write("\x1e")
e.window.setCursorPos(e.frame.w, e.frame.h) e.w_set_cur(e.frame.w, e.frame.h)
e.window.write("\x1f") e.w_write("\x1f")
end end
e.window.setTextColor(e.fg_bg.fgd) e.w_set_fgd(e.fg_bg.fgd)
e.window.setBackgroundColor(e.fg_bg.bkg) e.w_set_bkg(e.fg_bg.bkg)
end end
-- render the scroll bar and re-cacluate height & bounds -- render the scroll bar and re-cacluate height & bounds
@ -115,23 +115,23 @@ local function listbox(args)
for i = 2, e.frame.h - 1 do for i = 2, e.frame.h - 1 do
if (i >= offset and i < (bar_height + offset)) and (bar_height ~= max_bar_height) then if (i >= offset and i < (bar_height + offset)) and (bar_height ~= max_bar_height) then
if args.nav_fg_bg ~= nil then if args.nav_fg_bg ~= nil then
e.window.setBackgroundColor(args.nav_fg_bg.fgd) e.w_set_bkg(args.nav_fg_bg.fgd)
else else
e.window.setBackgroundColor(e.fg_bg.fgd) e.w_set_bkg(e.fg_bg.fgd)
end end
else else
if args.nav_fg_bg ~= nil then if args.nav_fg_bg ~= nil then
e.window.setBackgroundColor(args.nav_fg_bg.bkg) e.w_set_bkg(args.nav_fg_bg.bkg)
else else
e.window.setBackgroundColor(e.fg_bg.bkg) e.w_set_bkg(e.fg_bg.bkg)
end end
end end
e.window.setCursorPos(e.frame.w, i) e.w_set_cur(e.frame.w, i)
e.window.write(" ") e.w_write(" ")
end end
e.window.setBackgroundColor(e.fg_bg.bkg) e.w_set_bkg(e.fg_bg.bkg)
end end
-- update item y positions and move elements -- update item y positions and move elements

View File

@ -73,7 +73,7 @@ local function pipenet(args)
y_step = util.trinary(pipe.y1 == pipe.y2, 0, y_step) y_step = util.trinary(pipe.y1 == pipe.y2, 0, y_step)
end end
e.window.setCursorPos(x, y) e.w_set_cur(x, y)
local c = core.cpair(pipe.color, e.fg_bg.bkg) local c = core.cpair(pipe.color, e.fg_bg.bkg)
@ -84,24 +84,24 @@ local function pipenet(args)
if i == pipe.w then if i == pipe.w then
-- corner -- corner
if y_step > 0 then if y_step > 0 then
e.window.blit("\x93", c.blit_bkg, c.blit_fgd) e.w_blit("\x93", c.blit_bkg, c.blit_fgd)
else else
e.window.blit("\x8e", c.blit_fgd, c.blit_bkg) e.w_blit("\x8e", c.blit_fgd, c.blit_bkg)
end end
else else
e.window.blit("\x8c", c.blit_fgd, c.blit_bkg) e.w_blit("\x8c", c.blit_fgd, c.blit_bkg)
end end
else else
if i == pipe.w and y_step > 0 then if i == pipe.w and y_step > 0 then
-- corner -- corner
e.window.blit(" ", c.blit_bkg, c.blit_fgd) e.w_blit(" ", c.blit_bkg, c.blit_fgd)
else else
e.window.blit("\x8f", c.blit_fgd, c.blit_bkg) e.w_blit("\x8f", c.blit_fgd, c.blit_bkg)
end end
end end
x = x + x_step x = x + x_step
e.window.setCursorPos(x, y) e.w_set_cur(x, y)
end end
-- back up one -- back up one
@ -109,12 +109,12 @@ local function pipenet(args)
for _ = 1, pipe.h - 1 do for _ = 1, pipe.h - 1 do
y = y + y_step y = y + y_step
e.window.setCursorPos(x, y) e.w_set_cur(x, y)
if pipe.thin then if pipe.thin then
e.window.blit("\x95", c.blit_bkg, c.blit_fgd) e.w_blit("\x95", c.blit_bkg, c.blit_fgd)
else else
e.window.blit(" ", c.blit_bkg, c.blit_fgd) e.w_blit(" ", c.blit_bkg, c.blit_fgd)
end end
end end
else else
@ -124,26 +124,26 @@ local function pipenet(args)
if i == pipe.h then if i == pipe.h then
-- corner -- corner
if y_step < 0 then if y_step < 0 then
e.window.blit("\x97", c.blit_bkg, c.blit_fgd) e.w_blit("\x97", c.blit_bkg, c.blit_fgd)
elseif y_step > 0 then elseif y_step > 0 then
e.window.blit("\x8d", c.blit_fgd, c.blit_bkg) e.w_blit("\x8d", c.blit_fgd, c.blit_bkg)
else else
e.window.blit("\x8c", c.blit_fgd, c.blit_bkg) e.w_blit("\x8c", c.blit_fgd, c.blit_bkg)
end end
else else
e.window.blit("\x95", c.blit_fgd, c.blit_bkg) e.w_blit("\x95", c.blit_fgd, c.blit_bkg)
end end
else else
if i == pipe.h and y_step < 0 then if i == pipe.h and y_step < 0 then
-- corner -- corner
e.window.blit("\x83", c.blit_bkg, c.blit_fgd) e.w_blit("\x83", c.blit_bkg, c.blit_fgd)
else else
e.window.blit(" ", c.blit_bkg, c.blit_fgd) e.w_blit(" ", c.blit_bkg, c.blit_fgd)
end end
end end
y = y + y_step y = y + y_step
e.window.setCursorPos(x, y) e.w_set_cur(x, y)
end end
-- back up one -- back up one
@ -151,12 +151,12 @@ local function pipenet(args)
for _ = 1, pipe.w - 1 do for _ = 1, pipe.w - 1 do
x = x + x_step x = x + x_step
e.window.setCursorPos(x, y) e.w_set_cur(x, y)
if pipe.thin then if pipe.thin then
e.window.blit("\x8c", c.blit_fgd, c.blit_bkg) e.w_blit("\x8c", c.blit_fgd, c.blit_bkg)
else else
e.window.blit("\x83", c.blit_bkg, c.blit_fgd) e.w_blit("\x83", c.blit_bkg, c.blit_fgd)
end end
end end
end end
@ -298,12 +298,12 @@ local function pipenet(args)
end end
end end
e.window.setCursorPos(x, y) e.w_set_cur(x, y)
if invert then if invert then
e.window.blit(char, entry.bg, entry.fg) e.w_blit(char, entry.bg, entry.fg)
else else
e.window.blit(char, entry.fg, entry.bg) e.w_blit(char, entry.fg, entry.bg)
end end
end end
end end

View File

@ -56,7 +56,7 @@ local function rectangle(args)
-- draw bordered box if requested -- draw bordered box if requested
-- element constructor will have drawn basic colored rectangle regardless -- element constructor will have drawn basic colored rectangle regardless
if args.border ~= nil then if args.border ~= nil then
e.window.setCursorPos(1, 1) e.w_set_cur(1, 1)
local border_width = offset_x local border_width = offset_x
local border_height = offset_y local border_height = offset_y
@ -70,45 +70,45 @@ local function rectangle(args)
-- form the basic line strings and top/bottom blit strings -- form the basic line strings and top/bottom blit strings
local spaces = util.spaces(e.frame.w) local spaces = util.spaces(e.frame.w)
local blit_fg = util.strrep(e.fg_bg.blit_fgd, e.frame.w) local blit_fg = string.rep(e.fg_bg.blit_fgd, e.frame.w)
local blit_fg_sides = blit_fg local blit_fg_sides = blit_fg
local blit_bg_sides = "" local blit_bg_sides = ""
local blit_bg_top_bot = util.strrep(border_blit, e.frame.w) local blit_bg_top_bot = string.rep(border_blit, e.frame.w)
-- partial bars -- partial bars
local p_a, p_b, p_s local p_a, p_b, p_s
if args.thin == true then if args.thin == true then
if args.even_inner == true then if args.even_inner == true then
p_a = "\x9c" .. util.strrep("\x8c", inner_width) .. "\x93" p_a = "\x9c" .. string.rep("\x8c", inner_width) .. "\x93"
p_b = "\x8d" .. util.strrep("\x8c", inner_width) .. "\x8e" p_b = "\x8d" .. string.rep("\x8c", inner_width) .. "\x8e"
else else
p_a = "\x97" .. util.strrep("\x83", inner_width) .. "\x94" p_a = "\x97" .. string.rep("\x83", inner_width) .. "\x94"
p_b = "\x8a" .. util.strrep("\x8f", inner_width) .. "\x85" p_b = "\x8a" .. string.rep("\x8f", inner_width) .. "\x85"
end end
p_s = "\x95" .. util.spaces(inner_width) .. "\x95" p_s = "\x95" .. util.spaces(inner_width) .. "\x95"
else else
if args.even_inner == true then if args.even_inner == true then
p_a = util.strrep("\x83", inner_width + width_x2) p_a = string.rep("\x83", inner_width + width_x2)
p_b = util.strrep("\x8f", inner_width + width_x2) p_b = string.rep("\x8f", inner_width + width_x2)
else else
p_a = util.spaces(border_width) .. util.strrep("\x8f", inner_width) .. util.spaces(border_width) p_a = util.spaces(border_width) .. string.rep("\x8f", inner_width) .. util.spaces(border_width)
p_b = util.spaces(border_width) .. util.strrep("\x83", inner_width) .. util.spaces(border_width) p_b = util.spaces(border_width) .. string.rep("\x83", inner_width) .. util.spaces(border_width)
end end
p_s = spaces p_s = spaces
end end
local p_inv_fg = util.strrep(border_blit, border_width) .. util.strrep(e.fg_bg.blit_bkg, inner_width) .. local p_inv_fg = string.rep(border_blit, border_width) .. string.rep(e.fg_bg.blit_bkg, inner_width) ..
util.strrep(border_blit, border_width) string.rep(border_blit, border_width)
local p_inv_bg = util.strrep(e.fg_bg.blit_bkg, border_width) .. util.strrep(border_blit, inner_width) .. local p_inv_bg = string.rep(e.fg_bg.blit_bkg, border_width) .. string.rep(border_blit, inner_width) ..
util.strrep(e.fg_bg.blit_bkg, border_width) string.rep(e.fg_bg.blit_bkg, border_width)
if args.thin == true then if args.thin == true then
p_inv_fg = e.fg_bg.blit_bkg .. util.strrep(e.fg_bg.blit_bkg, inner_width) .. util.strrep(border_blit, border_width) p_inv_fg = e.fg_bg.blit_bkg .. string.rep(e.fg_bg.blit_bkg, inner_width) .. string.rep(border_blit, border_width)
p_inv_bg = border_blit .. util.strrep(border_blit, inner_width) .. util.strrep(e.fg_bg.blit_bkg, border_width) p_inv_bg = border_blit .. string.rep(border_blit, inner_width) .. string.rep(e.fg_bg.blit_bkg, border_width)
blit_fg_sides = border_blit .. util.strrep(e.fg_bg.blit_bkg, inner_width) .. e.fg_bg.blit_bkg blit_fg_sides = border_blit .. string.rep(e.fg_bg.blit_bkg, inner_width) .. e.fg_bg.blit_bkg
end end
-- form the body blit strings (sides are border, inside is normal) -- form the body blit strings (sides are border, inside is normal)
@ -127,28 +127,28 @@ local function rectangle(args)
-- draw rectangle with borders -- draw rectangle with borders
for y = 1, e.frame.h do for y = 1, e.frame.h do
e.window.setCursorPos(1, y) e.w_set_cur(1, y)
-- top border -- top border
if y <= border_height then if y <= border_height then
-- partial pixel fill -- partial pixel fill
if args.border.even and y == border_height then if args.border.even and y == border_height then
if args.thin == true then if args.thin == true then
e.window.blit(p_a, p_inv_bg, p_inv_fg) e.w_blit(p_a, p_inv_bg, p_inv_fg)
else else
local _fg = util.trinary(args.even_inner == true, util.strrep(e.fg_bg.blit_bkg, e.frame.w), p_inv_bg) local _fg = util.trinary(args.even_inner == true, string.rep(e.fg_bg.blit_bkg, e.frame.w), p_inv_bg)
local _bg = util.trinary(args.even_inner == true, blit_bg_top_bot, p_inv_fg) local _bg = util.trinary(args.even_inner == true, blit_bg_top_bot, p_inv_fg)
if width_x2 % 3 == 1 then if width_x2 % 3 == 1 then
e.window.blit(p_b, _fg, _bg) e.w_blit(p_b, _fg, _bg)
elseif width_x2 % 3 == 2 then elseif width_x2 % 3 == 2 then
e.window.blit(p_a, _fg, _bg) e.w_blit(p_a, _fg, _bg)
else else
-- skip line -- skip line
e.window.blit(spaces, blit_fg, blit_bg_sides) e.w_blit(spaces, blit_fg, blit_bg_sides)
end end
end end
else else
e.window.blit(spaces, blit_fg, blit_bg_top_bot) e.w_blit(spaces, blit_fg, blit_bg_top_bot)
end end
-- bottom border -- bottom border
elseif y > (e.frame.h - border_width) then elseif y > (e.frame.h - border_width) then
@ -156,31 +156,31 @@ local function rectangle(args)
if args.border.even and y == ((e.frame.h - border_width) + 1) then if args.border.even and y == ((e.frame.h - border_width) + 1) then
if args.thin == true then if args.thin == true then
if args.even_inner == true then if args.even_inner == true then
e.window.blit(p_b, blit_bg_top_bot, util.strrep(e.fg_bg.blit_bkg, e.frame.w)) e.w_blit(p_b, blit_bg_top_bot, string.rep(e.fg_bg.blit_bkg, e.frame.w))
else else
e.window.blit(p_b, util.strrep(e.fg_bg.blit_bkg, e.frame.w), blit_bg_top_bot) e.w_blit(p_b, string.rep(e.fg_bg.blit_bkg, e.frame.w), blit_bg_top_bot)
end end
else else
local _fg = util.trinary(args.even_inner == true, blit_bg_top_bot, p_inv_fg) local _fg = util.trinary(args.even_inner == true, blit_bg_top_bot, p_inv_fg)
local _bg = util.trinary(args.even_inner == true, util.strrep(e.fg_bg.blit_bkg, e.frame.w), blit_bg_top_bot) local _bg = util.trinary(args.even_inner == true, string.rep(e.fg_bg.blit_bkg, e.frame.w), blit_bg_top_bot)
if width_x2 % 3 == 1 then if width_x2 % 3 == 1 then
e.window.blit(p_a, _fg, _bg) e.w_blit(p_a, _fg, _bg)
elseif width_x2 % 3 == 2 then elseif width_x2 % 3 == 2 then
e.window.blit(p_b, _fg, _bg) e.w_blit(p_b, _fg, _bg)
else else
-- skip line -- skip line
e.window.blit(spaces, blit_fg, blit_bg_sides) e.w_blit(spaces, blit_fg, blit_bg_sides)
end end
end end
else else
e.window.blit(spaces, blit_fg, blit_bg_top_bot) e.w_blit(spaces, blit_fg, blit_bg_top_bot)
end end
else else
if args.thin == true then if args.thin == true then
e.window.blit(p_s, blit_fg_sides, blit_bg_sides) e.w_blit(p_s, blit_fg_sides, blit_bg_sides)
else else
e.window.blit(p_s, blit_fg, blit_bg_sides) e.w_blit(p_s, blit_fg, blit_bg_sides)
end end
end end
end end

View File

@ -45,14 +45,14 @@ local function textbox(args)
-- use cursor position to align this line -- use cursor position to align this line
if alignment == TEXT_ALIGN.CENTER then if alignment == TEXT_ALIGN.CENTER then
e.window.setCursorPos(math.floor((e.frame.w - len) / 2) + 1, i) e.w_set_cur(math.floor((e.frame.w - len) / 2) + 1, i)
elseif alignment == TEXT_ALIGN.RIGHT then elseif alignment == TEXT_ALIGN.RIGHT then
e.window.setCursorPos((e.frame.w - len) + 1, i) e.w_set_cur((e.frame.w - len) + 1, i)
else else
e.window.setCursorPos(1, i) e.w_set_cur(1, i)
end end
e.window.write(lines[i]) e.w_write(lines[i])
end end
end end

View File

@ -42,7 +42,7 @@ local function tiling(args)
-- border -- border
if args.border_c ~= nil then if args.border_c ~= nil then
e.window.setBackgroundColor(args.border_c) e.w_set_bkg(args.border_c)
e.window.clear() e.window.clear()
start_x = 1 + util.trinary(even, 2, 1) start_x = 1 + util.trinary(even, 2, 1)
@ -60,19 +60,19 @@ local function tiling(args)
-- create pattern -- create pattern
for y = start_y, inner_height + (start_y - 1) do for y = start_y, inner_height + (start_y - 1) do
e.window.setCursorPos(start_x, y) e.w_set_cur(start_x, y)
for _ = 1, inner_width do for _ = 1, inner_width do
if alternator then if alternator then
if even then if even then
e.window.blit(" ", "00", fill_a .. fill_a) e.w_blit(" ", "00", fill_a .. fill_a)
else else
e.window.blit(" ", "0", fill_a) e.w_blit(" ", "0", fill_a)
end end
else else
if even then if even then
e.window.blit(" ", "00", fill_b .. fill_b) e.w_blit(" ", "00", fill_b .. fill_b)
else else
e.window.blit(" ", "0", fill_b) e.w_blit(" ", "0", fill_b)
end end
end end

View File

@ -7,7 +7,7 @@ local iocontrol = require("pocket.iocontrol")
local PROTOCOL = comms.PROTOCOL local PROTOCOL = comms.PROTOCOL
local DEVICE_TYPE = comms.DEVICE_TYPE local DEVICE_TYPE = comms.DEVICE_TYPE
local ESTABLISH_ACK = comms.ESTABLISH_ACK local ESTABLISH_ACK = comms.ESTABLISH_ACK
local SCADA_MGMT_TYPE = comms.SCADA_MGMT_TYPE local MGMT_TYPE = comms.MGMT_TYPE
local LINK_STATE = iocontrol.LINK_STATE local LINK_STATE = iocontrol.LINK_STATE
@ -51,7 +51,7 @@ function pocket.comms(version, nic, pkt_channel, svr_channel, crd_channel, range
nic.open(pkt_channel) nic.open(pkt_channel)
-- send a management packet to the supervisor -- send a management packet to the supervisor
---@param msg_type SCADA_MGMT_TYPE ---@param msg_type MGMT_TYPE
---@param msg table ---@param msg table
local function _send_sv(msg_type, msg) local function _send_sv(msg_type, msg)
local s_pkt = comms.scada_packet() local s_pkt = comms.scada_packet()
@ -65,7 +65,7 @@ function pocket.comms(version, nic, pkt_channel, svr_channel, crd_channel, range
end end
-- send a management packet to the coordinator -- send a management packet to the coordinator
---@param msg_type SCADA_MGMT_TYPE ---@param msg_type MGMT_TYPE
---@param msg table ---@param msg table
local function _send_crd(msg_type, msg) local function _send_crd(msg_type, msg)
local s_pkt = comms.scada_packet() local s_pkt = comms.scada_packet()
@ -80,24 +80,24 @@ function pocket.comms(version, nic, pkt_channel, svr_channel, crd_channel, range
-- attempt supervisor connection establishment -- attempt supervisor connection establishment
local function _send_sv_establish() local function _send_sv_establish()
_send_sv(SCADA_MGMT_TYPE.ESTABLISH, { comms.version, version, DEVICE_TYPE.PKT }) _send_sv(MGMT_TYPE.ESTABLISH, { comms.version, version, DEVICE_TYPE.PKT })
end end
-- attempt coordinator API connection establishment -- attempt coordinator API connection establishment
local function _send_api_establish() local function _send_api_establish()
_send_crd(SCADA_MGMT_TYPE.ESTABLISH, { comms.version, version, DEVICE_TYPE.PKT }) _send_crd(MGMT_TYPE.ESTABLISH, { comms.version, version, DEVICE_TYPE.PKT })
end end
-- keep alive ack to supervisor -- keep alive ack to supervisor
---@param srv_time integer ---@param srv_time integer
local function _send_sv_keep_alive_ack(srv_time) local function _send_sv_keep_alive_ack(srv_time)
_send_sv(SCADA_MGMT_TYPE.KEEP_ALIVE, { srv_time, util.time() }) _send_sv(MGMT_TYPE.KEEP_ALIVE, { srv_time, util.time() })
end end
-- keep alive ack to coordinator -- keep alive ack to coordinator
---@param srv_time integer ---@param srv_time integer
local function _send_api_keep_alive_ack(srv_time) local function _send_api_keep_alive_ack(srv_time)
_send_crd(SCADA_MGMT_TYPE.KEEP_ALIVE, { srv_time, util.time() }) _send_crd(MGMT_TYPE.KEEP_ALIVE, { srv_time, util.time() })
end end
-- PUBLIC FUNCTIONS -- -- PUBLIC FUNCTIONS --
@ -111,7 +111,7 @@ function pocket.comms(version, nic, pkt_channel, svr_channel, crd_channel, range
self.sv.linked = false self.sv.linked = false
self.sv.r_seq_num = nil self.sv.r_seq_num = nil
self.sv.addr = comms.BROADCAST self.sv.addr = comms.BROADCAST
_send_sv(SCADA_MGMT_TYPE.CLOSE, {}) _send_sv(MGMT_TYPE.CLOSE, {})
end end
-- close connection to coordinator API server -- close connection to coordinator API server
@ -120,7 +120,7 @@ function pocket.comms(version, nic, pkt_channel, svr_channel, crd_channel, range
self.api.linked = false self.api.linked = false
self.api.r_seq_num = nil self.api.r_seq_num = nil
self.api.addr = comms.BROADCAST self.api.addr = comms.BROADCAST
_send_crd(SCADA_MGMT_TYPE.CLOSE, {}) _send_crd(MGMT_TYPE.CLOSE, {})
end end
-- close the connections to the servers -- close the connections to the servers
@ -157,21 +157,21 @@ function pocket.comms(version, nic, pkt_channel, svr_channel, crd_channel, range
-- supervisor get active alarm tones -- supervisor get active alarm tones
function public.diag__get_alarm_tones() function public.diag__get_alarm_tones()
if self.sv.linked then _send_sv(SCADA_MGMT_TYPE.DIAG_TONE_GET, {}) end if self.sv.linked then _send_sv(MGMT_TYPE.DIAG_TONE_GET, {}) end
end end
-- supervisor test alarm tones by tone -- supervisor test alarm tones by tone
---@param id TONE|0 tone ID, or 0 to stop all ---@param id TONE|0 tone ID, or 0 to stop all
---@param state boolean tone state ---@param state boolean tone state
function public.diag__set_alarm_tone(id, state) function public.diag__set_alarm_tone(id, state)
if self.sv.linked then _send_sv(SCADA_MGMT_TYPE.DIAG_TONE_SET, { id, state }) end if self.sv.linked then _send_sv(MGMT_TYPE.DIAG_TONE_SET, { id, state }) end
end end
-- supervisor test alarm tones by alarm -- supervisor test alarm tones by alarm
---@param id ALARM|0 alarm ID, 0 to stop all ---@param id ALARM|0 alarm ID, 0 to stop all
---@param state boolean alarm state ---@param state boolean alarm state
function public.diag__set_alarm(id, state) function public.diag__set_alarm(id, state)
if self.sv.linked then _send_sv(SCADA_MGMT_TYPE.DIAG_ALARM_SET, { id, state }) end if self.sv.linked then _send_sv(MGMT_TYPE.DIAG_ALARM_SET, { id, state }) end
end end
-- parse a packet -- parse a packet
@ -180,7 +180,7 @@ function pocket.comms(version, nic, pkt_channel, svr_channel, crd_channel, range
---@param reply_to integer ---@param reply_to integer
---@param message any ---@param message any
---@param distance integer ---@param distance integer
---@return mgmt_frame|capi_frame|nil packet ---@return mgmt_frame|crdn_frame|nil packet
function public.parse_packet(side, sender, reply_to, message, distance) function public.parse_packet(side, sender, reply_to, message, distance)
local s_pkt = nic.receive(side, sender, reply_to, message, distance) local s_pkt = nic.receive(side, sender, reply_to, message, distance)
local pkt = nil local pkt = nil
@ -192,11 +192,11 @@ function pocket.comms(version, nic, pkt_channel, svr_channel, crd_channel, range
if mgmt_pkt.decode(s_pkt) then if mgmt_pkt.decode(s_pkt) then
pkt = mgmt_pkt.get() pkt = mgmt_pkt.get()
end end
-- get as coordinator API packet -- get as coordinator packet
elseif s_pkt.protocol() == PROTOCOL.COORD_API then elseif s_pkt.protocol() == PROTOCOL.SCADA_CRDN then
local capi_pkt = comms.capi_packet() local crdn_pkt = comms.crdn_packet()
if capi_pkt.decode(s_pkt) then if crdn_pkt.decode(s_pkt) then
pkt = capi_pkt.get() pkt = crdn_pkt.get()
end end
else else
log.debug("attempted parse of illegal packet type " .. s_pkt.protocol(), true) log.debug("attempted parse of illegal packet type " .. s_pkt.protocol(), true)
@ -207,7 +207,7 @@ function pocket.comms(version, nic, pkt_channel, svr_channel, crd_channel, range
end end
-- handle a packet -- handle a packet
---@param packet mgmt_frame|capi_frame|nil ---@param packet mgmt_frame|crdn_frame|nil
function public.handle_packet(packet) function public.handle_packet(packet)
local diag = iocontrol.get_db().diag local diag = iocontrol.get_db().diag
@ -240,7 +240,7 @@ function pocket.comms(version, nic, pkt_channel, svr_channel, crd_channel, range
if protocol == PROTOCOL.SCADA_MGMT then if protocol == PROTOCOL.SCADA_MGMT then
---@cast packet mgmt_frame ---@cast packet mgmt_frame
if self.api.linked then if self.api.linked then
if packet.type == SCADA_MGMT_TYPE.KEEP_ALIVE then if packet.type == MGMT_TYPE.KEEP_ALIVE then
-- keep alive request received, echo back -- keep alive request received, echo back
if packet.length == 1 then if packet.length == 1 then
local timestamp = packet.data[1] local timestamp = packet.data[1]
@ -256,7 +256,7 @@ function pocket.comms(version, nic, pkt_channel, svr_channel, crd_channel, range
else else
log.debug("coordinator SCADA keep alive packet length mismatch") log.debug("coordinator SCADA keep alive packet length mismatch")
end end
elseif packet.type == SCADA_MGMT_TYPE.CLOSE then elseif packet.type == MGMT_TYPE.CLOSE then
-- handle session close -- handle session close
api_watchdog.cancel() api_watchdog.cancel()
self.api.linked = false self.api.linked = false
@ -266,7 +266,7 @@ function pocket.comms(version, nic, pkt_channel, svr_channel, crd_channel, range
else else
log.debug("received unknown SCADA_MGMT packet type " .. packet.type .. " from coordinator") log.debug("received unknown SCADA_MGMT packet type " .. packet.type .. " from coordinator")
end end
elseif packet.type == SCADA_MGMT_TYPE.ESTABLISH then elseif packet.type == MGMT_TYPE.ESTABLISH then
-- connection with coordinator established -- connection with coordinator established
if packet.length == 1 then if packet.length == 1 then
local est_ack = packet.data[1] local est_ack = packet.data[1]
@ -330,7 +330,7 @@ function pocket.comms(version, nic, pkt_channel, svr_channel, crd_channel, range
if protocol == PROTOCOL.SCADA_MGMT then if protocol == PROTOCOL.SCADA_MGMT then
---@cast packet mgmt_frame ---@cast packet mgmt_frame
if self.sv.linked then if self.sv.linked then
if packet.type == SCADA_MGMT_TYPE.KEEP_ALIVE then if packet.type == MGMT_TYPE.KEEP_ALIVE then
-- keep alive request received, echo back -- keep alive request received, echo back
if packet.length == 1 then if packet.length == 1 then
local timestamp = packet.data[1] local timestamp = packet.data[1]
@ -346,14 +346,14 @@ function pocket.comms(version, nic, pkt_channel, svr_channel, crd_channel, range
else else
log.debug("supervisor SCADA keep alive packet length mismatch") log.debug("supervisor SCADA keep alive packet length mismatch")
end end
elseif packet.type == SCADA_MGMT_TYPE.CLOSE then elseif packet.type == MGMT_TYPE.CLOSE then
-- handle session close -- handle session close
sv_watchdog.cancel() sv_watchdog.cancel()
self.sv.linked = false self.sv.linked = false
self.sv.r_seq_num = nil self.sv.r_seq_num = nil
self.sv.addr = comms.BROADCAST self.sv.addr = comms.BROADCAST
log.info("supervisor server connection closed by remote host") log.info("supervisor server connection closed by remote host")
elseif packet.type == SCADA_MGMT_TYPE.DIAG_TONE_GET then elseif packet.type == MGMT_TYPE.DIAG_TONE_GET then
if packet.length == 8 then if packet.length == 8 then
for i = 1, #packet.data do for i = 1, #packet.data do
diag.tone_test.tone_indicators[i].update(packet.data[i] == true) diag.tone_test.tone_indicators[i].update(packet.data[i] == true)
@ -361,7 +361,7 @@ function pocket.comms(version, nic, pkt_channel, svr_channel, crd_channel, range
else else
log.debug("supervisor SCADA diag alarm states packet length mismatch") log.debug("supervisor SCADA diag alarm states packet length mismatch")
end end
elseif packet.type == SCADA_MGMT_TYPE.DIAG_TONE_SET then elseif packet.type == MGMT_TYPE.DIAG_TONE_SET then
if packet.length == 1 and packet.data[1] == false then if packet.length == 1 and packet.data[1] == false then
diag.tone_test.ready_warn.set_value("testing denied") diag.tone_test.ready_warn.set_value("testing denied")
log.debug("supervisor SCADA diag tone set failed") log.debug("supervisor SCADA diag tone set failed")
@ -380,7 +380,7 @@ function pocket.comms(version, nic, pkt_channel, svr_channel, crd_channel, range
else else
log.debug("supervisor SCADA diag tone set packet length/type mismatch") log.debug("supervisor SCADA diag tone set packet length/type mismatch")
end end
elseif packet.type == SCADA_MGMT_TYPE.DIAG_ALARM_SET then elseif packet.type == MGMT_TYPE.DIAG_ALARM_SET then
if packet.length == 1 and packet.data[1] == false then if packet.length == 1 and packet.data[1] == false then
diag.tone_test.ready_warn.set_value("testing denied") diag.tone_test.ready_warn.set_value("testing denied")
log.debug("supervisor SCADA diag alarm set failed") log.debug("supervisor SCADA diag alarm set failed")
@ -401,7 +401,7 @@ function pocket.comms(version, nic, pkt_channel, svr_channel, crd_channel, range
else else
log.debug("received unknown SCADA_MGMT packet type " .. packet.type .. " from supervisor") log.debug("received unknown SCADA_MGMT packet type " .. packet.type .. " from supervisor")
end end
elseif packet.type == SCADA_MGMT_TYPE.ESTABLISH then elseif packet.type == MGMT_TYPE.ESTABLISH then
-- connection with supervisor established -- connection with supervisor established
if packet.length == 1 then if packet.length == 1 then
local est_ack = packet.data[1] local est_ack = packet.data[1]

View File

@ -18,7 +18,7 @@ local iocontrol = require("pocket.iocontrol")
local pocket = require("pocket.pocket") local pocket = require("pocket.pocket")
local renderer = require("pocket.renderer") local renderer = require("pocket.renderer")
local POCKET_VERSION = "v0.6.0-alpha" local POCKET_VERSION = "v0.6.1-alpha"
local println = util.println local println = util.println
local println_ts = util.println_ts local println_ts = util.println_ts

View File

@ -28,6 +28,9 @@ local TEXT_ALIGN = core.TEXT_ALIGN
local cpair = core.cpair local cpair = core.cpair
local border = core.border local border = core.border
local ind_grn = style.ind_grn
local ind_red = style.ind_red
-- create new front panel view -- create new front panel view
---@param panel graphics_element main displaybox ---@param panel graphics_element main displaybox
local function init(panel) local function init(panel)
@ -41,14 +44,14 @@ local function init(panel)
local system = Div{parent=panel,width=14,height=18,x=2,y=3} local system = Div{parent=panel,width=14,height=18,x=2,y=3}
local init_ok = LED{parent=system,label="STATUS",colors=cpair(colors.green,colors.red)} local init_ok = LED{parent=system,label="STATUS",colors=cpair(colors.green,colors.red)}
local heartbeat = LED{parent=system,label="HEARTBEAT",colors=cpair(colors.green,colors.green_off)} local heartbeat = LED{parent=system,label="HEARTBEAT",colors=ind_grn}
system.line_break() system.line_break()
init_ok.register(databus.ps, "init_ok", init_ok.update) init_ok.register(databus.ps, "init_ok", init_ok.update)
heartbeat.register(databus.ps, "heartbeat", heartbeat.update) heartbeat.register(databus.ps, "heartbeat", heartbeat.update)
local reactor = LEDPair{parent=system,label="REACTOR",off=colors.red,c1=colors.yellow,c2=colors.green} local reactor = LEDPair{parent=system,label="REACTOR",off=colors.red,c1=colors.yellow,c2=colors.green}
local modem = LED{parent=system,label="MODEM",colors=cpair(colors.green,colors.green_off)} local modem = LED{parent=system,label="MODEM",colors=ind_grn}
local network = RGBLED{parent=system,label="NETWORK",colors={colors.green,colors.red,colors.orange,colors.yellow,colors.gray}} local network = RGBLED{parent=system,label="NETWORK",colors={colors.green,colors.red,colors.orange,colors.yellow,colors.gray}}
network.update(types.PANEL_LINK_STATE.DISCONNECTED) network.update(types.PANEL_LINK_STATE.DISCONNECTED)
system.line_break() system.line_break()
@ -57,11 +60,11 @@ local function init(panel)
modem.register(databus.ps, "has_modem", modem.update) modem.register(databus.ps, "has_modem", modem.update)
network.register(databus.ps, "link_state", network.update) network.register(databus.ps, "link_state", network.update)
local rt_main = LED{parent=system,label="RT MAIN",colors=cpair(colors.green,colors.green_off)} local rt_main = LED{parent=system,label="RT MAIN",colors=ind_grn}
local rt_rps = LED{parent=system,label="RT RPS",colors=cpair(colors.green,colors.green_off)} local rt_rps = LED{parent=system,label="RT RPS",colors=ind_grn}
local rt_cmtx = LED{parent=system,label="RT COMMS TX",colors=cpair(colors.green,colors.green_off)} local rt_cmtx = LED{parent=system,label="RT COMMS TX",colors=ind_grn}
local rt_cmrx = LED{parent=system,label="RT COMMS RX",colors=cpair(colors.green,colors.green_off)} local rt_cmrx = LED{parent=system,label="RT COMMS RX",colors=ind_grn}
local rt_sctl = LED{parent=system,label="RT SPCTL",colors=cpair(colors.green,colors.green_off)} local rt_sctl = LED{parent=system,label="RT SPCTL",colors=ind_grn}
system.line_break() system.line_break()
rt_main.register(databus.ps, "routine__main", rt_main.update) rt_main.register(databus.ps, "routine__main", rt_main.update)
@ -80,7 +83,7 @@ local function init(panel)
local status = Div{parent=panel,width=19,height=18,x=17,y=3} local status = Div{parent=panel,width=19,height=18,x=17,y=3}
local active = LED{parent=status,x=2,width=12,label="RCT ACTIVE",colors=cpair(colors.green,colors.green_off)} local active = LED{parent=status,x=2,width=12,label="RCT ACTIVE",colors=ind_grn}
-- only show emergency coolant LED if emergency coolant is configured for this device -- only show emergency coolant LED if emergency coolant is configured for this device
if type(config.EMERGENCY_COOL) == "table" then if type(config.EMERGENCY_COOL) == "table" then
@ -90,7 +93,7 @@ local function init(panel)
local status_trip_rct = Rectangle{parent=status,width=20,height=3,x=1,border=border(1,colors.lightGray,true),even_inner=true,fg_bg=cpair(colors.black,colors.ivory)} local status_trip_rct = Rectangle{parent=status,width=20,height=3,x=1,border=border(1,colors.lightGray,true),even_inner=true,fg_bg=cpair(colors.black,colors.ivory)}
local status_trip = Div{parent=status_trip_rct,width=18,height=1,fg_bg=cpair(colors.black,colors.lightGray)} local status_trip = Div{parent=status_trip_rct,width=18,height=1,fg_bg=cpair(colors.black,colors.lightGray)}
local scram = LED{parent=status_trip,width=10,label="RPS TRIP",colors=cpair(colors.red,colors.red_off),flash=true,period=flasher.PERIOD.BLINK_250_MS} local scram = LED{parent=status_trip,width=10,label="RPS TRIP",colors=ind_red,flash=true,period=flasher.PERIOD.BLINK_250_MS}
local controls_rct = Rectangle{parent=status,width=17,height=3,x=1,border=border(1,colors.white,true),even_inner=true,fg_bg=cpair(colors.black,colors.ivory)} local controls_rct = Rectangle{parent=status,width=17,height=3,x=1,border=border(1,colors.white,true),even_inner=true,fg_bg=cpair(colors.black,colors.ivory)}
local controls = Div{parent=controls_rct,width=15,height=1,fg_bg=cpair(colors.black,colors.white)} local controls = Div{parent=controls_rct,width=15,height=1,fg_bg=cpair(colors.black,colors.white)}
@ -116,20 +119,20 @@ local function init(panel)
-- --
local rps = Rectangle{parent=panel,width=16,height=16,x=36,y=3,border=border(1,colors.lightGray),thin=true,fg_bg=cpair(colors.black,colors.lightGray)} local rps = Rectangle{parent=panel,width=16,height=16,x=36,y=3,border=border(1,colors.lightGray),thin=true,fg_bg=cpair(colors.black,colors.lightGray)}
local rps_man = LED{parent=rps,label="MANUAL",colors=cpair(colors.red,colors.red_off)} local rps_man = LED{parent=rps,label="MANUAL",colors=ind_red}
local rps_auto = LED{parent=rps,label="AUTOMATIC",colors=cpair(colors.red,colors.red_off)} local rps_auto = LED{parent=rps,label="AUTOMATIC",colors=ind_red}
local rps_tmo = LED{parent=rps,label="TIMEOUT",colors=cpair(colors.red,colors.red_off)} local rps_tmo = LED{parent=rps,label="TIMEOUT",colors=ind_red}
local rps_flt = LED{parent=rps,label="PLC FAULT",colors=cpair(colors.red,colors.red_off)} local rps_flt = LED{parent=rps,label="PLC FAULT",colors=ind_red}
local rps_fail = LED{parent=rps,label="RCT FAULT",colors=cpair(colors.red,colors.red_off)} local rps_fail = LED{parent=rps,label="RCT FAULT",colors=ind_red}
rps.line_break() rps.line_break()
local rps_dmg = LED{parent=rps,label="HI DAMAGE",colors=cpair(colors.red,colors.red_off)} local rps_dmg = LED{parent=rps,label="HI DAMAGE",colors=ind_red}
local rps_tmp = LED{parent=rps,label="HI TEMP",colors=cpair(colors.red,colors.red_off)} local rps_tmp = LED{parent=rps,label="HI TEMP",colors=ind_red}
rps.line_break() rps.line_break()
local rps_nof = LED{parent=rps,label="LO FUEL",colors=cpair(colors.red,colors.red_off)} local rps_nof = LED{parent=rps,label="LO FUEL",colors=ind_red}
local rps_wst = LED{parent=rps,label="HI WASTE",colors=cpair(colors.red,colors.red_off)} local rps_wst = LED{parent=rps,label="HI WASTE",colors=ind_red}
rps.line_break() rps.line_break()
local rps_ccl = LED{parent=rps,label="LO CCOOLANT",colors=cpair(colors.red,colors.red_off)} local rps_ccl = LED{parent=rps,label="LO CCOOLANT",colors=ind_red}
local rps_hcl = LED{parent=rps,label="HI HCOOLANT",colors=cpair(colors.red,colors.red_off)} local rps_hcl = LED{parent=rps,label="HI HCOOLANT",colors=ind_red}
rps_man.register(databus.ps, "rps_manual", rps_man.update) rps_man.register(databus.ps, "rps_manual", rps_man.update)
rps_auto.register(databus.ps, "rps_automatic", rps_auto.update) rps_auto.register(databus.ps, "rps_automatic", rps_auto.update)

View File

@ -39,4 +39,9 @@ style.colors = {
{ c = colors.brown, hex = 0x672223 } -- RED OFF { c = colors.brown, hex = 0x672223 } -- RED OFF
} }
-- COMMON COLOR PAIRS --
style.ind_grn = cpair(colors.green, colors.green_off)
style.ind_red = cpair(colors.red, colors.red_off)
return style return style

View File

@ -16,7 +16,7 @@ local PROTOCOL = comms.PROTOCOL
local DEVICE_TYPE = comms.DEVICE_TYPE local DEVICE_TYPE = comms.DEVICE_TYPE
local ESTABLISH_ACK = comms.ESTABLISH_ACK local ESTABLISH_ACK = comms.ESTABLISH_ACK
local RPLC_TYPE = comms.RPLC_TYPE local RPLC_TYPE = comms.RPLC_TYPE
local SCADA_MGMT_TYPE = comms.SCADA_MGMT_TYPE local MGMT_TYPE = comms.MGMT_TYPE
local AUTO_ACK = comms.PLC_AUTO_ACK local AUTO_ACK = comms.PLC_AUTO_ACK
local RPS_LIMITS = const.RPS_LIMITS local RPS_LIMITS = const.RPS_LIMITS
@ -489,7 +489,7 @@ function plc.comms(id, version, nic, plc_channel, svr_channel, range, reactor, r
end end
-- send a SCADA management packet -- send a SCADA management packet
---@param msg_type SCADA_MGMT_TYPE ---@param msg_type MGMT_TYPE
---@param msg table ---@param msg table
local function _send_mgmt(msg_type, msg) local function _send_mgmt(msg_type, msg)
local s_pkt = comms.scada_packet() local s_pkt = comms.scada_packet()
@ -600,7 +600,7 @@ function plc.comms(id, version, nic, plc_channel, svr_channel, range, reactor, r
-- keep alive ack -- keep alive ack
---@param srv_time integer ---@param srv_time integer
local function _send_keep_alive_ack(srv_time) local function _send_keep_alive_ack(srv_time)
_send_mgmt(SCADA_MGMT_TYPE.KEEP_ALIVE, { srv_time, util.time() }) _send_mgmt(MGMT_TYPE.KEEP_ALIVE, { srv_time, util.time() })
end end
-- general ack -- general ack
@ -668,12 +668,12 @@ function plc.comms(id, version, nic, plc_channel, svr_channel, range, reactor, r
function public.close() function public.close()
conn_watchdog.cancel() conn_watchdog.cancel()
public.unlink() public.unlink()
_send_mgmt(SCADA_MGMT_TYPE.CLOSE, {}) _send_mgmt(MGMT_TYPE.CLOSE, {})
end end
-- attempt to establish link with supervisor -- attempt to establish link with supervisor
function public.send_link_req() function public.send_link_req()
_send_mgmt(SCADA_MGMT_TYPE.ESTABLISH, { comms.version, version, DEVICE_TYPE.PLC, id }) _send_mgmt(MGMT_TYPE.ESTABLISH, { comms.version, version, DEVICE_TYPE.PLC, id })
end end
-- send live status information -- send live status information
@ -929,7 +929,7 @@ function plc.comms(id, version, nic, plc_channel, svr_channel, range, reactor, r
---@cast packet mgmt_frame ---@cast packet mgmt_frame
-- if linked, only accept packets from configured supervisor -- if linked, only accept packets from configured supervisor
if self.linked then if self.linked then
if packet.type == SCADA_MGMT_TYPE.KEEP_ALIVE then if packet.type == MGMT_TYPE.KEEP_ALIVE then
-- keep alive request received, echo back -- keep alive request received, echo back
if packet.length == 1 and type(packet.data[1]) == "number" then if packet.length == 1 and type(packet.data[1]) == "number" then
local timestamp = packet.data[1] local timestamp = packet.data[1]
@ -945,7 +945,7 @@ function plc.comms(id, version, nic, plc_channel, svr_channel, range, reactor, r
else else
log.debug("SCADA_MGMT keep alive packet length/type mismatch") log.debug("SCADA_MGMT keep alive packet length/type mismatch")
end end
elseif packet.type == SCADA_MGMT_TYPE.CLOSE then elseif packet.type == MGMT_TYPE.CLOSE then
-- handle session close -- handle session close
conn_watchdog.cancel() conn_watchdog.cancel()
public.unlink() public.unlink()
@ -954,7 +954,7 @@ function plc.comms(id, version, nic, plc_channel, svr_channel, range, reactor, r
else else
log.debug("received unsupported SCADA_MGMT packet type " .. packet.type) log.debug("received unsupported SCADA_MGMT packet type " .. packet.type)
end end
elseif packet.type == SCADA_MGMT_TYPE.ESTABLISH then elseif packet.type == MGMT_TYPE.ESTABLISH then
-- link request confirmation -- link request confirmation
if packet.length == 1 then if packet.length == 1 then
local est_ack = packet.data[1] local est_ack = packet.data[1]

View File

@ -19,7 +19,7 @@ local plc = require("reactor-plc.plc")
local renderer = require("reactor-plc.renderer") local renderer = require("reactor-plc.renderer")
local threads = require("reactor-plc.threads") local threads = require("reactor-plc.threads")
local R_PLC_VERSION = "v1.5.7" local R_PLC_VERSION = "v1.5.8"
local println = util.println local println = util.println
local println_ts = util.println_ts local println_ts = util.println_ts

View File

@ -22,8 +22,11 @@ local TEXT_ALIGN = core.TEXT_ALIGN
local cpair = core.cpair local cpair = core.cpair
local UNIT_TYPE_LABELS = { "UNKNOWN", "REDSTONE", "BOILER", "TURBINE", "DYNAMIC TANK", "IND MATRIX", "SPS", "SNA", "ENV DETECTOR" } local fp_label = style.fp_label
local ind_grn = style.ind_grn
local UNIT_TYPE_LABELS = { "UNKNOWN", "REDSTONE", "BOILER", "TURBINE", "DYNAMIC TANK", "IND MATRIX", "SPS", "SNA", "ENV DETECTOR" }
-- create new front panel view -- create new front panel view
---@param panel graphics_element main displaybox ---@param panel graphics_element main displaybox
@ -38,13 +41,13 @@ local function init(panel, units)
local system = Div{parent=panel,width=14,height=18,x=2,y=3} local system = Div{parent=panel,width=14,height=18,x=2,y=3}
local on = LED{parent=system,label="STATUS",colors=cpair(colors.green,colors.red)} local on = LED{parent=system,label="STATUS",colors=cpair(colors.green,colors.red)}
local heartbeat = LED{parent=system,label="HEARTBEAT",colors=cpair(colors.green,colors.green_off)} local heartbeat = LED{parent=system,label="HEARTBEAT",colors=ind_grn}
on.update(true) on.update(true)
system.line_break() system.line_break()
heartbeat.register(databus.ps, "heartbeat", heartbeat.update) heartbeat.register(databus.ps, "heartbeat", heartbeat.update)
local modem = LED{parent=system,label="MODEM",colors=cpair(colors.green,colors.green_off)} local modem = LED{parent=system,label="MODEM",colors=ind_grn}
local network = RGBLED{parent=system,label="NETWORK",colors={colors.green,colors.red,colors.orange,colors.yellow,colors.gray}} local network = RGBLED{parent=system,label="NETWORK",colors={colors.green,colors.red,colors.orange,colors.yellow,colors.gray}}
network.update(types.PANEL_LINK_STATE.DISCONNECTED) network.update(types.PANEL_LINK_STATE.DISCONNECTED)
system.line_break() system.line_break()
@ -52,8 +55,8 @@ local function init(panel, units)
modem.register(databus.ps, "has_modem", modem.update) modem.register(databus.ps, "has_modem", modem.update)
network.register(databus.ps, "link_state", network.update) network.register(databus.ps, "link_state", network.update)
local rt_main = LED{parent=system,label="RT MAIN",colors=cpair(colors.green,colors.green_off)} local rt_main = LED{parent=system,label="RT MAIN",colors=ind_grn}
local rt_comm = LED{parent=system,label="RT COMMS",colors=cpair(colors.green,colors.green_off)} local rt_comm = LED{parent=system,label="RT COMMS",colors=ind_grn}
system.line_break() system.line_break()
rt_main.register(databus.ps, "routine__main", rt_main.update) rt_main.register(databus.ps, "routine__main", rt_main.update)
@ -61,7 +64,7 @@ local function init(panel, units)
---@diagnostic disable-next-line: undefined-field ---@diagnostic disable-next-line: undefined-field
local comp_id = util.sprintf("(%d)", os.getComputerID()) local comp_id = util.sprintf("(%d)", os.getComputerID())
TextBox{parent=system,x=9,y=4,width=6,height=1,text=comp_id,fg_bg=cpair(colors.lightGray,colors.ivory)} TextBox{parent=system,x=9,y=4,width=6,height=1,text=comp_id,fg_bg=fp_label}
TextBox{parent=system,x=1,y=14,text="SPEAKERS",height=1,width=8,fg_bg=style.label} TextBox{parent=system,x=1,y=14,text="SPEAKERS",height=1,width=8,fg_bg=style.label}
local speaker_count = DataIndicator{parent=system,x=10,y=14,label="",format="%3d",value=0,width=3,fg_bg=cpair(colors.gray,colors.white)} local speaker_count = DataIndicator{parent=system,x=10,y=14,label="",format="%3d",value=0,width=3,fg_bg=cpair(colors.gray,colors.white)}
@ -71,7 +74,7 @@ local function init(panel, units)
-- about label -- about label
-- --
local about = Div{parent=panel,width=15,height=3,x=1,y=18,fg_bg=cpair(colors.lightGray,colors.ivory)} local about = Div{parent=panel,width=15,height=3,x=1,y=18,fg_bg=fp_label}
local fw_v = TextBox{parent=about,x=1,y=1,text="FW: v00.00.00",alignment=TEXT_ALIGN.LEFT,height=1} local fw_v = TextBox{parent=about,x=1,y=1,text="FW: v00.00.00",alignment=TEXT_ALIGN.LEFT,height=1}
local comms_v = TextBox{parent=about,x=1,y=2,text="NT: v00.00.00",alignment=TEXT_ALIGN.LEFT,height=1} local comms_v = TextBox{parent=about,x=1,y=2,text="NT: v00.00.00",alignment=TEXT_ALIGN.LEFT,height=1}
@ -90,7 +93,7 @@ local function init(panel, units)
-- show routine statuses -- show routine statuses
for i = 1, list_length do for i = 1, list_length do
TextBox{parent=threads,x=1,y=i,text=util.sprintf("%02d",i),height=1} TextBox{parent=threads,x=1,y=i,text=util.sprintf("%02d",i),height=1}
local rt_unit = LED{parent=threads,x=4,y=i,label="RT",colors=cpair(colors.green,colors.green_off)} local rt_unit = LED{parent=threads,x=4,y=i,label="RT",colors=ind_grn}
rt_unit.register(databus.ps, "routine__unit_" .. i, rt_unit.update) rt_unit.register(databus.ps, "routine__unit_" .. i, rt_unit.update)
end end
@ -115,7 +118,7 @@ local function init(panel, units)
-- assignment (unit # or facility) -- assignment (unit # or facility)
local for_unit = util.trinary(unit.reactor == 0, "\x1a FACIL ", "\x1a UNIT " .. unit.reactor) local for_unit = util.trinary(unit.reactor == 0, "\x1a FACIL ", "\x1a UNIT " .. unit.reactor)
TextBox{parent=unit_hw_statuses,y=i,x=19,text=for_unit,height=1,fg_bg=cpair(colors.lightGray,colors.ivory)} TextBox{parent=unit_hw_statuses,y=i,x=19,text=for_unit,height=1,fg_bg=fp_label}
end end
end end

View File

@ -39,4 +39,10 @@ style.colors = {
{ c = colors.brown, hex = 0x672223 } -- RED OFF { c = colors.brown, hex = 0x672223 } -- RED OFF
} }
-- COMMON COLOR PAIRS --
style.fp_label = cpair(colors.lightGray, colors.ivory)
style.ind_grn = cpair(colors.green, colors.green_off)
return style return style

View File

@ -14,7 +14,7 @@ local rtu = {}
local PROTOCOL = comms.PROTOCOL local PROTOCOL = comms.PROTOCOL
local DEVICE_TYPE = comms.DEVICE_TYPE local DEVICE_TYPE = comms.DEVICE_TYPE
local ESTABLISH_ACK = comms.ESTABLISH_ACK local ESTABLISH_ACK = comms.ESTABLISH_ACK
local SCADA_MGMT_TYPE = comms.SCADA_MGMT_TYPE local MGMT_TYPE = comms.MGMT_TYPE
local RTU_UNIT_TYPE = types.RTU_UNIT_TYPE local RTU_UNIT_TYPE = types.RTU_UNIT_TYPE
-- create a new RTU unit -- create a new RTU unit
@ -227,7 +227,7 @@ function rtu.comms(version, nic, rtu_channel, svr_channel, range, conn_watchdog)
nic.open(rtu_channel) nic.open(rtu_channel)
-- send a scada management packet -- send a scada management packet
---@param msg_type SCADA_MGMT_TYPE ---@param msg_type MGMT_TYPE
---@param msg table ---@param msg table
local function _send(msg_type, msg) local function _send(msg_type, msg)
local s_pkt = comms.scada_packet() local s_pkt = comms.scada_packet()
@ -243,7 +243,7 @@ function rtu.comms(version, nic, rtu_channel, svr_channel, range, conn_watchdog)
-- keep alive ack -- keep alive ack
---@param srv_time integer ---@param srv_time integer
local function _send_keep_alive_ack(srv_time) local function _send_keep_alive_ack(srv_time)
_send(SCADA_MGMT_TYPE.KEEP_ALIVE, { srv_time, util.time() }) _send(MGMT_TYPE.KEEP_ALIVE, { srv_time, util.time() })
end end
-- generate device advertisement table -- generate device advertisement table
@ -298,25 +298,25 @@ function rtu.comms(version, nic, rtu_channel, svr_channel, range, conn_watchdog)
function public.close(rtu_state) function public.close(rtu_state)
conn_watchdog.cancel() conn_watchdog.cancel()
public.unlink(rtu_state) public.unlink(rtu_state)
_send(SCADA_MGMT_TYPE.CLOSE, {}) _send(MGMT_TYPE.CLOSE, {})
end end
-- send establish request (includes advertisement) -- send establish request (includes advertisement)
---@param units table ---@param units table
function public.send_establish(units) function public.send_establish(units)
_send(SCADA_MGMT_TYPE.ESTABLISH, { comms.version, version, DEVICE_TYPE.RTU, _generate_advertisement(units) }) _send(MGMT_TYPE.ESTABLISH, { comms.version, version, DEVICE_TYPE.RTU, _generate_advertisement(units) })
end end
-- send capability advertisement -- send capability advertisement
---@param units table ---@param units table
function public.send_advertisement(units) function public.send_advertisement(units)
_send(SCADA_MGMT_TYPE.RTU_ADVERT, _generate_advertisement(units)) _send(MGMT_TYPE.RTU_ADVERT, _generate_advertisement(units))
end end
-- notify that a peripheral was remounted -- notify that a peripheral was remounted
---@param unit_index integer RTU unit ID ---@param unit_index integer RTU unit ID
function public.send_remounted(unit_index) function public.send_remounted(unit_index)
_send(SCADA_MGMT_TYPE.RTU_DEV_REMOUNT, { unit_index }) _send(MGMT_TYPE.RTU_DEV_REMOUNT, { unit_index })
end end
-- parse a MODBUS/SCADA packet -- parse a MODBUS/SCADA packet
@ -433,7 +433,7 @@ function rtu.comms(version, nic, rtu_channel, svr_channel, range, conn_watchdog)
---@cast packet mgmt_frame ---@cast packet mgmt_frame
-- SCADA management packet -- SCADA management packet
if rtu_state.linked then if rtu_state.linked then
if packet.type == SCADA_MGMT_TYPE.KEEP_ALIVE then if packet.type == MGMT_TYPE.KEEP_ALIVE then
-- keep alive request received, echo back -- keep alive request received, echo back
if packet.length == 1 and type(packet.data[1]) == "number" then if packet.length == 1 and type(packet.data[1]) == "number" then
local timestamp = packet.data[1] local timestamp = packet.data[1]
@ -449,16 +449,16 @@ function rtu.comms(version, nic, rtu_channel, svr_channel, range, conn_watchdog)
else else
log.debug("SCADA_MGMT keep alive packet length/type mismatch") log.debug("SCADA_MGMT keep alive packet length/type mismatch")
end end
elseif packet.type == SCADA_MGMT_TYPE.CLOSE then elseif packet.type == MGMT_TYPE.CLOSE then
-- close connection -- close connection
conn_watchdog.cancel() conn_watchdog.cancel()
public.unlink(rtu_state) public.unlink(rtu_state)
println_ts("server connection closed by remote host") println_ts("server connection closed by remote host")
log.warning("server connection closed by remote host") log.warning("server connection closed by remote host")
elseif packet.type == SCADA_MGMT_TYPE.RTU_ADVERT then elseif packet.type == MGMT_TYPE.RTU_ADVERT then
-- request for capabilities again -- request for capabilities again
public.send_advertisement(units) public.send_advertisement(units)
elseif packet.type == SCADA_MGMT_TYPE.RTU_TONE_ALARM then elseif packet.type == MGMT_TYPE.RTU_TONE_ALARM then
-- alarm tone update from supervisor -- alarm tone update from supervisor
if (packet.length == 1) and type(packet.data[1] == "table") and (#packet.data[1] == 8) then if (packet.length == 1) and type(packet.data[1] == "table") and (#packet.data[1] == 8) then
local states = packet.data[1] local states = packet.data[1]
@ -474,7 +474,7 @@ function rtu.comms(version, nic, rtu_channel, svr_channel, range, conn_watchdog)
-- not supported -- not supported
log.debug("received unsupported SCADA_MGMT message type " .. packet.type) log.debug("received unsupported SCADA_MGMT message type " .. packet.type)
end end
elseif packet.type == SCADA_MGMT_TYPE.ESTABLISH then elseif packet.type == MGMT_TYPE.ESTABLISH then
if packet.length == 1 then if packet.length == 1 then
local est_ack = packet.data[1] local est_ack = packet.data[1]

View File

@ -31,7 +31,7 @@ local sna_rtu = require("rtu.dev.sna_rtu")
local sps_rtu = require("rtu.dev.sps_rtu") local sps_rtu = require("rtu.dev.sps_rtu")
local turbinev_rtu = require("rtu.dev.turbinev_rtu") local turbinev_rtu = require("rtu.dev.turbinev_rtu")
local RTU_VERSION = "v1.6.2" local RTU_VERSION = "v1.6.3"
local RTU_UNIT_TYPE = types.RTU_UNIT_TYPE local RTU_UNIT_TYPE = types.RTU_UNIT_TYPE
local RTU_UNIT_HW_STATE = databus.RTU_UNIT_HW_STATE local RTU_UNIT_HW_STATE = databus.RTU_UNIT_HW_STATE

View File

@ -6,23 +6,25 @@ local log = require("scada-common.log")
local insert = table.insert local insert = table.insert
---@type integer computer ID
---@diagnostic disable-next-line: undefined-field ---@diagnostic disable-next-line: undefined-field
local COMPUTER_ID = os.getComputerID() ---@type integer computer ID local COMPUTER_ID = os.getComputerID()
local max_distance = nil ---@type number|nil maximum acceptable transmission distance ---@type number|nil maximum acceptable transmission distance
local max_distance = nil
---@class comms ---@class comms
local comms = {} local comms = {}
comms.version = "2.2.1" -- protocol version (non-protocol changes tracked by util.lua version)
comms.version = "2.3.0"
---@enum PROTOCOL ---@enum PROTOCOL
local PROTOCOL = { local PROTOCOL = {
MODBUS_TCP = 0, -- our "MODBUS TCP"-esque protocol MODBUS_TCP = 0, -- the "MODBUS TCP"-esque protocol
RPLC = 1, -- reactor PLC protocol RPLC = 1, -- reactor PLC protocol
SCADA_MGMT = 2, -- SCADA supervisor management, device advertisements, etc SCADA_MGMT = 2, -- SCADA supervisor management, device advertisements, etc
SCADA_CRDN = 3, -- data/control packets for coordinators to/from supervisory controllers SCADA_CRDN = 3 -- data/control packets for coordinators to/from supervisory controllers
COORD_API = 4 -- data/control packets for pocket computers to/from coordinators
} }
---@enum RPLC_TYPE ---@enum RPLC_TYPE
@ -40,8 +42,8 @@ local RPLC_TYPE = {
AUTO_BURN_RATE = 10 -- set an automatic burn rate, PLC will respond with status, enable toggle speed limited AUTO_BURN_RATE = 10 -- set an automatic burn rate, PLC will respond with status, enable toggle speed limited
} }
---@enum SCADA_MGMT_TYPE ---@enum MGMT_TYPE
local SCADA_MGMT_TYPE = { local MGMT_TYPE = {
ESTABLISH = 0, -- establish new connection ESTABLISH = 0, -- establish new connection
KEEP_ALIVE = 1, -- keep alive packet w/ RTT KEEP_ALIVE = 1, -- keep alive packet w/ RTT
CLOSE = 2, -- close a connection CLOSE = 2, -- close a connection
@ -53,8 +55,8 @@ local SCADA_MGMT_TYPE = {
DIAG_ALARM_SET = 8 -- diagnostic: set alarm to simulate audio for DIAG_ALARM_SET = 8 -- diagnostic: set alarm to simulate audio for
} }
---@enum SCADA_CRDN_TYPE ---@enum CRDN_TYPE
local SCADA_CRDN_TYPE = { local CRDN_TYPE = {
INITIAL_BUILDS = 0, -- initial, complete builds packet to the coordinator INITIAL_BUILDS = 0, -- initial, complete builds packet to the coordinator
FAC_BUILDS = 1, -- facility RTU builds FAC_BUILDS = 1, -- facility RTU builds
FAC_STATUS = 2, -- state of facility and facility devices FAC_STATUS = 2, -- state of facility and facility devices
@ -64,10 +66,6 @@ local SCADA_CRDN_TYPE = {
UNIT_CMD = 6 -- command a reactor unit UNIT_CMD = 6 -- command a reactor unit
} }
---@enum CAPI_TYPE
local CAPI_TYPE = {
}
---@enum ESTABLISH_ACK ---@enum ESTABLISH_ACK
local ESTABLISH_ACK = { local ESTABLISH_ACK = {
ALLOW = 0, -- link approved ALLOW = 0, -- link approved
@ -76,14 +74,8 @@ local ESTABLISH_ACK = {
BAD_VERSION = 3 -- link denied due to comms version mismatch BAD_VERSION = 3 -- link denied due to comms version mismatch
} }
---@enum DEVICE_TYPE ---@enum DEVICE_TYPE device types for establish messages
local DEVICE_TYPE = { local DEVICE_TYPE = { PLC = 0, RTU = 1, SVR = 2, CRD = 3, PKT = 4 }
PLC = 0, -- PLC device type for establish
RTU = 1, -- RTU device type for establish
SV = 2, -- supervisor device type for establish
CRDN = 3, -- coordinator device type for establish
PKT = 4 -- pocket device type for establish
}
---@enum PLC_AUTO_ACK ---@enum PLC_AUTO_ACK
local PLC_AUTO_ACK = { local PLC_AUTO_ACK = {
@ -119,9 +111,8 @@ local UNIT_COMMAND = {
comms.PROTOCOL = PROTOCOL comms.PROTOCOL = PROTOCOL
comms.RPLC_TYPE = RPLC_TYPE comms.RPLC_TYPE = RPLC_TYPE
comms.SCADA_MGMT_TYPE = SCADA_MGMT_TYPE comms.MGMT_TYPE = MGMT_TYPE
comms.SCADA_CRDN_TYPE = SCADA_CRDN_TYPE comms.CRDN_TYPE = CRDN_TYPE
comms.CAPI_TYPE = CAPI_TYPE
comms.ESTABLISH_ACK = ESTABLISH_ACK comms.ESTABLISH_ACK = ESTABLISH_ACK
comms.DEVICE_TYPE = DEVICE_TYPE comms.DEVICE_TYPE = DEVICE_TYPE
@ -134,8 +125,8 @@ comms.FAC_COMMAND = FAC_COMMAND
-- destination broadcast address (to all devices) -- destination broadcast address (to all devices)
comms.BROADCAST = -1 comms.BROADCAST = -1
---@alias packet scada_packet|modbus_packet|rplc_packet|mgmt_packet|crdn_packet|capi_packet ---@alias packet scada_packet|modbus_packet|rplc_packet|mgmt_packet|crdn_packet
---@alias frame modbus_frame|rplc_frame|mgmt_frame|crdn_frame|capi_frame ---@alias frame modbus_frame|rplc_frame|mgmt_frame|crdn_frame
-- configure the maximum allowable message receive distance<br> -- configure the maximum allowable message receive distance<br>
-- packets received with distances greater than this will be silently discarded -- packets received with distances greater than this will be silently discarded
@ -144,7 +135,7 @@ function comms.set_trusted_range(distance)
if distance == 0 then max_distance = nil else max_distance = distance end if distance == 0 then max_distance = nil else max_distance = distance end
end end
-- generic SCADA packet object -- generic SCADA packet
---@nodiscard ---@nodiscard
function comms.scada_packet() function comms.scada_packet()
local self = { local self = {
@ -199,9 +190,9 @@ function comms.scada_packet()
self.valid = false self.valid = false
self.raw = self.modem_msg_in.msg self.raw = self.modem_msg_in.msg
if (type(max_distance) == "number") and (distance > max_distance) then if (type(max_distance) == "number") and (type(distance) == "number") and (distance > max_distance) then
-- outside of maximum allowable transmission distance -- outside of maximum allowable transmission distance
-- log.debug("comms.scada_packet.receive(): discarding packet with distance " .. distance .. " outside of trusted range") -- log.debug("comms.scada_packet.receive(): discarding packet with distance " .. distance .. " (outside trusted range)")
else else
if type(self.raw) == "table" then if type(self.raw) == "table" then
if #self.raw == 5 then if #self.raw == 5 then
@ -227,12 +218,8 @@ function comms.scada_packet()
-- check if this packet is destined for this device -- check if this packet is destined for this device
local is_destination = (self.dest_addr == comms.BROADCAST) or (self.dest_addr == COMPUTER_ID) local is_destination = (self.dest_addr == comms.BROADCAST) or (self.dest_addr == COMPUTER_ID)
self.valid = is_destination and self.valid = is_destination and type(self.src_addr) == "number" and type(self.dest_addr) == "number" and
type(self.src_addr) == "number" and type(self.seq_num) == "number" and type(self.protocol) == "number" and type(self.payload) == "table"
type(self.dest_addr) == "number" and
type(self.seq_num) == "number" and
type(self.protocol) == "number" and
type(self.payload) == "table"
end end
end end
@ -275,7 +262,7 @@ function comms.scada_packet()
return public return public
end end
-- authenticated SCADA packet object -- authenticated SCADA packet
---@nodiscard ---@nodiscard
function comms.authd_packet() function comms.authd_packet()
local self = { local self = {
@ -325,7 +312,7 @@ function comms.authd_packet()
if (type(max_distance) == "number") and (type(distance) == "number") and (distance > max_distance) then if (type(max_distance) == "number") and (type(distance) == "number") and (distance > max_distance) then
-- outside of maximum allowable transmission distance -- outside of maximum allowable transmission distance
-- log.debug("comms.authd_packet.receive(): discarding packet with distance " .. distance .. " outside of trusted range") -- log.debug("comms.authd_packet.receive(): discarding packet with distance " .. distance .. " (outside trusted range)")
else else
if type(self.raw) == "table" then if type(self.raw) == "table" then
if #self.raw == 4 then if #self.raw == 4 then
@ -343,11 +330,8 @@ function comms.authd_packet()
-- check if this packet is destined for this device -- check if this packet is destined for this device
local is_destination = (self.dest_addr == comms.BROADCAST) or (self.dest_addr == COMPUTER_ID) local is_destination = (self.dest_addr == comms.BROADCAST) or (self.dest_addr == COMPUTER_ID)
self.valid = is_destination and self.valid = is_destination and type(self.src_addr) == "number" and type(self.dest_addr) == "number" and
type(self.src_addr) == "number" and type(self.mac) == "string" and type(self.payload) == "string"
type(self.dest_addr) == "number" and
type(self.mac) == "string" and
type(self.payload) == "string"
end end
end end
@ -381,8 +365,7 @@ function comms.authd_packet()
return public return public
end end
-- MODBUS packet<br> -- MODBUS packet, modeled after MODBUS TCP
-- modeled after MODBUS TCP packet
---@nodiscard ---@nodiscard
function comms.modbus_packet() function comms.modbus_packet()
local self = { local self = {
@ -436,9 +419,7 @@ function comms.modbus_packet()
public.make(data[1], data[2], data[3], { table.unpack(data, 4, #data) }) public.make(data[1], data[2], data[3], { table.unpack(data, 4, #data) })
end end
local valid = type(self.txn_id) == "number" and local valid = type(self.txn_id) == "number" and type(self.unit_id) == "number" and type(self.func_code) == "number"
type(self.unit_id) == "number" and
type(self.func_code) == "number"
return size_ok and valid return size_ok and valid
else else
@ -489,21 +470,6 @@ function comms.rplc_packet()
---@class rplc_packet ---@class rplc_packet
local public = {} local public = {}
-- check that type is known
local function _rplc_type_valid()
return self.type == RPLC_TYPE.STATUS or
self.type == RPLC_TYPE.MEK_STRUCT or
self.type == RPLC_TYPE.MEK_BURN_RATE or
self.type == RPLC_TYPE.RPS_ENABLE or
self.type == RPLC_TYPE.RPS_SCRAM or
self.type == RPLC_TYPE.RPS_ASCRAM or
self.type == RPLC_TYPE.RPS_STATUS or
self.type == RPLC_TYPE.RPS_ALARM or
self.type == RPLC_TYPE.RPS_RESET or
self.type == RPLC_TYPE.RPS_AUTO_RESET or
self.type == RPLC_TYPE.AUTO_BURN_RATE
end
-- make an RPLC packet -- make an RPLC packet
---@param id integer ---@param id integer
---@param packet_type RPLC_TYPE ---@param packet_type RPLC_TYPE
@ -539,7 +505,6 @@ function comms.rplc_packet()
if ok then if ok then
local data = frame.data() local data = frame.data()
public.make(data[1], data[2], { table.unpack(data, 3, #data) }) public.make(data[1], data[2], { table.unpack(data, 3, #data) })
ok = _rplc_type_valid()
end end
ok = ok and type(self.id) == "number" ok = ok and type(self.id) == "number"
@ -583,7 +548,7 @@ function comms.mgmt_packet()
local self = { local self = {
frame = nil, frame = nil,
raw = {}, raw = {},
type = 0, ---@type SCADA_MGMT_TYPE type = 0, ---@type MGMT_TYPE
length = 0, length = 0,
data = {} data = {}
} }
@ -591,22 +556,8 @@ function comms.mgmt_packet()
---@class mgmt_packet ---@class mgmt_packet
local public = {} local public = {}
-- check that type is known
local function _scada_type_valid()
return self.type == SCADA_MGMT_TYPE.ESTABLISH or
self.type == SCADA_MGMT_TYPE.KEEP_ALIVE or
self.type == SCADA_MGMT_TYPE.CLOSE or
self.type == SCADA_MGMT_TYPE.REMOTE_LINKED or
self.type == SCADA_MGMT_TYPE.RTU_ADVERT or
self.type == SCADA_MGMT_TYPE.RTU_DEV_REMOUNT or
self.type == SCADA_MGMT_TYPE.RTU_TONE_ALARM or
self.type == SCADA_MGMT_TYPE.DIAG_TONE_GET or
self.type == SCADA_MGMT_TYPE.DIAG_TONE_SET or
self.type == SCADA_MGMT_TYPE.DIAG_ALARM_SET
end
-- make a SCADA management packet -- make a SCADA management packet
---@param packet_type SCADA_MGMT_TYPE ---@param packet_type MGMT_TYPE
---@param data table ---@param data table
function public.make(packet_type, data) function public.make(packet_type, data)
if type(data) == "table" then if type(data) == "table" then
@ -638,7 +589,6 @@ function comms.mgmt_packet()
if ok then if ok then
local data = frame.data() local data = frame.data()
public.make(data[1], { table.unpack(data, 2, #data) }) public.make(data[1], { table.unpack(data, 2, #data) })
ok = _scada_type_valid()
end end
return ok return ok
@ -679,7 +629,7 @@ function comms.crdn_packet()
local self = { local self = {
frame = nil, frame = nil,
raw = {}, raw = {},
type = 0, ---@type SCADA_CRDN_TYPE type = 0, ---@type CRDN_TYPE
length = 0, length = 0,
data = {} data = {}
} }
@ -687,20 +637,8 @@ function comms.crdn_packet()
---@class crdn_packet ---@class crdn_packet
local public = {} local public = {}
-- check that type is known
---@nodiscard
local function _crdn_type_valid()
return self.type == SCADA_CRDN_TYPE.INITIAL_BUILDS or
self.type == SCADA_CRDN_TYPE.FAC_BUILDS or
self.type == SCADA_CRDN_TYPE.FAC_STATUS or
self.type == SCADA_CRDN_TYPE.FAC_CMD or
self.type == SCADA_CRDN_TYPE.UNIT_BUILDS or
self.type == SCADA_CRDN_TYPE.UNIT_STATUSES or
self.type == SCADA_CRDN_TYPE.UNIT_CMD
end
-- make a coordinator packet -- make a coordinator packet
---@param packet_type SCADA_CRDN_TYPE ---@param packet_type CRDN_TYPE
---@param data table ---@param data table
function public.make(packet_type, data) function public.make(packet_type, data)
if type(data) == "table" then if type(data) == "table" then
@ -732,7 +670,6 @@ function comms.crdn_packet()
if ok then if ok then
local data = frame.data() local data = frame.data()
public.make(data[1], { table.unpack(data, 2, #data) }) public.make(data[1], { table.unpack(data, 2, #data) })
ok = _crdn_type_valid()
end end
return ok return ok
@ -767,92 +704,4 @@ function comms.crdn_packet()
return public return public
end end
-- coordinator API (CAPI) packet
---@todo implement for pocket access, set enum type for self.type
---@nodiscard
function comms.capi_packet()
local self = {
frame = nil,
raw = {},
type = 0,
length = 0,
data = {}
}
---@class capi_packet
local public = {}
local function _capi_type_valid()
---@todo
return false
end
-- make a coordinator API packet
---@param packet_type CAPI_TYPE
---@param data table
function public.make(packet_type, data)
if type(data) == "table" then
-- packet accessor properties
self.type = packet_type
self.length = #data
self.data = data
-- populate raw array
self.raw = { self.type }
for i = 1, #data do
insert(self.raw, data[i])
end
else
log.error("comms.capi_packet.make(): data not table")
end
end
-- decode a coordinator API packet from a SCADA frame
---@param frame scada_packet
---@return boolean success
function public.decode(frame)
if frame then
self.frame = frame
if frame.protocol() == PROTOCOL.COORD_API then
local ok = frame.length() >= 1
if ok then
local data = frame.data()
public.make(data[1], { table.unpack(data, 2, #data) })
ok = _capi_type_valid()
end
return ok
else
log.debug("attempted COORD_API parse of incorrect protocol " .. frame.protocol(), true)
return false
end
else
log.debug("nil frame encountered", true)
return false
end
end
-- get raw to send
---@nodiscard
function public.raw_sendable() return self.raw end
-- get this packet as a frame with an immutable relation to this object
---@nodiscard
function public.get()
---@class capi_frame
local frame = {
scada_frame = self.frame,
type = self.type,
length = self.length,
data = self.data
}
return frame
end
return public
end
return comms return comms

View File

@ -8,7 +8,7 @@ local cc_strings = require("cc.strings")
local util = {} local util = {}
-- scada-common version -- scada-common version
util.version = "1.0.2" util.version = "1.1.0"
-- ENVIRONMENT CONSTANTS -- -- ENVIRONMENT CONSTANTS --
@ -76,25 +76,12 @@ function util.strval(val)
end end
end end
-- repeat a string n times
---@nodiscard
---@param str string
---@param n integer
---@return string
function util.strrep(str, n)
local repeated = ""
for _ = 1, n do repeated = repeated .. str end
return repeated
end
-- repeat a space n times -- repeat a space n times
---@nodiscard ---@nodiscard
---@param n integer ---@param n integer
---@return string ---@return string
function util.spaces(n) function util.spaces(n)
return util.strrep(" ", n) return string.rep(" ", n)
end end
-- pad text to a minimum width -- pad text to a minimum width

View File

@ -4,6 +4,8 @@
local databus = require("supervisor.databus") local databus = require("supervisor.databus")
local style = require("supervisor.panel.style")
local core = require("graphics.core") local core = require("graphics.core")
local Div = require("graphics.elements.div") local Div = require("graphics.elements.div")
@ -15,28 +17,31 @@ local TEXT_ALIGN = core.TEXT_ALIGN
local cpair = core.cpair local cpair = core.cpair
local black_lg = style.black_lg
local lg_white = style.lg_white
-- create a pocket diagnostics list entry -- create a pocket diagnostics list entry
---@param parent graphics_element parent ---@param parent graphics_element parent
---@param id integer PDG session ID ---@param id integer PDG session ID
local function init(parent, id) local function init(parent, id)
-- root div -- root div
local root = Div{parent=parent,x=2,y=2,height=4,width=parent.get_width()-2,hidden=true} local root = Div{parent=parent,x=2,y=2,height=4,width=parent.get_width()-2,hidden=true}
local entry = Div{parent=root,x=2,y=1,height=3,fg_bg=cpair(colors.black,colors.white)} local entry = Div{parent=root,x=2,y=1,height=3,fg_bg=style.bw_fg_bg}
local ps_prefix = "pdg_" .. id .. "_" local ps_prefix = "pdg_" .. id .. "_"
TextBox{parent=entry,x=1,y=1,text="",width=8,height=1,fg_bg=cpair(colors.black,colors.lightGray)} TextBox{parent=entry,x=1,y=1,text="",width=8,height=1,fg_bg=black_lg}
local pdg_addr = TextBox{parent=entry,x=1,y=2,text="@ C ??",alignment=TEXT_ALIGN.CENTER,width=8,height=1,fg_bg=cpair(colors.black,colors.lightGray),nav_active=cpair(colors.gray,colors.black)} local pdg_addr = TextBox{parent=entry,x=1,y=2,text="@ C ??",alignment=TEXT_ALIGN.CENTER,width=8,height=1,fg_bg=black_lg,nav_active=cpair(colors.gray,colors.black)}
TextBox{parent=entry,x=1,y=3,text="",width=8,height=1,fg_bg=cpair(colors.black,colors.lightGray)} TextBox{parent=entry,x=1,y=3,text="",width=8,height=1,fg_bg=black_lg}
pdg_addr.register(databus.ps, ps_prefix .. "addr", pdg_addr.set_value) pdg_addr.register(databus.ps, ps_prefix .. "addr", pdg_addr.set_value)
TextBox{parent=entry,x=10,y=2,text="FW:",width=3,height=1} TextBox{parent=entry,x=10,y=2,text="FW:",width=3,height=1}
local pdg_fw_v = TextBox{parent=entry,x=14,y=2,text=" ------- ",width=20,height=1,fg_bg=cpair(colors.lightGray,colors.white)} local pdg_fw_v = TextBox{parent=entry,x=14,y=2,text=" ------- ",width=20,height=1,fg_bg=lg_white}
pdg_fw_v.register(databus.ps, ps_prefix .. "fw", pdg_fw_v.set_value) pdg_fw_v.register(databus.ps, ps_prefix .. "fw", pdg_fw_v.set_value)
TextBox{parent=entry,x=35,y=2,text="RTT:",width=4,height=1} TextBox{parent=entry,x=35,y=2,text="RTT:",width=4,height=1}
local pdg_rtt = DataIndicator{parent=entry,x=40,y=2,label="",unit="",format="%5d",value=0,width=5,fg_bg=cpair(colors.lightGray,colors.white)} local pdg_rtt = DataIndicator{parent=entry,x=40,y=2,label="",unit="",format="%5d",value=0,width=5,fg_bg=lg_white}
TextBox{parent=entry,x=46,y=2,text="ms",width=4,height=1,fg_bg=cpair(colors.lightGray,colors.white)} TextBox{parent=entry,x=46,y=2,text="ms",width=4,height=1,fg_bg=lg_white}
pdg_rtt.register(databus.ps, ps_prefix .. "rtt", pdg_rtt.update) pdg_rtt.register(databus.ps, ps_prefix .. "rtt", pdg_rtt.update)
pdg_rtt.register(databus.ps, ps_prefix .. "rtt_color", pdg_rtt.recolor) pdg_rtt.register(databus.ps, ps_prefix .. "rtt_color", pdg_rtt.recolor)

View File

@ -4,6 +4,8 @@
local databus = require("supervisor.databus") local databus = require("supervisor.databus")
local style = require("supervisor.panel.style")
local core = require("graphics.core") local core = require("graphics.core")
local Div = require("graphics.elements.div") local Div = require("graphics.elements.div")
@ -15,32 +17,35 @@ local TEXT_ALIGN = core.TEXT_ALIGN
local cpair = core.cpair local cpair = core.cpair
local black_lg = style.black_lg
local lg_white = style.lg_white
-- create an RTU list entry -- create an RTU list entry
---@param parent graphics_element parent ---@param parent graphics_element parent
---@param id integer RTU session ID ---@param id integer RTU session ID
local function init(parent, id) local function init(parent, id)
-- root div -- root div
local root = Div{parent=parent,x=2,y=2,height=4,width=parent.get_width()-2,hidden=true} local root = Div{parent=parent,x=2,y=2,height=4,width=parent.get_width()-2,hidden=true}
local entry = Div{parent=root,x=2,y=1,height=3,fg_bg=cpair(colors.black,colors.white)} local entry = Div{parent=root,x=2,y=1,height=3,fg_bg=style.bw_fg_bg}
local ps_prefix = "rtu_" .. id .. "_" local ps_prefix = "rtu_" .. id .. "_"
TextBox{parent=entry,x=1,y=1,text="",width=8,height=1,fg_bg=cpair(colors.black,colors.lightGray)} TextBox{parent=entry,x=1,y=1,text="",width=8,height=1,fg_bg=black_lg}
local rtu_addr = TextBox{parent=entry,x=1,y=2,text="@ C ??",alignment=TEXT_ALIGN.CENTER,width=8,height=1,fg_bg=cpair(colors.black,colors.lightGray),nav_active=cpair(colors.gray,colors.black)} local rtu_addr = TextBox{parent=entry,x=1,y=2,text="@ C ??",alignment=TEXT_ALIGN.CENTER,width=8,height=1,fg_bg=black_lg,nav_active=cpair(colors.gray,colors.black)}
TextBox{parent=entry,x=1,y=3,text="",width=8,height=1,fg_bg=cpair(colors.black,colors.lightGray)} TextBox{parent=entry,x=1,y=3,text="",width=8,height=1,fg_bg=black_lg}
rtu_addr.register(databus.ps, ps_prefix .. "addr", rtu_addr.set_value) rtu_addr.register(databus.ps, ps_prefix .. "addr", rtu_addr.set_value)
TextBox{parent=entry,x=10,y=2,text="UNITS:",width=7,height=1} TextBox{parent=entry,x=10,y=2,text="UNITS:",width=7,height=1}
local unit_count = DataIndicator{parent=entry,x=17,y=2,label="",unit="",format="%2d",value=0,width=2,fg_bg=cpair(colors.gray,colors.white)} local unit_count = DataIndicator{parent=entry,x=17,y=2,label="",unit="",format="%2d",value=0,width=2,fg_bg=style.gray_white}
unit_count.register(databus.ps, ps_prefix .. "units", unit_count.set_value) unit_count.register(databus.ps, ps_prefix .. "units", unit_count.set_value)
TextBox{parent=entry,x=21,y=2,text="FW:",width=3,height=1} TextBox{parent=entry,x=21,y=2,text="FW:",width=3,height=1}
local rtu_fw_v = TextBox{parent=entry,x=25,y=2,text=" ------- ",width=9,height=1,fg_bg=cpair(colors.lightGray,colors.white)} local rtu_fw_v = TextBox{parent=entry,x=25,y=2,text=" ------- ",width=9,height=1,fg_bg=lg_white}
rtu_fw_v.register(databus.ps, ps_prefix .. "fw", rtu_fw_v.set_value) rtu_fw_v.register(databus.ps, ps_prefix .. "fw", rtu_fw_v.set_value)
TextBox{parent=entry,x=36,y=2,text="RTT:",width=4,height=1} TextBox{parent=entry,x=36,y=2,text="RTT:",width=4,height=1}
local rtu_rtt = DataIndicator{parent=entry,x=40,y=2,label="",unit="",format="%5d",value=0,width=5,fg_bg=cpair(colors.lightGray,colors.white)} local rtu_rtt = DataIndicator{parent=entry,x=40,y=2,label="",unit="",format="%5d",value=0,width=5,fg_bg=lg_white}
TextBox{parent=entry,x=46,y=2,text="ms",width=4,height=1,fg_bg=cpair(colors.lightGray,colors.white)} TextBox{parent=entry,x=46,y=2,text="ms",width=4,height=1,fg_bg=lg_white}
rtu_rtt.register(databus.ps, ps_prefix .. "rtt", rtu_rtt.update) rtu_rtt.register(databus.ps, ps_prefix .. "rtt", rtu_rtt.update)
rtu_rtt.register(databus.ps, ps_prefix .. "rtt_color", rtu_rtt.recolor) rtu_rtt.register(databus.ps, ps_prefix .. "rtt_color", rtu_rtt.recolor)

View File

@ -29,6 +29,14 @@ local TEXT_ALIGN = core.TEXT_ALIGN
local cpair = core.cpair local cpair = core.cpair
local bw_fg_bg = style.bw_fg_bg
local black_lg = style.black_lg
local lg_white = style.lg_white
local gry_wht = style.gray_white
local ind_grn = style.ind_grn
-- create new front panel view -- create new front panel view
---@param panel graphics_element main displaybox ---@param panel graphics_element main displaybox
local function init(panel) local function init(panel)
@ -45,26 +53,26 @@ local function init(panel)
local system = Div{parent=main_page,width=14,height=17,x=2,y=2} local system = Div{parent=main_page,width=14,height=17,x=2,y=2}
local on = LED{parent=system,label="STATUS",colors=cpair(colors.green,colors.red)} local on = LED{parent=system,label="STATUS",colors=cpair(colors.green,colors.red)}
local heartbeat = LED{parent=system,label="HEARTBEAT",colors=cpair(colors.green,colors.green_off)} local heartbeat = LED{parent=system,label="HEARTBEAT",colors=ind_grn}
on.update(true) on.update(true)
system.line_break() system.line_break()
heartbeat.register(databus.ps, "heartbeat", heartbeat.update) heartbeat.register(databus.ps, "heartbeat", heartbeat.update)
local modem = LED{parent=system,label="MODEM",colors=cpair(colors.green,colors.green_off)} local modem = LED{parent=system,label="MODEM",colors=ind_grn}
system.line_break() system.line_break()
modem.register(databus.ps, "has_modem", modem.update) modem.register(databus.ps, "has_modem", modem.update)
---@diagnostic disable-next-line: undefined-field ---@diagnostic disable-next-line: undefined-field
local comp_id = util.sprintf("(%d)", os.getComputerID()) local comp_id = util.sprintf("(%d)", os.getComputerID())
TextBox{parent=system,x=9,y=4,width=6,height=1,text=comp_id,fg_bg=cpair(colors.lightGray,colors.ivory)} TextBox{parent=system,x=9,y=4,width=6,height=1,text=comp_id,fg_bg=style.fp_label}
-- --
-- about footer -- about footer
-- --
local about = Div{parent=main_page,width=15,height=3,x=1,y=16,fg_bg=cpair(colors.lightGray,colors.ivory)} local about = Div{parent=main_page,width=15,height=3,x=1,y=16,fg_bg=style.fp_label}
local fw_v = TextBox{parent=about,x=1,y=1,text="FW: v00.00.00",alignment=TEXT_ALIGN.LEFT,height=1} local fw_v = TextBox{parent=about,x=1,y=1,text="FW: v00.00.00",alignment=TEXT_ALIGN.LEFT,height=1}
local comms_v = TextBox{parent=about,x=1,y=2,text="NT: v00.00.00",alignment=TEXT_ALIGN.LEFT,height=1} local comms_v = TextBox{parent=about,x=1,y=2,text="NT: v00.00.00",alignment=TEXT_ALIGN.LEFT,height=1}
@ -82,25 +90,25 @@ local function init(panel)
for i = 1, config.NUM_REACTORS do for i = 1, config.NUM_REACTORS do
local ps_prefix = "plc_" .. i .. "_" local ps_prefix = "plc_" .. i .. "_"
local plc_entry = Div{parent=plc_list,height=3,fg_bg=cpair(colors.black,colors.white)} local plc_entry = Div{parent=plc_list,height=3,fg_bg=bw_fg_bg}
TextBox{parent=plc_entry,x=1,y=1,text="",width=8,height=1,fg_bg=cpair(colors.black,colors.lightGray)} TextBox{parent=plc_entry,x=1,y=1,text="",width=8,height=1,fg_bg=black_lg}
TextBox{parent=plc_entry,x=1,y=2,text="UNIT "..i,alignment=TEXT_ALIGN.CENTER,width=8,height=1,fg_bg=cpair(colors.black,colors.lightGray)} TextBox{parent=plc_entry,x=1,y=2,text="UNIT "..i,alignment=TEXT_ALIGN.CENTER,width=8,height=1,fg_bg=black_lg}
TextBox{parent=plc_entry,x=1,y=3,text="",width=8,height=1,fg_bg=cpair(colors.black,colors.lightGray)} TextBox{parent=plc_entry,x=1,y=3,text="",width=8,height=1,fg_bg=black_lg}
local conn = LED{parent=plc_entry,x=10,y=2,label="LINK",colors=cpair(colors.green,colors.green_off)} local conn = LED{parent=plc_entry,x=10,y=2,label="LINK",colors=ind_grn}
conn.register(databus.ps, ps_prefix .. "conn", conn.update) conn.register(databus.ps, ps_prefix .. "conn", conn.update)
local plc_addr = TextBox{parent=plc_entry,x=17,y=2,text=" --- ",width=5,height=1,fg_bg=cpair(colors.gray,colors.white)} local plc_addr = TextBox{parent=plc_entry,x=17,y=2,text=" --- ",width=5,height=1,fg_bg=gry_wht}
plc_addr.register(databus.ps, ps_prefix .. "addr", plc_addr.set_value) plc_addr.register(databus.ps, ps_prefix .. "addr", plc_addr.set_value)
TextBox{parent=plc_entry,x=23,y=2,text="FW:",width=3,height=1} TextBox{parent=plc_entry,x=23,y=2,text="FW:",width=3,height=1}
local plc_fw_v = TextBox{parent=plc_entry,x=27,y=2,text=" ------- ",width=9,height=1,fg_bg=cpair(colors.lightGray,colors.white)} local plc_fw_v = TextBox{parent=plc_entry,x=27,y=2,text=" ------- ",width=9,height=1,fg_bg=lg_white}
plc_fw_v.register(databus.ps, ps_prefix .. "fw", plc_fw_v.set_value) plc_fw_v.register(databus.ps, ps_prefix .. "fw", plc_fw_v.set_value)
TextBox{parent=plc_entry,x=37,y=2,text="RTT:",width=4,height=1} TextBox{parent=plc_entry,x=37,y=2,text="RTT:",width=4,height=1}
local plc_rtt = DataIndicator{parent=plc_entry,x=42,y=2,label="",unit="",format="%4d",value=0,width=4,fg_bg=cpair(colors.lightGray,colors.white)} local plc_rtt = DataIndicator{parent=plc_entry,x=42,y=2,label="",unit="",format="%4d",value=0,width=4,fg_bg=lg_white}
TextBox{parent=plc_entry,x=47,y=2,text="ms",width=4,height=1,fg_bg=cpair(colors.lightGray,colors.white)} TextBox{parent=plc_entry,x=47,y=2,text="ms",width=4,height=1,fg_bg=lg_white}
plc_rtt.register(databus.ps, ps_prefix .. "rtt", plc_rtt.update) plc_rtt.register(databus.ps, ps_prefix .. "rtt", plc_rtt.update)
plc_rtt.register(databus.ps, ps_prefix .. "rtt_color", plc_rtt.recolor) plc_rtt.register(databus.ps, ps_prefix .. "rtt_color", plc_rtt.recolor)
@ -116,22 +124,22 @@ local function init(panel)
-- coordinator page -- coordinator page
local crd_page = Div{parent=page_div,x=1,y=1,hidden=true} local crd_page = Div{parent=page_div,x=1,y=1,hidden=true}
local crd_box = Div{parent=crd_page,x=2,y=2,width=49,height=4,fg_bg=cpair(colors.black,colors.white)} local crd_box = Div{parent=crd_page,x=2,y=2,width=49,height=4,fg_bg=bw_fg_bg}
local crd_conn = LED{parent=crd_box,x=2,y=2,label="CONNECTION",colors=cpair(colors.green,colors.green_off)} local crd_conn = LED{parent=crd_box,x=2,y=2,label="CONNECTION",colors=ind_grn}
crd_conn.register(databus.ps, "crd_conn", crd_conn.update) crd_conn.register(databus.ps, "crd_conn", crd_conn.update)
TextBox{parent=crd_box,x=4,y=3,text="COMPUTER",width=8,height=1,fg_bg=cpair(colors.gray,colors.white)} TextBox{parent=crd_box,x=4,y=3,text="COMPUTER",width=8,height=1,fg_bg=gry_wht}
local crd_addr = TextBox{parent=crd_box,x=13,y=3,text="---",width=5,height=1,fg_bg=cpair(colors.gray,colors.white)} local crd_addr = TextBox{parent=crd_box,x=13,y=3,text="---",width=5,height=1,fg_bg=gry_wht}
crd_addr.register(databus.ps, "crd_addr", crd_addr.set_value) crd_addr.register(databus.ps, "crd_addr", crd_addr.set_value)
TextBox{parent=crd_box,x=22,y=2,text="FW:",width=3,height=1} TextBox{parent=crd_box,x=22,y=2,text="FW:",width=3,height=1}
local crd_fw_v = TextBox{parent=crd_box,x=26,y=2,text=" ------- ",width=9,height=1,fg_bg=cpair(colors.lightGray,colors.white)} local crd_fw_v = TextBox{parent=crd_box,x=26,y=2,text=" ------- ",width=9,height=1,fg_bg=lg_white}
crd_fw_v.register(databus.ps, "crd_fw", crd_fw_v.set_value) crd_fw_v.register(databus.ps, "crd_fw", crd_fw_v.set_value)
TextBox{parent=crd_box,x=36,y=2,text="RTT:",width=4,height=1} TextBox{parent=crd_box,x=36,y=2,text="RTT:",width=4,height=1}
local crd_rtt = DataIndicator{parent=crd_box,x=41,y=2,label="",unit="",format="%5d",value=0,width=5,fg_bg=cpair(colors.lightGray,colors.white)} local crd_rtt = DataIndicator{parent=crd_box,x=41,y=2,label="",unit="",format="%5d",value=0,width=5,fg_bg=lg_white}
TextBox{parent=crd_box,x=47,y=2,text="ms",width=4,height=1,fg_bg=cpair(colors.lightGray,colors.white)} TextBox{parent=crd_box,x=47,y=2,text="ms",width=4,height=1,fg_bg=lg_white}
crd_rtt.register(databus.ps, "crd_rtt", crd_rtt.update) crd_rtt.register(databus.ps, "crd_rtt", crd_rtt.update)
crd_rtt.register(databus.ps, "crd_rtt_color", crd_rtt.recolor) crd_rtt.register(databus.ps, "crd_rtt_color", crd_rtt.recolor)
@ -155,7 +163,7 @@ local function init(panel)
{ name = "PKT", color = cpair(colors.black, colors.ivory) }, { name = "PKT", color = cpair(colors.black, colors.ivory) },
} }
TabBar{parent=panel,y=2,tabs=tabs,min_width=9,callback=page_pane.set_value,fg_bg=cpair(colors.black,colors.white)} TabBar{parent=panel,y=2,tabs=tabs,min_width=9,callback=page_pane.set_value,fg_bg=bw_fg_bg}
-- link RTU/PDG list management to PGI -- link RTU/PDG list management to PGI
pgi.link_elements(rtu_list, rtu_entry, pdg_list, pdg_entry) pgi.link_elements(rtu_list, rtu_entry, pdg_list, pdg_entry)

View File

@ -39,4 +39,16 @@ style.colors = {
{ c = colors.brown, hex = 0x672223 } -- RED OFF { c = colors.brown, hex = 0x672223 } -- RED OFF
} }
-- COMMON COLOR PAIRS --
style.text_fg_bg = cpair(colors.black, colors.ivory)
style.bw_fg_bg = cpair(colors.black, colors.white)
style.fp_label = cpair(colors.lightGray, colors.ivory)
style.black_lg = cpair(colors.black, colors.lightGray)
style.lg_white = cpair(colors.lightGray, colors.white)
style.gray_white = cpair(colors.gray, colors.white)
style.ind_grn = cpair(colors.green, colors.green_off)
return style return style

View File

@ -10,8 +10,8 @@ local svqtypes = require("supervisor.session.svqtypes")
local coordinator = {} local coordinator = {}
local PROTOCOL = comms.PROTOCOL local PROTOCOL = comms.PROTOCOL
local SCADA_MGMT_TYPE = comms.SCADA_MGMT_TYPE local MGMT_TYPE = comms.MGMT_TYPE
local SCADA_CRDN_TYPE = comms.SCADA_CRDN_TYPE local CRDN_TYPE = comms.CRDN_TYPE
local UNIT_COMMAND = comms.UNIT_COMMAND local UNIT_COMMAND = comms.UNIT_COMMAND
local FAC_COMMAND = comms.FAC_COMMAND local FAC_COMMAND = comms.FAC_COMMAND
@ -94,7 +94,7 @@ function coordinator.new_session(id, s_addr, in_queue, out_queue, timeout, facil
end end
-- send a CRDN packet -- send a CRDN packet
---@param msg_type SCADA_CRDN_TYPE ---@param msg_type CRDN_TYPE
---@param msg table ---@param msg table
local function _send(msg_type, msg) local function _send(msg_type, msg)
local s_pkt = comms.scada_packet() local s_pkt = comms.scada_packet()
@ -108,7 +108,7 @@ function coordinator.new_session(id, s_addr, in_queue, out_queue, timeout, facil
end end
-- send a SCADA management packet -- send a SCADA management packet
---@param msg_type SCADA_MGMT_TYPE ---@param msg_type MGMT_TYPE
---@param msg table ---@param msg table
local function _send_mgmt(msg_type, msg) local function _send_mgmt(msg_type, msg)
local s_pkt = comms.scada_packet() local s_pkt = comms.scada_packet()
@ -130,12 +130,12 @@ function coordinator.new_session(id, s_addr, in_queue, out_queue, timeout, facil
unit_builds[unit.get_id()] = unit.get_build() unit_builds[unit.get_id()] = unit.get_build()
end end
_send(SCADA_CRDN_TYPE.INITIAL_BUILDS, { facility.get_build(), unit_builds }) _send(CRDN_TYPE.INITIAL_BUILDS, { facility.get_build(), unit_builds })
end end
-- send facility builds -- send facility builds
local function _send_fac_builds() local function _send_fac_builds()
_send(SCADA_CRDN_TYPE.FAC_BUILDS, { facility.get_build() }) _send(CRDN_TYPE.FAC_BUILDS, { facility.get_build() })
end end
-- send unit builds -- send unit builds
@ -147,7 +147,7 @@ function coordinator.new_session(id, s_addr, in_queue, out_queue, timeout, facil
builds[unit.get_id()] = unit.get_build() builds[unit.get_id()] = unit.get_build()
end end
_send(SCADA_CRDN_TYPE.UNIT_BUILDS, { builds }) _send(CRDN_TYPE.UNIT_BUILDS, { builds })
end end
-- send facility status -- send facility status
@ -158,7 +158,7 @@ function coordinator.new_session(id, s_addr, in_queue, out_queue, timeout, facil
facility.get_alarm_tones() facility.get_alarm_tones()
} }
_send(SCADA_CRDN_TYPE.FAC_STATUS, status) _send(CRDN_TYPE.FAC_STATUS, status)
end end
-- send unit statuses -- send unit statuses
@ -178,7 +178,7 @@ function coordinator.new_session(id, s_addr, in_queue, out_queue, timeout, facil
} }
end end
_send(SCADA_CRDN_TYPE.UNIT_STATUSES, status) _send(CRDN_TYPE.UNIT_STATUSES, status)
end end
-- handle a packet -- handle a packet
@ -200,7 +200,7 @@ function coordinator.new_session(id, s_addr, in_queue, out_queue, timeout, facil
-- process packet -- process packet
if pkt.scada_frame.protocol() == PROTOCOL.SCADA_MGMT then if pkt.scada_frame.protocol() == PROTOCOL.SCADA_MGMT then
---@cast pkt mgmt_frame ---@cast pkt mgmt_frame
if pkt.type == SCADA_MGMT_TYPE.KEEP_ALIVE then if pkt.type == MGMT_TYPE.KEEP_ALIVE then
-- keep alive reply -- keep alive reply
if pkt.length == 2 then if pkt.length == 2 then
local srv_start = pkt.data[1] local srv_start = pkt.data[1]
@ -219,7 +219,7 @@ function coordinator.new_session(id, s_addr, in_queue, out_queue, timeout, facil
else else
log.debug(log_header .. "SCADA keep alive packet length mismatch") log.debug(log_header .. "SCADA keep alive packet length mismatch")
end end
elseif pkt.type == SCADA_MGMT_TYPE.CLOSE then elseif pkt.type == MGMT_TYPE.CLOSE then
-- close the session -- close the session
_close() _close()
else else
@ -227,22 +227,22 @@ function coordinator.new_session(id, s_addr, in_queue, out_queue, timeout, facil
end end
elseif pkt.scada_frame.protocol() == PROTOCOL.SCADA_CRDN then elseif pkt.scada_frame.protocol() == PROTOCOL.SCADA_CRDN then
---@cast pkt crdn_frame ---@cast pkt crdn_frame
if pkt.type == SCADA_CRDN_TYPE.INITIAL_BUILDS then if pkt.type == CRDN_TYPE.INITIAL_BUILDS then
-- acknowledgement to coordinator receiving builds -- acknowledgement to coordinator receiving builds
self.acks.builds = true self.acks.builds = true
elseif pkt.type == SCADA_CRDN_TYPE.FAC_BUILDS then elseif pkt.type == CRDN_TYPE.FAC_BUILDS then
-- acknowledgement to coordinator receiving builds -- acknowledgement to coordinator receiving builds
self.acks.fac_builds = true self.acks.fac_builds = true
elseif pkt.type == SCADA_CRDN_TYPE.FAC_CMD then elseif pkt.type == CRDN_TYPE.FAC_CMD then
if pkt.length >= 1 then if pkt.length >= 1 then
local cmd = pkt.data[1] local cmd = pkt.data[1]
if cmd == FAC_COMMAND.SCRAM_ALL then if cmd == FAC_COMMAND.SCRAM_ALL then
facility.scram_all() facility.scram_all()
_send(SCADA_CRDN_TYPE.FAC_CMD, { cmd, true }) _send(CRDN_TYPE.FAC_CMD, { cmd, true })
elseif cmd == FAC_COMMAND.STOP then elseif cmd == FAC_COMMAND.STOP then
facility.auto_stop() facility.auto_stop()
_send(SCADA_CRDN_TYPE.FAC_CMD, { cmd, true }) _send(CRDN_TYPE.FAC_CMD, { cmd, true })
elseif cmd == FAC_COMMAND.START then elseif cmd == FAC_COMMAND.START then
if pkt.length == 6 then if pkt.length == 6 then
---@type coord_auto_config ---@type coord_auto_config
@ -254,22 +254,22 @@ function coordinator.new_session(id, s_addr, in_queue, out_queue, timeout, facil
limits = pkt.data[6] limits = pkt.data[6]
} }
_send(SCADA_CRDN_TYPE.FAC_CMD, { cmd, table.unpack(facility.auto_start(config)) }) _send(CRDN_TYPE.FAC_CMD, { cmd, table.unpack(facility.auto_start(config)) })
else else
log.debug(log_header .. "CRDN auto start (with configuration) packet length mismatch") log.debug(log_header .. "CRDN auto start (with configuration) packet length mismatch")
end end
elseif cmd == FAC_COMMAND.ACK_ALL_ALARMS then elseif cmd == FAC_COMMAND.ACK_ALL_ALARMS then
facility.ack_all() facility.ack_all()
_send(SCADA_CRDN_TYPE.FAC_CMD, { cmd, true }) _send(CRDN_TYPE.FAC_CMD, { cmd, true })
elseif cmd == FAC_COMMAND.SET_WASTE_MODE then elseif cmd == FAC_COMMAND.SET_WASTE_MODE then
if pkt.length == 2 then if pkt.length == 2 then
_send(SCADA_CRDN_TYPE.FAC_CMD, { cmd, facility.set_waste_product(pkt.data[2]) }) _send(CRDN_TYPE.FAC_CMD, { cmd, facility.set_waste_product(pkt.data[2]) })
else else
log.debug(log_header .. "CRDN set waste mode packet length mismatch") log.debug(log_header .. "CRDN set waste mode packet length mismatch")
end end
elseif cmd == FAC_COMMAND.SET_PU_FB then elseif cmd == FAC_COMMAND.SET_PU_FB then
if pkt.length == 2 then if pkt.length == 2 then
_send(SCADA_CRDN_TYPE.FAC_CMD, { cmd, facility.set_pu_fallback(pkt.data[2]) }) _send(CRDN_TYPE.FAC_CMD, { cmd, facility.set_pu_fallback(pkt.data[2]) })
else else
log.debug(log_header .. "CRDN set pu fallback packet length mismatch") log.debug(log_header .. "CRDN set pu fallback packet length mismatch")
end end
@ -279,10 +279,10 @@ function coordinator.new_session(id, s_addr, in_queue, out_queue, timeout, facil
else else
log.debug(log_header .. "CRDN facility command packet length mismatch") log.debug(log_header .. "CRDN facility command packet length mismatch")
end end
elseif pkt.type == SCADA_CRDN_TYPE.UNIT_BUILDS then elseif pkt.type == CRDN_TYPE.UNIT_BUILDS then
-- acknowledgement to coordinator receiving builds -- acknowledgement to coordinator receiving builds
self.acks.unit_builds = true self.acks.unit_builds = true
elseif pkt.type == SCADA_CRDN_TYPE.UNIT_CMD then elseif pkt.type == CRDN_TYPE.UNIT_CMD then
if pkt.length >= 2 then if pkt.length >= 2 then
-- get command and unit id -- get command and unit id
local cmd = pkt.data[1] local cmd = pkt.data[1]
@ -315,7 +315,7 @@ function coordinator.new_session(id, s_addr, in_queue, out_queue, timeout, facil
end end
elseif cmd == UNIT_COMMAND.ACK_ALL_ALARMS then elseif cmd == UNIT_COMMAND.ACK_ALL_ALARMS then
unit.ack_all() unit.ack_all()
_send(SCADA_CRDN_TYPE.UNIT_CMD, { cmd, uid, true }) _send(CRDN_TYPE.UNIT_CMD, { cmd, uid, true })
elseif cmd == UNIT_COMMAND.ACK_ALARM then elseif cmd == UNIT_COMMAND.ACK_ALARM then
if pkt.length == 3 then if pkt.length == 3 then
unit.ack_alarm(pkt.data[3]) unit.ack_alarm(pkt.data[3])
@ -331,7 +331,7 @@ function coordinator.new_session(id, s_addr, in_queue, out_queue, timeout, facil
elseif cmd == UNIT_COMMAND.SET_GROUP then elseif cmd == UNIT_COMMAND.SET_GROUP then
if (pkt.length == 3) and (type(pkt.data[3]) == "number") and (pkt.data[3] >= 0) and (pkt.data[3] <= 4) then if (pkt.length == 3) and (type(pkt.data[3]) == "number") and (pkt.data[3] >= 0) and (pkt.data[3] <= 4) then
facility.set_group(unit.get_id(), pkt.data[3]) facility.set_group(unit.get_id(), pkt.data[3])
_send(SCADA_CRDN_TYPE.UNIT_CMD, { cmd, uid, pkt.data[3] }) _send(CRDN_TYPE.UNIT_CMD, { cmd, uid, pkt.data[3] })
else else
log.debug(log_header .. "CRDN unit command set group missing group id") log.debug(log_header .. "CRDN unit command set group missing group id")
end end
@ -374,7 +374,7 @@ function coordinator.new_session(id, s_addr, in_queue, out_queue, timeout, facil
-- close the connection -- close the connection
function public.close() function public.close()
_close() _close()
_send_mgmt(SCADA_MGMT_TYPE.CLOSE, {}) _send_mgmt(MGMT_TYPE.CLOSE, {})
println("connection to coordinator " .. id .. " closed by server") println("connection to coordinator " .. id .. " closed by server")
log.info(log_header .. "session closed by server") log.info(log_header .. "session closed by server")
end end
@ -406,7 +406,7 @@ function coordinator.new_session(id, s_addr, in_queue, out_queue, timeout, facil
if cmd.key == CRD_S_DATA.CMD_ACK then if cmd.key == CRD_S_DATA.CMD_ACK then
local ack = cmd.val ---@type coord_ack local ack = cmd.val ---@type coord_ack
_send(SCADA_CRDN_TYPE.UNIT_CMD, { ack.cmd, ack.unit, ack.ack }) _send(CRDN_TYPE.UNIT_CMD, { ack.cmd, ack.unit, ack.ack })
elseif cmd.key == CRD_S_DATA.RESEND_PLC_BUILD then elseif cmd.key == CRD_S_DATA.RESEND_PLC_BUILD then
-- re-send PLC build -- re-send PLC build
-- retry logic will be kept as-is, so as long as no retry is needed, this will be a small update -- retry logic will be kept as-is, so as long as no retry is needed, this will be a small update
@ -419,7 +419,7 @@ function coordinator.new_session(id, s_addr, in_queue, out_queue, timeout, facil
local unit = self.units[unit_id] ---@type reactor_unit local unit = self.units[unit_id] ---@type reactor_unit
builds[unit_id] = unit.get_build(-1) builds[unit_id] = unit.get_build(-1)
_send(SCADA_CRDN_TYPE.UNIT_BUILDS, { builds }) _send(CRDN_TYPE.UNIT_BUILDS, { builds })
elseif cmd.key == CRD_S_DATA.RESEND_RTU_BUILD then elseif cmd.key == CRD_S_DATA.RESEND_RTU_BUILD then
local unit_id = cmd.val.unit local unit_id = cmd.val.unit
if unit_id > 0 then if unit_id > 0 then
@ -433,14 +433,14 @@ function coordinator.new_session(id, s_addr, in_queue, out_queue, timeout, facil
local unit = self.units[unit_id] ---@type reactor_unit local unit = self.units[unit_id] ---@type reactor_unit
builds[unit_id] = unit.get_build(cmd.val.type) builds[unit_id] = unit.get_build(cmd.val.type)
_send(SCADA_CRDN_TYPE.UNIT_BUILDS, { builds }) _send(CRDN_TYPE.UNIT_BUILDS, { builds })
else else
-- re-send facility RTU builds -- re-send facility RTU builds
-- retry logic will be kept as-is, so as long as no retry is needed, this will be a small update -- retry logic will be kept as-is, so as long as no retry is needed, this will be a small update
self.retry_times.f_builds_packet = util.time() + PARTIAL_RETRY_PERIOD self.retry_times.f_builds_packet = util.time() + PARTIAL_RETRY_PERIOD
self.acks.fac_builds = false self.acks.fac_builds = false
_send(SCADA_CRDN_TYPE.FAC_BUILDS, { facility.get_build(cmd.val.type) }) _send(CRDN_TYPE.FAC_BUILDS, { facility.get_build(cmd.val.type) })
end end
else else
log.error(log_header .. "unsupported data command received in in_queue (this is a bug)", true) log.error(log_header .. "unsupported data command received in in_queue (this is a bug)", true)
@ -474,7 +474,7 @@ function coordinator.new_session(id, s_addr, in_queue, out_queue, timeout, facil
periodics.keep_alive = periodics.keep_alive + elapsed periodics.keep_alive = periodics.keep_alive + elapsed
if periodics.keep_alive >= PERIODICS.KEEP_ALIVE then if periodics.keep_alive >= PERIODICS.KEEP_ALIVE then
_send_mgmt(SCADA_MGMT_TYPE.KEEP_ALIVE, { util.time() }) _send_mgmt(MGMT_TYPE.KEEP_ALIVE, { util.time() })
periodics.keep_alive = 0 periodics.keep_alive = 0
end end

View File

@ -12,7 +12,7 @@ local plc = {}
local PROTOCOL = comms.PROTOCOL local PROTOCOL = comms.PROTOCOL
local RPLC_TYPE = comms.RPLC_TYPE local RPLC_TYPE = comms.RPLC_TYPE
local SCADA_MGMT_TYPE = comms.SCADA_MGMT_TYPE local MGMT_TYPE = comms.MGMT_TYPE
local PLC_AUTO_ACK = comms.PLC_AUTO_ACK local PLC_AUTO_ACK = comms.PLC_AUTO_ACK
local UNIT_COMMAND = comms.UNIT_COMMAND local UNIT_COMMAND = comms.UNIT_COMMAND
@ -258,7 +258,7 @@ function plc.new_session(id, s_addr, reactor_id, in_queue, out_queue, timeout, f
end end
-- send a SCADA management packet -- send a SCADA management packet
---@param msg_type SCADA_MGMT_TYPE ---@param msg_type MGMT_TYPE
---@param msg table ---@param msg table
local function _send_mgmt(msg_type, msg) local function _send_mgmt(msg_type, msg)
local s_pkt = comms.scada_packet() local s_pkt = comms.scada_packet()
@ -482,7 +482,7 @@ function plc.new_session(id, s_addr, reactor_id, in_queue, out_queue, timeout, f
end end
elseif pkt.scada_frame.protocol() == PROTOCOL.SCADA_MGMT then elseif pkt.scada_frame.protocol() == PROTOCOL.SCADA_MGMT then
---@cast pkt mgmt_frame ---@cast pkt mgmt_frame
if pkt.type == SCADA_MGMT_TYPE.KEEP_ALIVE then if pkt.type == MGMT_TYPE.KEEP_ALIVE then
-- keep alive reply -- keep alive reply
if pkt.length == 2 then if pkt.length == 2 then
local srv_start = pkt.data[1] local srv_start = pkt.data[1]
@ -501,7 +501,7 @@ function plc.new_session(id, s_addr, reactor_id, in_queue, out_queue, timeout, f
else else
log.debug(log_header .. "SCADA keep alive packet length mismatch") log.debug(log_header .. "SCADA keep alive packet length mismatch")
end end
elseif pkt.type == SCADA_MGMT_TYPE.CLOSE then elseif pkt.type == MGMT_TYPE.CLOSE then
-- close the session -- close the session
_close() _close()
else else
@ -595,7 +595,7 @@ function plc.new_session(id, s_addr, reactor_id, in_queue, out_queue, timeout, f
-- close the connection -- close the connection
function public.close() function public.close()
_close() _close()
_send_mgmt(SCADA_MGMT_TYPE.CLOSE, {}) _send_mgmt(MGMT_TYPE.CLOSE, {})
println("connection to reactor " .. reactor_id .. " PLC closed by server") println("connection to reactor " .. reactor_id .. " PLC closed by server")
log.info(log_header .. "session closed by server") log.info(log_header .. "session closed by server")
end end
@ -726,7 +726,7 @@ function plc.new_session(id, s_addr, reactor_id, in_queue, out_queue, timeout, f
periodics.keep_alive = periodics.keep_alive + elapsed periodics.keep_alive = periodics.keep_alive + elapsed
if periodics.keep_alive >= PERIODICS.KEEP_ALIVE then if periodics.keep_alive >= PERIODICS.KEEP_ALIVE then
_send_mgmt(SCADA_MGMT_TYPE.KEEP_ALIVE, { util.time() }) _send_mgmt(MGMT_TYPE.KEEP_ALIVE, { util.time() })
periodics.keep_alive = 0 periodics.keep_alive = 0
end end

View File

@ -7,7 +7,7 @@ local databus = require("supervisor.databus")
local pocket = {} local pocket = {}
local PROTOCOL = comms.PROTOCOL local PROTOCOL = comms.PROTOCOL
local SCADA_MGMT_TYPE = comms.SCADA_MGMT_TYPE local MGMT_TYPE = comms.MGMT_TYPE
-- retry time constants in ms -- retry time constants in ms
-- local INITIAL_WAIT = 1500 -- local INITIAL_WAIT = 1500
@ -76,7 +76,7 @@ function pocket.new_session(id, s_addr, in_queue, out_queue, timeout, facility,
end end
-- send a SCADA management packet -- send a SCADA management packet
---@param msg_type SCADA_MGMT_TYPE ---@param msg_type MGMT_TYPE
---@param msg table ---@param msg table
local function _send_mgmt(msg_type, msg) local function _send_mgmt(msg_type, msg)
local s_pkt = comms.scada_packet() local s_pkt = comms.scada_packet()
@ -108,7 +108,7 @@ function pocket.new_session(id, s_addr, in_queue, out_queue, timeout, facility,
-- process packet -- process packet
if pkt.scada_frame.protocol() == PROTOCOL.SCADA_MGMT then if pkt.scada_frame.protocol() == PROTOCOL.SCADA_MGMT then
---@cast pkt mgmt_frame ---@cast pkt mgmt_frame
if pkt.type == SCADA_MGMT_TYPE.KEEP_ALIVE then if pkt.type == MGMT_TYPE.KEEP_ALIVE then
-- keep alive reply -- keep alive reply
if pkt.length == 2 then if pkt.length == 2 then
local srv_start = pkt.data[1] local srv_start = pkt.data[1]
@ -127,13 +127,13 @@ function pocket.new_session(id, s_addr, in_queue, out_queue, timeout, facility,
else else
log.debug(log_header .. "SCADA keep alive packet length mismatch") log.debug(log_header .. "SCADA keep alive packet length mismatch")
end end
elseif pkt.type == SCADA_MGMT_TYPE.CLOSE then elseif pkt.type == MGMT_TYPE.CLOSE then
-- close the session -- close the session
_close() _close()
elseif pkt.type == SCADA_MGMT_TYPE.DIAG_TONE_GET then elseif pkt.type == MGMT_TYPE.DIAG_TONE_GET then
-- get the state of alarm tones -- get the state of alarm tones
_send_mgmt(SCADA_MGMT_TYPE.DIAG_TONE_GET, facility.get_alarm_tones()) _send_mgmt(MGMT_TYPE.DIAG_TONE_GET, facility.get_alarm_tones())
elseif pkt.type == SCADA_MGMT_TYPE.DIAG_TONE_SET then elseif pkt.type == MGMT_TYPE.DIAG_TONE_SET then
local valid = false local valid = false
-- attempt to set a tone state -- attempt to set a tone state
@ -144,7 +144,7 @@ function pocket.new_session(id, s_addr, in_queue, out_queue, timeout, facility,
-- try to set tone states, then send back if testing is allowed -- try to set tone states, then send back if testing is allowed
local allow_testing, test_tone_states = facility.diag_set_test_tone(pkt.data[1], pkt.data[2]) local allow_testing, test_tone_states = facility.diag_set_test_tone(pkt.data[1], pkt.data[2])
_send_mgmt(SCADA_MGMT_TYPE.DIAG_TONE_SET, { allow_testing, test_tone_states }) _send_mgmt(MGMT_TYPE.DIAG_TONE_SET, { allow_testing, test_tone_states })
else else
log.debug(log_header .. "SCADA diag tone set packet data type mismatch") log.debug(log_header .. "SCADA diag tone set packet data type mismatch")
end end
@ -155,8 +155,8 @@ function pocket.new_session(id, s_addr, in_queue, out_queue, timeout, facility,
log.debug(log_header .. "DIAG_TONE_SET is blocked without HMAC for security") log.debug(log_header .. "DIAG_TONE_SET is blocked without HMAC for security")
end end
if not valid then _send_mgmt(SCADA_MGMT_TYPE.DIAG_TONE_SET, { false }) end if not valid then _send_mgmt(MGMT_TYPE.DIAG_TONE_SET, { false }) end
elseif pkt.type == SCADA_MGMT_TYPE.DIAG_ALARM_SET then elseif pkt.type == MGMT_TYPE.DIAG_ALARM_SET then
local valid = false local valid = false
-- attempt to set an alarm state -- attempt to set an alarm state
@ -167,7 +167,7 @@ function pocket.new_session(id, s_addr, in_queue, out_queue, timeout, facility,
-- try to set alarm states, then send back if testing is allowed -- try to set alarm states, then send back if testing is allowed
local allow_testing, test_alarm_states = facility.diag_set_test_alarm(pkt.data[1], pkt.data[2]) local allow_testing, test_alarm_states = facility.diag_set_test_alarm(pkt.data[1], pkt.data[2])
_send_mgmt(SCADA_MGMT_TYPE.DIAG_ALARM_SET, { allow_testing, test_alarm_states }) _send_mgmt(MGMT_TYPE.DIAG_ALARM_SET, { allow_testing, test_alarm_states })
else else
log.debug(log_header .. "SCADA diag alarm set packet data type mismatch") log.debug(log_header .. "SCADA diag alarm set packet data type mismatch")
end end
@ -178,7 +178,7 @@ function pocket.new_session(id, s_addr, in_queue, out_queue, timeout, facility,
log.debug(log_header .. "DIAG_ALARM_SET is blocked without HMAC for security") log.debug(log_header .. "DIAG_ALARM_SET is blocked without HMAC for security")
end end
if not valid then _send_mgmt(SCADA_MGMT_TYPE.DIAG_ALARM_SET, { false }) end if not valid then _send_mgmt(MGMT_TYPE.DIAG_ALARM_SET, { false }) end
else else
log.debug(log_header .. "handler received unsupported SCADA_MGMT packet type " .. pkt.type) log.debug(log_header .. "handler received unsupported SCADA_MGMT packet type " .. pkt.type)
end end
@ -204,7 +204,7 @@ function pocket.new_session(id, s_addr, in_queue, out_queue, timeout, facility,
-- close the connection -- close the connection
function public.close() function public.close()
_close() _close()
_send_mgmt(SCADA_MGMT_TYPE.CLOSE, {}) _send_mgmt(MGMT_TYPE.CLOSE, {})
println("connection to pocket diag session " .. id .. " closed by server") println("connection to pocket diag session " .. id .. " closed by server")
log.info(log_header .. "session closed by server") log.info(log_header .. "session closed by server")
end end
@ -261,7 +261,7 @@ function pocket.new_session(id, s_addr, in_queue, out_queue, timeout, facility,
periodics.keep_alive = periodics.keep_alive + elapsed periodics.keep_alive = periodics.keep_alive + elapsed
if periodics.keep_alive >= PERIODICS.KEEP_ALIVE then if periodics.keep_alive >= PERIODICS.KEEP_ALIVE then
_send_mgmt(SCADA_MGMT_TYPE.KEEP_ALIVE, { util.time() }) _send_mgmt(MGMT_TYPE.KEEP_ALIVE, { util.time() })
periodics.keep_alive = 0 periodics.keep_alive = 0
end end

View File

@ -22,7 +22,7 @@ local svrs_turbinev = require("supervisor.session.rtu.turbinev")
local rtu = {} local rtu = {}
local PROTOCOL = comms.PROTOCOL local PROTOCOL = comms.PROTOCOL
local SCADA_MGMT_TYPE = comms.SCADA_MGMT_TYPE local MGMT_TYPE = comms.MGMT_TYPE
local RTU_UNIT_TYPE = types.RTU_UNIT_TYPE local RTU_UNIT_TYPE = types.RTU_UNIT_TYPE
local PERIODICS = { local PERIODICS = {
@ -223,7 +223,7 @@ function rtu.new_session(id, s_addr, in_queue, out_queue, timeout, advertisement
end end
-- send a SCADA management packet -- send a SCADA management packet
---@param msg_type SCADA_MGMT_TYPE ---@param msg_type MGMT_TYPE
---@param msg table ---@param msg table
local function _send_mgmt(msg_type, msg) local function _send_mgmt(msg_type, msg)
local s_pkt = comms.scada_packet() local s_pkt = comms.scada_packet()
@ -262,7 +262,7 @@ function rtu.new_session(id, s_addr, in_queue, out_queue, timeout, advertisement
elseif pkt.scada_frame.protocol() == PROTOCOL.SCADA_MGMT then elseif pkt.scada_frame.protocol() == PROTOCOL.SCADA_MGMT then
---@cast pkt mgmt_frame ---@cast pkt mgmt_frame
-- handle management packet -- handle management packet
if pkt.type == SCADA_MGMT_TYPE.KEEP_ALIVE then if pkt.type == MGMT_TYPE.KEEP_ALIVE then
-- keep alive reply -- keep alive reply
if pkt.length == 2 then if pkt.length == 2 then
local srv_start = pkt.data[1] local srv_start = pkt.data[1]
@ -281,17 +281,17 @@ function rtu.new_session(id, s_addr, in_queue, out_queue, timeout, advertisement
else else
log.debug(log_header .. "SCADA keep alive packet length mismatch") log.debug(log_header .. "SCADA keep alive packet length mismatch")
end end
elseif pkt.type == SCADA_MGMT_TYPE.CLOSE then elseif pkt.type == MGMT_TYPE.CLOSE then
-- close the session -- close the session
_close() _close()
elseif pkt.type == SCADA_MGMT_TYPE.RTU_ADVERT then elseif pkt.type == MGMT_TYPE.RTU_ADVERT then
-- RTU unit advertisement -- RTU unit advertisement
log.debug(log_header .. "received updated advertisement") log.debug(log_header .. "received updated advertisement")
self.advert = pkt.data self.advert = pkt.data
-- handle advertisement; this will re-create all unit sub-sessions -- handle advertisement; this will re-create all unit sub-sessions
_handle_advertisement() _handle_advertisement()
elseif pkt.type == SCADA_MGMT_TYPE.RTU_DEV_REMOUNT then elseif pkt.type == MGMT_TYPE.RTU_DEV_REMOUNT then
if pkt.length == 1 then if pkt.length == 1 then
local unit_id = pkt.data[1] local unit_id = pkt.data[1]
if self.units[unit_id] ~= nil then if self.units[unit_id] ~= nil then
@ -322,7 +322,7 @@ function rtu.new_session(id, s_addr, in_queue, out_queue, timeout, advertisement
-- close the connection -- close the connection
function public.close() function public.close()
_close() _close()
_send_mgmt(SCADA_MGMT_TYPE.CLOSE, {}) _send_mgmt(MGMT_TYPE.CLOSE, {})
println(log_header .. "connection to RTU closed by server") println(log_header .. "connection to RTU closed by server")
log.info(log_header .. "session closed by server") log.info(log_header .. "session closed by server")
end end
@ -387,7 +387,7 @@ function rtu.new_session(id, s_addr, in_queue, out_queue, timeout, advertisement
periodics.keep_alive = periodics.keep_alive + elapsed periodics.keep_alive = periodics.keep_alive + elapsed
if periodics.keep_alive >= PERIODICS.KEEP_ALIVE then if periodics.keep_alive >= PERIODICS.KEEP_ALIVE then
_send_mgmt(SCADA_MGMT_TYPE.KEEP_ALIVE, { util.time() }) _send_mgmt(MGMT_TYPE.KEEP_ALIVE, { util.time() })
periodics.keep_alive = 0 periodics.keep_alive = 0
end end
@ -395,7 +395,7 @@ function rtu.new_session(id, s_addr, in_queue, out_queue, timeout, advertisement
periodics.alarm_tones = periodics.alarm_tones + elapsed periodics.alarm_tones = periodics.alarm_tones + elapsed
if periodics.alarm_tones >= PERIODICS.ALARM_TONES then if periodics.alarm_tones >= PERIODICS.ALARM_TONES then
_send_mgmt(SCADA_MGMT_TYPE.RTU_TONE_ALARM, { facility.get_alarm_tones() }) _send_mgmt(MGMT_TYPE.RTU_TONE_ALARM, { facility.get_alarm_tones() })
periodics.alarm_tones = 0 periodics.alarm_tones = 0
end end

View File

@ -11,7 +11,7 @@ local supervisor = {}
local PROTOCOL = comms.PROTOCOL local PROTOCOL = comms.PROTOCOL
local DEVICE_TYPE = comms.DEVICE_TYPE local DEVICE_TYPE = comms.DEVICE_TYPE
local ESTABLISH_ACK = comms.ESTABLISH_ACK local ESTABLISH_ACK = comms.ESTABLISH_ACK
local SCADA_MGMT_TYPE = comms.SCADA_MGMT_TYPE local MGMT_TYPE = comms.MGMT_TYPE
-- supervisory controller communications -- supervisory controller communications
---@nodiscard ---@nodiscard
@ -58,7 +58,7 @@ function supervisor.comms(_version, nic, fp_ok)
local s_pkt = comms.scada_packet() local s_pkt = comms.scada_packet()
local m_pkt = comms.mgmt_packet() local m_pkt = comms.mgmt_packet()
m_pkt.make(SCADA_MGMT_TYPE.ESTABLISH, { ack, data }) m_pkt.make(MGMT_TYPE.ESTABLISH, { ack, data })
s_pkt.make(packet.src_addr(), packet.seq_num() + 1, PROTOCOL.SCADA_MGMT, m_pkt.raw_sendable()) s_pkt.make(packet.src_addr(), packet.seq_num() + 1, PROTOCOL.SCADA_MGMT, m_pkt.raw_sendable())
nic.transmit(packet.remote_channel(), svr_channel, s_pkt) nic.transmit(packet.remote_channel(), svr_channel, s_pkt)
@ -147,7 +147,7 @@ function supervisor.comms(_version, nic, fp_ok)
if session ~= nil then if session ~= nil then
-- pass the packet onto the session handler -- pass the packet onto the session handler
session.in_queue.push_packet(packet) session.in_queue.push_packet(packet)
elseif packet.type == SCADA_MGMT_TYPE.ESTABLISH then elseif packet.type == MGMT_TYPE.ESTABLISH then
-- establish a new session -- establish a new session
local last_ack = self.last_est_acks[src_addr] local last_ack = self.last_est_acks[src_addr]
@ -221,7 +221,7 @@ function supervisor.comms(_version, nic, fp_ok)
if session ~= nil then if session ~= nil then
-- pass the packet onto the session handler -- pass the packet onto the session handler
session.in_queue.push_packet(packet) session.in_queue.push_packet(packet)
elseif packet.type == SCADA_MGMT_TYPE.ESTABLISH then elseif packet.type == MGMT_TYPE.ESTABLISH then
-- establish a new session -- establish a new session
local last_ack = self.last_est_acks[src_addr] local last_ack = self.last_est_acks[src_addr]
@ -275,7 +275,7 @@ function supervisor.comms(_version, nic, fp_ok)
if session ~= nil then if session ~= nil then
-- pass the packet onto the session handler -- pass the packet onto the session handler
session.in_queue.push_packet(packet) session.in_queue.push_packet(packet)
elseif packet.type == SCADA_MGMT_TYPE.ESTABLISH then elseif packet.type == MGMT_TYPE.ESTABLISH then
-- establish a new session -- establish a new session
local last_ack = self.last_est_acks[src_addr] local last_ack = self.last_est_acks[src_addr]
@ -291,7 +291,7 @@ function supervisor.comms(_version, nic, fp_ok)
end end
_send_establish(packet.scada_frame, ESTABLISH_ACK.BAD_VERSION) _send_establish(packet.scada_frame, ESTABLISH_ACK.BAD_VERSION)
elseif dev_type == DEVICE_TYPE.CRDN then elseif dev_type == DEVICE_TYPE.CRD then
-- this is an attempt to establish a new coordinator session -- this is an attempt to establish a new coordinator session
local s_id = svsessions.establish_crd_session(src_addr, firmware_v) local s_id = svsessions.establish_crd_session(src_addr, firmware_v)
@ -342,7 +342,7 @@ function supervisor.comms(_version, nic, fp_ok)
if session ~= nil then if session ~= nil then
-- pass the packet onto the session handler -- pass the packet onto the session handler
session.in_queue.push_packet(packet) session.in_queue.push_packet(packet)
elseif packet.type == SCADA_MGMT_TYPE.ESTABLISH then elseif packet.type == MGMT_TYPE.ESTABLISH then
-- establish a new session -- establish a new session
local last_ack = self.last_est_acks[src_addr] local last_ack = self.last_est_acks[src_addr]