You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
185 lines
4.2 KiB
185 lines
4.2 KiB
local serialization = require("serialization")
|
|
local uuid = require("uuid")
|
|
|
|
local Version = {0, 1}
|
|
|
|
local Message = {
|
|
Hello = 0x48454c4f,
|
|
Register = 0x52454749,
|
|
Deregister = 0x44524547,
|
|
NounRequest = 0x4e524551,
|
|
NounResponse = 0x4e524553,
|
|
VerbRequest = 0x56524551,
|
|
VerbResponse = 0x56524553,
|
|
ListenRequest = 0x4c524551,
|
|
ListenNotify = 0x4c4e4f54,
|
|
ListenCancel = 0x4c535450,
|
|
}
|
|
|
|
local function query_param(self, v)
|
|
return {ty=self.ty, v=v}
|
|
end
|
|
local Query = {
|
|
Change = {ty=0x434847},
|
|
Rising = {ty=0x524953},
|
|
Falling = {ty=0x46414c},
|
|
Equals = setmetatable({ty=0x455155}, {__call=query_param}),
|
|
Above = setmetatable({ty=0x414256}, {__call=query_param}),
|
|
Below = setmetatable({ty=0x424c4f}, {__call=query_param}),
|
|
}
|
|
|
|
-- Network ---------------------------------------------------------------- {{{
|
|
local Network = {
|
|
default_port = 0xBC00 | (Version[1] << 4) | Version[2],
|
|
}
|
|
|
|
function Network:new(modem, port)
|
|
if type(modem) == "number" then
|
|
port = modem
|
|
modem = nil
|
|
end
|
|
local self = {
|
|
modem = modem or require("component").modem,
|
|
port = port or Network.default_port,
|
|
}
|
|
setmetatable(self, {__index=Network})
|
|
|
|
return self
|
|
end
|
|
setmetatable(Network, {__call=Network.new})
|
|
|
|
function Network:start(callback)
|
|
self.modem.open(self.port)
|
|
self.listener = function(_, addr_lo, addr_remote, port, _, msg)
|
|
-- Filter everything we don't care about
|
|
if addr_lo ~= self.modem.address then return end
|
|
if port ~= self.port then return end
|
|
callback(addr_remote, serialization.unserialize(msg))
|
|
end
|
|
require("event").listen("modem_message", self.listener)
|
|
end
|
|
|
|
function Network:send(addr, msg)
|
|
self.modem.send(addr, self.port, serialization.serialize(msg))
|
|
end
|
|
|
|
function Network:broadcast(msg)
|
|
self.modem.broadcast(self.port, serialization.serialize(msg))
|
|
end
|
|
|
|
function Network:stop()
|
|
require("event").ignore("modem_message", self.listener)
|
|
self.modem.close(self.port)
|
|
end
|
|
-- }}}
|
|
|
|
-- BaseControl ------------------------------------------------------------ {{{
|
|
local BaseControl = {
|
|
version = Version,
|
|
Message = Message,
|
|
Query = Query,
|
|
Network = Network,
|
|
}
|
|
|
|
function BaseControl:new(self, network)
|
|
local self = {
|
|
locals = {
|
|
nouns = {},
|
|
verbs = {},
|
|
},
|
|
remotes = {
|
|
nouns = {},
|
|
verbs = {},
|
|
},
|
|
live = false,
|
|
network = network or Network:new(),
|
|
}
|
|
setmetatable(self, {__index=BaseControl, __call=BaseControl.new})
|
|
|
|
self.network:start(function() error("net unimplemented") end)
|
|
|
|
return self
|
|
end
|
|
|
|
function BaseControl:register(name, value)
|
|
if self.live then
|
|
error("can't register \""..name.."\" after finalizing")
|
|
end
|
|
|
|
if type(value) == "function" then
|
|
if self.locals.verbs[name] ~= nil then
|
|
error("\""..name.."\" already registered")
|
|
else
|
|
self.locals.verbs[name] = value
|
|
end
|
|
else
|
|
if self.locals.nouns[name] ~= nil then
|
|
error("\""..name.."\" already registered")
|
|
else
|
|
self.locals.nouns[name] = value
|
|
end
|
|
end
|
|
end
|
|
|
|
function BaseControl:finalize(waits, timeout)
|
|
local self = self
|
|
if self == BaseControl then
|
|
-- Called as a constructor
|
|
self = BaseControl:new()
|
|
end
|
|
|
|
self.live = true
|
|
return self
|
|
end
|
|
|
|
-- Nouns {{{
|
|
function BaseControl:has_noun(noun)
|
|
return self.locals.nouns[noun] ~= nil or self.remotes.nouns[noun] ~= nil
|
|
end
|
|
|
|
function BaseControl:nouns(local_only)
|
|
local nouns = {}
|
|
for noun in pairs(self.locals.nouns) do
|
|
table.insert(nouns, noun)
|
|
end
|
|
-- TODO: Remote
|
|
return nouns
|
|
end
|
|
|
|
function BaseControl:get(noun, timeout)
|
|
if self.locals.nouns[noun] ~= nil then
|
|
return self.locals.nouns[noun]
|
|
elseif self.locals.verbs[noun] ~= nil then
|
|
error("\""..noun.."\" is not a noun")
|
|
else
|
|
return nil
|
|
end
|
|
end
|
|
|
|
function BaseControl:set(name, value)
|
|
error("set unimplemented")
|
|
end
|
|
-- }}}
|
|
|
|
-- Verbs {{{
|
|
function BaseControl:has_verb(verb)
|
|
return self.locals.verbs[verb] ~= nil or self.remotes.verbs[verb] ~= nil
|
|
end
|
|
|
|
function BaseControl:verbs(local_only)
|
|
local verbs = {}
|
|
for verb in pairs(self.locals.verbs) do
|
|
table.insert(verbs, verb)
|
|
end
|
|
-- TODO: Remote
|
|
return verbs
|
|
end
|
|
|
|
function BaseControl:call(verb, ...)
|
|
error("call unimplemented")
|
|
end
|
|
-- }}}
|
|
-- }}}
|
|
|
|
return setmetatable(BaseControl, {__call=BaseControl.new})
|