diff options
-rw-r--r-- | run.lua | 9 | ||||
-rw-r--r-- | wakeup.lua | 150 |
2 files changed, 94 insertions, 65 deletions
@@ -1,6 +1,11 @@ local wakeup = require("wakeup") return function () - wakeup:init() - tmr.create():alarm(1000, tmr.ALARM_SINGLE, function () wakeup:run() end) + tmr.create():alarm( + 500, + tmr.ALARM_AUTO, + function (timer) + wakeup:step(timer) + collectgarbage() + end) end @@ -15,49 +15,45 @@ function magic_packet (mac) end -function wakeup:open () - self.udp = net.createUDPSocket() +--- Perform the most basic preparations right after device booted up. +function wakeup:boot () + gpio.write(4, gpio.HIGH) + gpio.mode(4, gpio.OUTPUT) + self.data = magic_packet(self.mac) + self.step = self.connect end -function wakeup:close () - if self.udp then - self.udp:close() - end +--- This is the current state action of the wake-up state machine. It is a callable that has [[(self, [timer]) -> nil]] +--- signature. Steps are called sequentially, usually by a tmr.timer. +wakeup.step = wakeup.boot + + +--- Marks a failure that is pointless to attempt to recover from, e.g., if provided configuration is incomplete. +function wakeup:hard_failure (timer) + print("Aborting...") + return timer:unregister() end ---- Creates a new counter that has :up() method that returns true until it gets called N [[times]]. Then it returns only ---- false. -local -function new_counter (times) - return { - count = 0, - times = times, - up = function (self) - self.count = self.count + 1 - return self.count <= self.times - end, - } +--- Marks a failure that device may recover from by restarting itself. +function wakeup:soft_failure () + node.restart() end ---- Begins to send Wake-on-LAN magic packets to the broadcast [[.addr]] for selected [[.mac]]. Packets are sent several ---- [[times]] each separated by [[interval]]. Callback is called [[after]] all packets are sent. -function wakeup:sendout (interval, times, after) - self:open() - local count = new_counter(times) - return tmr.create():alarm(interval, tmr.ALARM_SEMI, function (timer) - if count:up() then - print("Waking up", self.mac, self.addr) - self.udp:send(self.port, self.addr, self.data) - timer:start() - else - timer:unregister() - self:close() - after() - end +function wakeup:connect () + self.step = self.wait_for_ip + wifi.eventmon.register(wifi.eventmon.STA_GOT_IP, function () + self.step = self.sync_time end) + wifi.setmode(wifi.STATION, false) + wifi.sta.connect() +end + + +function wakeup:wait_for_ip () + -- no-op -- TODO: soft_failure if too long? end @@ -69,6 +65,25 @@ function wakeup:now () end +function wakeup:sync_time () + self.step = self.wait_for_time + sntp.sync( + self.sntp, + function () + self.step = self.check_time + end, + function (code, err) + print("SNTP sync failed", code, err) + self.step = self.soft_failure + end) +end + + +function wakeup:wait_for_time () + -- no-op -- TODO: soft_failure if too long? +end + + local function compare (time, pattern) for key, value in pairs(pattern) do @@ -80,40 +95,49 @@ function compare (time, pattern) end -function wakeup:init () - gpio.write(4, gpio.HIGH) - gpio.mode(4, gpio.OUTPUT) - self.data = magic_packet(self.mac) +--- Creates a new counter that has :up() method that returns true until it gets called N [[times]]. Then it returns only +--- false. +local +function new_counter (times) + return { + count = 0, + times = times, + up = function (self) + self.count = self.count + 1 + return self.count <= self.times + end, + } +end - wifi.eventmon.register(wifi.eventmon.STA_GOT_IP, function () - sntp.sync( - self.sntp, - function () - if compare(self:now(), self.when) then - gpio.write(4, gpio.LOW) - self:sendout(500, 5, function () - wifi.setmode(wifi.NULLMODE, false) - gpio.write(4, gpio.HIGH) - end) - else - print("Not yet time") - wifi.setmode(wifi.NULLMODE, false) - tmr.create():alarm(25000, tmr.ALARM_SINGLE, function () - self:run() - end) - end - end, - function (code, err) - print("SNTP sync failed", code, err) - node.restart() - end) - end) + +--- Creates new state machine action that sends out Wake-on-LAN magic packets to configured host N [[times]]. +local +function start_sendout (times) + local self = new_counter(times) + self.udp = net.createUDPSocket() + return function (wakeup, timer) + if self:up() then + print("Waking up", wakeup.mac, wakeup.addr) + self.udp:send(wakeup.port, wakeup.addr, wakeup.data) + else + self.udp:close() + timer:unregister() + wifi.setmode(wifi.NULLMODE, false) + gpio.write(4, gpio.HIGH) + print("Done") + end + end end -function wakeup:run () - wifi.setmode(wifi.STATION, false) - wifi.sta.connect() +function wakeup:check_time (timer) + if compare(self:now(), self.when) then + gpio.write(4, gpio.LOW) + self.step = start_sendout(5) + else + print("Not yet time") + timer:unregister() + end end |