From 4400f66ce40f7bcdf9dcdad02bb18681f18573ad Mon Sep 17 00:00:00 2001 From: Olav Bakke Svendsen Date: Thu, 30 May 2024 15:00:50 +0200 Subject: [PATCH] Rotation Speed Controller Remote --- rscr/README | 38 +++++++++ rscr/config.lua | 13 +++ rscr/controller.lua | 137 +++++++++++++++++++++++++++++++ rscr/package | 3 + rscr/remote.lua | 195 ++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 386 insertions(+) create mode 100644 rscr/README create mode 100644 rscr/config.lua create mode 100644 rscr/controller.lua create mode 100644 rscr/package create mode 100644 rscr/remote.lua diff --git a/rscr/README b/rscr/README new file mode 100644 index 0000000..c24a7ac --- /dev/null +++ b/rscr/README @@ -0,0 +1,38 @@ +print[[ +rscr - Rotational Speed Controller Remote + +programs: + - rscr-controller + - rscr-remote + +Listen for modem messages, chat messages and mouse clicks to update speed controller +there is the computer that listens and updates the speeds, +and theres any number of computers sending modem messages. + +when controlled by redstone signal: + map 1-15 (restone signal) to allowed range of controller + - sends a modem message to controller with redstone input + - controller updates and broadcasts new value + +controller spec: +configurations: + - allowed range + - modem port +envents being handled: + - modem messages from remotes + - chat box + +remote spec: +configurations: + - input side (??) + - modem port +events being handled: + - redstone changes (on input side) (??) + - modem messages from controller receive port + +plan + (scrap the redstone stuff) + setup a dummy controller running dmesg + create remote + +]] diff --git a/rscr/config.lua b/rscr/config.lua new file mode 100644 index 0000000..30e0746 --- /dev/null +++ b/rscr/config.lua @@ -0,0 +1,13 @@ +-- configuration file for rscr-remote and rscr-controller + +return + { controller_name = "speedcontroller" + , modem = nil + , monitor = nil + , speed_controller = nil + , stressometer = nil + , controller_port = 15 + , remote_port = 16 + , min_speed = 0 + , max_speed = 256 + } diff --git a/rscr/controller.lua b/rscr/controller.lua new file mode 100644 index 0000000..ec1831a --- /dev/null +++ b/rscr/controller.lua @@ -0,0 +1,137 @@ +local config = dofile("/etc/rscr.lua") + +local modem +do + local m + if config.modem ~= nil then + m = peripheral.wrap(config.modem) + else + m = peripheral.find("modem") + end + if m then + modem = peripheral.getName(m) + peripheral.call(modem, "open", config.controller_port) + else + print("No modem connected") + return false + end +end + +local speed_controller +do + local sc + if config.speed_controller ~= nil then + sc = peripheral.wrap(config.speed_controller) + else + sc = peripheral.find("Create_RotationSpeedController") + end + if sc then + speed_controller = peripheral.getName(sc) + else + print("No rotation speed controller connected") + return false + end +end + +local stressometer +do + local sm + if config.stressometer ~= nil then + sm = peripheral.wrap(config.stressometer) + else + sm = peripheral.find("Create_Stressometer") + end + if sm then + stressometer = peripheral.getName(sm) + else + print("No stressometer connected, limited functionality") + end +end + +local transmit = function(payload) + peripheral.call(modem, "transmit", config.remote_port, config.controller_port, textutils.serialize(payload, { compact = true })) +end + +local st = + { name = config.controller_name + , speed = + { absolute = 0 + , percentage = 0 + } + , stress = + { absolute = 0 + , capacity = 0 + , percentage = 0 + } + } + +do if not stressometer then st.stress = nil end end + +-- if called without argument: (getter) +-- watch for changes. returns true if changed, false otherwise. +-- if called with table: (setter) +-- make changes accordingly. return true +local update = function(set_speed) + local new_st = textutils.unserialize(textutils.serialize(st)) + local updated = false + local x = config.max_speed - config.min_speed + + if set_speed and set_speed >= 0 and set_speed <= 100 then + new_st.speed.absolute = math.floor(((set_speed / 100) * x) + config.min_speed + 0.5) + peripheral.call(speed_controller, "setTargetSpeed", new_st.speed.absolute) + updated = true + else + new_st.speed.absolute = peripheral.call(speed_controller, "getTargetSpeed") + if new_st.speed.absolute ~= st.speed.absolute then updated = true end + end + new_st.speed.percentage = math.floor(((new_st.speed.absolute - config.min_speed) / x * 10000) + 0.5) / 100 + + if stressometer then + sleep(0) -- if speed was just set, this is needed + new_st.stress.absolute = stressometer and peripheral.call(stressometer, "getStress") + new_st.stress.capacity = stressometer and peripheral.call(stressometer, "getStressCapacity") + if new_st.stress.capacity == 0 then + new_st.stress.percentage = 0 + else + new_st.stress.percentage = math.floor(((new_st.stress.absolute / new_st.stress.capacity) * 10000) + 0.5) / 100 + end + if new_st.stress.absolute ~= st.stress.absolute or + new_st.stress.capacity ~= st.stress.capacity then + updated = true + end + end + + if updated then st = new_st end + return updated +end + +local receive +receive = function() + local _, p, c_port, r_port, msg, _ = os.pullEvent("modem_message") + if p == modem and + c_port == config.controller_port and + r_port == config.remote_port then + local t = textutils.unserialize(msg) + if t.connect then + transmit(st) + elseif t.set_speed then + update(t.set_speed) + transmit(st) + end + end + return receive() +end + +local update_remotes +update_remotes = function() + if update() then + transmit(st) + print(os.clock(), "updating...") + else + print(os.clock(), "nothing to update") + end + os.sleep(2) + return update_remotes() +end + +parallel.waitForAny(receive, update_remotes) diff --git a/rscr/package b/rscr/package new file mode 100644 index 0000000..5688982 --- /dev/null +++ b/rscr/package @@ -0,0 +1,3 @@ +cc rscr/controller.lua:/bin/rscr-controller.lua:o +cc rscr/remote.lua:/bin/rscr-remote.lua:o +cc rscr/config.lua:/etc/rscr.lua diff --git a/rscr/remote.lua b/rscr/remote.lua new file mode 100644 index 0000000..20238e3 --- /dev/null +++ b/rscr/remote.lua @@ -0,0 +1,195 @@ +-- gui for a 15*10 advanced monitor (single monitor with text scale 0.5) +-- sends modem messages to controller on touch event +-- listens for modem messages from controller + +local config = dofile("/etc/rscr.lua") + +local modem +do + local m + if config.modem ~= nil then + m = peripheral.wrap(config.modem) + else + m = peripheral.find("modem") + end + if m then + modem = peripheral.getName(m) + peripheral.call(modem, "open", config.remote_port) + else + print("No modem connected") + return false + end +end + +local monitor +do + local m + if config.monitor ~= nil then + m = peripheral.wrap(config.monitor) + else + m = peripheral.find("monitor") + end + if m then + monitor = peripheral.getName(m) + peripheral.call(monitor, "setTextScale", 0.5) + else + print("No advanced monitor connected") + return false + end +end + + +local st = + { name = "connecting..." + , speed = + { absolute = 0 + , percentage = 0 + } + , stress = nil +-- { absolute = 0 +-- , max = 0 +-- , percentage = +-- } + } + +local bar = function(len, percentage, solid) + if len < 1 then error("Status bar needs a positive (integral) length") end + local bars = math.floor(((len-1)*percentage/100) + 0.5) + 1 + local str = "" + for i = 1, len do + if i <= bars then + str = str .. "|" + else + str = str .. " " + end + end + + local c + if solid then + c = function(i) return solid end + elseif percentage == 0 then + c = function(i) return "7" end + else + c = function(i) + local p = (i-1)/(len-1) + if p < 0.6 then return "d" -- green + elseif p < 0.8 then return "1" -- orange + else return "e" -- red + end + end + end + + local fg, bg = "", "" + for i = 1, len do + bg = bg .. "f" + fg = fg .. c(i) + end + return str, fg, bg +end + +-- local print_bar = function(t, unit, width, y) +-- local m = peripheral.wrap(monitor) +-- m.setCursorPos(1, y) +-- m.write(tostring(t.absolute).." "..unit) +-- local percentage = tostring(t.percentage).."%" +-- m.setCursorPos(width - string.len(percentage) + 1, y) +-- m.write(percentage) +-- m.setCursorPos(1, y + 1) +-- m.blit(bar(width, t.percentage)) +-- end + +local draw = function() + local m = peripheral.wrap(monitor) + local width, _ = m.getSize() + local overstressed = st.stress and st.stress.absolute > st.stress.capacity + + m.clear() + m.setCursorPos(1,1) + m.setTextColor(colors.white) + if overstressed then + m.setBackgroundColor(colors.red) + else + m.setBackgroundColor(colors.gray) + end + local pad + pad = function(i) + if i > 0 then return " "..pad(i-1) + else return "" end + end + m.write(st.name..pad(width)) + m.setBackgroundColor(colors.black) + m.setCursorPos(1,2) + m.setBackgroundColor(colors.black) + + m.setCursorPos(1,3) + m.write(tostring(st.speed.absolute).." RPM") + local speed_percentage = tostring(st.speed.percentage).."%" + m.setCursorPos(width - string.len(speed_percentage) + 1, 3) + m.write(speed_percentage) + m.setCursorPos(1, 4) + m.blit(bar(width, st.speed.percentage)) + + m.setCursorPos(1,6) + if st.stress then + m.write("~"..tostring(math.floor((st.stress.absolute/1000)+0.5)).." KSU") + local stress_percentage = tostring(st.stress.percentage).."%" + m.setCursorPos(width - string.len(stress_percentage) + 1, 6) + m.write(stress_percentage) + m.setCursorPos(1,7) + m.blit(bar(width, st.stress.percentage, overstressed and "e")) + m.setCursorPos(1,8) + m.write("total: ~"..tostring(math.floor((st.stress.capacity/1000)+0.5)).." KSU") + m.setCursorPos(1,9) + m.write("avail: ~"..tostring(math.floor(((st.stress.capacity - st.stress.absolute)/1000)+0.5)).." KSU") + else + m.setTextColor(colors.gray) + m.write("No stress") + m.setCursorPos(1,7) + m.write("information") + m.setCursorPos(1,8) + m.write("available") + m.setTextColor(colors.white) + end +end + +local transmit = function(payload) + peripheral.call(modem, "transmit", config.controller_port, config.remote_port, textutils.serialize(payload, { compact = true })) +end + +local touch_screen +touch_screen = function() + local _, p, x, y = os.pullEvent("monitor_touch") + if p ~= monitor then return touch_screen() end + local m = peripheral.wrap(monitor) + local width, _ = m.getSize() + if x >= 1 and x <= width then + draw() + -- todo: don't hard code the y position + m.setCursorPos(x, 4) + m.blit("|", "0", "f") + transmit({ set_speed = math.floor((x-1)/(width-1)*10000)/100 }) + end + return touch_screen() +end + +local receive +receive = function() + local _, p, r_port, c_port, msg, _ = os.pullEvent("modem_message") + if p == modem and + r_port == config.remote_port and + c_port == config.controller_port then + local new_st = textutils.unserialize(msg) + st = new_st + draw() + end + return receive() +end + +local on_terminate = function() + os.pullEventRaw("terminate") + peripheral.call(monitor, "clear") +end + +draw() +transmit({ connect = true }) +parallel.waitForAny(on_terminate, touch_screen, receive) -- 2.30.2