Reputation: 3883
I am working on embedded system using C
and linux
. User can connect to the device via SSH or a console serial cable. He can do this through PuTTY or Tera Term. My question is, after he is connected, how can I know his window's width? I have tried different approaches, they work if I simulate my system on a linux pc, but none of them work on the device:
ioctl()
struct winsize ws;
ioctl(..., TIOCGWINSZ, &ws);
This method works on pc, but it always returns 0 on the device.
tgetnum()
setupterm((char *)0, 1, (int *)0);
CGR_INT columns = tgetnum("co");
This method works on pc, but it always returns 80x24 on the device.
getmaxyx()
CGR_INT xdim;
CGR_INT ydim;
initscr();
refresh();
getmaxyx(stdscr, ydim, xdim);
This method works on pc, but it always returns 0 on the device
Upvotes: 4
Views: 8471
Reputation: 54505
A serial device doesn't negotiate the window size, so TIOCGWINSZ
will always fail for that case -- unless one loads "correct values", e.g., using the resize
program, or uses stty
, etc., to do this. But resize
is more reliable for that case.
The different results from tgetnum
and getmaxxy
leave out the information which would help explain this: the value of TERM
which is used, and (possibly) the different terminal databases used:
TIOCGWINSZ
. If it is not available, it will use the size from the terminal description.Given the results reported by OP, that tgetnum call used a different terminal description than what was used in the curses calls.
Further reading:
resize
works for this situationUpvotes: 0
Reputation: 8532
A serial line does not have a way to negotiate the size of the terminal. Running a real xterm et.al. over a TTY/PTY device pair uses the TIOCSWINSZ
/TIOCGWINSZ
ioctl()
pair to pass this information.
Traditionally, this information was kept in termcap
or terminfo
about the real physical piece-of-glass-with-phosphor-coating terminals such as a DEC VT220. This is a static fixed database of values known ahead of time, which was correct around the time that a "terminal" literally was this fixed piece of hardware, but doesn't work so well in modern times of terminals being just some piece of program that draws to a framebuffer or similar.
I'd suggest the best method would be to try TIOCGWINSZ
, if that fails use terminfo
's tgetnum("co")
, and if that fails just presume 80x24.
Upvotes: 4
Reputation: 23858
I use this code to print a bunch of equals signs as a divider. Works on most boxes/terms I've tried. Not sure what devices you are talking about. Worth a try I guess ;-)
#include <termios.h>
#include <sys/ioctl.h>
#include <stdio.h>
int main(int argc, char *argv[])
{
struct winsize ws;
ioctl(0, TIOCGWINSZ, &ws);
int i=0;
for(;i<10*ws.ws_col;++i) printf("=");
printf("\n");
return 0;
}
Upvotes: 3
Reputation: 10551
TIOCGWINSZ is the way to go. Your device in question has to announce its size, otherwise this just can't work. Take xterm as an example:
device —— ttyS driver —— ttyS0 devnode —— screen/minicom
xterm —— pty devnode —— pty driver —— pts devnode —— bash
xterm does ioctl(TIOCSWINSZ) the first time it is spawned to let the tty driver know the window size. bash and programs spawned from it can then inquire it. If you resize the xterm window, it will tell the tty driver the new size, and xterm also emits SIGWINCH to its child process (bash in this case) to notify it of the size change.
None of this happens with devices (such as yours) that have no idea what they are connected to in the first place. Neither does the tty driver know what is connected to it. (Nor does it usually care.) xterm can tell the driver the size, because it can issue an ioctl, but ioctls are not transported via serial for example. What it would in theory take is a specialized kernel driver that knows how to communicate size changes with your particular device (perhaps a protocol on top of serial so that no rewrite of a core component is needed).
Note that the connected device may not even have a concept of a fixed region—e.g. a printer could be considered to have practically infinitely many lines.
ncurses just assumes 80x24 if it sees 0x0, because the programmer defined it that way. That size may not be correct, and in practice usually is not because people can resize their windows (even if they can't, like on tty1, they can still use stuff like screen(1) and shrink the size to something less than 80x24).
Upvotes: 4