--- /dev/null
+package.loaded["morse"] = dofile("morse/morse.lua")
+
+local dit = 500 -- milliseconds
+
+function loaddrawfn(name)
+ local m = (require"morse")(name)
+ printerr(name)
+ return function (t,_,g,r,b)
+ local function onf()
+ print(string.format("%x %x %x",r,g,b))
+ end
+ local function offf() print("0 0 0") end
+
+ local function morsecb(dur,on)
+ if on then onf() else offf() end
+ t:register(dur*250,tmr.ALARM_SINGLE,function()
+ local did = m(morsecb)
+ if not did then
+ offf() -- off at end
+ -- t:register(1000,tmr.ALARM_SINGLE,function() (require"morse")(name)(morsecb) end) -- cyclic behavior
+ t:register(dit,tmr.ALARM_SINGLE,function() onf() end) -- solid at end
+ end
+ end)
+ end
+ -- begin by being solid on for 10 dit times, then off for 4, then run
+ -- morse sequence
+ onf()
+ t:register(10*dit,tmr.ALARM_SINGLE, function()
+ offf() ; t:register(4*dit,tmr.ALARM_SINGLE,function() m(morsecb) end)
+ end)
+ end
+end
+
+function doremotedraw() end
--- /dev/null
+-- emulate enough framebuffer functionality
+remotefb.length = 32
+function remotefb.set(self,ix,a1,a2,a3)
+ -- printerr(ix,a1,a2,a3)
+ if ix > self.length then return end
+ if type(a1) == 'string' and a2 == nil and a3 == nil then
+ self[ix] = a1
+ else
+ self[ix] = string.char(math.floor(a1),math.floor(a2),math.floor(a3))
+ end
+end
+function remotefb.size(self) return self.length end
+function remotefb.fade(self,factor,out)
+ local ix, f
+ if out
+ then f = function(c) return string.char(string.byte(c,1) / factor) end
+ else f = function(c) return string.char(string.byte(c,1) * factor) end
+ end
+ for ix = 1,self.length do self[ix] = self[ix]:gsub(".", f) end
+end
+function remotefb.fill(self,...)
+ local i
+ for i = 1,self.length do self:set(i,...) end
+end
+
+local function drawfailsafe(t,fb,g,r,b) end
+function loaddrawfn(name)
+ local f = loadfile (string.format("examples/lamp/draw-%s.lua",name))
+ local fn = f and f()
+ if fn
+ then return function(t,fb,g,r,b) fn(t,fb,g,r,b) end
+ else return drawfailsafe
+ end
+end
+
+local outfn = "/run/user/1000/lamp-purple.xpm"
+local drawstr = "abcdefghijklmnopqrstuvwxzy123456"
+local drawstr2 = ""
+local function computedrawstr2()
+ local ix = 0, r, c
+ for r = 1,4 do
+ local line = ""
+ for c = 1,8 do
+ ix = ix + 1
+ local h = drawstr:sub(ix,ix)
+ if c ~= 1 then line = line .. "0" end
+ line = line .. h .. h
+ end
+ line = line .. "\n"
+ if r ~= 1 then drawstr2 = drawstr2 .. "00000000000000000000000\n" end
+ drawstr2 = drawstr2 .. line
+ drawstr2 = drawstr2 .. line
+ end
+end
+computedrawstr2()
+local function pixelval(byteval)
+
+end
+function dodraw()
+ local f = io.open(outfn,"w+")
+ f:write("! XPM2\n23 11 33 1\n") -- header
+ f:write("0 c #000000\n")
+ local ix = 0, r, c
+ for r = 1,4 do
+ for c = 1,8 do
+ ix = ix + 1
+ f:write(string.format("%s c #%02x%02x%02x\n",
+ drawstr:sub(ix,ix),
+ string.byte(remotefb[ix],2)*16, -- r
+ string.byte(remotefb[ix],1)*16, -- g
+ string.byte(remotefb[ix],3)*16 -- b
+ ))
+ end
+ end
+ f:write(drawstr2)
+ f:close()
+ -- io.stderr:write("draw\n")
+ io.write("\n\n") -- XXX? WTF?
+ io.flush()
+end
+doremotedraw = dodraw
--- /dev/null
+-- Expects to be fed a series of draw commands on stdin and a worker module
+-- lua file (e.g. ...-xpm.lua or ...-morse.lua) as argv[1].
+--
+-- This wraps around lamp-remote.lua for all the parsing logic (ain't code
+-- reuse great?) and expects the worker modules to provide "enough" of the
+-- nodemcu environment for whatever else they load. e.g. -xpm provides a
+-- full frame buffer emulation and loads the various draw-*.lua modules just
+-- like the hardware, while -morse does nothing of the sort.
+
+cq = require "cqueues"
+local cqs = require "cqueues.signal"
+cqc = cq.new()
+package.loaded["fifo"] = dofile("fifo/fifo.lua") -- ick, but hey, it works!
+
+function printerr(...)
+ local s = "", i, v
+ for i,v in ipairs{...} do s = s .. tostring(v) .. "\t" end
+ s = s .. "\n"
+ io.stderr:write(s)
+end
+
+-- Emulate tq with facilities available thanks to cqueues
+tq = dofile("tq/tq.lua")(nil)
+tq.now = function() return cq.monotime() * 1000000 end
+tq.arm = function(self,fn,t) cqc:wrap(function() cq.poll(t/1000) ; fn() end) end
+
+-- how backwards is this!? We are using tq as faked above for tmr support
+-- since it's not obvious to me how to remove pending events in cqueues.
+tmr = {}
+tmr.ALARM_AUTO = 0
+function tmr.unregister(self)
+ if self.tqe then tq:dequeue(self.tqe); self.tqe = nil end
+end
+function tmr.register(self,period,mode,fn)
+ tmr.unregister(self)
+
+ local fnwrap
+ if mode == tmr.ALARM_AUTO then
+ -- persist by re-registering after fire
+ fnwrap = function() tmr.register(self,period,mode,fn); fn() end
+ else
+ fnwrap = fn
+ end
+
+ self.tqe = tq:queue(period,fnwrap)
+end
+
+remotetmr = {}
+remotetmr.tqe = nil
+remotetmr.register = tmr.register
+remotetmr.unregister = tmr.unregister
+
+remotefb = {}
+
+if arg[1] then dofile(arg[1]) else print("You probably meant to give a filename"); os.exit(1) end
+
+cqc:wrap(function()
+ while true do
+ cq.poll({ pollfd = 0, events = 'r' })
+ local line = io.read() -- XXX :(
+ if line == nil or line == "" then return end
+ dofile("examples/lamp/lamp-remote.lua")(line)
+ end
+end)
+io.stdout:setvbuf("no")
+
+cqc:wrap(function()
+ cq.poll(cqs.listen(cqs.SIGINT, cqs.SIGTERM, cqs.SIGQUIT))
+ print("exit")
+ os.exit()
+end)
+cqs.block(cqs.SIGINT)
+cqs.block(cqs.SIGTERM)
+cqs.block(cqs.SIGQUIT)
+
+cqc:wrap(function()
+ cq.poll(cqs.listen(cqs.SIGHUP))
+ print("hup")
+end)
+cqs.block(cqs.SIGHUP)
+
+assert(cqc:loop())