Rotation Speed Controller Remote
authorOlav Bakke Svendsen <mail@olavbs.no>
Thu, 30 May 2024 13:00:50 +0000 (15:00 +0200)
committerOlav Bakke Svendsen <mail@olavbs.no>
Thu, 30 May 2024 13:00:50 +0000 (15:00 +0200)
rscr/README [new file with mode: 0644]
rscr/config.lua [new file with mode: 0644]
rscr/controller.lua [new file with mode: 0644]
rscr/package [new file with mode: 0644]
rscr/remote.lua [new file with mode: 0644]

diff --git a/rscr/README b/rscr/README
new file mode 100644 (file)
index 0000000..c24a7ac
--- /dev/null
@@ -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 (file)
index 0000000..30e0746
--- /dev/null
@@ -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 (file)
index 0000000..ec1831a
--- /dev/null
@@ -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 (file)
index 0000000..5688982
--- /dev/null
@@ -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 (file)
index 0000000..20238e3
--- /dev/null
@@ -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)