--- /dev/null
+return function(q)
+ local k,v
+ print("FIFOQ")
+ for k,v in ipairs(q) do print("",k,v) end
+end
--- /dev/null
+-- Remove an element and pass it to k; if that returns a function, leave that
+-- pending at the top of the fifo. Thus, we can get events that do multiple
+-- things. If the queue is empty, do not invoke k but flag it to enable
+-- immediate execution at the next call to queue.
+--
+-- Returns 'true' if the queue was not empty, 'false' otherwise.
+local function dequeue(q,k)
+ if #q > 0
+ then local new = k(q[1]) ; if new == nil then table.remove(q,1) else q[1] = new end ; return true
+ else q._go = true ; return false
+ end
+end
+-- Queue a on queue q.
+--
+-- If k is provided and the queue has previously drained, dequeue immediately
+-- as if k had passed to dequeue. This is useful when k will arrange for
+-- subsequent dequeues.
+local function queue(q,a,k)
+ table.insert(q,a)
+ if k ~= nil and q._go then q._go = false; q:dequeue(k) end
+end
+-- return a FIFO constructor
+return function()
+ return { ['_go'] = true ; ['queue'] = queue ; ['dequeue'] = dequeue }
+end
-if [ -z ${HOST:-} ]; then
+if [ -z ${MCUHOST:-} ]; then
# Uses LUATOOL to push init and dependencies to the device; bootstrap!
PUSHCMD="${LUATOOL} --delay 0.1 -p ${MCUPORT} -b ${MCUBAUD}"
dopush() { ${PUSHCMD} -f $1 -t ${2:-`basename $1`}; }
dopushcompile() { ${PUSHCMD} -f $1 -t ${2:-`basename $1`} -c; }
else
- # Uses host/pushvia to push everything if HOST is set
- PUSHCMD="./host/pushvia.expect ${HOST} ${PORT:-23}"
+ # Uses host/pushvia to push everything if MCUHOST is set
+ PUSHCMD="./host/pushvia.expect ${MCUHOST} ${PORT:-23}"
dopush() { ${PUSHCMD} ${2:-`basename $1`} $1; }
dopushcompile() { ${PUSHCMD} ${2:-`basename $1`} $1 compile; }
fi
. ./host/pushcommon.sh
dopushcompile util/diag.lua
+dopushcompile fifo/fifo.lua
+dopushcompile fifo/fifo-diag.lua
dopushcompile tq/tq.lua
dopushcompile tq/tq-diag.lua
dopushcompile net/nwfnet.lua
dopushcompile net/nwfnet-sntp.lua
dopushcompile net/nwfnet-go.lua
dopushcompile net/nwfnet-diag.lua
-dopush net/conf/nwfnet.conf
-dopush net/conf/nwfnet.cert
-dopush net/conf/nwfnet.conf2
-dopushcompile util/fifosock.lua
+#dopush net/conf/nwfnet.conf
+#dopush net/conf/nwfnet.cert
+#dopush net/conf/nwfnet.conf2
+dopushcompile net/fifosock.lua
dopushcompile telnetd/telnetd.lua
dopushcompile telnetd/telnetd-file.lua
dopushcompile telnetd/telnetd-diag.lua
--- /dev/null
+-- STATELESS
+--
+-- Wrap a socket object so that it queues sends. Must call :fini after
+-- done to avoid a memory leak (that I don't understand in full)
+--
+-- Ideally, import this once, wrap all the sockets you need, and then forget
+-- it. If one needs new sockets periodically, it is unclear to me whether
+-- it's better to load this once and hold it in RAM or to load it every
+-- time.
+return function(fifo,sock)
+ local function dosend(s) sock:send(s) end
+ sock:on("sent", function() fifo:dequeue(dosend) end)
+
+ local nsock = {}
+ function nsock.send(_,s)
+ if s == nil or s == "" then return end
+ fifo:queue(s,dosend)
+ end
+ function nsock.fini(_) sock = nil end
+ local sockit = getmetatable(sock)["__index"]
+ setmetatable(nsock,{ __index = function(_,k)
+ local fn = sockit[k]
+ return function(a,...) if a == nsock then fn(sock,...) else fn(a,...) end end
+ end })
+ return nsock
+end
k(true)
end
function self.server(sock_)
- local sock = (dofile("fifosock.lc")).wrap(sock_)
+ local sock = (dofile("fifosock.lc"))((require "fifo")(), sock_)
local dosend = function(...) sock:send(...) end
local k = function(c) if c then sock:send("\n$ ") else sock:close() end end
sock:on("receive",function(s_,input) self.rx(dosend,input,k) end)
- sock:on("disconnection",function(s_) tryon("disconn",sock); sock.fini(); sock=nil end)
+ sock:on("disconnection",function(s_) tryon("disconn",sock) ; sock:fini() end)
tryon("conn",sock)
sock:send("\n$ ")
end
--- /dev/null
+fmk = dofile("util/fifo.lua")
+tmk = dofile("tq/tq.lua")
+tdiag = loadfile("tq/tq-diag.lua")()
+
+f = fmk()
+t = tmk()
+
+ttime = 0
+tfirearm = nil
+t.arm = function(_,fire,when) tfirearm = fire; print("t arm: ", when) end
+t.now = function(_) return ttime end
+function tfire(step)
+ ttime = ttime + step*1000
+ if tfirearm
+ then print("t fire"); tfa = tfirearm; tfirearm = nil; tfa()
+ else print("t fizzle")
+ end
+end
+
+function tqp(w,s) t:queue(w,print,s) end
+function td()
+ tdiag(t,
+ function(...) print("td set",...) end,
+ function(...) print("td elem",...) end)
+end
+
+function deq(n)
+ if f:dequeue(function(e) print("deq", e) ; return n end)
+ then print("deq enqueue"); t:queue(1000,deq,nil)
+ end
+end
+
+f:queue(1)
+f:queue(2)
+f:queue(3)
+f:queue(4)
+
+print("SETUP")
+t:queue(1000,deq,5)
+t:queue(1500,deq,6)
+t:queue(2000,deq,7)
+td()
+print()
+
+print("PREMATURE FIRE")
+tfire(50)
+td()
+print()
+
+print("POSTMATURE FIRE")
+tfire(1000)
+td()
+print()
+
+print("EXACT FIRE 1")
+tfire(450)
+td()
+print()
+
+print("EXACT FIRE 2")
+tfire(500)
+td()
+print()
+
+tfire(50)
+print()
+
+tfire(450)
+print()
+
+tfire(500)
+print()
+
+tfire(50)
+print()
+
+tfire(450)
+print()
+
+tfire(600)
+print()
+
+td()
+print()
--- /dev/null
+t = dofile("tq/tq.lua")()
+
+tdiag = dofile("tq/tq-diag.lua")
+function td()
+ tdiag(t,
+ function(...) print("td set",...) end,
+ function(...) print("td elem",...) end)
+end
+
+ttime = 0
+tfirearm = nil
+tfirewhen = nil
+t.arm = function(_,fire,when) tfirearm = fire ; tfirewhen = when end
+t.now = function(_) return ttime end
+function tfire(step)
+ ttime = ttime + step*1000
+ if tfirearm then tfa = tfirearm; tfirearm = nil; tfa() end
+end
+
+ctr = 0
+function rec()
+ ctr = ctr + 1; t:queue(math.random(5),rec)
+end
+rec()
+
+for i = 1, 100000 do tfire(tfirewhen or 1) end
+print(ctr, ttime)
+td()
-- DEPENDS: tmr [only by default]
local fire, doarm
function fire(self)
- local cbs = table.remove(self._q,1)
- if #self._q > 0 then doarm(self, self._q[1]["t"]) end
- local v
- for _,v in ipairs(cbs) do v() end
+ local cbt = {}
+ local entryt = self:now()
+ local lapsed = (entryt - self._tst)/1000
+ if #self._q > 0 and lapsed < self._q[1].t then
+ -- premature fire? adjust and rearm
+ self._q[1].t = self._q[1].t - lapsed
+ doarm(self, self._q[1].t)
+ return
+ end
+ while #self._q > 0 and self._q[1].t <= lapsed do
+ -- collect events in the past into cbt
+ local cbs = table.remove(self._q,1)
+ lapsed = lapsed - cbs.t
+ table.insert(cbt,cbs)
+ end
+ if #self._q > 0 then
+ -- leftover events: credit excess lapsed time and rearm
+ self._q[1].t = self._q[1].t - lapsed
+ doarm(self, self._q[1].t)
+ end
+ -- run all collected callbacks, having adjusted queue
+ local k, cbs, v
+ for k,cbs in ipairs(cbt) do for k,v in ipairs(cbs) do v() end end
end
function doarm(self,when) self:arm(function() fire(self) end, when); self._tst = self:now() end
local function queue(self,when,what,...)
if #self._q > 0 then
local lapsed = (self:now() - self._tst)/1000
- self._q[1]["t"] = self._q[1]["t"] - lapsed
+ self._q[1].t = self._q[1].t - lapsed
end
local ix = 0; local tleft = when
while (ix < #self._q) do
- if (tleft < self._q[ix+1]["t"]) then break end
- ix = ix + 1; tleft = tleft - self._q[ix]["t"]
+ if (tleft < self._q[ix+1].t) then break end
+ ix = ix + 1; tleft = tleft - self._q[ix].t
end
local warg = {...}; local nwarg = select('#',...)
local wfn = function () return what(unpack(warg,1,nwarg)) end
end
table.insert(self._q,ix+1,{["t"] = tleft, [1] = wfn})
if ix+1 < #self._q then
- self._q[ix+2]["t"] = self._q[ix+2]["t"] - tleft
+ self._q[ix+2].t = self._q[ix+2].t - tleft
end
return wfn
end
+++ /dev/null
--- STATELESS
-local fs = {}
-function fs.wrap(sock)
- local sf = {}
- local sfe = true
- local function sfd() if #sf > 0 then sock:send(table.remove(sf,1)) else sfe = true end end
- sock:on("sent", sfd)
- local nsock = {}
- nsock.send = function(k,s)
- if s == nil or s == "" then return end
- table.insert(sf,s)
- if sfe then sfe = false; sfd() end
- end
- nsock.fini = function() sf=nil; sock=nil end
- local sockit = getmetatable(sock)["__index"]
- setmetatable(nsock,{ __index = function(_,k)
- local fn = sockit[k]
- return function(a,...) if a == nsock then fn(sock,...) else fn(a,...) end end
- end })
- return nsock
-end
-return fs