Advertisement
Tindrith

Clone of kla_sch's Program

Jan 28th, 2015
186
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. --
  2. -- Master control and monitor turbines of a active cooled
  3. -- Big Reactor (http://big-reactors.com/).
  4. --
  5. -- Author: kla_sch
  6. --
  7. -- History:
  8. --     v0.1, 2014-12-29:
  9. --         - first version
  10. --
  11. --     v0.2, 2015-01-02
  12. --         - smaller monitors (25 characters) and portable computers supported.
  13. --         - change table layout to fit 50 characters per line.
  14. --         - minor bugfixes
  15. --         - code improvments (thanks to wieselkatze)
  16. --
  17. --     v0.3, 2015-01-05
  18. --         - now support OpenPeripheral Terminal Glasses
  19. --         - minor bugfixes
  20. --
  21. -- Save as "startup"
  22.  
  23. --
  24. -- Constant values (configuration)
  25. --
  26.  
  27. -- Loop time
  28. local loopT=1
  29.  
  30. -- Modem channel to send status requests to any turbine.
  31. local stateRequestChannel = 32768 -- Broadcast channel.
  32.  
  33.  
  34. -- Position of display on terminal glasses.
  35. -- The position 0,0 (posX, posY) is the upper left corner of the display.
  36. -- There are also some other basic style values.
  37. local tGlassStyle = {
  38.    posX = 5,         -- Horizontal position from the left side
  39.    posY = 5,         -- Vertical position from top
  40.    lineHeight = 8,   -- Height of line
  41.    rulerHeight = 2,  -- Height of ruler
  42.    borderWidth = 2,  -- Width of box border
  43.    padding = 2,      -- Padding between box and text
  44.    spacing = 2       -- Spacing between lines
  45. }
  46.  
  47.  
  48.  
  49. --
  50. -- Internal values:
  51. --
  52.  
  53. local turbineTable = {} -- state of turbines
  54. local labelArr = {} -- sorted array of turbine computer labels
  55.  
  56. local glassesStates = nil -- table to hold state of the terminal glasses
  57.  
  58. -- Cycle flag for small monitors (width of 25 chars)
  59. local cycleDisplayStates = {}
  60.  
  61. --
  62. -- Send modem request to any attached modem
  63. --
  64. local function sendBroadcastRequest()
  65.    local pList = peripheral.getNames()
  66.    local i, name
  67.    for i, name in pairs(pList) do
  68.       if peripheral.getType(name) == "modem" then
  69.          peripheral.call(name, "open", os.getComputerID())
  70.          peripheral.call(name, "transmit",
  71.                          stateRequestChannel, os.getComputerID(),
  72.                          "BR_turbine_get_state")
  73.       end
  74.    end
  75. end
  76.  
  77.  
  78. --
  79. -- Send turbine speed change request to any attached modem
  80. --
  81. -- Parameters:
  82. --     computerId - Id of turbine controller
  83. --     speed      - new speed
  84. --
  85. local function sendSpeedChange(computerId, speed)
  86.    local pList = peripheral.getNames()
  87.    local i, name
  88.    for i, name in pairs(pList) do
  89.       if peripheral.getType(name) == "modem" then
  90.          peripheral.call(name, "open", os.getComputerID())
  91.          peripheral.call(name, "transmit",
  92.                          computerId, os.getComputerID(),
  93.                          "BR_turbine_set_speed:" .. speed)
  94.       end
  95.    end
  96. end
  97.  
  98.  
  99. --
  100. -- Format integer value, align right. (repace buggy string.format)
  101. --
  102. -- Parameters:
  103. --     number - The output value
  104. --     width  - Output width
  105. --
  106. -- Return:
  107. --     Formated string
  108. --
  109. local function format_int(number, width)
  110.    local result = tostring(math.floor(number + 0.5))
  111.    if string.len(result) < width then
  112.       result = string.rep(" ", width - string.len(result)) .. result
  113.    end
  114.  
  115.    return result
  116. end
  117.  
  118.  
  119. --
  120. -- Format string value, align left, cut off. (repace buggy string.format)
  121. --
  122. -- Parameters:
  123. --     str   - the output value
  124. --     width - output width
  125. --
  126. -- Return:
  127. --     formated string
  128. --
  129. local function format_str(str, width)
  130.    if string.len(str) < width then -- fill
  131.       result = str .. string.rep(" ", width - string.len(str))
  132.    elseif string.len(str) > width then -- cut
  133.       result = string.sub(str, 1, width)
  134.    else
  135.       result = str
  136.    end
  137.  
  138.    return result
  139. end
  140.  
  141.  
  142. --
  143. -- Glasses: Format string value, align left, cutt off.
  144. --
  145. -- This function does not work well, if you use a buggy version of
  146. -- Open Peripherals. Older versions returns the wrong width of the string.
  147. --
  148. -- Parameters:
  149. --     glasses - Wraped glasses bridge
  150. --     str   - the output value
  151. --     width - maximum output width (pixed)
  152. --
  153. -- Returns: A string that fits
  154. --
  155. local function format_gl_str(glasses, str, width)
  156.    local strLen = glasses.getStringWidth(str)
  157.    if strLen <= width then
  158.       return str -- It fits
  159.    end
  160.  
  161.    -- Too long: Test differnet lengths
  162.    local minLen = 1
  163.    local maxLen = string.len(str)
  164.    while maxLen - minLen > 1 do
  165.       local testLen = minLen + math.floor( (maxLen - minLen) / 2)
  166.  
  167.       if glasses.getStringWidth(string.sub(str, 1, testLen)) > width then
  168.          maxLen = testLen
  169.       else
  170.          minLen = testLen
  171.       end
  172.    end
  173.  
  174.    return string.sub(str, 1, minLen)
  175. end
  176.  
  177. --
  178. -- Format float value, align right. (repace buggy string.format)
  179. --
  180. -- Parameters:
  181. --     number    - the output value
  182. --     width     - output width
  183. --     precision - precision of number
  184. --
  185. -- Return:
  186. --     formated string
  187. --
  188. local function format_float(number, width, precision)
  189.    local pExp = 10 ^ precision
  190.    local result = tostring(math.floor(number * pExp + 0.5) / pExp)
  191.  
  192.    local s,e = string.find(result, ".", 1, true)
  193.    if s == nil then
  194.       result = result .. "." .. string.rep("0", precision)
  195.    else
  196.       local pLen = string.len(result) - s
  197.       if pLen < precision then -- fill with '0'
  198.          result = result .. string.rep("0", precision - pLen)
  199.       end
  200.    end
  201.  
  202.    if string.len(result) < width then -- fill with ' '
  203.       result = string.rep(" ", width - string.len(result)) .. result
  204.    end
  205.  
  206.    return result
  207. end
  208.  
  209.  
  210.  
  211. --
  212. -- Write text with colors, if possible (advance monitor)
  213. --
  214. -- Parameters:
  215. --     mon   - handle of monitor
  216. --     color - text color
  217. --     text  - text to write
  218. --
  219. local function writeColor(mon, color, text)
  220.    if mon.isColor() then
  221.       mon.setTextColor(color)
  222.    end
  223.    mon.write(text)
  224.    if mon.isColor() then
  225.       mon.setTextColor(colors.white)
  226.    end
  227. end
  228.  
  229.  
  230. --
  231. -- Scale the monitor text size to needed size of output text.
  232. --
  233. -- This function try to scale the monitor text size, so that it is enoth for
  234. -- "optHeight" lines with "optWidth" characters. If it is not possible
  235. -- (text scale is not supported or the connected monitor is too small),
  236. -- it also accept "minHeight" lines and "minWidth" characters.
  237. --
  238. -- Parameters:
  239. --     mon        - handle of monitor.
  240. --     minWidth   - Minimum number of columns needed.
  241. --     optWidth   - Optimal number of columns desired.
  242. --     minHeight  - Minimum number of rows needed.
  243. --     optHeight  - Optimal number of rows desired.
  244. --
  245. -- Return:
  246. --     Size of monitor after scaling: width, height.
  247. --     If the monitor is too small, it returns nul,nil.
  248. --
  249. local function scaleMonitor(mon, minWidth, optWidth, minHeight, optHeight)
  250.    if mon.setTextScale ~= nil then
  251.        mon.setTextScale(1)
  252.    end
  253.  
  254.    local width, height = mon.getSize()
  255.  
  256.    if mon.setTextScale == nil then
  257.       -- Scale not available
  258.       if width < minWidth or height < minHeight then
  259.          return nil, nil -- too small
  260.       else
  261.          return width, height
  262.       end
  263.    end
  264.  
  265.    if width < optWidth or height < optHeight then
  266.       -- too small: try to scale down.
  267.       mon.setTextScale(0.5)
  268.  
  269.       width, height = mon.getSize()
  270.       if width < minWidth or height < minHeight then
  271.          return nil, nil -- still too small
  272.       end
  273.    else
  274.       -- Huge monitors? Try to scale up, if possible (max scale=5).
  275.       local scale = math.min(width / optWidth, height / optHeight, 5)
  276.       scale = math.floor(scale * 2) / 2 -- multiple of 0.5
  277.  
  278.       if scale > 1 then
  279.          mon.setTextScale(scale)
  280.          width, height = mon.getSize()
  281.       end
  282.    end
  283.  
  284.    return width, height
  285. end
  286.  
  287.  
  288. --
  289. -- Display turbine data to monitor
  290. --
  291. -- Parameters:
  292. --     mon - Name of monitor. "#term" for computer terminal.
  293. --
  294. local function displayTableOnMonitor(monName)
  295.    local mon
  296.  
  297.    if monName == "#term" then
  298.       mon = term
  299.    else
  300.       mon = peripheral.wrap(monName)
  301.    end
  302.  
  303.    mon.clear()
  304.  
  305.    local width, height = scaleMonitor(mon, 25, 50, 5, 5)
  306.  
  307.    if width == nil or height == nil then
  308.       return -- Montitor is too small
  309.    end
  310.  
  311.    local cycleState = nil
  312.  
  313.    if width < 50 then
  314.       -- small monitor
  315.       height = height - 1 -- one line for information
  316.  
  317.       cycleState = cycleDisplayStates[monName]
  318.  
  319.       if cycleState == nil then
  320.          -- initialize cycle state
  321.          cycleDisplayStates[monName] = "RPM"
  322.       end
  323.  
  324.       if cycleState == "RPM" then
  325.          mon.setCursorPos(1,1)
  326.          mon.write("Label          TRPM ARPM")
  327.          mon.setCursorPos(1,2)
  328.          mon.write("============== ==== ====")
  329.       elseif cycleState == "Flow" then
  330.          mon.setCursorPos(1,1)
  331.          mon.write("Label          MFlow AFlow")
  332.          mon.setCursorPos(1,2)
  333.          mon.write("============== ===== =====")
  334.       elseif cycleState == "EnergyRate" then
  335.          mon.setCursorPos(1,1)
  336.          mon.write("Label          kRF/t")
  337.          mon.setCursorPos(1,2)
  338.          mon.write("============== =====")
  339.       elseif cycleState == "EnergyStored" then
  340.          mon.setCursorPos(1,1)
  341.          mon.write("Label          Energy")
  342.          mon.setCursorPos(1,2)
  343.          mon.write("============== =======")
  344.       end
  345.  
  346.       mon.setCursorPos(1, height + 1)
  347.       if pocket then
  348.          mon.write("* Press space to cycle")
  349.       else
  350.          mon.write("* Click here to cycle")
  351.       end
  352.    else
  353.       cycleDisplayStates[monName] = nil -- full sized monitor
  354.  
  355.       mon.setCursorPos(1,1)
  356.       mon.write("Label          TRPM ARPM MFlow AFlow kRF/t Energy ")
  357.       mon.setCursorPos(1,2)
  358.       mon.write("============== ==== ==== ===== ===== ===== =======")
  359.    end
  360.  
  361.    local i, label, tState
  362.  
  363.    labelArr = {}
  364.    for label, tState in pairs(turbineTable) do
  365.       table.insert(labelArr, label)
  366.    end
  367.  
  368.    table.sort(labelArr)
  369.  
  370.    local line = 3
  371.    for i, label in pairs(labelArr) do
  372.       tState = turbineTable[label]
  373.  
  374.       if line <= height then
  375.          mon.setCursorPos(1, line)
  376.  
  377.          -- prefix
  378.          if tState.active then
  379.             label = "+" .. label
  380.             writeColor(mon, colors.green, format_str(label, 14))
  381.          else
  382.             label = "-" .. label
  383.             writeColor(mon, colors.red, format_str(label, 14))
  384.          end
  385.  
  386.  
  387.          if cycleState == nil or cycleState == "RPM" then
  388.             -- target speed
  389.             if tState.tSpeed == 0 then
  390.                writeColor(mon, colors.red, "  OFF")
  391.             else
  392.                mon.write(" "..format_int(tState.tSpeed, 4))
  393.             end
  394.            
  395.             -- actual speed
  396.             if math.floor(tState.rotorSpeed*10 + 0.5)/10 == tState.tSpeed then
  397.                writeColor(mon, colors.green,
  398.                           " " ..format_int(tState.rotorSpeed, 4))
  399.             elseif tState.rotorSpeed > 2000 then
  400.                writeColor(mon, colors.red,
  401.                           " " ..format_int(tState.rotorSpeed, 4))
  402.             else
  403.                writeColor(mon, colors.orange,
  404.                           " " ..format_int(tState.rotorSpeed, 4))
  405.             end
  406.          end
  407.  
  408.          if cycleState == nil or cycleState == "Flow" then
  409.             -- steam flow
  410.             mon.write(" "..format_int(tState.fluidFlowRateMax, 5))
  411.  
  412.             if tState.fluidFlowRate == tState.fluidFlowRateMax then
  413.                writeColor(mon, colors.green,
  414.                           " "..format_int(tState.fluidFlowRate, 5))
  415.             else
  416.                writeColor(mon, colors.orange,
  417.                           " "..format_int(tState.fluidFlowRate, 5))
  418.             end
  419.  
  420.          end
  421.  
  422.          if cycleState == nil or cycleState == "EnergyRate" then
  423.             -- energy rate
  424.             mon.write(" "..format_float(tState.energyProducedLastTick / 1000,
  425.                                         5, 2))
  426.          end
  427.  
  428.          if cycleState == nil or cycleState == "EnergyStored" then
  429.             -- energy stored
  430.             mon.write(" "..format_int(tState.energyStored, 7))
  431.          end
  432.  
  433.          line = line + 1
  434.       end
  435.    end
  436. end
  437.  
  438.  
  439. --
  440. -- Displays a bordered box
  441. --
  442. -- Parameters:
  443. --     glasses - wraped glasses bridge
  444. --     width   -- outer width of the box
  445. --     height  -- inner width of the box
  446. --
  447. local function displayBoxToGlasses(glasses, width, height)
  448.    glasses.addBox(tGlassStyle.posX, tGlassStyle.posY,
  449.                   width, height, 0xFFFF00, 0.5)
  450.    width = width - 2 * tGlassStyle.borderWidth
  451.    height = height - 2 * tGlassStyle.borderWidth
  452.    glasses.addBox(tGlassStyle.posX + tGlassStyle.borderWidth,
  453.                   tGlassStyle.posY + tGlassStyle.borderWidth,
  454.                   width, height, 0x0000FF, 0.5)
  455. end
  456.  
  457.  
  458. --
  459. -- Display a help box on terminal glasses
  460. --
  461. -- Parameters:
  462. --     glasses - wraped glasses bridge
  463. --
  464. local function displayHelpToGlasses(glasses)
  465.    glasses.clear()
  466.  
  467.    local boxHeight =
  468.       2 * tGlassStyle.borderWidth                          -- two borders
  469.       + 2 * tGlassStyle.padding                            -- two paddings
  470.       + 4 * tGlassStyle.lineHeight                         -- toppic
  471.       + 9 * (tGlassStyle.lineHeight + tGlassStyle.padding) -- 8 lines
  472.  
  473.    displayBoxToGlasses(glasses, 300, boxHeight)
  474.  
  475.    local textX =
  476.       tGlassStyle.posX + tGlassStyle.borderWidth + tGlassStyle.padding
  477.    local textY =
  478.       tGlassStyle.posY + tGlassStyle.borderWidth + tGlassStyle.padding
  479.  
  480.    local tabStopWidth = 120
  481.  
  482.    local header =
  483.       glasses.addText(textX, textY, "Terminal Glasses Commands")
  484.    header.setScale(2)
  485.  
  486.    textY = textY + 4 * tGlassStyle.lineHeight
  487.  
  488.    glasses.addText(textX, textY, "$$help")
  489.    glasses.addText(textX + tabStopWidth, textY,
  490.                    "open this help screen")
  491.  
  492.    textY = textY + tGlassStyle.lineHeight + tGlassStyle.spacing
  493.  
  494.    glasses.addText(textX, textY, "$$hide")
  495.    glasses.addText(textX + tabStopWidth, textY,
  496.                    "hide all screens")
  497.    
  498.    textY = textY + tGlassStyle.lineHeight + tGlassStyle.spacing
  499.  
  500.    glasses.addText(textX, textY, "$$show")
  501.    glasses.addText(textX + tabStopWidth, textY,
  502.                    "show table with turbines")
  503.  
  504.    textY = textY + tGlassStyle.lineHeight + tGlassStyle.spacing
  505.  
  506.    glasses.addText(textX, textY, "$$show <name>")
  507.    glasses.addText(textX + tabStopWidth, textY,
  508.                    "show turbine data of <name>")
  509.  
  510.    textY = textY + tGlassStyle.lineHeight + tGlassStyle.spacing
  511.  
  512.    glasses.addText(textX, textY, "$$speed off <name>")
  513.    glasses.addText(textX + tabStopWidth, textY,
  514.                    "set turbine <name> to off")
  515.  
  516.    textY = textY + tGlassStyle.lineHeight + tGlassStyle.spacing
  517.  
  518.    glasses.addText(textX, textY, "$$speed 900 <name>")
  519.    glasses.addText(textX + tabStopWidth, textY,
  520.                    "set turbine <name> to 900 RPM")
  521.  
  522.    textY = textY + tGlassStyle.lineHeight + tGlassStyle.spacing
  523.  
  524.    glasses.addText(textX, textY, "$$speed 1800 <name>")
  525.    glasses.addText(textX + tabStopWidth, textY,
  526.                    "set turbine <name> to 1800 RPM")  
  527.  
  528.    textY = textY + 2 * (tGlassStyle.lineHeight + tGlassStyle.spacing)
  529.  
  530.    glasses.addText(textX, textY, "Exit this help with $$show or $$hide")
  531. end
  532.  
  533.  
  534.  
  535. --
  536. -- Display error message on terminal glasses
  537. --
  538. -- Parameters:
  539. --     glasses - wraped glasses bridge
  540. --     msgId   - identifier of error
  541. --
  542. local function displayErrorMsgToGlasses(glasses, msgId)
  543.    glasses.clear()
  544.  
  545.    local boxHeight =
  546.       2 * tGlassStyle.borderWidth                          -- two borders
  547.       + 2 * tGlassStyle.padding                            -- two paddings
  548.       + 4 * tGlassStyle.lineHeight                         -- toppic
  549.       + 3 * (tGlassStyle.lineHeight + tGlassStyle.padding) -- 3 lines
  550.  
  551.    displayBoxToGlasses(glasses, 280, boxHeight)
  552.  
  553.    local textX =
  554.       tGlassStyle.posX + tGlassStyle.borderWidth + tGlassStyle.padding
  555.    local textY =
  556.       tGlassStyle.posY + tGlassStyle.borderWidth + tGlassStyle.padding
  557.  
  558.    local header =
  559.       glasses.addText(textX, textY, "Command Error")
  560.    header.setScale(2)
  561.  
  562.    textY = textY + 4 * tGlassStyle.lineHeight
  563.  
  564.    local msgText
  565.    if msgId == "turbine_not_found" then
  566.       msgText = "The turbine you entered was not found in table"
  567.    elseif msgId == "remote_control_disabled" then
  568.       msgText = "Remote control feature disabled at turbine"
  569.    elseif msgId == "speed_missing" then
  570.       msgText = "New target speed is missing"
  571.    elseif msgId == "invalid_turbine_speed" then
  572.       msgText = "Invalid turbine speed value"
  573.    end
  574.    glasses.addText(textX, textY, msgText, 0xF2B233)
  575.  
  576.    textY = textY + 2 * tGlassStyle.lineHeight
  577.    
  578.    glasses.addText(textX, textY, "Type in $$help for help or try again")
  579. end
  580.  
  581. --
  582. -- Display single information line to terminal glasses
  583. --
  584. -- Parameters:
  585. --     glasses - wraped handler of terminal glasses bridge
  586. --     x       - X-Position of label
  587. --     y       - Y-Position of line
  588. --     lable   - Label of information line
  589. --     value   - value of information line
  590. --     color   - color for value
  591. --     update  - flag: only update information
  592. --
  593. local function displayInfoLineOnGlasses(glasses, x, y, label, value,
  594.                                         color, update)
  595.    local tabStopWidth = 100
  596.    if update then
  597.       glassesStates.infoTxt[label].setText(value)
  598.    else
  599.       glasses.addText(x, y, label)
  600.       glassesStates.infoTxt[label] =
  601.          glasses.addText(x + tabStopWidth, y, value)
  602.    end
  603.  
  604.    glassesStates.infoTxt[label].setColor(color)
  605. end
  606.  
  607.  
  608. --
  609. -- Display any known informations of a single turbine to terminal glasses
  610. --
  611. -- Parameters:
  612. --     glasses - wraped handler of terminal glasses bridge
  613. --
  614. local function displayInfoOnGlasses(glasses)
  615.    if glassesStates.infoTurbine == nil then
  616.       glassesStates.show = "table"
  617.       return -- no turbine name? ups!
  618.    end
  619.  
  620.    local tState = turbineTable[glassesStates.infoTurbine]
  621.  
  622.    local noInfo = "<no information>"
  623.    local textX =
  624.       tGlassStyle.posX + tGlassStyle.borderWidth + tGlassStyle.padding
  625.    local textY =
  626.       tGlassStyle.posY + tGlassStyle.borderWidth + tGlassStyle.padding
  627.  
  628.    local updateOnly = true
  629.    if glassesStates.infoTxt == nil then
  630.       -- need a new box
  631.       updateOnly = false
  632.       glassesStates.infoTxt = {}
  633.  
  634.       glasses.clear()
  635.  
  636.       local boxHeight =
  637.          2 * tGlassStyle.borderWidth                           -- two borders
  638.          + 2 * tGlassStyle.padding                             -- two paddings
  639.          + 4 * tGlassStyle.lineHeight                          -- toppic
  640.          + 13 * (tGlassStyle.lineHeight + tGlassStyle.padding) -- 13 lines
  641.  
  642.       displayBoxToGlasses(glasses, 240, boxHeight)
  643.  
  644.       local header =
  645.          glasses.addText(textX, textY, "Turbine information")
  646.       header.setScale(2)
  647.  
  648.       textY = textY + 4 * tGlassStyle.lineHeight
  649.    end
  650.  
  651.    local outStr, color
  652.  
  653.    -- Label
  654.    outStr = glassesStates.infoTurbine
  655.    if tState ~= nil and tState.active then
  656.       color=0x00FF00 -- green
  657.    else
  658.       color=0xFF0000 -- red
  659.    end
  660.  
  661.    displayInfoLineOnGlasses(glasses, textX, textY,
  662.                             "Label", outStr, color, updateOnly)
  663.  
  664.    textY = textY + tGlassStyle.lineHeight + tGlassStyle.spacing
  665.    
  666.    -- Active state
  667.    if tState ~= nil and tState.active then
  668.       outStr = "Activated"
  669.       color = 0x00FF00
  670.    elseif tState == nil then
  671.       outStr = "Turbine not reachable"
  672.       color = 0xFF0000
  673.    else
  674.       outStr = "Deactivated"
  675.       color = 0xFF0000
  676.    end
  677.  
  678.    displayInfoLineOnGlasses(glasses, textX, textY,
  679.                             "State", outStr, color, updateOnly)
  680.    
  681.    textY = textY + tGlassStyle.lineHeight + tGlassStyle.spacing
  682.    
  683.    -- Remote Control
  684.    if tState then
  685.       if tState.remoteControl then
  686.          outStr = "Activated"
  687.          color = 0x00FF00 -- green
  688.       else
  689.          outStr = "Deactivated"
  690.          color = 0xFF0000 -- red
  691.       end
  692.    else
  693.       outStr = noInfo
  694.       color = 0xFF0000 -- red
  695.    end
  696.    
  697.    displayInfoLineOnGlasses(glasses, textX, textY,
  698.                             "Remote Control", outStr, color, updateOnly)
  699.    
  700.    textY = textY + tGlassStyle.lineHeight + tGlassStyle.spacing
  701.  
  702.    -- Target Speed
  703.    if tState then
  704.       outStr = tostring(math.floor(tState.tSpeed + 0.5)) .. " RPM"
  705.       color = 0xFFFFFF -- white
  706.    else
  707.       outStr = noInfo
  708.       color = 0xFF0000 -- red
  709.    end
  710.  
  711.    displayInfoLineOnGlasses(glasses, textX, textY,
  712.                             "Target Speed", outStr, color, updateOnly)
  713.    textY = textY + tGlassStyle.lineHeight + tGlassStyle.spacing
  714.    
  715.    -- Actual Speed
  716.    if tState then
  717.       local rotorSpeed = math.floor(tState.rotorSpeed*10+ 0.5) /10
  718.       outStr = tostring(rotorSpeed) .. " RPM"
  719.       if rotorSpeed == tState.tSpeed
  720.       then
  721.          color = 0x00FF00 -- green
  722.       elseif rotorSpeed >= 2000 then
  723.          color = 0xFF0000 -- red
  724.       else
  725.          color = 0xF2B233 -- orange
  726.       end
  727.    else
  728.       outStr = noInfo
  729.       color = 0xFF0000
  730.    end
  731.  
  732.    displayInfoLineOnGlasses(glasses, textX, textY,
  733.                             "Actual Speed", outStr, color, updateOnly)
  734.    textY = textY + tGlassStyle.lineHeight + tGlassStyle.spacing
  735.  
  736.    -- Maximum Flow Rate
  737.    if tState then
  738.       local flowRateMax =
  739.          math.floor(tState.fluidFlowRateMax * 10 + 0.5) / 10
  740.       local flowRateMaxMax =
  741.          math.floor(tState.fluidFlowRateMaxMax * 10 + 0.5) / 10
  742.  
  743.       outStr =
  744.          tostring(flowRateMax) .. " mB/t"
  745.          .." of " .. tostring(flowRateMaxMax) .. " mB/t"
  746.       color = 0xFFFFFF -- white
  747.    else
  748.       outStr = noInfo
  749.       color = 0xFF0000 -- red
  750.    end
  751.    displayInfoLineOnGlasses(glasses, textX, textY,
  752.                             "Max Flow Rate", outStr, color, updateOnly)
  753.    textY = textY + tGlassStyle.lineHeight + tGlassStyle.spacing
  754.  
  755.    -- Actual Flow Rate
  756.    if tState then
  757.       local fluidFlowRate = math.floor(tState.fluidFlowRate * 10 + 0.5) / 10
  758.       outStr = tostring(fluidFlowRate) .. " mB/t"
  759.       if tState.fluidFlowRateMax == tState.fluidFlowRate then
  760.          color = 0x00FF00 -- green
  761.       else
  762.          color = 0xF2B233 -- orange
  763.       end
  764.    else
  765.       outStr = noInfo
  766.       color = 0xFF0000 -- red
  767.    end
  768.  
  769.    displayInfoLineOnGlasses(glasses, textX, textY,
  770.                             "Act Flow Rate", outStr, color, updateOnly)
  771.    textY = textY + tGlassStyle.lineHeight + tGlassStyle.spacing
  772.  
  773.    -- Energy Output
  774.    if tState then
  775.       local energyOut = math.floor(tState.energyProducedLastTick + 0.5)
  776.       outStr = tostring(energyOut) .. " RF/t"
  777.       color = 0xFFFFFF -- white
  778.    else
  779.       outStr = noInfo
  780.       color = 0xFF0000 -- red
  781.    end
  782.    
  783.    displayInfoLineOnGlasses(glasses, textX, textY,
  784.                             "Energy Output", outStr, color, updateOnly)
  785.    textY = textY + tGlassStyle.lineHeight + tGlassStyle.spacing
  786.  
  787.    -- Energy Stored
  788.    if tState then
  789.       local energy = math.floor(tState.energyStored + 0.5)
  790.       outStr = tostring(energy) .. " RF"
  791.       color = 0xFFFFFF -- white
  792.    else
  793.       outStr = noInfo
  794.       color = 0xFF0000 -- red
  795.    end
  796.    displayInfoLineOnGlasses(glasses, textX, textY,
  797.                             "Energy Stored", outStr, color, updateOnly)
  798.    textY = textY + tGlassStyle.lineHeight + tGlassStyle.spacing
  799.    
  800.    -- Intake Fluid
  801.    if tState then
  802.       local inputAmount = math.floor(tState.inputAmount * 10 + 0.5) / 10
  803.       local inputType = "-"
  804.       if tState.inputType then
  805.          inputType = tState.inputType
  806.       end
  807.       outStr = tostring(inputAmount) .. " mB (" .. inputType .. ")"
  808.       color = 0xFFFFFF -- white
  809.    else
  810.       outStr = noInfo
  811.       color = 0xFF0000 -- red
  812.    end
  813.    displayInfoLineOnGlasses(glasses, textX, textY,
  814.                             "Intake Fluid", outStr, color, updateOnly)
  815.    textY = textY + tGlassStyle.lineHeight + tGlassStyle.spacing
  816.    
  817.    -- Exhaust Fluid
  818.    if tState then
  819.       local outputAmount = math.floor(tState.outputAmount * 10 + 0.5) / 10
  820.       local outputType = "-"
  821.       if tState.outputType then
  822.          outputType = tState.outputType
  823.       end
  824.       outStr = tostring(outputAmount) .. " mB (" .. outputType .. ")"
  825.       color = 0xFFFFFF -- white
  826.    else
  827.       outStr = noInfo
  828.       color = 0xFF0000 -- red
  829.    end
  830.    displayInfoLineOnGlasses(glasses, textX, textY,
  831.                             "Exhaust Fluid", outStr, color, updateOnly)
  832.    textY = textY + tGlassStyle.lineHeight + tGlassStyle.spacing
  833.    
  834.    -- Max Fluid Amount
  835.    if tState then
  836.       local fluidAmount = math.floor(tState.fluidAmountMax * 10 + 0.5) / 10
  837.       outStr = tostring(fluidAmount) .. " mB"
  838.       color = 0xFFFFFF -- white
  839.    else
  840.       outStr = noInfo
  841.       color = 0xFF0000 -- red
  842.    end
  843.    displayInfoLineOnGlasses(glasses, textX, textY,
  844.                             "Max Fluid Amount", outStr, color, updateOnly)
  845.    textY = textY + tGlassStyle.lineHeight + tGlassStyle.spacing
  846.    
  847.    -- Infuctor
  848.    if tState then
  849.       if tState.inductorEngaged == nil then
  850.          outStr = "<not available>"
  851.          color = 0xF2B233 -- orange
  852.       elseif tState.inductorEngaged then
  853.          outStr = "Engaged"
  854.          color = 0x00FF00 -- green
  855.       else
  856.          outStr = "Disengaged"
  857.          color = 0xF2B233 -- orange
  858.       end
  859.    else
  860.       outStr = noInfo
  861.       color = 0xFF0000 -- red
  862.    end
  863.    displayInfoLineOnGlasses(glasses, textX, textY,
  864.                             "Inductor", outStr, color, updateOnly)
  865. end
  866.  
  867. --
  868. -- Display table on terminal glasses
  869. --
  870. -- Parameters:
  871. --     glasses - wraped terminal bridge device
  872. --
  873. local function displayTableOnGlasses(glasses)
  874.    labelArr = {}
  875.    local label, tState
  876.    for label, tState in pairs(turbineTable) do
  877.       table.insert(labelArr, label)
  878.    end
  879.  
  880.    table.sort(labelArr)
  881.  
  882.    local updateOnly = (glassesStates.prevTableEntries == #labelArr)
  883.    glassesStates.prevTableEntries = #labelArr
  884.  
  885.    if not updateOnly then
  886.       -- redraw box
  887.       local boxWidth =
  888.           51 * 8   -- Space enought for 52 characters
  889.              + 2 * tGlassStyle.borderWidth     -- two borders (top/bottom)
  890.              + 2 * tGlassStyle.padding         -- two padding (top/bottom)
  891.  
  892.       local boxHeight =
  893.          tGlassStyle.lineHeight -- header line
  894.          + tGlassStyle.spacing -- spacing of header line
  895.          + tGlassStyle.rulerHeight + tGlassStyle.spacing -- ruler with spacing
  896.          + (tGlassStyle.lineHeight + tGlassStyle.spacing)
  897.            * #labelArr -- Table lines
  898.          + 2 * tGlassStyle.borderWidth -- two borders (left/right)
  899.          + 2 * tGlassStyle.padding     -- two paddings (left/right)
  900.  
  901.       glasses.clear()
  902.       displayBoxToGlasses(glasses, boxWidth, boxHeight)
  903.    end
  904.  
  905.    -- Table Header
  906.    local textX =
  907.       tGlassStyle.posX + tGlassStyle.borderWidth + tGlassStyle.padding
  908.    local textY =
  909.       tGlassStyle.posY + tGlassStyle.borderWidth + tGlassStyle.padding
  910.  
  911.    if not updateOnly then
  912.       glasses.addText(textX, textY, "Label")
  913.       glasses.addText(textX + (8*16), textY, "TRPM")
  914.       glasses.addText(textX + (8*21), textY, "ARPM")
  915.       glasses.addText(textX + (8*26), textY, "MFlow")
  916.       glasses.addText(textX + (8*32), textY, "AFlow")
  917.       glasses.addText(textX + (8*38), textY, "kRF/t")
  918.       glasses.addText(textX + (8*44), textY, "Energy")
  919.  
  920.       glasses.addBox(tGlassStyle.posX
  921.                         + tGlassStyle.borderWidth,
  922.                      tGlassStyle.posY
  923.                         + tGlassStyle.borderWidth
  924.                         + tGlassStyle.padding
  925.                         + tGlassStyle.lineHeight + tGlassStyle.spacing,
  926.                      51 * 8 + 2 * tGlassStyle.padding, 2,
  927.                      0xFFFFFF)
  928.    end
  929.  
  930.    -- Table lines
  931.    local i
  932.    for i, label in pairs(labelArr) do
  933.       tState = turbineTable[label]
  934.  
  935.       -- Label
  936.       local linePos =
  937.          tGlassStyle.posY            -- Y-Pos
  938.          + tGlassStyle.borderWidth   -- the border
  939.          + tGlassStyle.padding       -- the padding
  940.          + tGlassStyle.lineHeight    -- header line
  941.          + tGlassStyle.rulerHeight   -- ruler
  942.          + 2 * tGlassStyle.spacing   -- 2 * spacings (header+ruler)
  943.          + (i-1) * (tGlassStyle.lineHeight + tGlassStyle.spacing)
  944.  
  945.       if not glassesStates.tabTxt[i] then
  946.          glassesStates.tabTxt[i] = {}
  947.       end
  948.  
  949.       local outStr = format_gl_str(glasses, label, (15*8))
  950.       if updateOnly then
  951.          glassesStates.tabTxt[i].label.setText(outStr)
  952.       else
  953.          glassesStates.tabTxt[i].label =
  954.             glasses.addText(textX, linePos, outStr)
  955.       end
  956.  
  957.       if tState.active then
  958.          glassesStates.tabTxt[i].label.setColor(0x00FF00)
  959.       else
  960.          glassesStates.tabTxt[i].label.setColor(0xFF0000)
  961.       end
  962.  
  963.       -- TRPM
  964.       if tState.tSpeed == 0 then
  965.          outStr = "OFF"
  966.       else
  967.          outStr = tostring(math.floor(tState.tSpeed + 0.5))
  968.       end
  969.      
  970.       if updateOnly then
  971.          glassesStates.tabTxt[i].TRPM.setText(outStr)
  972.       else
  973.          glassesStates.tabTxt[i].TRPM =
  974.             glasses.addText(textX + (8*16), linePos, outStr)
  975.       end
  976.  
  977.       if tState.tSpeed == 0 then
  978.          glassesStates.tabTxt[i].TRPM.setColor(0xFF0000) -- red
  979.       else
  980.          glassesStates.tabTxt[i].TRPM.setColor(0xFFFFFF) -- white
  981.       end
  982.  
  983.       -- APRM
  984.       outStr = tostring(math.floor(tState.rotorSpeed + 0.5))
  985.       if updateOnly then
  986.          glassesStates.tabTxt[i].ARPM.setText(outStr)
  987.       else
  988.          glassesStates.tabTxt[i].ARPM =
  989.             glasses.addText(textX + (8*21), linePos, outStr)
  990.       end
  991.  
  992.       if math.floor(tState.rotorSpeed*10 + 0.5)/10 == tState.tSpeed then
  993.          glassesStates.tabTxt[i].ARPM.setColor(0x00FF00) -- green
  994.       elseif tState.rotorSpeed > 2000 then
  995.          glassesStates.tabTxt[i].ARPM.setColor(0xFF0000) -- red
  996.       else
  997.          glassesStates.tabTxt[i].ARPM.setColor(0xF2B233) -- orange
  998.       end
  999.          
  1000.  
  1001.       -- TFlow
  1002.       outStr = tostring(math.floor(tState.fluidFlowRateMax + 0.5))
  1003.       if updateOnly then
  1004.          glassesStates.tabTxt[i].TFlow.setText(outStr)
  1005.       else
  1006.          glassesStates.tabTxt[i].TFlow =
  1007.             glasses.addText(textX + (8*26), linePos, outStr)
  1008.       end
  1009.  
  1010.       -- AFlow
  1011.       outStr = tostring(math.floor(tState.fluidFlowRate + 0.5))
  1012.       if updateOnly then
  1013.          glassesStates.tabTxt[i].AFlow.setText(outStr)
  1014.       else
  1015.          glassesStates.tabTxt[i].AFlow =
  1016.             glasses.addText(textX + (8*32), linePos, outStr)
  1017.       end
  1018.  
  1019.       if tState.fluidFlowRate == tState.fluidFlowRateMax then
  1020.          glassesStates.tabTxt[i].AFlow.setColor(0x00FF00) -- green
  1021.       else
  1022.          glassesStates.tabTxt[i].AFlow.setColor(0xF2B233) -- orange
  1023.       end
  1024.  
  1025.       -- kRF/t
  1026.       local kRFt = tState.energyProducedLastTick / 1000
  1027.       outStr = tostring(math.floor(kRFt*100 + 0.5) / 100)
  1028.       if updateOnly then
  1029.          glassesStates.tabTxt[i].kRFt.setText(outStr)
  1030.       else
  1031.          glassesStates.tabTxt[i].kRFt =
  1032.             glasses.addText(textX + (8*38), linePos, outStr)
  1033.       end
  1034.  
  1035.       -- Energy
  1036.       outStr = tostring(math.floor(tState.energyStored + 0.5))
  1037.       if updateOnly then
  1038.          glassesStates.tabTxt[i].Energy.setText(outStr)
  1039.       else
  1040.          glassesStates.tabTxt[i].Energy =
  1041.             glasses.addText(textX + (8*44), linePos, outStr)
  1042.       end
  1043.    end
  1044. end
  1045.  
  1046.  
  1047. --
  1048. -- Display table on terminal glasses
  1049. --
  1050. -- Parameters:
  1051. --     name - name (side) of device
  1052. --
  1053. local function displayOnGlasses(name)
  1054.    local glasses = peripheral.wrap(name)
  1055.  
  1056.    if glassesStates == nil then
  1057.       -- initialize states of terminal glasses
  1058.       glasses.clear()
  1059.  
  1060.       glassesStates = {
  1061.          mode = "table",         -- mode of display
  1062.          show = "hidden",        -- what mode is currently shown
  1063.          recoverMode = "hidden", -- mode to recover after speed change error
  1064.          infoTurbine = nil,      -- name of turbine for info screen
  1065.          prevTableEntries = 0,   -- previous number of turbines in table
  1066.          tabTxt = {},            -- old text boxes of table screen
  1067.          infoTxt = nil           -- old text boxes of info screen
  1068.       }
  1069.    end
  1070.  
  1071.    -- Show table
  1072.    if glassesStates.mode == "table" then
  1073.       if glassesStates.show ~= "table" then
  1074.          -- reset: a brand new box is required.
  1075.          glassesStates.prevTableEntries = 0
  1076.       end
  1077.  
  1078.       displayTableOnGlasses(glasses)
  1079.       glassesStates.show = "table"
  1080.       return
  1081.    end
  1082.  
  1083.    -- Info box
  1084.    if glassesStates.mode == "info" then
  1085.       if glassesStates.show ~= "info" then
  1086.          -- reset: a brand new box is required.
  1087.          glassesStates.infoTxt = nil
  1088.       end
  1089.  
  1090.       displayInfoOnGlasses(glasses)
  1091.       glassesStates.show = "info"
  1092.       return
  1093.    end
  1094.  
  1095.  
  1096.    -- Hide any screen
  1097.    if glassesStates.mode == "hidden" then
  1098.       if glassesStates.show == "hidden" then
  1099.          return -- already hidden
  1100.       end
  1101.  
  1102.       glasses.clear()
  1103.       glassesStates.show = "hidden"
  1104.       return
  1105.    end
  1106.  
  1107.    -- Show the help box
  1108.    if glassesStates.mode == "help" then
  1109.       if glassesStates.show == "help" then
  1110.          return -- already show help screen
  1111.       end
  1112.  
  1113.       glasses.clear()
  1114.       displayHelpToGlasses(glasses)
  1115.       glassesStates.show = "help"
  1116.       return
  1117.    end
  1118.  
  1119.    -- show error message
  1120.    if string.sub(glassesStates.mode,1,4) == "err:" then
  1121.       if glassesStates.show == glassesStates.mode then
  1122.          return -- already showing this message
  1123.       end
  1124.      
  1125.       glasses.clear()
  1126.       displayErrorMsgToGlasses(glasses, string.sub(glassesStates.mode, 5))
  1127.       glassesStates.show = glassesStates.mode
  1128.       return
  1129.    end
  1130.  
  1131.    return
  1132. end
  1133.  
  1134.  
  1135. --
  1136. -- Display turbine data to any connected monitor, if possible
  1137. --
  1138. local function displayTable()
  1139.  
  1140.    displayTableOnMonitor("#term")
  1141.  
  1142.    if pocket then
  1143.       -- Pocket computer: ignore monitors
  1144.       return
  1145.    end
  1146.  
  1147.  
  1148.    local glassesName = nil
  1149.    local pList = peripheral.getNames()
  1150.    local i, name
  1151.    for i, name in pairs(pList) do
  1152.       if peripheral.getType(name) == "monitor" then
  1153.          -- found monitor as peripheral
  1154.          displayTableOnMonitor(name)
  1155.       end
  1156.       if peripheral.getType(name) == "openperipheral_glassesbridge" then
  1157.          -- found terminal glasses
  1158.          glassesName = name
  1159.       end
  1160.    end
  1161.  
  1162.    if glassesName then
  1163.       -- Display table and other stuff on terminal glasses
  1164.       displayOnGlasses(glassesName)
  1165.    end
  1166. end
  1167.  
  1168. --
  1169. -- Cycle informations on monitor
  1170. --
  1171. -- Parameters:
  1172. --     monName - Name of monitor to cycle the informations
  1173. --
  1174. local function doCycleInformations(monName)
  1175.    if cycleDisplayStates[monName] == nil then
  1176.       return -- not a cycled (small) monitor
  1177.    end
  1178.  
  1179.    if cycleDisplayStates[monName] == "RPM" then
  1180.       cycleDisplayStates[monName] = "Flow"
  1181.    elseif cycleDisplayStates[monName] == "Flow" then
  1182.       cycleDisplayStates[monName] = "EnergyRate"
  1183.    elseif cycleDisplayStates[monName] == "EnergyRate" then
  1184.       cycleDisplayStates[monName] = "EnergyStored"
  1185.    else
  1186.       cycleDisplayStates[monName] = "RPM"
  1187.    end
  1188.    displayTable()
  1189. end
  1190.  
  1191.  
  1192. --
  1193. -- Display sub window to change target speed
  1194. --
  1195. -- Parameters:
  1196. --    name  - monitor name or "#term"
  1197. --    xPos  - x-Position of click
  1198. --    yPos  - y-Position of click
  1199. --
  1200. -- Return:
  1201. --    turbine state, new speed
  1202. --
  1203. local function changeSpeed(monName, xPos, yPos)
  1204.    if yPos < 3 then
  1205.       doCycleInformations(monName)
  1206.       return nil,-1
  1207.    end
  1208.  
  1209.    local mon
  1210.    if monName == "#term" then
  1211.       mon = term -- terminal
  1212.    else
  1213.       mon = peripheral.wrap(monName) -- wrap monitor
  1214.    end
  1215.    local monWidth, monHeight = mon.getSize()
  1216.  
  1217.    if yPos == monHeight and cycleDisplayStates[monName] ~= nil then
  1218.       doCycleInformations(monName)
  1219.       return nil,-1
  1220.    end
  1221.  
  1222.    local label = labelArr[yPos - 2]
  1223.    if label == nil
  1224.    then
  1225.       return nil,-1
  1226.    end
  1227.  
  1228.    local tState = turbineTable[label]
  1229.    if tState == nil or not tState.remoteControl then
  1230.       return nil,-1
  1231.    end
  1232.  
  1233.    local dispX = xPos - 11
  1234.    local dispY = yPos - 3
  1235.  
  1236.    if dispX < 1 then
  1237.       dispX = 1
  1238.    end
  1239.  
  1240.    if dispX + 23 > monWidth then
  1241.       dispX = monWidth - 22
  1242.    end
  1243.  
  1244.    if dispY < 1 then
  1245.       dispY = 1
  1246.    end
  1247.  
  1248.    if dispY + 5 > monHeight then
  1249.       dispY = monHeight - 4
  1250.    end
  1251.  
  1252.    mon.setCursorPos(dispX, dispY)
  1253.    mon.write("+---------------------+")
  1254.  
  1255.    mon.setCursorPos(dispX, dispY+1)
  1256.    mon.write("| ")
  1257.    mon.setTextColor(colors.orange)
  1258.    mon.write("Change target speed")
  1259.    mon.setTextColor(colors.white)
  1260.    mon.write(" |")
  1261.  
  1262.    mon.setCursorPos(dispX, dispY+2)
  1263.    mon.write("| ")
  1264.    mon.setTextColor(colors.orange)
  1265.    mon.write("of ")
  1266.    mon.setTextColor(colors.yellow)
  1267.    mon.write(format_str(label, 16))
  1268.    mon.setTextColor(colors.white)
  1269.    mon.write(" |")
  1270.  
  1271.    mon.setCursorPos(dispX, dispY+3)
  1272.    mon.write("| ")
  1273.    mon.setTextColor(colors.red)
  1274.    if tState.tSpeed == 0 then
  1275.       mon.setBackgroundColor(colors.blue)
  1276.    end
  1277.    mon.write(" OFF ")
  1278.    mon.setBackgroundColor(colors.black)
  1279.    mon.write("  ")
  1280.    mon.setTextColor(colors.green)
  1281.    if tState.tSpeed == 900 then
  1282.       mon.setBackgroundColor(colors.blue)
  1283.    end
  1284.    mon.write(" 900 ")
  1285.    mon.setBackgroundColor(colors.black)
  1286.    mon.write(" ")
  1287.    if tState.tSpeed == 1800 then
  1288.       mon.setBackgroundColor(colors.blue)
  1289.    end
  1290.    mon.write(" 1800 ")
  1291.    mon.setBackgroundColor(colors.black)
  1292.    mon.setTextColor(colors.white)
  1293.    mon.write(" |")
  1294.  
  1295.    mon.setCursorPos(dispX, dispY+4)
  1296.    mon.write("+---------------------+")
  1297.  
  1298.    local evt, p1, p2, p3
  1299.    repeat
  1300.       -- Event loop
  1301.       evt, p1, p2, p3 = os.pullEvent()
  1302.    until (evt == "mouse_click" and monName == "#term")
  1303.       or (evt == "monitor_touch" and p1 == monName)
  1304.  
  1305.    local newSpeed = -1
  1306.    if p3 == dispY+3 then
  1307.       if p2 >= dispX+2 and p2 <= dispX+6 then
  1308.          -- OFF
  1309.          newSpeed = 0
  1310.       elseif p2 >= dispX+9 and p2 <= dispX+13 then
  1311.          -- 900
  1312.          newSpeed = 900
  1313.       elseif p2 >= dispX+15 and p2 <= dispX+20 then
  1314.          -- 1800
  1315.          newSpeed = 1800
  1316.       end
  1317.  
  1318.       return tState, newSpeed
  1319.    end
  1320.  
  1321.    return nil, -1
  1322. end
  1323.  
  1324.  
  1325. --
  1326. -- Parse an execute turbine commends
  1327. --
  1328. -- Parameters:
  1329. --     cmdline - the chat command
  1330. --
  1331. local function parseAndExecGlassesCommands(cmdline)
  1332.    local args = {}
  1333.  
  1334.    local cmd=nil
  1335.    for arg in string.gmatch(cmdline, "([^ ]*)[ ]*") do
  1336.       if cmd == nil  then
  1337.          cmd = arg
  1338.       else
  1339.          table.insert(args, arg)
  1340.       end
  1341.    end
  1342.  
  1343.    if cmd == "hide" then
  1344.       glassesStates.mode = "hidden"
  1345.    elseif cmd == "show" then
  1346.       glassesStates.mode = "table"
  1347.       if args[1] ~= nil then
  1348.          local tName = args[1]
  1349.          local i=2
  1350.          while args[i] ~= nil do
  1351.             tName = tName .. " " .. args[i]
  1352.             i = i + 1
  1353.          end
  1354.          
  1355.          local tState = turbineTable[tName]
  1356.          if tState == nil then
  1357.             if string.sub(glassesStates.mode,1,4) ~= "err:" then
  1358.                glassesStates.recoverMode = glassesStates.mode
  1359.             end
  1360.             glassesStates.mode = "err:turbine_not_found"
  1361.             return
  1362.          end
  1363.          glassesStates.mode = "info"
  1364.          glassesStates.infoTurbine = tName
  1365.       end
  1366.    elseif cmd == "help" then
  1367.       glassesStates.mode = "help"
  1368.    elseif cmd == "speed" then
  1369.       local speed = args[1]
  1370.       local tName = args[2]
  1371.  
  1372.       if tName == nil then
  1373.          glassesStates.mode = "help"
  1374.          return
  1375.       end
  1376.  
  1377.       local i=3
  1378.       while args[i] ~= nil do
  1379.          tName = tName .. " " .. args[i]
  1380.          i = i + 1
  1381.       end
  1382.  
  1383.       local tState = turbineTable[tName]
  1384.       if tState == nil then
  1385.          if string.sub(glassesStates.mode,1,4) ~= "err:" then
  1386.             glassesStates.recoverMode = glassesStates.mode
  1387.          end
  1388.          glassesStates.mode = "err:turbine_not_found"
  1389.          return
  1390.       end
  1391.  
  1392.       if not tState.remoteControl then
  1393.          if string.sub(glassesStates.mode,1,4) ~= "err:" then
  1394.             glassesStates.recoverMode = glassesStates.mode
  1395.          end
  1396.          glassesStates.mode = "err:remote_control_disabled"
  1397.          return
  1398.       end
  1399.  
  1400.       if speed == nil then
  1401.          if string.sub(glassesStates.mode,1,4) ~= "err:" then
  1402.             glassesStates.recoverMode = glassesStates.mode
  1403.          end
  1404.          glassesStates.mode = "err:speed_missing"
  1405.          return
  1406.       end
  1407.  
  1408.       local newSpeed
  1409.       if speed == "off" or speed == "0" then
  1410.          newSpeed = 0
  1411.       elseif speed == "900" then
  1412.          newSpeed = 900
  1413.       elseif speed == "1800" then
  1414.          newSpeed = 1800
  1415.       else
  1416.          if string.sub(glassesStates.mode,1,4) ~= "err:" then
  1417.             glassesStates.recoverMode = glassesStates.mode
  1418.          end
  1419.          glassesStates.mode = "err:invalid_turbine_speed"
  1420.          return
  1421.       end
  1422.  
  1423.       sendSpeedChange(tState.computerId, newSpeed)
  1424.  
  1425.       if string.sub(glassesStates.mode,1,4) == "err:" then
  1426.          glassesStates.mode = glassesStates.recoverMode
  1427.       end
  1428.    else
  1429.       glassesStates.mode = "help"
  1430.       return
  1431.    end
  1432. end
  1433.  
  1434.  
  1435. while true do
  1436.    sendBroadcastRequest()
  1437.  
  1438.    local tID = os.startTimer(loopT)
  1439.    turbineTable = {}
  1440.    repeat
  1441.       -- Event loop
  1442.       local evt, p1, p2, p3, p4, p5 = os.pullEvent()
  1443.       if evt == "modem_message"
  1444.          and p2 == os.getComputerID()
  1445.          and p3 == stateRequestChannel
  1446.       then
  1447.          local rState = textutils.unserialize(tostring(p4))
  1448.          if rState ~= nil
  1449.             and type(rState) == "table"
  1450.             and rState.version ~= nil
  1451.             and rState.version == "Turbine V0.1"
  1452.          then
  1453.             -- seems to be a suitable data structure
  1454.             turbineTable[rState.label] = rState
  1455.          end
  1456.       elseif evt == "monitor_touch" or evt == "mouse_click" then
  1457.          local tState, newSpeed
  1458.          if evt == "monitor_touch" then
  1459.             -- Monitor click
  1460.             tState, newSpeed = changeSpeed(p1, p2, p3)
  1461.          else
  1462.             -- Computer click
  1463.             tState, newSpeed = changeSpeed("#term", p2, p3)
  1464.          end
  1465.  
  1466.          if tState ~= nil then
  1467.             sendSpeedChange(tState.computerId, newSpeed)
  1468.          end
  1469.  
  1470.          -- Sumulate timer event
  1471.          evt = "timer"
  1472.          p1 = tID
  1473.       elseif evt == "char" and pocket then
  1474.          -- pocket computers: cycle display
  1475.          if p1 == " " or p1 == "\n" or p1 == "\t" then
  1476.             doCycleInformations("#term")
  1477.          end
  1478.       elseif evt == "chat_command" then
  1479.          parseAndExecGlassesCommands(p1)
  1480.       end
  1481.    until evt == "timer" and p1 == tID
  1482.    displayTable()
  1483. end
  1484.  
  1485. --
  1486. -- EOF
  1487. --
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement