From b26a48165de7a46623c10a9575acfe0b0c51e4b4 Mon Sep 17 00:00:00 2001 From: 20kdc Date: Thu, 23 Mar 2017 01:17:57 +0000 Subject: [PATCH] Added a system for building 'light nodes' with minified OC-specific source. The light node system should only be used where necessary, as light nodes contribute absolutely nothing to network messaging. Maybe a minified full port of culib could be made for a "medium node", which would be (protocol behavior-wise) exactly like normal nodes, but minified and with interfaces cut down internally. --- oc/Makefile | 7 +++ oc/app/iot-mgr.lua | 4 +- oc/ecomponents/app-rsctrl | 40 ++++++++++++++++ oc/ecomponents/base | 41 ++++++++++++++++ oc/ecomponents/relib | 99 +++++++++++++++++++++++++++++++++++++++ oc/postprocess.lua | 37 +++++++++++++++ oc/uc-rsctl.lua | 76 ++++++++++++++++++++++++++++++ 7 files changed, 302 insertions(+), 2 deletions(-) create mode 100644 oc/Makefile create mode 100644 oc/ecomponents/app-rsctrl create mode 100644 oc/ecomponents/base create mode 100644 oc/ecomponents/relib create mode 100644 oc/postprocess.lua create mode 100644 oc/uc-rsctl.lua diff --git a/oc/Makefile b/oc/Makefile new file mode 100644 index 0000000..8c6eda5 --- /dev/null +++ b/oc/Makefile @@ -0,0 +1,7 @@ +all: uc-rsctl.lua + +uc-rsctl.lua: postprocess.lua ecomponents/base ecomponents/relib ecomponents/app-rsctrl + cat ecomponents/base ecomponents/relib ecomponents/app-rsctrl | lua postprocess.lua > uc-rsctl.lua + +clean: .PHONY + rm -f uc-rsctl.lua diff --git a/oc/app/iot-mgr.lua b/oc/app/iot-mgr.lua index d54d0dd..1aaac37 100644 --- a/oc/app/iot-mgr.lua +++ b/oc/app/iot-mgr.lua @@ -2,7 +2,7 @@ -- No warranty is provided, implied or otherwise. -- Controller for objects following the 'IoT protocol' --- (see provided microcontroller source) +-- (see provided microcontroller source for a lightweight OC implementation) local occure = require("occure") local event = require("event") @@ -26,7 +26,7 @@ local function getHelper(tp, tfrom, tto, p, d, u) if p == 4 then if tto == occure.getHostname() then if d:sub(1, 1) == packet(3, getTarg, "") then - print(d) + print(d:sub(2)) didGet = true end end diff --git a/oc/ecomponents/app-rsctrl b/oc/ecomponents/app-rsctrl new file mode 100644 index 0000000..3e30aed --- /dev/null +++ b/oc/ecomponents/app-rsctrl @@ -0,0 +1,40 @@ +-- I, 20kdc, release this into the public domain. +-- No warranty is provided, implied or otherwise. +%-- EXAMPLE IoT Redstone Top Controller -- + +UR=C.proxy(C.list("redstone")()) +function UT(p) + US=p + if#p>0then + UR.setOutput(1,15) + else + UR.setOutput(1,0) + end +end +UT("") +function UG(t) + RS(t,4,"\xC0\x42active.\x81setName") +end +N={ + [0]=UG, + [1]=function(f)RS(f,4,"\xC1"..US)end, + [0x41]=function(_,p)UT(p)end, + [0x82]=function(_,p)if#p>0then TH=p end end, +} +function UI(f,t,p,d) + local m=t==TH + if p==1 and(t=="*"or m)then + UG(f) + end + if p==4 and m then + if N[d:byte(1)]then + N[d:byte(1)](f,d:sub(2)) + end + end +end + +while true do local x={computer.pullSignal(1)}RF() + if"modem_message"==x[1]and 4957==x[4]and TC==x[6]then + RC(UI,TR(x[7])) + end +end diff --git a/oc/ecomponents/base b/oc/ecomponents/base new file mode 100644 index 0000000..5ec1cd2 --- /dev/null +++ b/oc/ecomponents/base @@ -0,0 +1,41 @@ +-- I, 20kdc, release this into the public domain. +-- No warranty is provided, implied or otherwise. + +-- 'Copper' networking implementation +-- TINY EDITION (This node doesn't do routing.) +-- for EEPROM usage. +-- NOTE: space is considered "explicit", newline isn't. tab is always deleted. + +-- Variables: +-- TH (hostname) +-- TX (modem proxy) +-- TC (the string "copper") +-- S (short for 'string') +-- C (short for 'component') + +-- Functions: +-- TN: Decode Name +-- TR: Receive Message handling (returns s/d/m rather than using a callback) +-- TS: Send Message (notably, this has no 'from') +-- TB: The TX.broadcast function + +TH,S,C,TC="hostname",string,component,"copper" +TX=C.proxy(C.list("modem")()) +TX.open(4957) +TB=TX.broadcast +function TN(m) + if#m<2then return end + local n=m:byte(1)+2return m:sub(2,n),m:sub(n+1) +end +function TR(m) + local h,s,m,d=m:byte(),TN(m:sub(2)) + if s then + d,m=TN(m) + if d then + return s,d,m + end + end +end +function TS(d,m) + TB(4957,TC,S.char(0,#TH-1)..TH..S.char(#d-1)..d..m) +end diff --git a/oc/ecomponents/relib b/oc/ecomponents/relib new file mode 100644 index 0000000..249083a --- /dev/null +++ b/oc/ecomponents/relib @@ -0,0 +1,99 @@ +-- I, 20kdc, release this into the public domain. +-- No warranty is provided, implied or otherwise. + +-- 'Copper' networking implementation +-- for EEPROM usage. Filters to hostname and broadcast for ease of use. + +-- Expects 'base'. + +-- Variables: +-- R1 to R4: Tuning parameters in the order in the "big" version. +-- RT: timers +-- RA: weAcked +-- RN: needsAck, but no success callback, so just the timer. + +-- Functions: +-- RU: Current time. +-- RP: Add timer. +-- RK: Kill timer. +-- RC: Message receive raw. +-- RF: Refresh system. +-- RG: Generate 1 random char (as a number) +-- RS: Send message. + +R1,R2,R3,R4=0x40,60,12,2.5 +RT,RA,RN,RU={},{},{},computer.uptime +function RP(f,x) + if#RT=7then + -- Keep in mind the ID used by tables is (originalPacketToName..GID) + -- ',k' unspecified value "trick" + local p,b,g,k=d:byte(2)+(d:byte(1)*256),d:byte(7),d:sub(1,5) + + if b==0x01or b==0x00then + k=t..g + if not RA[k] then + r(f,t,p,d:sub(8)) + else + RK(RA[k]) + end + RA[k]=RP(function()RA[k]=nil end,R2) + -- Only ACK under certain conditions. + if not(b~=0x01or t~=TH)then + TS(f,d:sub(1,6).."\x02") + end + end + + k=f..g + + if b==0x02 and RN[k]then + RK(RN[k]) + RN[k]=nil + end + end +end + +-- Refresh function to clean up & execute timers. +function RF() + local i,t=1,RU() + while#RT>i do + if t>RT[i][2]then + table.remove(RT,i)[1]() + else + i=i+1 + end + end +end + +-- It is shorter to have this than not have it or localize it. *sigh* +function RG() + return math.random(256)-1 +end + +function RS(t,p,d) + -- j,x unspecified. x is used in j. + local g,a,j,x=S.char(math.floor(p/256),p%256,RG(),RG(),RG()),-1 + j=function() + a=a+1 + x=nil + if a~=R3 then + TS(t,g..S.char(a,1)..d) + x=RP(j,R4) + end + RN[t..g]=x + end j() +end diff --git a/oc/postprocess.lua b/oc/postprocess.lua new file mode 100644 index 0000000..7e0060b --- /dev/null +++ b/oc/postprocess.lua @@ -0,0 +1,37 @@ +-- Postprocessor +local lastchar = " " +local text = io.read("*a") + +text = "\n" .. text + +-- the most important step: everything assumes \n +text = text:gsub("\r", "") + +-- tabs are always useless. +-- get rid of them *before* removing comments so indented comments also get scrubbed. +text = text:gsub("\t", "") + +text = text:gsub("\n%-%-[^\n]+", "") + +-- This is run after comment removal so that comments can be re-added. +text = text:gsub("\n%%[^\n]+", function(s) + return "\n" .. s:sub(3) +end) +local otext = text +local function pass() + text = text:gsub(".\n+.", function(i) + local l = i:sub(1, 1) .. i:sub(#i) + if not l:match("[^%(%)%{%}].") then + return l + end + return i:sub(1, 1) .. "\n" .. i:sub(#i) + end) +end +pass() +while otext ~= text do + otext = text + pass() +end +-- Final processing +text = text:gsub("^\n+", ""):gsub("\n+$", "") +io.write(text) diff --git a/oc/uc-rsctl.lua b/oc/uc-rsctl.lua new file mode 100644 index 0000000..e585290 --- /dev/null +++ b/oc/uc-rsctl.lua @@ -0,0 +1,76 @@ +TH,S,C,TC="hostname",string,component,"copper" +TX=C.proxy(C.list("modem")())TX.open(4957)TB=TX.broadcast +function TN(m)if#m<2then return end +local n=m:byte(1)+2return m:sub(2,n),m:sub(n+1)end +function TR(m)local h,s,m,d=m:byte(),TN(m:sub(2))if s then +d,m=TN(m)if d then +return s,d,m +end +end +end +function TS(d,m)TB(4957,TC,S.char(0,#TH-1)..TH..S.char(#d-1)..d..m)end +R1,R2,R3,R4=0x40,60,12,2.5 +RT,RA,RN,RU={},{},{},computer.uptime +function RP(f,x)if#RT=7then +local p,b,g,k=d:byte(2)+(d:byte(1)*256),d:byte(7),d:sub(1,5)if b==0x01or b==0x00then +k=t..g +if not RA[k] then +r(f,t,p,d:sub(8))else +RK(RA[k])end +RA[k]=RP(function()RA[k]=nil end,R2)if not(b~=0x01or t~=TH)then +TS(f,d:sub(1,6).."\x02")end +end +k=f..g +if b==0x02 and RN[k]then +RK(RN[k])RN[k]=nil +end +end +end +function RF()local i,t=1,RU()while#RT>i do +if t>RT[i][2]then +table.remove(RT,i)[1]()else +i=i+1 +end +end +end +function RG()return math.random(256)-1 +end +function RS(t,p,d)local g,a,j,x=S.char(math.floor(p/256),p%256,RG(),RG(),RG()),-1 +j=function()a=a+1 +x=nil +if a~=R3 then +TS(t,g..S.char(a,1)..d)x=RP(j,R4)end +RN[t..g]=x +end j()end +-- EXAMPLE IoT Redstone Top Controller -- +UR=C.proxy(C.list("redstone")())function UT(p)US=p +if#p>0then +UR.setOutput(1,15)else +UR.setOutput(1,0)end +end +UT("")function UG(t)RS(t,4,"\xC0\x42active.\x81setName")end +N={[0]=UG, +[1]=function(f)RS(f,4,"\xC1"..US)end, +[0x41]=function(_,p)UT(p)end, +[0x82]=function(_,p)if#p>0then TH=p end end, +} +function UI(f,t,p,d)local m=t==TH +if p==1 and(t=="*"or m)then +UG(f)end +if p==4 and m then +if N[d:byte(1)]then +N[d:byte(1)](f,d:sub(2))end +end +end +while true do local x={computer.pullSignal(1)}RF()if"modem_message"==x[1]and 4957==x[4]and TC==x[6]then +RC(UI,TR(x[7]))end +end \ No newline at end of file