端末グラフィックス

printfが小さく、ncursesが大きい場合









データが多すぎる場合、コンソールプログラムの標準printf出力では不十分な場合があります。 特に、多くの異なるイベントがあり、異なるデータがおかしなリストに変わる場合。 このデータはUARTを介してコントローラーから取得でき、GUIプログラムの種類について考えることはありません。 また、通常のbashスクリプトを使用して、何らかの種類の疑似グラフィックインターフェイスを固定することもできます。



すぐに言わなければなりません。最初は自転車の発明のように思えるかもしれません。素晴らしいncursesライブラリがあるからです。 そのメリットを損なうことはありませんが、多くの場合、その機能は余りにも冗長です。 さらに、コントローラーへの移植性が低く、確かに冗長性があります。 ただし、疑似グラフィックを操作するためのいくつかのマクロと関数は、自分でスケッチできます。



問題の声明



コントローラのプログラミングに携わった人は、デバッグ中に情報を表示するためにロシア語でUARTコンソールまたはUAPPを使用することがよくあります。 以前は、このインターフェイスの説明をHabréの投稿で提供しました 。 十分な量の多様な情報があると、それをキャッチすることは完全に不可能になります。 特に、一部のアナログセンサーからのデータが継続的に送信される場合、さらにポートのステータスなどを監視する必要がある場合、複数ページのログになります。 その結果、人々はコンピューター側でハンドラーを作成し始め、ソリューションは完全に耐えられなくなり、最も重要なことに、多くの時間が無駄になります。 しかし、実際には、コントローラーからのさまざまな情報をすべて1つのターミナルウィンドウに収めることができ、サードパーティのソフトウェアを作成せずに使用すると便利です。 その結果、当社のソリューションはポータブルになり(任意の端末が必要です)、デバッグに必要なプログラマーの時間を節約できます。



系統的な例



この例はより教育的で系統的ですが、どのコントローラーでも実際のデバイスに簡単に適合させることができます。 また、類推により、すべてbash、pytonなどで動作します。



接触センサーが8ビットポートに接続され、状態がオンとオフになり、アナログ3軸センサーがあり、その状態を表示する必要があるコントローラーがあり、さらにコントローラーに時刻、日付があり、正確性を制御したいとします時間表示; 最後に、そこでイベント(停電など)が発生する可能性があり、そこで緊急にオペレーターに通知する必要があります。 要約すると:





そのような情報がUARTを介してただ愚かに送信された場合、それは読めないゴミになるとすぐに見積もることができます。 しかし、それは注文することができ、すべては次のようになります(テキストエディターでスケッチ):









私はmcから愚かなフレームをコピーしました。 美しさを望む人は、ユニコードにどのフレームがあるかを見ることができます。 上記では、数値は座標専用に書かれています。



アイデアははっきりしているように思えますが、それを端末に実装する方法は? そして、ここから本当の魔法が始まります! 「 そして今、私たちは吹かなければなりません!あなたが吹かなければ、奇跡は起こりません! 」Hmayak Hakobyan



エスケープシーケンス



最初に、この章では、ESCシーケンスを使用した端末管理に関する講義を展開することを計画しました。 しかし、その場合、記事は単にわいせつな次元にまで成長していたので、いくつかの概念のみを説明し、残りはインターネットまたはマニュアルで見つけることができます。

ターミナルは、データを入力および表示できるI / Oデバイスです。 以前は、ターミナルはモニターとキーボードであり、COMポートを介してコンピューターに接続されていました。以前のバージョンではテレタイプでさえも接続されていました。









テレタイプモデル33( ウィキペディアからの写真)



今日、ターミナルは、LinuxやCOMポートで動作するターミナルのように、仮想ターミナルになることができるプログラムです。 これらの端末はすべて、古典的なハイパーターミナルでも、いくつかの基準を満たしています。 ご想像のとおり、このような端末は管理する必要があります。 画面に表示される通常のASCII文字があり、カーソルの座標の指定、画面のクリア、色の設定などを可能にする特別な文字シーケンスがあります。 HabréとGytimeに関する記事では、これらのESCシーケンスについて繰り返し触れています。 Linux用のドライバーを作成するときにディスプレイを制御する際に(誰も読まないネタバレの説明)、ESCシーケンスによっても制御されるwifi無線用バイヤーのディスプレイに関する記事でそれらを使用しました。



誰かがBBSの時代を見つけたなら、これらのボードが「美しい」ものであったことを覚えているでしょう。色、特定の情報入出力フィールドなどがありました。 この喜びはすべて、そのようなコントロールキャラクターの助けを借りて推測されました。 シンボルは、00(NUL)、0x07(BEL)、0x08(BS)、0x09(HT)、0x0a(LF)、0x0b(VT)の14コードのいずれかを含む場合(変換テーブルによる変換前)を制御していると見なされます。 、0x0c(FF)、0x0d(CR)、0x0e(SO)、0x0f(SI)、0x18(CAN)、0x1a(SUB)、0x1b(ESC)、0x7f(DEL)。 私たちは主に、文字ESC = 0x1b、 '\ 033'または '\ e'に興味があります。 これらのシーケンスの詳細については、man console_codesのマニュアル、またはロシア語インターネットを参照してください



カーソルの制御に加えて、端末をさまざまな色で着色することもできます(もちろん、色付けされている場合)。 最も単純なBASHスクリプトを使用して、端末の色を確認できます。



for fgbg in 38 48 ; do #Foreground/Background for color in {0..256} ; do #Colors #Display the color echo -en "\e[${fgbg};5;${color}m ${color}\t\e[0m" #Display 10 colors per lines if [ $((($color + 1) % 10)) == 0 ] ; then echo #New line fi done echo #New line done exit 0
      
      





実行の結果は次のようになります。









コンソール(およびすべての端末)の色とフォントの詳細については、例を参照してください



ここでは、投稿タイトルの写真など、BASHスクリプトで面白いイースターエッグを作成するために必要な情報が既にあります。









より詳細には、bashでイースターエッグを作ったので、LJで読むことができます。



siですべてを整理しましょう



私のプログラミングマスタークラスでこの例を挙げて、ここで紹介します。 テキスト属性を設定し、画面をクリアし、カーソルを上隅に移動し、カーソルを特定の位置に移動するマクロを作成します。



 #define home() printf(ESC "[H") //Move cursor to the indicated row, column (origin at 1,1) #define clrscr() printf(ESC "[2J") //lear the screen, move to (1,1) #define gotoxy(x,y) printf(ESC "[%d;%dH", y, x); #define visible_cursor() printf(ESC "[?251"); //Set Display Attribute Mode <ESC>[{attr1};...;{attrn}m #define resetcolor() printf(ESC "[0m") #define set_display_atrib(color) printf(ESC "[%dm",color)
      
      





可能であれば、特に遅いシステムでは、printfを使用しない方が良いでしょう。その動作は非常に遅いからです。 より軽量なディスプレイ出力関数(COMポート)に置き換えることをお勧めします。



色の属性を個別のマクロの形式で個別のヘッダーファイルにスローします。



ヘッダーファイル
 #ifndef __TERM_EXAMPLE__ #define __TERM_EXAMPLE__ #define ESC "\033" //Format text #define RESET 0 #define BRIGHT 1 #define DIM 2 #define UNDERSCORE 3 #define BLINK 4 #define REVERSE 5 #define HIDDEN 6 //Foreground Colours (text) #define F_BLACK 30 #define F_RED 31 #define F_GREEN 32 #define F_YELLOW 33 #define F_BLUE 34 #define F_MAGENTA 35 #define F_CYAN 36 #define F_WHITE 37 //Background Colours #define B_BLACK 40 #define B_RED 41 #define B_GREEN 42 #define B_YELLOW 44 #define B_BLUE 44 #define B_MAGENTA 45 #define B_CYAN 46 #define B_WHITE 47 #endif /*__TERM_EXAMPLE__*/
      
      







Foreground-テキスト自体に色を付け、 Background-テキストの下地に注意してください。



すべてのマクロの動作を示す小さなプログラムを作成しましょう。



デモプログラム
 int main (void) { home(); clrscr(); printf("Home + clrscr\n"); gotoxy(20,7); printf("gotoxy(20,7)"); gotoxy(1,10); printf("gotoxy(1,10) \n\n"); set_display_atrib(BRIGHT); printf("Formatting text:\n"); resetcolor(); set_display_atrib(BRIGHT); printf("Bold\n"); resetcolor(); set_display_atrib(DIM); printf("Dim\n"); resetcolor(); set_display_atrib(BLINK); printf("Blink\n"); resetcolor(); set_display_atrib(REVERSE); printf("Reverse\n"); printf("\n"); set_display_atrib(BRIGHT); printf("Text color example:\n"); resetcolor(); set_display_atrib(F_RED); printf("Red\n"); resetcolor(); set_display_atrib(F_GREEN); printf("Green\n"); resetcolor(); set_display_atrib(F_BLUE); printf("Blue\n"); resetcolor(); set_display_atrib(F_CYAN); printf("Cyan\n"); resetcolor(); set_display_atrib(BRIGHT); printf("\nBottom color example:\n"); resetcolor(); set_display_atrib(B_RED); printf("Red\n"); resetcolor(); set_display_atrib(B_GREEN); printf("Green\n"); resetcolor(); set_display_atrib(B_BLUE); printf("Blue\n"); resetcolor(); set_display_atrib(B_CYAN); printf("Cyan\n"); printf("\n"); resetcolor(); return 0; }
      
      







仕事の結果:







テキストの属性は破棄する必要があることに注意してください。そうしないと、属性が継承されます。



コントローラーが出力するデータのシミュレーション





私たちのTKを満たすプログラムをスケッチすることは小さな問題になりました:ポートピンの状態、加速度計、日付と時刻、エラーメッセージを表示します。 コードは、任意のコントローラーに簡単に移植できるように作成されています。 特にgithubで簡単に見ることができるので、テキストをコードの断片で散らかしません。私はいくつかのポイントだけに焦点を合わせます。



メイン関数では、カーソルを左上隅に移動し、画面をクリアして、frame_draw();関数を使用してフレームを描画します。 データフレームを1回だけ描​​画し、すべてのデータをそれぞれの位置に表示するだけです。 controller_emulator();関数に制御を渡した後。



controller_emulator()関数内。 30秒ごとに、ユーザーのメッセージを正常からエラーに変更し、ポートでデータを生成し(「実行」ビットが実装されます)、加速度計で乱数を生成します。 タスクのこの関数を簡単に書き換えることができます。 3つの関数を使用してすべてのデータを表示します。



  print_accelerometer(a); print_port_bits(port); print_time_date(tm_info);
      
      





フレームは基本的に単純に描かれ、定義済みの色属性を持つ関数を置きます:



 void frame_draw () { home(); set_display_atrib(B_BLUE); // 123456789012345678901 puts( "┌─────────┐┌─────────┐\n" //0 "│ ││ │\n" //1 "│ ││ │\n" //2 "│ ││ │\n" //3 "│ │├─────────┤\n" //4 "│ ││ │\n" //5 "│ ││ │\n" //6 "│ ││ │\n" //7 "│ ││ │\n" //8 "└─────────┘└─────────┘\n" //9 "┌────────────────────┐\n" //10 "│ │\n" //11 "└────────────────────┘"); //12 resetcolor(); }
      
      





また、例として、print_port_bits関数をソートします。



 void print_port_bits (unsigned char port) { int i; unsigned char maxPow = 1<<(8-1); set_display_atrib(B_BLUE); set_display_atrib(BRIGHT); for(i=0;i<8;++i){ // print last bit and shift left. gotoxy(2,2 + i); if (port & maxPow) { set_display_atrib(F_GREEN); printf("pin%d= on ",i); } else { set_display_atrib(F_RED); printf("pin%d= off",i); } port = port<<1; } resetcolor(); }
      
      





符号なしバイトを取ります。 テキストの属性(太字、背景は青)を設定し、ビットを交互に表示します。それぞれがgotoxyマクロ(2,2 + i)を使用して独自の位置にあります。 また、ビットがゼロか1かに応じて、テキストをそれぞれ赤または緑に色付けします。



プログラムの結果は、コードと同様に自分で確認する方が良いです。 しかし、プログラムをgitするのが面倒で、それがどのように機能するかを見たいだけの人のために、私は仕事のgifを持ってきます:











私が注意したいのは、すべての位置が#defineで示されており、ある位置から計算されることが最善であるということです。 したがって、すべてのコードを耕すことなく、1つの場所でマクロを変更するだけで、データ出力を適切な場所に移動できます。



合計



エスケープシーケンスを使用して、ターミナルウィンドウのサイズ、マウスクリックイベントなどを取得することもできます。 彼女を混乱させないために、この記事では特にこれらの例を引用しませんでした。 これらの例を自分で見つけることができます。 Linux用のプログラムには、一般に、端末制御、エコー表示、速度などのあらゆる種類の便利な機能があります。



私の意見では、端末プログラムとの相互作用のメカニズムを知ることは必要かつ有用です。 特に、COMポートとその派生物を使用してプログラムのデバッグが最も頻繁に実行されるコントローラーおよび組み込みソリューションの開発者向け。



便利なリンク:



1. Linuxコンソールのエスケープとエスケープシーケンス

2. コンソールと色属性に関するすべてを例で色付けする方法

3. この記事のサンプルプログラム

4. bashスクリプトでイースターエッグを作成する例



All Articles