2011-12-15 16 views
3

私はClinuxを使って組み込みシステムに取り組んでいます。ユーザーはSSHまたはコンソールシリアルケーブル経由でデバイスに接続できます。彼はPuTTYまたはTera Termを通してこれを行うことができます。私の質問は、彼が接続された後、どのように私は彼のウィンドウの幅を知ることができますか?私はLinuxのPC上で自分のシステムをシミュレートする場合、彼らは仕事、異なるアプローチを試してみましたが、それらのどれもが、デバイス上で動作しません:ターミナルウィンドウの幅を取得するには?

  1. ioctl()

    struct winsize ws; 
    ioctl(..., TIOCGWINSZ, &ws); 
    

    この方法は、PC上で動作しますが、それデバイス上で常に0を返します。

  2. tgetnum()

    setupterm((char *)0, 1, (int *)0); 
    CGR_INT columns = tgetnum("co"); 
    

    この方法は、PC上で動作しますが、それは常にデバイス上で80x24を返します。

  3. getmaxyx()

    CGR_INT xdim; 
    CGR_INT ydim; 
    initscr(); 
    refresh(); 
    getmaxyx(stdscr, ydim, xdim); 
    

    この方法は、PC上で動作しますが、それは常に

答えて

2

TIOCGWINSZが進むべき道であるデバイスに0を返します。問題のデバイスがそのサイズをアナウンスする必要があります。そうでなければ、これは機能しません。一例としてのxtermを取る:

device —— ttyS driver —— ttyS0 devnode —— screen/minicom 
xterm —— pty devnode —— pty driver —— pts devnode —— bash 

xtermがのioctl(TIOCSWINSZ)ttyドライバは、ウィンドウのサイズを知っているように生み出される最初の時間を行います。 bashとそれから生成されたプログラムがそれを調べることができます。 xtermウィンドウのサイズを変更すると、ttyドライバに新しいサイズが通知され、xtermはサイズ変更を通知するためにSIGWINCHを子プロセス(この場合はbash)に送信します。

これは、最初に接続しているものが何もわからないデバイス(あなたのようなもの)では発生しません。また、ttyドライバは、接続されているものを知っていません。 xtermはioctlを発行することができるのでドライバにサイズを伝えることができますが、ioctlは例えばシリアル経由では転送されません。理論的には、特定のデバイス(おそらくコアコンポーネントの書き換えが不要なシリアルの上にあるプロトコルなど)でサイズ変更を伝える方法を知っている専門のカーネルドライバがあります。

接続されたデバイスには固定領域の概念さえありません。プリンタは実質的に無数に多くのラインを有すると見なすことができる。

ncursesは、プログラマがそのように定義したため、0x0を見ると80x24と仮定します。そのサイズは正確ではないかもしれません。実際には、通常、人々は自分のウィンドウのサイズを変更できるので(tty1のように、スクリーン(1)のようなものを使用して80x24未満のサイズに縮小することはできません)。

+0

こんにちは、ヨルゲンセン、ご返信ありがとうございます。あなたはこの数字についてもっと説明できますか?device-ttySドライバ - ttyS0 devnode - screen/minicom xterm - pty devnode - ptyドライバ - pts devnode - bash?私はかなり理解していない。たとえば、 "pty devnode"とは何ですか? – martial

+0

別のことは、私の問題の解決策はドライバを変更することです?どのドライバー? – martial

+0

あなたの説明によると、SSHとシリアルコンソールの動作は異なるでしょう。異なるドライバが関与しているからです。シリアルコンソールの場合は、SSHの場合、それは何か(何ですか?)です。私は正しい? – martial

3

このコードを使用して、等号の束を仕切りとして印刷します。私が試したほとんどのボックス/用語に作用します。あなたが話しているデバイスがわからない試してみる価値あり;-)

#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; 
} 
+0

提案に感謝します。私は実際にこの方法を使用しました、それはPC上で動作しますが、私の組み込み機器ではありません – martial

+0

ありがとう、それは動作します!私は、ioctl()の最初の引数ではなく、STDIN_FILENO、STDOUT_FILENO、またはSTDERR_FILENOを0の代わりに使用できると考えています。通常はすべて同じターミナルウィンドウにバインドされています。私はそれらをMac OSのターミナルアプリケーションで試してみましたが、すべて同じ結果を出しました。 STDIN_FILENOは0と定義されているため、この例ではSTDIN_FILENOを暗黙的に使用しています。 – GuidC0DE

0

シリアル回線には、端末のサイズをネゴシエートする方法がありません。実際のxterm et.alを実行する。 TTY/PTYデバイスペアでは、TIOCSWINSZ/TIOCGWINSZioctl()ペアを使用してこの情報を渡します。

伝統的に、この情報は、DEC VT220のような実際の物理的なガラス片を有する蛍光体被覆端子については、termcapまたはterminfoに保持されていました。これは前もって知られていた静的固定値のデータベースであり、 "端末"がこの固定されたハードウェアであった頃は正しいが、現代の端末ではちょうどプログラムの一部ではあまりうまく機能しないフレームバッファなどに描画されます。

tgetnum("co")が失敗した場合は、TIOCGWINSZを試してみて、それが80x24と仮定すると失敗する場合は、最善の方法をお勧めします。

関連する問題