summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorcheapie <no-email-for-you@example.com>2017-01-20 01:26:42 -0600
committercheapie <no-email-for-you@example.com>2017-01-20 01:26:42 -0600
commiteba7b01888cf6383c4e986bc6d5f5d511c6566f7 (patch)
tree1e3ffed84d8bebd62db81c3226be842e742dc644
parent71fb7ba9e77201005124766b24ab107b1fe908b1 (diff)
downloadltc4000e-eba7b01888cf6383c4e986bc6d5f5d511c6566f7.tar
ltc4000e-eba7b01888cf6383c4e986bc6d5f5d511c6566f7.tar.gz
ltc4000e-eba7b01888cf6383c4e986bc6d5f5d511c6566f7.tar.bz2
ltc4000e-eba7b01888cf6383c4e986bc6d5f5d511c6566f7.tar.xz
ltc4000e-eba7b01888cf6383c4e986bc6d5f5d511c6566f7.zip
Convert interrupts to use node timers
-rw-r--r--fw.lua66
-rw-r--r--init.lua107
2 files changed, 128 insertions, 45 deletions
diff --git a/fw.lua b/fw.lua
index 31cdd45..f15d082 100644
--- a/fw.lua
+++ b/fw.lua
@@ -157,7 +157,7 @@ elseif was_timed then
end
--Detector signal handling
-if (not mem.phaselocked and not mem.preempt) and event.type == "digiline" and string.sub(event.channel,1,9) == "detector_" then
+if (not mem.phaselocked and not mem.preempt) and event.type == "digiline" and string.sub(event.channel,1,9) == "detector_" and not mem.stoptime then
local detname = string.sub(event.channel,10)
if mem.stats[detname] then
mem.stats[detname] = mem.stats[detname] + 1
@@ -191,7 +191,7 @@ if (not mem.phaselocked and not mem.preempt) and event.type == "digiline" and st
end
end
-if event.type == "digiline" and mem.pedbuttontype == 2 and event.channel == "pedbutton" then
+if event.type == "digiline" and mem.pedbuttontype == 2 and event.channel == "pedbutton" and not mem.stoptime then
if event.msg == "main" then
log("Emulating detector_ap/cp for TrafficNeXt compatibility",true)
mem.det.ap = true
@@ -214,6 +214,8 @@ if event.type == "interrupt" and (event.iid == "gapout" or event.iid == "maxgree
log("Reached maximum green",true)
end
--Either gapped out or reached max green, go to next step
+ interrupt(nil,"gapout")
+ interrupt(nil,"maxgreen")
interrupt(0,"tick")
end
end
@@ -224,7 +226,7 @@ if (event.channel == "detector_b" or event.channel == "detector_d") and (mem.cyc
end
--Preemption logic
-if event.type == "digiline" and string.sub(event.channel,1,8) == "preempt_" then
+if event.type == "digiline" and string.sub(event.channel,1,8) == "preempt_" and not mem.stoptime then
log("Preemption detector activated",true)
mem.preempt = string.sub(event.channel,9,10)
log("Entering preemption on approach "..mem.preempt.." from state "..(mem.cycle or "idle"),true)
@@ -251,7 +253,7 @@ if event.type == "digiline" and string.sub(event.channel,1,8) == "preempt_" then
end
--Phase logic for already-running cycles
-if mem.busy and event.type == "interrupt" and event.iid == "tick" and not mem.phaselocked then
+if mem.busy and event.type == "interrupt" and (event.iid == "tick" or event.iid == "manualtick") and not mem.phaselocked and (event.iid == "manualtick" or not mem.stoptime) then
log("Continuing existing cycle at phase "..mem.cycle,true)
if mem.cycle == "preempt_yellow" then
for k,v in pairs(mem.currentphase) do
@@ -580,7 +582,7 @@ end
--Phase logic for starting new cycles
detactive = false
for _,_ in pairs(mem.det) do detactive = true end
-if (not mem.busy) and detactive then
+if (not mem.busy) and detactive and (not mem.stoptime) then
if mem.phaselocked then
log("Not starting cycle due to phase lock",true)
elseif mem.preempt then
@@ -656,6 +658,8 @@ if event.type == "digiline" and event.channel == "touchscreen" then
mem.menu = "stats"
elseif fields.mode then
mem.menu = "mode"
+ elseif fields.diag then
+ mem.menu = "diag"
end
elseif mem.menu == "run" then
if fields.menu then
@@ -712,7 +716,7 @@ if event.type == "digiline" and event.channel == "touchscreen" then
for _,v in pairs({"a","b","c","d","at","bt","ct","dt","ap","bp","cp","dp"}) do
if fields[v] then
mem.det[v] = true
- interrupt(0) --Forces the program to be re-run since the cycle logic is up there ^^
+ interrupt(0,"tick") --Forces the program to be re-run since the cycle logic is up there ^^
end
end
end
@@ -770,7 +774,33 @@ if event.type == "digiline" and event.channel == "touchscreen" then
mem.normalmode = pivot(modes)[fields.normalmode]
mem.schedmode = pivot(modes)[fields.schedmode]
mem.menu = "main"
- interrupt(0) -- Some of these need to take immediate effect
+ interrupt(0,"rerun") -- Some of these need to take immediate effect
+ end
+ elseif mem.menu == "diag" then
+ if fields.cancel then
+ mem.menu = "main"
+ elseif fields.startstop then
+ if mem.stoptime then
+ mem.stoptime = false
+ interrupt(1,"tick")
+ else
+ mem.stoptime = true
+ interrupt(nil,"tick")
+ end
+ elseif fields.stepnow then
+ interrupt(0,"manualtick")
+ elseif fields.reboot then
+ mem.phaselocked = true
+ mem.cycle = nil
+ mem.menu = "reboot"
+ mem.busy = false
+ mem.preempt = nil
+ mem.stoptime = true
+ interrupt(10,"reboot")
+ interrupt(nil,"step")
+ interrupt(nil,"rerun")
+ interrupt(nil,"gapout")
+ interrupt(nil,"maxgreen")
end
else
logfault("Unrecognized menu "..mem.menu,false)
@@ -778,6 +808,14 @@ if event.type == "digiline" and event.channel == "touchscreen" then
end
end
+if event.iid == "reboot" then
+ mem.phaselocked = false
+ mem.menu = "main"
+ mem.stoptime = false
+ mem.cycle = nil
+ interrupt(0,"tick")
+end
+
--Light control signal sending
if mem.phaselocked then
mem.busy = false
@@ -815,6 +853,7 @@ if mem.menu == "main" then
table.insert(disp,{command="addbutton",X=7,Y=5,W=2,H=1,name="mancyc",label="Manual Call Entry"})
table.insert(disp,{command="addbutton",X=1,Y=7,W=2,H=1,name="stats",label="Statistics"})
table.insert(disp,{command="addbutton",X=4,Y=7,W=2,H=1,name="mode",label="Mode/Schedule"})
+ table.insert(disp,{command="addbutton",X=7,Y=7,W=2,H=1,name="diag",label="Diagnostics"})
elseif mem.menu == "run" then
table.insert(disp,{command="addlabel",X=0,Y=0,label=mem.name})
table.insert(disp,{command="addlabel",X=0,Y=1,label="Advanced Mesecons Devices LTC-4000E"})
@@ -901,8 +940,7 @@ elseif mem.menu == "log" then
table.insert(disp,{command="addlabel",X=0,Y=1.5,label="No Faults"})
end
elseif mem.menu == "monitoring" then
- --interrupt(0.6,"monflash")
- mem.monflash = true
+ interrupt(1,"monflash")
local monitor_textures = {}
monitor_textures.O = "streets_tl_off.png"
@@ -1130,6 +1168,16 @@ elseif mem.menu == "mode" then
table.insert(disp,{command="addfield",X=0.5,Y=5.5,W=2,H=1,name="schedend",label="Schedule End Hour",default=tostring(mem.schedend)})
table.insert(disp,{command="addbutton",X=3,Y=7,W=2,H=1,name="save",label="Save"})
table.insert(disp,{command="addbutton",X=6,Y=7,W=2,H=1,name="cancel",label="Cancel"})
+elseif mem.menu == "diag" then
+ table.insert(disp,{command="addlabel",X=0,Y=0,label="Diagnostics"})
+ table.insert(disp,{command="addlabel",X=0,Y=1,label="State: "..(mem.cycle or "Idle")})
+ table.insert(disp,{command="addbutton",X=0,Y=2,W=2,H=1,name="startstop",label=(mem.stoptime and "Start Time" or "Stop Time")})
+ table.insert(disp,{command="addbutton",X=0,Y=3,W=2,H=1,name="stepnow",label="Next Step"})
+ table.insert(disp,{command="addbutton",X=0,Y=5,W=2,H=1,name="reboot",label="Reboot"})
+ table.insert(disp,{command="addbutton",X=0,Y=7,W=2,H=1,name="cancel",label="Back"})
+elseif mem.menu == "reboot" then
+ table.insert(disp,{command="addlabel",X=0,Y=0,label="Rebooting, please wait..."})
+ table.insert(disp,{command="addlabel",X=0,Y=0.5,label="This will take about 10 seconds."})
else
logfault("Unrecognized menu "..mem.menu,false)
mem.menu = "run"
diff --git a/init.lua b/init.lua
index c45740e..e95a537 100644
--- a/init.lua
+++ b/init.lua
@@ -230,6 +230,43 @@ local function ts_on_digiline_receive(pos,msg)
update_ts_formspec(pos,data)
end
+--Interrupt node timer stuff
+local function getnextinterrupt(interrupts)
+ local nextint = 0
+ for k,v in pairs(interrupts) do
+ if nextint == 0 or v < nextint then
+ nextint = v
+ end
+ end
+ if nextint ~= 0 then return(nextint) end
+end
+
+local function getcurrentinterrupts(interrupts)
+ local current = {}
+ for k,v in pairs(interrupts) do
+ if v <= os.time() then
+ table.insert(current,k)
+ end
+ end
+ return(current)
+end
+
+local function setinterrupt(pos,time,iid)
+ local meta = minetest.get_meta(pos)
+ local timer = minetest.get_node_timer(pos)
+ local interrupts = minetest.deserialize(meta:get_string("interrupts")) or {}
+ if time == nil then
+ interrupts[iid] = nil
+ else
+ interrupts[iid] = os.time()+time
+ end
+ local nextint = getnextinterrupt(interrupts)
+ if nextint then
+ timer:start(nextint-os.time())
+ end
+ meta:set_string("interrupts",minetest.serialize(interrupts))
+end
+
--Load the (mostly unmodified) firmware
local fw = loadfile(minetest.get_modpath("ltc4000e")..DIR_DELIM.."fw.lua")
@@ -284,22 +321,9 @@ local function run(pos,event)
end
function context.interrupt(time,iid)
- --Enforce a minimum interrupt time of half a second
- time = math.max(time,0.5)
- if iid == "gapout" then
- --This one can have the time changed on-the-fly, so it has to be done with node timers
- local timer = minetest.get_node_timer(pos)
- if time then
- timer:start(time)
- else
- timer:stop()
- end
- else
- local event = {}
- event.type = "interrupt"
- event.iid = iid
- minetest.after(time,run,pos,event)
- end
+ --Enforce a minimum interrupt time of one second
+ if time ~= nil then time = math.max(time,1) end
+ setinterrupt(pos,time,iid)
end
--This is where the magic happens...
@@ -316,6 +340,33 @@ local function run(pos,event)
meta:set_string("mem",minetest.serialize(context.mem))
end
+local function oninterrupt(pos)
+ local meta = minetest.get_meta(pos)
+ local timer = minetest.get_node_timer(pos)
+ local interrupts = minetest.deserialize(meta:get_string("interrupts")) or {}
+ local current = getcurrentinterrupts(interrupts)
+ for _,i in ipairs(current) do
+ interrupts[i] = nil
+ local event = {}
+ event.type = "interrupt"
+ event.iid = i
+ run(pos,event)
+ end
+ local interrupts = minetest.deserialize(meta:get_string("interrupts")) or {} --Reload as it may have changed
+ for _,i in ipairs(current) do
+ if interrupts[i] and interrupts[i] <= os.time() then
+ interrupts[i] = nil
+ end
+ end
+ local nextint = getnextinterrupt(interrupts)
+ if nextint then
+ timer:start(nextint-os.time())
+ else
+ timer:stop()
+ end
+ meta:set_string("interrupts",minetest.serialize(interrupts))
+end
+
local function ts_on_receive_fields(pos,formname,fields,sender)
local meta = minetest.get_meta(pos)
local playername = sender:get_player_name()
@@ -358,12 +409,7 @@ minetest.register_node("ltc4000e:polemount", {
local event = {type="program"}
run(pos,event)
end,
- on_timer = function(pos)
- local event = {}
- event.type = "interrupt"
- event.iid = "gapout"
- run(pos,event)
- end,
+ on_timer = oninterrupt,
node_box = {
type = "fixed",
fixed = polemount_nodebox
@@ -466,12 +512,7 @@ minetest.register_node("ltc4000e:nema_bottom", {
end,pos)
return ret
end,
- on_timer = function(pos)
- local event = {}
- event.type = "interrupt"
- event.iid = "gapout"
- run(pos,event)
- end,
+ on_timer = oninterrupt,
on_punch = function(pos,node,puncher)
if not puncher:is_player() then
return
@@ -615,12 +656,7 @@ minetest.register_node("ltc4000e:nema_bottom_open", {
minetest.set_node(fronttoppos,{name="air"})
end,
on_rotate = false,
- on_timer = function(pos)
- local event = {}
- event.type = "interrupt"
- event.iid = "gapout"
- run(pos,event)
- end,
+ on_timer = oninterrupt,
on_punch = function(pos,node,puncher)
if not puncher:is_player() then
return
@@ -749,12 +785,11 @@ minetest.register_node("ltc4000e:door_top", {
sounds = default.node_sound_metal_defaults()
})
---Make sure lights don't "stall" if unloaded
+--Make sure lights don't "stall" if unloaded and not yet converted to node timers
minetest.register_lbm({
label = "Restart LTC-4000E timers",
name = "ltc4000e:restart_timers",
nodenames = {"ltc4000e:polemount","ltc4000e:nema_bottom","ltc4000e:nema_bottom_open"},
- run_at_every_load = true,
action = function(pos)
local meta = minetest.get_meta(pos)
local mem = minetest.deserialize(meta:get_string("mem"))