DIY KVM IP 2.0

今回は、前の記事のデバイスの一種の「バグ修正」を紹介します。 別の実装オプションについては、 次を参照してください。



結果として生じた自転車を見て、考えを思いつき、できるだけ多くの欠点を修正しました。 すなわち:





動画から特別なことは何もできなかったとすぐに言います。私たちは自分の持っているものに満足しなければなりませんが、悲しいことについては話しません。



そして、私たちは、きれいな手、冷たい頭、暖かい心を持って進みます。 コンポーネントは、Raspberry PIの代わりに劇的に変更されました。OrangePIを使用し、Arduino UNOの代わりに、前の記事で説明したまさにチップ(Atmega16u2)のみを使用します。



コンポーネントの数は変更されていません。



1. UVCビデオキャプチャボード:







2. VGA to AVコンバーター:







私はこれで別のコンバーターを試しました:







しかし、奇跡は起こらず、ビデオ品質は向上しませんでしたが、その逆もありませんでした。



3. Atmega16u2:







4.私の場合のオレンジPI、オレンジpi PCモデル:







このマイクロコンピューターについて一言。 Allwinner H3プロセッサ(AWPアーキテクチャに基づく安価な4コアプロセッサ)、1ギガバイトのRAM 3 USB、HDMIなどに基づいており、完全な説明はインターネット上で見つけることは難しくありません。



準備段階



Orangepiにオペレーティングシステムをインストールする



ここにフォーラムへのリンクがあります。このフォーラムスレッドには多くの有用な情報があります。もちろん、すべてが英語であり、OrangePI-PC_Ubuntu_Vivid_Mate.imgディストリビューションに興味があります。mega.nzまたはGoogleドライブからダウンロードできます。 ヘッダーに「メガまたはGoogleドライブからダウンロード」という行があります。リンクをクリックしてダウンロードします。



イメージをUSBフラッシュドライブに転送する手順は、ラズベリーの場合と同じです。Windowsでは、ddコマンドを使用してLinuxでwin32ディスクイメージャーライターを使用できます。



小さな余談。 オレンジパイや、Allwinnerの中国のプロセッサで構築された同様のマイクロコンピューターは、ハードウェア(ハードウェア)ではなく、ソフトウェア(ソフトウェア)、より正確にはOS機能と「完全性」という点で、ラズベリーよりかなり劣っています。 最適化されたファイルシステムではなく、機能が低下したカーネル、膨大な数のバグ、これがすべての問題ではありません。 この状況は、プロセッサの製造元が最初はAndroidを実行するタブレット(スマートフォンも含む)に焦点を当てていたために発生しました。製造元の観点からは、完全なLinuxディストリビューションには明らかに経済的実現性がなかったため Linuxカーネルは、原始的な行動しかできない野菜に変わった生涯から、まさにトマトのために削減されました。 長い間、AndroidのコアにLinuxディストリビューションがあり、おそらく安価なマーケティングの動きのようなものだったので、愛好家のためではないとしても、それは続けられていたでしょう。



しかし、ラムに戻りましょう。 配布が記録され、システムが実行されています。



モーションをカスタマイズする



コンソールに移動します。 orangepi



root



またはroot



orangepi



パスワード



パッケージの更新:



 sudo apt-get update && sudo apt-get upgrade –y
      
      





モーションをインストール



前の記事と同様のすべての設定:



記事の断片
 sudo apt-get install motion -y
      
      





自動実行構成を編集します。



 sudo nano /etc/default/motion
      
      





start_motion_daemon



「yes」を設定します。 変更を保存しますCtrl + x、y、Enter。



モーション自体の構成を編集します(a):



 sudo nano /etc/motion/motion.conf
      
      





パラメーター値を次のように変更します。



このパラメーターは、アプリケーションをサービスとして起動することを定義します。



 daemon on
      
      





これらのパラメーターは、送信される画像の解像度を決定します。より高い解像度を設定しても意味がありません。 ビデオキャプチャはPALまたはSECAM標準に制限され、その解像度は720x576です。 これは偶然に迷惑な欠陥ですが、それについては後で詳しく説明します。



 width 800 height 600
      
      





フレームレート:



 framerate 25
      
      





スクリーンショットの保存を無効にします。



 output_normal off
      
      





画像伝送品質:



 webcam_quality 100
      
      





フレームレート:



 webcam_maxrate 25
      
      





他のIPからの接続に関する制限の削除



 webcam_localhost off
      
      





変更を保存しますCtrl + x、y、Enter。



コンソールはまだ閉じていません。



コンパイル準備



制御を移すために、プログラムを作成します。すべてを以下で詳細に説明し、その間に基本的な準備を行います。



コンパイルに必要なものをすべてインストールします。プログラムはCになります。



 sudo apt-get install build-essential -y
      
      





ncursesライブラリをインストールし、キー値をキャプチャします。



 sudo apt-get install ncurses -y
      
      





次のように記述できるように、シリアルポートの所有者になります。



 sudo chown orangepi /dev/ttyS2
      
      





エディターでカーネルモジュールのロード構成を開きます。



 sudo nano /etc/modules
      
      





gpio-sunxi



コメントを解除します。 このアクションで、gpio、またはむしろそれを操作するためのモジュールをアクティブにします。これについては後で説明します。



自動実行の編集:



 sudo nano /etc/rc.local
      
      





次のchown -R orangepi /sys/devices/platform/*



exit



行の前に追加します。 このコマンドは、orangepiユーザーをGPIOポートとの対話を担当する仮想ファイルの所有者にします。



理論的には、グループを作成し、権利を割り当て、ユーザーをグループに追加する方が正しいのですが、これはすべてデモモデルです(よく知られている漫画のキャラクターを思い出します)。 もちろん、私はあなたがすべきことをすべてすることを決して禁じません。



変更を保存して再起動します。



 sudo reboot
      
      





ハードウェアについて少し話しましょう。



Atmega16u2



制御を移すために、追加のマイクロコントローラーとArduinoIDEを使用せずにAtmega16u2チップを直接使用することが決定され、マイクロコンピューターで直接実行可能コードを実行します。



前の記事で、アルデュインのロジックを分析します。



キー値は、シリアルポートを介してAtmega328pマイクロコントローラー(Arduino UNO上の大きな長方形のチップ)に送信され、HIDKeyboard.hで指定された配列から、いわゆる「USB HIDキーボードキーコード」がAtmega16u2マイクロコントローラーに(再びシリアルポートを介して)送信されましたUSBを介してターゲットコンピュータに送信されます。 シリアル→Atmega328p→シリアル→Atmega16u2→USB



一般に、Atmega328pは仲介者の役割を果たしました。もちろん、これを削除することは論理的です。これを行うため、Orangepiの下のアルドゥイン向けのコードを書き直し、Atmega16u2を直接接続します。



当然、裸のマイクロ回路は使用できません;少なくとも最小限のバインディングが必要です。

このリンクのレビューを読むことをお勧めします。





ご覧のように、このスキームは初心者でも簡単に対処できます。ヒンジ取り付けで不要な要素は多くありません。空中に垂れないように水晶振動子を固定することをお勧めします。 ところで、発電機は、回路から突然はっきりしない場合、16メガヘルツでなければなりません。 また、ATmega32u2の回路がATmega16u2およびATmega8u2にも適しているという事実に注意を払ってはなりません。



Arduino UNOボードを使用している場合は、それを使用できます。連絡先tx-No. 0、rx-No. 1に接続する必要があります。Atmega328pmikruhaを取り外して、無駄に電力を消費せず、シリアルポートエーテルを詰まらないようにすることをお勧めします。



ロジックレベルについて思い出す必要はありません。すべては前の記事と同じです。シリアルポートOrange PIはRaspberry PIと3.3ボルトで同様に動作し、電圧の整合が必要です。



ATmega16u2ファームウェアの場合、 リセット脚を地面で1秒間閉じ、ファームウェアをフリップで埋める必要があります。



私は詳細に説明しません、それはすでに最後でした。 これで準備は終わりました。ビジネスに取り掛かりましょう。



プログラムを書く



キーを転送し、コンバーターをリモートで制御するために、小さなプログラムを作成します。



理論



最初は、UNO-HIDKeyboard-Libraryからソースを移植するだけで急ぎました。これは、前回使用したArduino IDEのライブラリ(HIDKeyboard.cppおよびHIDKeyboard.hファイル)ですが、この機能はアイデアには十分ではありませんでした。



Linux-Remote-HIDKeyboardを紹介しますが、その名前はまあまあですが、テキストLRHIDKeyboard.cppまたはrkeysend(コンパイル済みバイナリ)で後で呼び出す必要がありました。



ソースコードは、LRHIDKeyboard.cppとHIDKeyboard.hの2つのファイルで構成されます。 HIDKeyboard.hは、UNO-HIDKeyboard-Libraryの同じヘッダーファイルです。 配列は「USB HIDキーボードキーコード」に変換するためにこのファイルに格納されます。エラーを修正して配列を拡張する自由を取り、HIDKeyboard.cppとの互換性が保持されたため、必要に応じてArduinsに使用できます。



USB HIDキーボードキーコード-これらはUSBを介して送信されるキーのキーです。詳細については、 こちら (pdf)を参照してください。



ヘッダーファイルHIDKeyboard.hには2つの配列があります。最初の配列は通常のキーを定義するためのもので、2番目の配列はシフトキーを持つキー用です。 端末からのキャプチャ中に取得された10進数は、配列要素の番号と比較され、「0x7f」(16進数)のような要素に置き換えられます。 たとえば、「a」キーの値は10進数の「4」または16進数の「04」、「ESCAPE」キーは10進数の「41」または16進数の「29」です。16進数がキーを押すことを示すためにマイクロサーキットに送信されます。



練習する



Orangepiコンソールを開き、次のようにプログラムを保存するディレクトリを作成します。



 cd ~ mkdir PROG cd PROG
      
      





HIDKeyboard.h



およびLRHIDKeyboard.cpp



作成しLRHIDKeyboard.cpp







 touch HIDKeyboard.h touch LRHIDKeyboard.cpp
      
      





HIDKeyboard.hエディターで開きます。



 nano HIDKeyboard.h
      
      





リストの内容をコピーします。



HIDKeyboard.hのリスト
 #ifndef HIDKeyboard_h #define HIDKeyboard_h //#include "Arduino.h" /**************************************************************************** * SPECIAL CHARACTER DEFINES * * These are the HID values for keys that do not output characters * ****************************************************************************/ // HID Values of Function Keys #define F1 0x3a #define F2 0x3b #define F3 0x3c #define F4 0x3d #define F5 0x3e #define F6 0x3f #define F7 0x40 #define F8 0x41 #define F9 0x42 #define F10 0x43 #define F11 0x44 #define F12 0x45 // HID Values of Special Keys #define ENTER 0x28 #define ESCAPE 0x29 #define BACKSPACE 0x2a #define TAB 0x2b #define SPACEBAR 0x2c #define CAPSLOCK 0x39 #define PRINTSCREEN 0x46 #define SCROLLLOCK 0x47 #define PAUSE 0x48 #define INSERT 0x49 #define HOME 0x4a #define PAGEUP 0x4b #define DELETE 0x4c #define END 0x4d #define PAGEDOWN 0x4e #define RIGHTARROW 0x4f #define LEFTARROW 0x50 #define DOWNARROW 0x51 #define UPARROW 0x52 // HID Values of Keypad Keys #define NUMLOCK 0x53 #define KEYPADSLASH 0x54 #define KEYPADSTAR 0x55 #define KEYPADMINUS 0x56 #define KEYPADPLUS 0x57 #define KEYPADENTER 0x58 #define KEYPAD1 0x59 #define KEYPAD2 0x5a #define KEYPAD3 0x5b #define KEYPAD4 0x5c #define KEYPAD5 0x5d #define KEYPAD6 0x5e #define KEYPAD7 0x5f #define KEYPAD8 0x60 #define KEYPAD9 0x61 #define KEYPAD0 0x62 #define KEYPADPERIOD 0x63 // HID Values of System Keys #define KEYBOARDAPPLICATION 0x65 #define KEYBOARDPOWER 0x66 #define VOLUMEMUTE 0x7f #define VOLUMEUP 0x80 #define VOLUMEDOWN 0x81 // Common-use modifiers #define LCTRL 0x01 #define SHIFT 0x02 #define ALT 0x04 #define GUI 0x08 /**************************************************************************** * * ASCII->HID LOOKUP TABLE * * Taken from the HID Table definition at * http://www.usb.org/developers/devclass_docs/Hut1_11.pdf * * This array maps the ASCII value of a type-able character to its * corresponding HID value. * * Example: * 'a' = ASCII value 97 = HID value 0x04 * HIDTable['a'] = HIDTable[97] = 0x04 * * NOTE: * "Shift Modified" HID values are the same as the non Shift-Modified values * for any given character, eg the HID value for '2' is equal to the * HID value for '@'. The Shift-Modified value is sent by setting the * modifier value (buf[0]) to the corresponding modifier value in the * modifier table. * ****************************************************************************/ const static uint8_t HIDTable[] = { 0x00, // 0 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2A, 0x2b, 0x28, // 10 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 20 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x29, 0x00, 0x00, 0x00, // 30 0x00, 0x2c, 0x1e, 0x34, 0x20, 0x21, 0x22, 0x24, 0x34, 0x26, // 40 0x27, 0x25, 0x2e, 0x36, 0x2d, 0x37, 0x38, 0x27, 0x1e, 0x1f, // 50 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x33, 0x33, 0x36, // 60 0x2e, 0x37, 0x38, 0x1f, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, // 70 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, // 80 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, // 90 0x2f, 0x31, 0x30, 0x23, 0x2d, 0x35, 0x04, 0x05, 0x06, 0x07, // 100 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, // 110 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, // 120 0x1c, 0x1d, 0x2f, 0x31, 0x30, 0x35, 0x4c, 0x00, 0x00, 0x00, // 130 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 140 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 150 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 160 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 170 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 180 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 190 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 200 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 210 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 220 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 230 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 240 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 250 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x51, 0x52, 0x50, // 260 0x4f, 0x4a, 0x2a, 0x00, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, // 270 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x00, 0x00, 0x00, 0x00, // 280 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 290 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 300 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 310 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 320 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4c, // 330 0x49, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4e, 0x4b, 0x00, // 340 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 350 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4d, // 360 }; /**************************************************************************** * * ASCII->MODIFIER LOOKUP TABLE * * Looks up whether or not the HID report should use the SHIFT modifier. * * Example: * The character '2' and the character '@' have different ASCII values but * the same HID value. This table uses the ASCII value to determine if * we should hold shift while sending the key. eg: * * HIDTable['2'] = 0x1f and modifierTable['2'] = 0 * HIDTable['@'] = 0x1f and modifierTable['@'] = SHIFT * * There's probaly a better way to do this, but it's functional. * ****************************************************************************/ const static uint8_t modifierTable[] = { 0x00, // 0 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 10 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 20 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 30 0x00, 0x00, SHIFT, SHIFT, SHIFT, SHIFT, SHIFT, SHIFT, 0x00, SHIFT, // 40 SHIFT, SHIFT, SHIFT, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 50 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, SHIFT, 0x00, SHIFT, // 60 0x00, SHIFT, SHIFT, SHIFT, SHIFT, SHIFT, SHIFT, SHIFT, SHIFT, SHIFT, // 70 SHIFT, SHIFT, SHIFT, SHIFT, SHIFT, SHIFT, SHIFT, SHIFT, SHIFT, SHIFT, // 80 SHIFT, SHIFT, SHIFT, SHIFT, SHIFT, SHIFT, SHIFT, SHIFT, SHIFT, SHIFT, // 90 0x00, 0x00, 0x00, SHIFT, SHIFT, 0x00, 0x00, 0x00, 0x00, 0x00, // 100 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 110 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 120 0x00, 0x00, SHIFT, SHIFT, SHIFT, SHIFT, 0x00 // 127 }; class HIDKeyboard { public: // Constructor HIDKeyboard(); // Public functions void begin(); // Starts the required serial communication (9600 baud) void pressKey(uint8_t modifier, uint8_t key); // Looks up key in HIDTable and sends with a modifier void pressKey(uint8_t key); // Sends key report without modifier (modifier = 0) void pressSpecialKey(uint8_t modifier, uint8_t specialKey); // Sends specialKey with a modifier void pressSpecialKey(uint8_t specialKey); // Sends specialKey without modifier void releaseKey(); // Releases keys (clears key and modifier) void print(char* sequence); // Prints string <sequence> void println(char* sequence); // Prints string <sequence> followed by a carriage return private: // HID report buffer uint8_t buf[8]; // In report, buf[0] = modifier and buf[2] = key HID value }; #endif
      
      







Ctrl + x、y、Enterを保存



そしてまた:



 nano LRHIDKeyboard.cpp
      
      





リストの内容をコピーします。



LRHIDKeyboard.cppのリスト
 #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <fcntl.h> #include <errno.h> #include <termios.h> #include <time.h> #include <ncurses.h> #include "HIDKeyboard.h" char myport[] = "/dev/ttyS2"; //  serial port     //        char nul[] = ""; char menu[] = "/sys/class/gpio_sw/PA14/data"; // char zoom[] = "/sys/class/gpio_sw/PD14/data"; // char kup[] = "/sys/class/gpio_sw/PC4/data"; // char kdn[] = "/sys/class/gpio_sw/PC7/data"; // char klf[] = "/sys/class/gpio_sw/PG8/data"; // char krt[] = "/sys/class/gpio_sw/PA21/data"; // uint8_t buf[8] = { 0 }; /* Keyboard report buffer */ int open_port(char *devname) // serial port { int fd; fd = open(devname, O_RDWR | O_NOCTTY | O_NDELAY); if(fd == -1) // { printw("Port is not open! %s" , devname); return -1; } else { fcntl(fd, F_SETFL, 0); printw("Open port %s", devname); } //  struct termios port_settings; cfsetispeed(&port_settings, B9600); cfsetospeed(&port_settings, B9600); port_settings.c_cflag &= ~PARENB; port_settings.c_cflag &= ~CSTOPB; port_settings.c_cflag &= ~CSIZE; port_settings.c_cflag |= CS8; tcsetattr(fd, TCSANOW, &port_settings); return(fd); } int alt_check(int check) //   ALT,     ALT,   "0" { if(check == 27) { nodelay(stdscr,TRUE); check = getch(); if (check == -1) return ESCAPE; //     Esc nodelay(stdscr,FALSE); return check; } //else return 0; return 0; } int hot_key(int fd, int alt, int vchar) // { if(alt != 0) { if (alt == 330) // "Alt" + "Delete"  Ctrl + Alt + Delete { vchar = 0; buf[0] = 0x04|0x01; buf[2] = HIDTable[alt]; write(fd, buf, 8); return 0; } if (alt == 114) // "Alt" + "r"  Win + r { vchar = 0; buf[0] = 0x08; buf[2] = HIDTable[alt]; write(fd, buf, 8); return 0; } if (alt == 52) // "Alt" + "4"  Alt + F4 { vchar = 0; buf[0] = 0x04; buf[2] = 0x3d; write(fd, buf, 8); return 0; } if (alt == 116) // "Alt" + "t"  Alt + Tab { vchar = 0; buf[0] = 0x04; buf[2] = 0x2b; write(fd, buf, 8); return 0; } if (alt == 44) // "Alt" + ","  Alt + Shift { vchar = 0; buf[0] = 0x04|0x02; write(fd, buf, 8); return 0; } if (alt == 46) // "Alt" + "."  Ctrl + Shift { vchar = 0; buf[0] = 0x01|0x02; write(fd, buf, 8); return 0; } } else { if (vchar == 17) //   "Ctrl" + "q" { endwin(); exit(0); } //  *nul = '\0'; if (vchar == 28) strcpy(nul, menu); // "Ctrl" + "\" if (vchar == 31) strcpy(nul, zoom); // "Ctrl" + "/" if (vchar == 566) strcpy(nul, kup); // "Ctrl" + "up" if (vchar == 525) strcpy(nul, kdn); // "Ctrl" + "down" if (vchar == 545) strcpy(nul, klf); // "Ctrl" + "left" if (vchar == 560) strcpy(nul, krt); // "Ctrl" + "right" FILE *f = fopen(nul, "w"); //  if (f != '\0') { fwrite("1", 1, 1, f); int wrt = fclose(f); //   usleep(70000); if (wrt == 0) { FILE *f = fopen(nul, "w"); fwrite("0", 1, 1, f); fclose(f); } else printf("error write file: %s", nul); return 0; } return vchar; } } int send_key(int fd, int altkey, int getkey) //  { if (altkey == ESCAPE) { buf[0] = 0x00; buf[2] = 0x29; write(fd, buf, 8); return 1; } if (altkey != 0) { buf[0] = 0x04; buf[2] = HIDTable[altkey]; write(fd, buf, 8); return 1; } else { if (getkey == 0) return 0; //printf("KEY NAME : %s - %d\n", keyname(getkey),getkey); //  buf[0] = modifierTable[getkey]; buf[2] = HIDTable[getkey]; write(fd, buf, 8); return 1; } return(-1); } int release_key(int fd) //    { buf[0] = 0; buf[2] = 0; write(fd, buf, 8); } int main(void) { initscr(); keypad(stdscr,TRUE); //    raw(); //   int fd = open_port(myport); printw("\nHOT KEYS: Alt + Delete = Ctrl + Alt + Delete Alt + r = Win + r Alt + 4 = Alt + F4 Alt + t = Alt + Tab Alt + , = Alt + Shift Alt + . = Ctrl + Shift"); printw("\nGPIO: MENU = Ctrl + \\ ZOOM = Ctrl + / UP = Ctrl + up DOWN = Ctrl + down LEFT = Ctrl + left RIGHT = Ctrl + right"); printw("\n Exit = Ctrl + q"); move(10,1); refresh(); while (fd != -1) { int pkey = getch(); int alt = alt_check(pkey); int hot = hot_key(fd, alt, pkey); send_key(fd, alt, hot); release_key(fd); } endwin(); }
      
      







Ctrl + x、y、Enterを保存します。



コンパイル中



 g++ LRHIDKeyboard.cpp -o rkeysend -lncurses
      
      





rkeysendは、コンパイル中に取得された実行可能ファイルの名前です

-端末のキーをキャプチャし、同じ端末にテキストメッセージを送信するために使用されるncursesライブラリをコンパイルするときの-Incurses接続。



コンパイルが成功したら、GPIOポートに進むことができます。



コンバーター管理



「新しくコンパイルされた」プログラムは、キーを転送するだけでなく、コンバーターを制御することもできます。 理由を説明します。 まず、画像、明るさ、コントラスト、シャープネスなどを調整できます。 第二に、コンバーターから受け取った画像の解像度= 720x576について既に書きました。 そのため、コンバーターには画像の一部のみを表示するモードがありますが、解像度は変更されません。つまり、このモードを使用して、画像のより詳細を考慮することができます。



コンバーターはGPIOによって制御されます。 GPIOは確かに汎用入力/出力を既に知っていますが、ロシア語の場合、マイクロコンピュータが外部世界とやり取りする一種の方法であるウィキペディアの「汎用入力/出力インターフェイス」のかなり正確な定義が好きでした。



Orangepi PCをコンバーターに接続します



そして、コンバーターをGPIOに接続します。 コンバーターには物理制御ボタンがあります:左、右、下、上、メニュー、ズーム。 これらは、図のように次の原則に従って接続されます。 この図は、ボタンの機能のみを示しています。









コンバーターにはポートがあり、電圧を測定し、目的のレベルに応じて、メニューを開く、画像を拡大する、画像を移動するなどのアクションを実行します。



ボタンを制御するために、光入力AOT128Aを備えたバイポーラトランジスタを使用しました。









トランジスターのエミッターとコレクターは、グランドとボタンの接点にはんだ付けされています。 トランジスタのカソードをグランドに接続(はんだ付け)します。 トランジスタのアノードは、33オームの抵抗を介して目的のGPIOポートに接続されます。





何かを変更する場合、覚えておいてください:



このトランジスタのアノードの制御電圧は1.6V以下であり、この値を超えると、トランジスタが非常に加熱し始め、熱破壊が発生する可能性があります。 Orangepiとコンバーターに同じ電源を使用することをお勧めします。そうしないと、電位差により画像が変わる場合があります。



トランジスタのアノードを次のGPIOポートに接続します: PA14-メニュー、 PD14-ズーム、 PC4-上部、 PC7-下部、 PG8-左、 PA21-右。



ATmega16u2チップを接続するためのシリアルポートは、ポート11(RX)および13(TX)にあります。 画像のように接続します



さて、すべてが接続されました。 最初は、単一のポートを使用して1つの電界効果トランジスターでコンバーターを制御したかったのですが、どういうわけかうまくいかず、PWMリップルがトランジスターに伝達され、その結果抵抗がフロートし始め、フィルター回路を平滑化するオプションがありますが、これは設計を非常に複雑にします SPIまたはI2Cを介してデジタルポテンショメータを使用するオプションがまだあります。すべてはすでに手元にあります。



打ち上げ



すべてが正しく接続されているかどうかを確認します。



  1. Orangepi GPIOからコンバーター
  2. VGAからコンピューターへのコンバーター(スレーブ)
  3. ビデオキャプチャカードのAV入力へのAV出力コンバーター
  4. USBpi USBpiキャプチャカード
  5. OrangepiからATmega8U2 / 16U2 / 32U2チップ
  6. チップATmega8U2 / 16U2 / 32U2をUSB経由でコンピューター(スレーブ)経由で
  7. SSH経由のOrangepiへのコンピューター(マスター)


プログラムを実行する



Ha Orangepiは、コンパイルされたプログラムを起動します。開いているシリアルポートとキーの組み合わせを示す碑文が表示されます。 そのようなもの。







タスクマネージャーを呼び出したり、レイアウトを変更したりするキーボードショートカットがあります。たとえば、「Alt + Del」と入力する必要があるターミナルで「Ctrl + Alt + Del」を押すと、プログラムがターミナルウィンドウの上部から起動するときに可能な組み合わせが書き込まれます。



前の記事と同様に、ビデオはモーションによってブロードキャストされ、 orangepi:8081



で入手できます。 さて、それで、経験を繰り返すために必要なすべての情報が述べられ、ミッションが完了しました。



要約すると:



ビデオ転送



ビデオはAV入力を介して送信されるため、非常に低品質のままでしたが、コンバーターのリモート制御が可能になり、メニューで目的のアイテムを選択すると、同じ解像度で部分的に画面を見ることができます。



ビデオの品質に関する問題には可能な解決策がありますが、唯一の大きな欠点は価格です:



1. Velocap U2m USB 2.0 HDMI

2. UVC USB 3.0 HDMI



私はこれらのオプションを試したことがありません。なぜなら高価だからです。記事を読んだ人の誰かがチャンスをつかむかもしれません。

おそらくマイコンボードを節約してOrangepi PCをOrangepi oneまたはOrangepi Zeroに変更できます。そのコストは約500ルーブルです。 しかし、Orangepi Zeroには問題がある可能性があります。それぞれ異なるプロセッサ、異なるカーネルの異なるディストリビューションがあり、必要なドライバーとモジュールが利用できない可能性があります。たとえば、マザーボードの電源とリセットの接点を閉じるためにリレーを接続することもできます。



売上原価



VGA-AVコンバーターは約700ルーブルです。

ビデオキャプチャカードは約500ルーブルです。

Orangepi PC約1000rub。

ATmega8U2 / 16U2 / 32U2約150rub。



合計: 2350こする。



さて、この記事を読んだすべての人のおかげで、この記事は終わりました。 実際にあなたが成功することを願っています。 計画していたすべてを実行することはできませんでしたが、結果は興味深いもので、特にそのような価格でした。 もちろん、出来上がったデバイスには改良が必要ですが、まだ存在する権利があると思います。 すべてのベストプラクティスを、保証なしに、良い手でそのまま提供します。 ご清聴ありがとうございました!



All Articles