]> hydra-www.ietfng.org Git - acmetensortoys-esp-lua_ctfws/commitdiff
Tweak ctfws display device example
authorNathaniel Wesley Filardo <nwf@cs.jhu.edu>
Mon, 23 Jan 2017 01:00:14 +0000 (20:00 -0500)
committerNathaniel Wesley Filardo <nwf@cs.jhu.edu>
Mon, 23 Jan 2017 01:02:10 +0000 (20:02 -0500)
README.rst
ctfws-lcd.lua
init2.lua
init3.lua [new file with mode: 0644]
pushall.sh

index e4a37551e610fad0fbf61c5ffe3be51e82380922..d58be2222bbe5fe968c8c2ae6e6cd578c42bc2ca 100644 (file)
@@ -18,16 +18,25 @@ of parsing.
 Centrally-set topics:
 
 * ``ctfws/game/config`` the string ``none`` or a whitespace-separated text field:
+
   * ``starttime`` -- NTP seconds indicating start state
+
   * ``setupduration`` -- setup duration, in seconds
+
   * ``rounds`` -- number of rounds
+
   * ``roundduration`` -- seconds per round
+
   * ``nflags`` -- number of flags per team
+
   * any additional fields are to be ignored.
 
 * ``ctfws/game/flags`` -- whitespace-separated text field:
+
   * ``red`` -- red team flag capture count (int)
   * ``yel`` -- yellow team flag capture count (int)
+
   * any additional fields are to be ignored.
 
 * ``ctfws/game/endtime`` -- a single number, denoting NTP seconds of a
@@ -57,6 +66,7 @@ guest account for a hypothetical CtFwS app.
 Device-set topics:
 
 * ``ctfws/dev/$DEVICENAME/beat``
+
   * one of ``alive``, ``beat``, or ``dead`` (LWT; no further fields)
   * ``time`` (UNIX time, from local clock)
   * ``ap`` (MAC addr)
@@ -93,20 +103,20 @@ To send MQTT messages, try variants of these.  Note that in all cases, we
 set messages persistent so that devices that (re)connect mid-way into a game
 get the latest messages automatically.
 
-  * To start a game::
+* To start a game::
 
     mosquitto_pub -h $MQTT_SERVER -u ctfwsmaster -P asdf -q 1 -t ctfws/game/flags -r -m '0 0'
     mosquitto_pub -h $MQTT_SERVER -u ctfwsmaster -P asdf -q 1 -t ctfws/game/config -r -m `date +%s`' 900 3 900 10'
 
-  * To post information::
+* To post information::
 
     mosquitto_pub -h $MQTT_SERVER -u ctfwsmaster -P asdf -q 1 -t ctfws/game/flags -r -m '1 2'
     mosquitto_pub -h $MQTT_SERVER -u ctfwsmaster -P asdf -q 1 -t ctfws/game/message -r -m 'Red team captured a flag!'
 
-  * To end a game::
+* To end a game::
 
     mosquitto_pub -h $MQTT_SERVER -u ctfwsmaster -P asdf -q 1 -t ctfws/game/endtime -r -m `date +%s` 
-
 Jail Glyph Timers
 #################
 
@@ -136,6 +146,34 @@ AP they're associated with.
 The device should otherwise function more or less as a glorified stopwatch
 under centralized control.
 
+NodeMCU modules used
+====================
+
+Please ensure that your build of NodeMCU supports the following modules:
+
+* ``bit`` (for LCD)
+* ``cjson``
+* ``cron``
+* ``file``
+* ``i2c`` (for LCD)
+* ``mqtt``
+* ``net``
+* ``node``
+* ``rtctime``
+* ``sntp``
+* ``tmr``
+* ``wifi``
+
+Additionally,
+
+* ``mDNS`` may be a good idea, too, if you want to talk to your device over,
+  e.g. telnet, and want it to have a somewhat friendly name.
+
+* ``rtcmem`` may be useful if you wish to stash a little bit of state
+  frequently and don't want to write to flash.
+
+* ``uart`` is in most default builds but is not necessary, if you need space.
+
 BOM
 ===
 
@@ -165,7 +203,7 @@ Setup time display::
     0         1         
     01234567890123456789
     SETUP    :   MM:SS.s
-    NN⚑: R=0 Y=0
+       NN⚑: R=0 Y=0
     messagemessagemessag
     START IN :   MM:SS.s
 
@@ -174,7 +212,7 @@ Steady state display::
     0         1         
     01234567890123456789
     ROUND r/R :  MM:SS.s
-    NN⚑: R=NN Y=NN
+       NN⚑: R=NN Y=NN
     messagemessagemessag
     JAILBREAK :  MM:SS.s
 
index 1a40e3b5f59ad45641083701ca8338161bdf5a1b..b23ce3c38997222d6e80d74d4e1e1519d47196ff 100644 (file)
@@ -68,18 +68,34 @@ local function drawSteadyBotLine(self,rix,maxt,rem)
   drawDS(lcd,3,13,maxt,self.dl_remain ,rem); self.dl_remain  = rem
 end
 
+local function attention(self)
+  if self.attnState then return end
+
+  local tq = self.tq
+  local lcd = self.lcd
+
+  local function doBlink()
+    if self.attnState <= 0 then self.attnState = nil ; return end
+    self.attnState = self.attnState - 1
+    lcd:light(false)
+    tq:queue(250, function() lcd:light(true); tq:queue(500, doBlink) end)
+  end
+
+  self.attnState = 2
+  tq:queue(250, doBlink)
+end
+
 -- returns true if timers should keep going or false if we should wait for
 -- the next message or event
 local function drawTimes(self)
   local ctfws = self.ctfws
   local rix, maxt, ela = ctfws:times(rtctime.get)
   if rix == nil then
-    -- XXX beep to get attention
     drawNoGame(self.lcd, maxt)
     return false
   end
   if rix ~= self.dl_round then
-    if self.dl_round ~= nil then end -- XXX beep when not forcibly reset
+    if self.dl_round ~= nil then attention(self) end -- XXX beep when not forcibly reset
     self.dl_round = rix
     self.dl_elapsed = nil -- force redraws of times on round boundaries
     self.dl_remain  = nil
@@ -92,7 +108,9 @@ end
 local function drawFlags(self)
   local lcd = self.lcd
   local ctfws = self.ctfws
-  lcd:put(lcd:locate(1,0),"                    ")
+  if ctfws.flagsN then -- try not to blank a flagsmessage unless we have reason
+    lcd:put(lcd:locate(1,0),"                    ")
+  end
   if ctfws.startT then
     local str = string.format("%d\000: R=%d Y=%d",
                                ctfws.flagsN, ctfws.flagsR, ctfws.flagsY)
@@ -144,10 +162,12 @@ return function(ctfws, lcd, tq, t)
   self.tq = tq
   self.mtmr = t
 
-  self.reset = reset
-  self.drawTimes   = drawTimes
-  self.drawFlags   = drawFlags
-  self.drawMessage = drawMessage
+  self.attnState       = nil
+
+  self.reset            = reset
+  self.drawTimes        = drawTimes
+  self.drawFlags        = drawFlags
+  self.drawMessage      = drawMessage
   self.drawFlagsMessage = drawFlagsMessage
 
   -- load custom flag glyph
index 0afe3f71b12c59fbbe31d9207d4a1f9112b73687..52e8d6235620f15635f98811822fd075875dd1eb 100644 (file)
--- a/init2.lua
+++ b/init2.lua
--- common module initialization
-cron.schedule("*/5 * * * *", function(e) dofile("nwfnet-sntp.lc").dosntp(nil) end)
-nwfnet = require "nwfnet"
+-- It's early in boot, so we have plenty of RAM.  Compile
+-- the rest of the firmware from source if it's there.
+local k,v
+for k,v in pairs(file.list()) do
+  local ix, _ = k:find("^.*%.lua$")
+  if ix and k ~= "init.lua" then
+    print("early compile",k)
+    node.compile(k); file.remove(k)
+  end
+end
 
-tq = (dofile "tq.lc")(tmr.create())
 
 -- Hardware initialization
-i2c.setup(0,2,1,i2c.SLOW)  -- init i2c as per silk screen (GPIO4, GPIO5)
+i2c.setup(0,2,1,i2c.SLOW)  -- init i2c on GPIO4 and GPIO5
 lcd = dofile("lcd1602.lc")(0x27)
 
--- Game logic modules
-ctfws = dofile("ctfws.lc")()
-ctfws:setFlags(0,0)
-
-msg_tmr = tmr.create()
-ctfws_lcd = dofile("ctfws-lcd.lc")(ctfws, lcd, tq, msg_tmr)
-ctfws_tmr = tmr.create()
-
--- Draw the default display
-ctfws_lcd:drawTimes()
-ctfws_lcd:drawFlagsMessage("BOOT...")
-
--- MQTT plumbing
-
-mqc, mqttUser = dofile("nwfmqtt.lc").mkclient("nwfmqtt.conf")
-local mqttBootTopic  = string.format("ctfws/dev/%s/beat",mqttUser)
-mqc:lwt(mqttBootTopic,"dead",1,1)
-
--- This is not, properly speaking, OK, but it's so convenient
-ctfws_lcd:drawMessage(string.format("I am: %s", mqttUser))
-
-local myBSSID = "00:00:00:00:00:00"
-
-local mqtt_reconn_cronentry
-local function mqtt_reconn()
-  mqtt_reconn_cronentry = cron.schedule("* * * * *", function(e)
-    mqc:close(); dofile("nwfmqtt.lc").connect(mqc,"nwfmqtt.conf")
-  end)
-  dofile("nwfmqtt.lc").connect(mqc,"nwfmqtt.conf")
-end
-
-local mqtt_beat_cronentry
-local function mqtt_beat()
-  mqtt_beat_cronentry = cron.schedule("*/5 * * * *", function(e) 
-    mqc:publish(mqttBootTopic,string.format("beat %d %s",rtctime.get(),myBSSID),1,1)
-  end)
-end
-
-local function ctfws_lcd_draw_all()
-    ctfws_lcd:reset()
-    ctfws_lcd:drawFlags()
-    ctfws_lcd:drawTimes()
-end
-
-local function ctfws_start_tmr()
-  ctfws_tmr:alarm(100,tmr.ALARM_AUTO,function()
-    if not ctfws_lcd:drawTimes() then ctfws_tmr:unregister() end
-  end)
-end
-
-nwfnet.onmqtt["init"] = function(c,t,m)
-  if t == "ctfws/game/config" then
-    ctfws_tmr:unregister()
-    if not m or m == "none"
-     then ctfws:deconfig()
-     else local st, sd, nr, rd, nf = m:match("^%s*(%d+)%s+(%d+)%s+(%d+)%s+(%d+)%s+(%d+).*$")
-          if st == nil
-           then ctfws:deconfig()
-           else -- the game's afoot!
-                ctfws:config(tonumber(st), tonumber(sd), tonumber(nr),
-                             tonumber(rd), tonumber(nf))
-                ctfws_start_tmr()
-          end
-    end
-    ctfws_lcd_draw_all()
-  elseif t == "ctfws/game/endtime" then
-    ctfws:setEndTime(tonumber(m))
-    ctfws_lcd_draw_all()
-    ctfws_start_tmr() -- might have been unset; restart display if so
-  elseif t == "ctfws/game/flags" then
-   if not m then ctfws:setFlags(0,0); return end
-   local fr, fy = m:match("^%s*(%d+)%s+(%d+).*$")
-   if fr ~= nil then
-     ctfws:setFlags(tonumber(fr),tonumber(fy))
-     ctfws_lcd:drawFlags()
-   end
-  elseif t:match("^ctfws/game/message") then
-    ctfws_lcd:drawMessage(m)
-  end
-end
-nwfnet.onnet["init"] = function(e,c)
-  if     e == "mqttdscn" and c == mqc then
-    if mqtt_beat_cronentry then mqtt_beat_cronentry:unschedule() mqtt_beat_cronentry = nil end
-    if not mqtt_reconn_cronentry then mqtt_reconn() end
-    ctfws_lcd:drawFlagsMessage("MQTT Disconnected")
-  elseif e == "mqttconn" and c == mqc then
-    if mqtt_reconn_cronentry then mqtt_reconn_cronentry:unschedule() mqtt_reconn_cronentry = nil end
-    if not mqtt_beat_cronentry then mqtt_beat() end
-    mqc:publish(mqttBootTopic,"alive",1,1)
-    mqc:subscribe("ctfws/game/config",1)
-    mqc:subscribe("ctfws/game/endtime",1)
-    mqc:subscribe("ctfws/game/flags",1)
-    mqc:subscribe("ctfws/game/message",1)      -- broadcast messages
-    mqc:subscribe("ctfws/game/message/jail",1) -- jail-specific messages
-    ctfws_lcd:drawFlagsMessage("MQTT CONNECTED")
-  elseif e == "wstagoip"              then
-    if not mqtt_reconn_cronentry then mqtt_reconn() end
-    ctfws_lcd:drawFlagsMessage(string.format("DHCP %s",c.IP))
-  elseif e == "wstaconn"              then
-    myBSSID = c.BSSID
-    ctfws_lcd:drawFlagsMessage(string.format("WIFI %s",c.SSID))
-  elseif e == "sntpsync"              then
-    -- If we have a game configuration and just got SNTP sync, it might
-    -- be that we just lept far into the future, so go ahead and start
-    -- the game!
-    if ctfws.startT then ctfws_start_tmr() end
-  end
-end
+tq = (dofile "tq.lc")(tmr.create())
 
-ctfws_lcd:drawFlagsMessage("CONNECTING...")
-dofile("nwfnet-diag.lc")(true)
-dofile("nwfnet-go.lc")
+-- give the LCD time to initialize properly
+tq:queue(125, function() dofile("init3.lc") end)
diff --git a/init3.lua b/init3.lua
new file mode 100644 (file)
index 0000000..e1d5318
--- /dev/null
+++ b/init3.lua
@@ -0,0 +1,120 @@
+-- common module initialization
+cron.schedule("*/5 * * * *", function(e) dofile("nwfnet-sntp.lc").dosntp(nil) end)
+nwfnet = require "nwfnet"
+
+-- Game logic modules
+ctfws = dofile("ctfws.lc")()
+ctfws:setFlags(0,0)
+
+msg_tmr = tmr.create()
+ctfws_lcd = dofile("ctfws-lcd.lc")(ctfws, lcd, tq, msg_tmr)
+ctfws_tmr = tmr.create()
+
+-- Draw the default display
+ctfws_lcd:drawTimes()
+ctfws_lcd:drawFlagsMessage("BOOT...")
+
+-- MQTT plumbing
+mqc, mqttUser = dofile("nwfmqtt.lc").mkclient("nwfmqtt.conf")
+local mqttBootTopic  = string.format("ctfws/dev/%s/beat",mqttUser)
+mqc:lwt(mqttBootTopic,"dead",1,1)
+
+-- This is not, properly speaking, OK, but it's so convenient
+ctfws_lcd:drawMessage(string.format("I am: %s", mqttUser))
+
+local myBSSID = "00:00:00:00:00:00"
+
+local mqtt_reconn_cronentry
+local function mqtt_reconn()
+  mqtt_reconn_cronentry = cron.schedule("* * * * *", function(e)
+    mqc:close(); dofile("nwfmqtt.lc").connect(mqc,"nwfmqtt.conf")
+  end)
+  dofile("nwfmqtt.lc").connect(mqc,"nwfmqtt.conf")
+end
+
+local mqtt_beat_cronentry
+local function mqtt_beat()
+  mqtt_beat_cronentry = cron.schedule("*/5 * * * *", function(e) 
+    mqc:publish(mqttBootTopic,string.format("beat %d %s",rtctime.get(),myBSSID),1,1)
+  end)
+end
+
+local function ctfws_lcd_draw_all()
+    ctfws_lcd:reset()
+    ctfws_lcd:drawFlags()
+    ctfws_lcd:drawTimes()
+end
+
+local function ctfws_start_tmr()
+  ctfws_tmr:alarm(100,tmr.ALARM_AUTO,function()
+    if not ctfws_lcd:drawTimes() then ctfws_tmr:unregister() end
+  end)
+end
+
+nwfnet.onmqtt["init"] = function(c,t,m)
+  if t == "ctfws/game/config" then
+    ctfws_tmr:unregister()
+    if not m or m == "none"
+     then ctfws:deconfig()
+          ctfws_lcd_draw_all()
+     else local st, sd, nr, rd, nf = m:match("^%s*(%d+)%s+(%d+)%s+(%d+)%s+(%d+)%s+(%d+).*$")
+          if st == nil
+           then ctfws:deconfig()
+           else -- the game's afoot!
+                ctfws:config(tonumber(st), tonumber(sd), tonumber(nr),
+                             tonumber(rd), tonumber(nf))
+                ctfws_start_tmr()
+          end
+          ctfws_lcd_draw_all()
+    end
+  elseif t == "ctfws/game/endtime" then
+    ctfws:setEndTime(tonumber(m))
+    ctfws_lcd_draw_all()
+    ctfws_start_tmr() -- might have been unset; restart display if so
+  elseif t == "ctfws/game/flags" then
+   if not m then ctfws:setFlags(0,0); return end
+   local fr, fy = m:match("^%s*(%d+)%s+(%d+).*$")
+   if fr ~= nil then
+     ctfws:setFlags(tonumber(fr),tonumber(fy))
+     ctfws_lcd:drawFlags()
+   end
+  elseif t:match("^ctfws/game/message") then
+    ctfws_lcd:drawMessage(m)
+  end
+end
+
+-- network callbacks
+
+nwfnet.onnet["init"] = function(e,c)
+  if     e == "mqttdscn" and c == mqc then
+    if mqtt_beat_cronentry then mqtt_beat_cronentry:unschedule() mqtt_beat_cronentry = nil end
+    if not mqtt_reconn_cronentry then mqtt_reconn() end
+    ctfws_lcd:drawFlagsMessage("MQTT Disconnected")
+  elseif e == "mqttconn" and c == mqc then
+    if mqtt_reconn_cronentry then mqtt_reconn_cronentry:unschedule() mqtt_reconn_cronentry = nil end
+    if not mqtt_beat_cronentry then mqtt_beat() end
+    mqc:publish(mqttBootTopic,"alive",1,1)
+    mqc:subscribe("ctfws/game/config",1)
+    mqc:subscribe("ctfws/game/endtime",1)
+    mqc:subscribe("ctfws/game/flags",1)
+    mqc:subscribe("ctfws/game/message",1)      -- broadcast messages
+    mqc:subscribe("ctfws/game/message/jail",1) -- jail-specific messages
+    ctfws_lcd:drawFlagsMessage("MQTT CONNECTED")
+  elseif e == "wstagoip"              then
+    if not mqtt_reconn_cronentry then mqtt_reconn() end
+    ctfws_lcd:drawFlagsMessage(string.format("DHCP %s",c.IP))
+  elseif e == "wstaconn"              then
+    myBSSID = c.BSSID
+    ctfws_lcd:drawFlagsMessage(string.format("WIFI %s",c.SSID))
+  elseif e == "sntpsync"              then
+    -- If we have a game configuration and just got SNTP sync, it might
+    -- be that we just lept far into the future, so go ahead and start
+    -- the game!
+    if ctfws.startT then ctfws_start_tmr() end
+  end
+end
+
+-- hook us up to the network!
+ctfws_lcd:drawFlagsMessage("CONNECTING...")
+-- dofile("nwfnet-diag.lc")(true)
+dofile("nwfnet-go.lc")
index 81db084c8ff29c184ed4c880c99248606b6282c7..aa2baa9fb145427aa4d174d331ae92d79a0304bb 100755 (executable)
@@ -4,13 +4,14 @@ set -e -u
 
 . ./host/pushcommon.sh
 
-#dopushcompile net/nwfmqtt.lua
-#dopush        examples/ctfws/conf/nwfnet.conf
+dopushcompile net/nwfmqtt.lua
+dopush        examples/ctfws/conf/nwfnet.conf
 dopush        examples/ctfws/conf/nwfnet.conf2
 dopush        examples/ctfws/conf/nwfmqtt.conf
-#dopushcompile _external/dvv-nodemcu-thingies/lcd1602.lua
+dopushcompile _external/lcd1602.lua
 dopushcompile examples/ctfws/ctfws.lua
 dopushcompile examples/ctfws/ctfws-lcd.lua
+dopushcompile examples/ctfws/init3.lua
 dopushcompile examples/ctfws/init2.lua
 
 echo "SUCCESS"