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

Switching the screen the terminal is bound to.

Question

Hi everyone !

First of all, I should precise that I'm quite new to OC and Lua, but already used to programming in general.

 

What I'm trying to do :

I have a basic setup with a computer and a screen attached to it. Another screen (a larger one) is connected via a network cable. Both screens have a keyboard attached to them, and the computer have two graphic cards (one per screen), one is a Tier 3 card and the other a Tier 2.

I would like to be able to use the big screen for displaying informations about my power plant, and the smaller one to control the computer (ie. the terminal should live in the smaller screen). Unfortunately when booting, the terminal attaches to a random GPU and a random screen. Sometimes it's on the large screen, sometimes on the small one. That led me to create a startup script that would care of binding the correct screen to the correct GPU (the large screen with the T3 GPU), and make the terminal use the smaller screen.

Problem is that anything seems to apply. After having bound the screen and GPU to the terminal with term.bind(screen, gpu) , nothing changes. term.screen and term.gpu stay the same, and nothing actually happens to the terminal. It just stays on the screen it booted on.

Here's a screenshot of what is currently happening (the larger screen is referred as "Auxiliary screen" and the smaller as "Master screen")

1529958252-2018-06-25-21-55-49.png

As you can see, primary GPU, screen and keyboard components refers to the correct devices, but aren't used (the shell is still on the large screen). term.gpu/screen/keyboard returns the same adresses as before running the script.

 

The code I've written so far :

local component = require("component")
local term = require("term")

local gpus = component.list("gpu")
local screens = component.list("screen")

local mgpu, mscreen --Master
local sgpu, sscreen	--Aux.


--Finding the GPUs

for addr, type in gpus do
  print("GPU found : @" .. addr)

  local gpu = component.proxy(addr)
  local vx,vy = gpu.getViewport()
  
  print("  Viewport : " .. vx .. "," .. vy)
  
  if gpu.slot == 0 then
    print("  Master GPU (slot 0)")
    mgpu = gpu
  elseif gpu.slot == 1 then
    print("  Auxilliary GPU (slot 1)")
    sgpu = gpu
  end
end


--Finding the screens

local maxScreenSize = 0

for addr, type in screens do
  local screen = component.proxy(addr)
  local w,h = screen.getAspectRatio()
  
  print("Screen found : " .. w .. "," .. h .. " @" .. screen.address)
  
  if (w*h) > maxScreenSize then
    if mscreen then
      sscreen = mscreen
    end
   
     maxScreenSize = w*h
    mscreen = screen
  else
    sscreen = screen
  end

  
  local keyboards = screen.getKeyboards()
  
  for i,addr in ipairs(keyboards) do
    print("  Keyboard : @" .. addr)
  end
  
  if not keyboards[1] then
    print("Warning : no keyboard found for this screen : " .. screen.address)
  end
end

print("Master screen : @" .. mscreen.address)
print("Aux. screen : @" .. sscreen.address)

io.read() --used to prevent the screen to be cleared when switched without leaving time to read the above adresses


--Bind the correct screens to the correct GPUs

mgpu.bind(mscreen.address, false)
sgpu.bind(sscreen.address, false)

mgpu.setResolution(155,45)
sgpu.setResolution(50,25)


--Set the default components the terminal should use

component.setPrimary("gpu", sgpu.address)
os.sleep(0.05)
component.setPrimary("screen", sscreen.address)
os.sleep(0.05)
component.setPrimary("keyboard", component.invoke(sgpu.getScreen(), "getKeyboards")[1])

term.bind(sgpu, sscreen, component.invoke(sgpu.getScreen(), "getKeyboards")[1])

os.sleep(0.05)

print("Initialization complete !") --This should always be printed on the small screen (hint: it isn't. :( )

 

I'd be glad if someone could find a solution to that. Thnaks by advance for your answers

Greetings form France :)

 

Edit : fixed an error about term.gpu/screen/keyboard

Link to post
Share on other sites

6 answers to this question

Recommended Posts

  • 1

For reasons... Not sure why, but the doc on term.bind is incorrect. term.bind actually take a gpu proxy and a term window(internal hidden feature). If you want to control which screen is used you can do some thing like this...

local termScreen = ... -- # the screen you want a term on
local termGpu = ... -- # the gpu the term should use

-- # bind the screen to the proper gpu
termGpu = component.proxy(termGpu)
termGpu.bind(termScreen)

-- # if the term is not bound to our term gpu/screen pair
term.bind(termGpu) -- # second arg is actually a process window. nil get current term process window

Hope this clears shit up...

Link to post
Share on other sites
  • 0

Unfortunately this did not solve the problem. It seems that term.bind actually does nothing. If the terminal was bound to the correct GPU during boot, everything will work fine, else it won't.

Here's another screenshot illustrating that weird behavior :

1530007453-2018-06-26-11-10-48.png

term.bind doesn't seems to act in any way on which GPU the terminal is bound to.

Should I open an issue ?

Link to post
Share on other sites
  • 1
  • Solution

Maybe, opening a term window shouldn't be such a pain.. I have done it before, just need to remember and test how I did it... I'll post back asap

I figured a way to switch terminals. Dunno if its a "good" way or not but it should work.

local component = require "component"
local process = require "process"
local term = require "term"

local termGpuAddr, termScrAddr = ... -- # use whatever logic you would to get the relevant component address (this line will cause an error if you dont shove some address in)

local termGpu = component.proxy(termGpuAddr)
termGpu.bind(termScrAddr) -- # component bind

-- # I thought you could get the current term window with `process.info().data.window` or `rawget(process.info().data, 'window')` or `term.internal.window()`
-- # for some reason getting the current window was giving me nil, even with rawget :/
local window = term.internal.open() -- # create new term window
term.bind(termGpu, window) -- # bind pty to gpu
window.keyboard = component.invoke(termScrAddr, 'getKeyboards')[1] -- # dont forget a keyboard or it will use the last term kb

-- # lastly you have to assign the window to an actual process. here we'll assign the init process our window. all child processes will inherit this window
local init_index = 1
-- # find the highest process (init)
while true do
  if process.info(init_index + 1) then
  	init_index = init_index + 1
  else
    break
  end
end

-- # cram 'er in there. If you only want the current process to use the pty just use `process.info().data.window = window`
process.info(init_index).data.window = window

This is tested and should work. It did for me anyway. just adjust for termGpuAddr and termScrAddr

Edited by Molinko
**fixed
Link to post
Share on other sites
  • 1

I feel like I should add some more information.. Just some things I learned asking around and poking at the OpenOS source. So here it goes. Term "windows" aren't really a feature of the OS, they're kinda hidden, and in my quest to abuse them I learned that at the moment they're kinda 'half baked', although functional. If you look at the `term` library you'll see that a lot of methods take an optional `window` argument but the library lacks a documented way to create or get a new or active pty. Wtf mang. Another tip would be to note that the computer has no preference for screen and/or keyboard proximity, hence why you're in this mess in the first place. So it would be handy to know that the "boot screen" is what will become the "primary" screen component and thus the init process(highest process in the OS) will bind the boot screen and first gpu compatible with that screen. `tty.window`  is referenced in `process.info(init_index).data.window`

You can see more of this reflected in the concept of primary components and that even extends to the /dev dir... i.e.

-- # get the first non-'primary' component of `ctype`
local function getSecondary(ctype)
  -- # dev component/ listings start at 0. Thus /dev/components/by-type/`ctype`/1 is the second gpu..
  local fd = assert(io.open('/dev/components/by-type/'..ctype..'/1/address', 'r'))
  local address = fd:read('*a')
  fd:close()
  return address
end

You could use this in my example above.

local component = require "component"
local process = require "process"
local term = require "term"

local function getSecondary(ctype)
  local fd = assert(io.open('/dev/components/by-type/'..ctype..'/1/address', 'r'))
  local address = fd:read('*a')
  fd:close()
  return address
end

-- # Get the first non-primary gpu and screen, assuming that this is in a condition where we want to switch the screen...
local termGpuAddr, termScrAddr = getSecondary('gpu'), getSecondary('screen')

local termGpu = component.proxy(termGpuAddr)
termGpu.bind(termScrAddr)

local window = term.internal.open()
term.bind(termGpu, window)
window.keyboard = component.invoke(termScrAddr, 'getKeyboards')[1]

local init_index = 1
while true do
  if process.info(init_index + 1) then
    init_index = init_index + 1
  else
    break
  end
end

process.info(init_index).data.window = window

I hope some of this info may save you some time.. Good luck. And feel free to ask away bud

Link to post
Share on other sites
  • 0

Thank you for your answer ! Your workaround with tty windows worked perfectly for me.

Just two things to mention :

  • When using this on boot, sometimes when the correct GPU isn't initially bound to the pty, creating a new window without parameters then attaching it to the root process will cause internal errors in tty.lua. So providing parameters to term.internal.open() is mandatory in this case :
    local w,h = gpu.getResolution()
    local window = term.internal.open(0,0,w,h)
    Else the window's width and height will be nil. This isn't a problem when used after boot, directly in the shell.
  • Adding a keyboard via window.keyboard isn't mandatory (in my specific case) because I already set the correct keyboard as primary in my main code.

Again thanks you very much !

Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Answer this question...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...

×
×
  • Create New...

Important Information

By using this site, you agree to our Terms of Use and Privacy Policy.