Jump to content
  • Sky
  • Blueberry
  • Slate
  • Blackcurrant
  • Watermelon
  • Strawberry
  • Orange
  • Banana
  • Apple
  • Emerald
  • Chocolate
  • Charcoal
  • Announcements

    • Lizzy Trickster

      Latest Stable OpenComputers Version   11/26/16

      The latest released version of OpenComputers is version 1.7 for MC 1.7.10, 1.8.9, 1.9.4, 1.10.2, 1.11.2 & 1.12.1. See more information here! Beta/Dev builds can be found at the Jenkins Build Server (ci.cil.li)

Question

I'm working on a small bit of code that reads from a IC2 power storage block and displays it's current and maximum storage. I also want it to toggle a Reactor based on either a keypress or a CLI menu option.

As the code has to refresh a LOT, I think a keypress option is the easiest way, but I can't, for the life of me, figure it out. Here's what I have so far...

os.execute("cls")

-- Hook the component
local component = require("component")
local term = require("term")
local side = require("sides")
local keyboard = require("keyboard")
local event = require("event")
local rs = component.redstone
local batbox = component.cesu
local board = component.keyboard

function toggleBox()
    if rs.getOutput(side.top) == 18 then
        rs.setOutput(side.top, 0)
    else
        rs.setOutput(side.top, 18)
    end
end

local function keyCheck()
    while true do
        e = event.pull(1, "key_up")
        if e == "enter" then
            toggleBox()
        elseif e == "back" then
            running = false
        end
    end
end

keyChecker = coroutine.create(keyCheck)

function main()
    running = true
    while true do
       
        -- Get the tank information, results are in table format
        local tInfo = batbox
        local cap = tonumber(batbox.getCapacity())
        local fill = tonumber(batbox.getStored())

        -- Output as you want... a very simple way:
        print("CESU Power Levels and Controls")
        print("Energy Stored : "..fill)
        print("CESU Capacity : "..cap)
        print("\n Press Enter to toggle reactor.")
        print("Press Back to return to OpenOS.")
        term.setCursor(1,1)
    end
end

main()

And yes, I now see the redundancy of having "cls" there, when I have 'term.setCursor(1,1)' there...

What is it that I am missing?

Share this post


Link to post
Share on other sites

13 answers to this question

Recommended Posts

  • 0
-- Initialize
local component = require("component")
local term = require("term")
local side = require("sides")
local keyboard = require("keyboard")
local event = require("event")
local rs = component.redstone
local batbox = component.cesu
local board = component.keyboard

--Toggle reactor
function toggleBox()
    if rs.getOutput(side.top) > 0 then
        rs.setOutput(side.top, 0)
    else
        rs.setOutput(side.top, 15)
    end
end

-- main Loop
local function main()
    --Store string for displaying information
    local info = [[
CESU Power Levels and Controls
Energy Stored : %s
CESU Capacity : %s

Press Enter to toggle reactor.
Press Back to return to OpenOS.
  ]]
    
    -- Program loop
    while true do
        --Put the cursor top left.
        term.setCursor(1, 1)
        --Retrieve and print information
        print( info:format(batbox.getStored(), batbox.getCapacity()) )
        -- Check for event every second
        local e = table.pack(event.pull(1))
        --Conditional If-Then-Else, Looking for specific keys, or interrupt.
        if e[1] == "key_up" and e[4] == keyboard.keys.enter then 
            toggleBox()
        elseif e[1] == "interrupted" or e[1] == "key_up" and e[4] == keyboard.keys.back then 
            break 
        end
      end
    
    term.clear() -- # clean up after program.
end

--Start program
main()

And THIS is my final code. Love how it works, and seeing that IfThen statement makes me think that I can even expand how this program works! Thank you.

 

Now... to make a better looking screen for it...

Share this post


Link to post
Share on other sites
  • 1

I wanted to fix a small thing. Before, your program would tick every second with event.pull(1, "key_up"), currently with the code i suggested it will not. try this edit for one that update the batbox info every second..

local function main()
  local time = 0
  local info = [[
  CESU Power Levels and Controls
  Energy Stored : %s
  CESU Capacity : %s

  Press Enter to toggle reactor.
  Press Back to return to OpenOS.
  ]]
    
    while true do
      term.setCursor(1, 1)
      print( info:format(batbox.getStored(), batbox.getCapacity()) )
      local e = table.pack(event.pull(1)) -- # resumes at least every second or on any event
      if e[1] == "key_up" and e[4] == keyboard.keys.enter then
        toggleBox()
      elseif e[1] == "interrupted"--[[soft interrupt]] or e[1] == "key_up" and e[4] == keyboard.keys.back then
        break
      end
    end
    
    term.clear() -- clean up after program.
end

 

Share this post


Link to post
Share on other sites
  • 0

The code looks great.. One problem stands out and that is that your keyChecker coroutine isn't being run. Also, Your main function and the keyCheck function both have a loop that will block one another if keyChecker is run within main. Try this solution out. I believe its what you're going for....

function main()
  local running = true
  local e = nil

  repeat
    -- Get the tank information, results are in table format
    local tInfo = batbox
    local cap = tonumber(batbox.getCapacity())
    local fill = tonumber(batbox.getStored())

    -- Output as you want... a very simple way:
    print("CESU Power Levels and Controls")
    print("Energy Stored : "..fill)
    print("CESU Capacity : "..cap)
    print("\n Press Enter to toggle reactor.")
    print("Press Back to return to OpenOS.")
    term.setCursor(1,1)

    e = event.pull(1, "key_up")
    if e == "key_up" then
      toggleBox()
    elseif e == "back" then
      running = false
    end

  until not running or e == "terminated"
end

 

Share this post


Link to post
Share on other sites
  • 0
28 minutes ago, Molinko said:

The code looks great.. One problem stands out and that is that your keyChecker coroutine isn't being run. Also, Your main function and the keyCheck function both have a loop that will block one another if keyChecker is run within main. Try this solution out. I believe its what you're going for....


function main()
  local running = true
  local e = nil

  repeat
    -- Get the tank information, results are in table format
    local tInfo = batbox
    local cap = tonumber(batbox.getCapacity())
    local fill = tonumber(batbox.getStored())

    -- Output as you want... a very simple way:
    print("CESU Power Levels and Controls")
    print("Energy Stored : "..fill)
    print("CESU Capacity : "..cap)
    print("\n Press Enter to toggle reactor.")
    print("Press Back to return to OpenOS.")
    term.setCursor(1,1)

    e = event.pull(1, "key_up")
    if e == "key_up" then
      toggleBox()
    elseif e == "back" then
      running = false
    end

  until not running or e == "terminated"
end

 

If you look at the original code, it is checking for two specific keys. Backspace or "back" and Enter, to do two separate things. Let me see if this works, and how I can tweak it.

EDIT:

Swapped out main() with yours, and my functionality is still there, but it is STILL not reacting to key presses or events at all.

Share this post


Link to post
Share on other sites
  • 0

From what I can see, when the backspace is hit the program should just end (i.e breaking or ending the 'main loop'). The enter key should update the state of the box or (toggle it :p).

The loop i made from your code will 1. draw the screen for initialization. 2. wait 1 second and refresh or receive a key up event. 3. depending on the event, toggleBox or set running to false. 4. in the until clause we check if the event was a terminated event (if the user pressed ctrl+C) to terminate the program. Either 'back' or the terminate event will break the loop and leave the main function thus ending the program. I hope I was clear... If not... Ask away

Share this post


Link to post
Share on other sites
  • 0
Posted (edited)
17 minutes ago, Molinko said:

From what I can see, when the backspace is hit the program should just end (i.e breaking or ending the 'main loop'). The enter key should update the state of the box or (toggle it :p).

The loop i made from your code will 1. draw the screen for initialization. 2. wait 1 second and refresh or receive a key up event. 3. depending on the event, toggleBox or set running to false. 4. in the until clause we check if the event was a terminated event (if the user pressed ctrl+C) to terminate the program. Either 'back' or the terminate event will break the loop and leave the main function thus ending the program. I hope I was clear... If not... Ask away

It's not even reacting to the interrupt (Ctrl+C). It is NOT acting upon any events, at all.

EDIT:

Well, I found ONE problem... it's not updating the file when I save it in an external editor...

Edit edit: 

Well, it's now producing an error when I Ctrl+Alt+C, but other than that, no change.

Edit edit edit:

Well, it DOES INDEED activate toggleBox() now, but that's on ANY key_up event, NOT on ENTER ONLY. 

Edited by Xlaits

Share this post


Link to post
Share on other sites
  • 0
Posted (edited)

Sorry for the delay... Yeah, my first example was shit.. Im sorry for that. I've made another (tested) version.

local component = require("component")
local term = require("term")
local side = require("sides")
local keyboard = require("keyboard")
local event = require("event")
local rs = component.redstone
local batbox = component.cesu
local board = component.keyboard

function toggleBox()
  -- # this was wonky aswell i think. rs usually goes 0 - 15 or maybe RP channels 0 - 255 ??
    if rs.getOutput(side.left) > 0 then
        rs.setOutput(side.left, 0)
    else
        rs.setOutput(side.left, 15)
    end
end

local function main()
  local info = [[
  CESU Power Levels and Controls
  Energy Stored : %s
  CESU Capacity : %s

  Press Enter to toggle reactor.
  Press Back to return to OpenOS.
  ]]
    
    while true do
      term.setCursor(1, 1)
      print( info:format(batbox.getStored(), batbox.getCapacity()) )
      local e = {event.pullMultiple("key_up", "interrupted")}
      if e[1] == "key_up" and e[4] == keyboard.keys.enter then toggleBox()
      elseif e[1] == "interrupted" or e[1] == "key_up" and e[4] == keyboard.keys.back then break end
    end
    
    term.clear() -- # clean up after program.
end

term.clear() -- # clear screen before start.
main()

Sorry for the shit starting advice :P

Edited by Molinko
shit formatting...

Share this post


Link to post
Share on other sites
  • 0

Apparently Ctrl-C is a soft interrupt and must be pulled specifically. Also I fucked up the draw order in the first example, because of no testing.... 

Share this post


Link to post
Share on other sites
  • 0
33 minutes ago, Molinko said:

Sorry for the delay... Yeah, my first example was shit.. Im sorry for that. I've made another (tested) version.


local component = require("component")
local term = require("term")
local side = require("sides")
local keyboard = require("keyboard")
local event = require("event")
local rs = component.redstone
local batbox = component.cesu
local board = component.keyboard

function toggleBox()
  -- # this was wonky aswell i think. rs usually goes 0 - 15 or maybe RP channels 0 - 255 ??
    if rs.getOutput(side.left) > 0 then
        rs.setOutput(side.left, 0)
    else
        rs.setOutput(side.left, 15)
    end
end

local function main()
  local info = [[
  CESU Power Levels and Controls
  Energy Stored : %s
  CESU Capacity : %s

  Press Enter to toggle reactor.
  Press Back to return to OpenOS.
  ]]
    
    while true do
      term.setCursor(1, 1)
      print( info:format(batbox.getStored(), batbox.getCapacity()) )
      local e = {event.pullMultiple("key_up", "interrupted")}
      if e[1] == "key_up" and e[4] == keyboard.keys.enter then toggleBox()
      elseif e[1] == "interrupted" or e[1] == "key_up" and e[4] == keyboard.keys.back then break end
    end
    
    term.clear() -- # clean up after program.
end

term.clear() -- # clear screen before start.
main()

Sorry for the shit starting advice :P

No, it's fine. Made me think.

I like the storing of the printed line as a multi-line quote. And clearing the program's output is a nice touch. The term.clear() above main is NOT NEEDED, as the program will do that once main is run. Yeah, it's one line, but hey, efficiency.

I also realized my idiotic mistake with the redstone power, and had fixed that while waiting. Great minds think alike, I suppose.

Share this post


Link to post
Share on other sites
  • 0
1 minute ago, Molinko said:

I wanted to fix a small thing. Before, your program would tick every second with event.pull(1, "key_up"), currently with the code i suggested it will not. try this edit for one that update the batbox info every second..


local function main()
  local time = 0
  local info = [[
  CESU Power Levels and Controls
  Energy Stored : %s
  CESU Capacity : %s

  Press Enter to toggle reactor.
  Press Back to return to OpenOS.
  ]]
    
    while true do
      term.setCursor(1, 1)
      print( info:format(batbox.getStored(), batbox.getCapacity()) )
      local e = table.pack(event.pull(1)) -- # resumes at least every second or on any event
      if e[1] == "key_up" and e[4] == keyboard.keys.enter then
        toggleBox()
      elseif e[1] == "interrupted"--[[soft interrupt]] or e[1] == "key_up" and e[4] == keyboard.keys.back then
        break
      end
    end
    
    term.clear() -- clean up after program.
end

 

I was JUST about to mention that it wasn't updating on it's own. Thanks for the fix.

Share this post


Link to post
Share on other sites
  • 0

in your sample code you create a coroutine, but you never resume it. Coroutines run like function calls, and yields are like having multiple returns points in said method. The solutions provided are good solutions, but i just wanted to point out that your original code has the right idea, you were just expecting that your code would run  two sections autonomously and in parallel, which is possible with threads (we have threads in OpenOS now)

your original sample of code would work just find if you replace

coroutine.create(keyCheck)

 

with

local thread = require("thread")

thread.create(keyCheck)

 

read more info here: http://ocdoc.cil.li/api:thread

Share this post


Link to post
Share on other sites
  • 0

Hi I tried out the code but keep throwing a red flag and saying no primary CESU and I even tried the MFSU and did the same thing how do I fix this. I am using the adaptor also. Also what is the redstone function for?

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

×