From: Nathaniel Wesley Filardo Date: Fri, 16 Dec 2016 07:12:03 +0000 (-0500) Subject: lamp: revise remote protocol X-Git-Url: https://hydra-www.ietfng.org/gitweb/?a=commitdiff_plain;h=77a5fabce13a2f3fa1704403b0dc4d3a5a0e86f1;p=acmetensortoys-esp-lua_lamp lamp: revise remote protocol A new, improved lamp-remote.lua. The protocol herein is backwards compatible with everything ever automatically generated by earlier versions, but is not in general compatible with the old scheme. I think I like this one better. --- diff --git a/init2.lua b/init2.lua index 7278d24..2228b18 100644 --- a/init2.lua +++ b/init2.lua @@ -58,7 +58,7 @@ mqtt_revert = nil nwfnet.onmqtt["lamp"] = function(c,t,m) if t and m and t:find("^lamp/[^/]+/out") then dofile("lamp-remote.lc")(m) end end -- TODO: messages to specific lamps? Multiple brokers? -function lamp_announce(fn,g,r,b) mqc:publish(mqttBcastPfx,string.format("0 %s %x %x %x ;",fn,r,g,b),1,1) end +function lamp_announce(fn,g,r,b) mqc:publish(mqttBcastPfx,string.format("new; draw %s %x %x %x;",fn,r,g,b),1,1) end -- mqtt setup local mqtt_beat_cancel diff --git a/lamp-remote.lua b/lamp-remote.lua index 8ebfcbf..e780a12 100644 --- a/lamp-remote.lua +++ b/lamp-remote.lua @@ -1,23 +1,59 @@ --- GLOBAL: tq, remotefb, doremotedraw, remotetmr, loaddrawfn, remotetqh +-- GLOBAL: tq, remotefb, doremotedraw, remotetmr, loaddrawfn, remotetqh, remotefifo + +if not remotefifo then remotefifo = (require "fifo")() end + +-- dequeue from remotefifo; if nothing to dequeue, clean up +local function fdq() + if not remotefifo:dequeue(function(k) k() end) + then remotetqh = nil; remotefifo = nil + end +end + +-- queue to remotefifo; if fifo has emptied, fire callback immediately, +-- otherwise, let the functions manage their own timeline +local function fq(what) + remotefifo:queue(what,fdq) +end return function(msg) - if remotetqh then tq:dequeue(remotetqh) end - local fifo = (require "fifo")() - local function fdq() if not fifo:dequeue(function(k) k() end) then remotetqh = nil end end + local vt = { + ['new'] = function(_) + -- really only sensible at the start of a message; throw out + -- the existing fifo, if any, and stop whatever time event is + -- pending + remotefifo = (require "fifo")() + tq:dequeue(remotetqh) + end, + ['wait'] = function(s) + -- step the fifo in d milliseconds + local d = tonumber(s) + if d and d > 0 then fq(function() remotetqh = tq:queue(d,fdq) end) end + end, + ['draw'] = function(s) + -- engage a drawing function and post a time event to pop the fifo + -- on the next tick (for, e.g., delay's use). This is done on a + -- callback to prevent deep stacks. + local m,r,g,b = s:match("^(%w+)%s+(%x+)%s+(%x+)%s+(%x+)%s*$") + g = tonumber(g,16); r = tonumber(r,16); b = tonumber(b,16) + if m then + fq(function() + remotetmr:unregister() + loaddrawfn(m)(remotetmr,remotefb,g,r,b); doremotedraw() + remotetqh = tq:queue(1,fdq) + end) + end + end, + } - local d,m,r,g,b + vt["0"] = vt.draw -- XXX hack for backwards compatibility - for d,m,r,g,b in msg:gmatch("(%d+)%s+(%w+)%s+(%x+)%s+(%x+)%s+(%x+)%s*;") do - g = tonumber(g,16); r = tonumber(r,16); b = tonumber(b,16); d = tonumber(d) - if d and d > 0 then - fifo:queue(function() remotetqh = tq:queue(d,fdq) end) - end - fifo:queue(function() - remotetmr:unregister() - loaddrawfn(m)(remotetmr,remotefb,g,r,b); doremotedraw() - remotetqh = tq:queue(1,fdq) -- run on callback to avoid stack problems - end) + -- loop over all ;-delimited statements in the message and fire + -- them off. Note that by default this will *append* to the fifo, + -- making messages not entirely idempotent (unless they start with + -- "new"). + local c,as + for c,as in msg:gmatch("(%w*)%s*([^;]*);%s*") do + if c then vt[c](as) end end - fdq() -- start party end