emWin VNCサーバー

## VNCサーバー
6.8
　mWin VNCサーバーは組み込み機器の管理や他の目的にも使用できます
圧縮エンコーディングをサポートしています (hextile) 
VNCはバーチャル・ネットワーク・コンピューティング（Virtual Network Computing）の略称です
クライアント・サーバー方式に基づく，シンプルなディスプレイ・プロトコルによってユーザーはインターネットを通してどこからでも，どのようなアーキテクチャのマシンからでも，TCP/IP通信を通して画面表示とデスクトップ環境の制御が行えます
言い換えると:
組み込みデバイスのディスプレイ・コンテンツはクライアント・ソフトを使用するコンピュータで見ることが出来ます (例えばPC);
マウスやキーボードによる操作も可能です
この機能はemWinシミュレーションで使用可能です．トライアル版でも使えます
emWin VNCサポートは基本パッケージに付属せず，単独で提供される場合もあります
VNC supportはemWinカラーを必要とします
ファイルシステムが有効な場合，クライアントとターゲット間でemWin VNCクライアントを使ってファイル転送ができます

### イントロダクション
　VNCは2つのコンポーネントを含みます
画面を生成するサーバーと，実際にディスプレイに描画を行うビューワーです
リモートマシン (ターゲットもしくはシミュレーション)は閲覧されるだけではありません．マウスとキーボード操作で制御されます
サーバーとビューワーは，別なアーキテクチャーの別々なマシンの場合もあります
サーバーとビューワーを接続するプロトコルは (RFB V3.3) シンプルです．オープンでプラットフォームに依存しないものです
ビューワーに状態は保存されません
サーバーとビューワーの接続が切れたあとの再接続でどのようなデータ消失も起こしません
どこかで再度接続されますので，ユーザーは移動も可能ですVNCサーバーを使うと，どこからでもターゲットデバイスを制御でき，好きなタイミングでスクリーンショットを取ることができます(例えば手動で)

#### ファイル転送
　RFB V3.3の通常の機能に加えて，emWin VNCサーバーはファイル転送をサポートします
ファイル転送はRFBプロトコルの規約には含まれないことに注意して下さい
ファイル転送がサポートされるクライアントはemVNCだけです．
RFBプロトコルに標準的なファイル転送方法はありません
したがって，emVNCクライアントのみと共に機能する，非標準的なプロトコル拡張を必要とします
emVNCはemWin VNCサーバーとクライアント・マシンの間でだけファイル転送を行えます

#### 必要事項
TCP/IPスタック
サーバーとビューワー間の通信はTCP/IP接続に基づくため，VNCはTCP/IPスタックを必要とします
Win32シミュレーション環境では，TCP/IP (Winsock)は通常存在します
ターゲットにもTCP/IPスタックが必要になります
TCP/IPスタックはemWinには含まれません
柔軟なインターフェースによって，どの様なTCP/IPスタックでも使用できます
マルチタスク
VNCサーバーは独立したスレッドで動作させる必要があります
したがってemWin VNCサーバーはマルチタスク・システムを必要とします
ファイルシステム(ファイル転送の場合のみ)
ファイル転送機能を使用する場合のみ，ファイルシステムを必要とします

emWin VNCサーバーはポインタ―・イベントメッセージとキーボード・イベントメッセージをサポートします

エンコード
サーバーはrawエンコーディング及び，hextileエンコーディングをサポートします

性能
　多くのビューワーは，descent圧縮をサポートするhextileエンコーディングをサポートします
典型的な1/4 VGA スクリーンは標準で 20 - 50 Kバイトのデータを必要とします
サーバーは増分（インクリメンタル）アップデートを処理します
多くのケースで書き換える画面領域は全体ではなく同じ部分なので，送信すべきデータは小さくなります
次の表に性能一覧を示します

ハードウェア | コンフィグレーション | ms / screen
---|---|---
STM32F4, 168MHz, internal RAM, WQVGA, 16bpp | HexTile | 32 ms
STM32F4, 168MHz, internal RAM, WQVGA, 16bpp | Raw | 76 ms
ARM7, 50MHz, external RAM cached, QVGA, 16bpp | HexTile | 250 ms

マルチサーバー
　完全にスレッドセーフでリエントラント可能な実装です
複数のVNCサーバーを同じCPUでディスプレイのレイヤー別に実行可能です
ターゲットが複数のディスプレイもしくはレイヤーを持っている場合，これはとても便利です(of course the same holds true for the simulation) 
1度に1つのレイヤーに1つのVNCサーバー;
ビューワーとの接続が終わったら，他のものと接続可能です

### emVNCクライアント
　emVNCクライアントはemWin基本パッケージに含まれます．toolsフォルダにemVNC.exeとして入っています
MS WindowsからVNCサーバーにVNC接続を確立できます
ビューワーはRFBプロトコル 3.3を使います
これはemWinを含む異なるVNCサーバーでテストされています．TightVNCやRealVNCと同じようにです

#### VNCサーバーとの接続
　emVNCが開始されると，接続するためにVNCサーバーのネットワーク・アドレスの入力を求められます

同じPCを使ったシミュレーションによるVNCサーバーとの接続 
ローカルホストで動作するVNCサーバーにアクセス可能です
ローカルホスト
テキストコントロール（プロンプト？）が空の時に，<RETURN>キーか“Connect”ボタンを押すとローカルホストと接続されます
異なるPCやターゲットで動作するVNCサーバーとの接続するにはネットか名前を入力します
192.168.1.14 もしくは Paul02
さらに特定のサーバーに接続するために，サーバー・インデックスを指定する場合もあります
192.168.1.14:1 もしくは Paul02:1
スクリーンショット
次のスクリーンショットはビューワーを示します
シミュレーションとの接続
ターゲットとの接続

#### ファイル転送ダイアログを開く
　VNCクライアントの常に表示されているメニューバーに加えて，ファイル転送ダイアログを開くためのシステム・メニューを追加しました

システムメニューはemVNCシンボルの左上をクリックするかキーボードショートカットの<ALT>+<SPACE>で開きます

メニューオプションの’Open file transfer window’は接続したサーバーが，ファイル転送サポートを開始している場合のみ有効です

#### ファイル転送ウィンドウ
　ファイル転送ウィンドウは，サーバー側とクライアント側に分かれています
これは両方の現在選択されたディレクトリの内容を示しています
以下の操作が可能です:
ファイル選択(複数)
<STRG>を押したまま，シングルクリックで複数ファイル選択，もしくは<STRG>を押したまま目的のファイルまで<UP>か<DOWN>でカーソルを移動し， <SPACE>を押す
1つのファイル送信
ファイルをダブルクリックすると1つのファイルを転送します
選択されているファイルを送信
>>ボタンと<<ボタンを使ってスタートできます．クライアントからサーバーは>>．サーバーからクライアントは<<です
選択されているファイルを削除
Deleteボタンで，サーバーもしくはクライアントの選択されているファイルを削除できます
再読み込み
Refreshボタンを押すとコンテンツを再読み込みします

ファイル転送ウィンドウを閉じる
<ESC>を押すかクローズボタンを押す

### emWin VNCサーバー
#### emWin VNCサーバーの開始
VNCサーバーを開始するにはGUI_VNC_X_StartServer()関数を呼びます

```
void MainTask(void) {

GUI_Init();

  GUI_VNC_X_StartServer(0,   // Layer index  0);  // Server index
  ...
}
```

　上記の関数コールは接続にそなえ，5900番ポートをリッスンするスレッドを生成します
接続が確認された後，GUI_VNC_Process()が呼ばれます
ポート
VNCサーバーはポート590xをリッスンします．xはサーバーインデックスです
ほとんどのPCサーバーでは，ディスプレイはデフォルトの0なのでポートは5900になります

#### ファイル転送サポートの有効化
　GUI_VNC_X_StartServer()の代わりにGUI_VNC_X_StartServerFT()を呼ぶことで，ファイル転送は有効になります
VNC-threadタスクの開始に加えて，それは関数アクセスのポインタを含むAPIテーブルを設定します
さらにファイル転送に必要なRFBプロトコル拡張を有効にします

#### シミュレーションでのVNCサーバーの開始
　シミュレーション・ライブラリでアプリケーション・コードから呼び出す必要のあるGUI_VNC_X_StartServer()関数の実装が準備されています
生成したスレッドで接続してくる相手が発見されるまでポート590xをリッスンし，実際のサーバー実装であるGUI_VNC_Process()を呼びます

#### ターゲットシステムでのVNCサーバー開始の例
　ターゲットでVNCサーバーを使うために，GUI_VNC_X_StartServer()かGUI_VNC_X_StartServerFT()の実装が必要です．それらは 有効な IPライブラリと共に機能します．ファイル転送を行う時，ファイルシステムも必要です
embOS/IPやemFileと共に，その機能の実装を使う方法のサンプルは，Sample\GUI_X\GUI_VNC_X_StartServer.cにあります
このサンプルでは，GUI_VNC_CONTEXT構造体にメモリを割り当てるための，ダイナミックアロケーションは使っていません．この実装では1つのサーバーのみ有効です
このサンプルはembOS/IPとemFile以外のライブラリを使うために調整を行うスターティングポイントとして有用です
このケースで必要になる調整は少ないです

### 必要なRAMとROM
ROM
ARM7の場合，hextileエンコーディングで約4.9 KB．hextileエンコーディング無しで約3.5KB
RAM
VNCサポートはスタティックなデータを使用しません
GUI_VNC_CONTEXT構造体の各インスタンスは約60バイトを使用します

その他
それぞれのインスタンスは1つのTCP/IPソケットとスレッドを必要とします

### VNCサーバーAPI
　以下の表にVNC関係の関数をアルファベット順で示します
詳細
function descriptions follow:
関数

処理 | 内容
---|---
GUI_VNC_AttachToLayer() | VNCサーバーに1つのレイヤーをアタッチする．マルチレイヤ―・コンフィグレーションでない場合は，与えられるインデックスは0でなければなりません
GUI_VNC_EnableFileTransfer() | ファイル転送拡張を有効にする
GUI_VNC_EnableKeyboardInput() | VNCを通したキーボード入力を有効/無効にする
GUI_VNC_GetNumConnections() | サーバーの接続数を返す
GUI_VNC_Process() | 実際のVNCサーバー;
ビューワーとの通信を初期化
GUI_VNC_RingBell() | クライアントにベルがあれば，ベルを鳴らす
GUI_VNC_SetFS_API() | ファイルアクセスを使ってファンクション・テーブルを設定
GUI_VNC_SetLockFrame() | GUIが描画処理する間，ディスプレイを読み込まないようにVNCサーバーをコンフィグする
GUI_VNC_SetPassword() | サーバーに接続するためのパスワードを設定する
GUI_VNC_SetProgName() | ビューワーのタイトルバーに表示されるテキストを設定する
GUI_VNC_SetRetryCount() | 書き込みエラーの際にリトライする回数を設定する
GUI_VNC_SetSize() | クライアントに転送する領域を設定する
GUI_VNC_X_StartServer() | 接続してくるクライアントをリッスンするスレッドを開始する処理が呼ばれ，VNCサーバーが開始される
GUI_VNC_X_StartServerFT() | 上記の関数と同じ処理に加え，ファイル転送もサポートする

データ構造
構造 | 内容
---|---
IP_FS_API | ファイルアクセス用の関数ポインタを含むテーブル

#### Functions
##### `GUI_VNC_AttachToLayer()`
Description
この関数は与えられたレイヤーをVNCサーバーにアタッチします

シグネチャ
`void GUI_VNC_AttachToLayer(GUI_VNC_CONTEXT * pContext, int LayerIndex);`

引数

引数 | 内容
---|---
pContext | GUI_VNC_CONTEXT構造体のポインタ
LayerIndex | サーバーがハンドルするためのレイヤーのインデックス．0が起点通常のシングルレイヤーのコンフィグレーションでは，この引数は0です

返値
= 0 成功
≠ 0 失敗

##### `GUI_VNC_EnableFileTransfer()`
Description
ファイル転送拡張を有効/無効にする

シグネチャ
`void GUI_VNC_EnableFileTransfer(unsigned OnOff);`

引数

引数 | 内容
---|---
OnOff | 1の場合はキーボード入力が有効，0は無効

返値
= 0 成功の場合
≠ 0 失敗の場合

追加情報
ファイル転送を有効にするため，この処理はGUI_VNC_X_StartServerFT()から呼ばれる必要があります
ターゲット上でファイル転送を有効にするサンプルコードはSample\GUI_X\GUI_VNC_X_StartServer.cを参照して下さい

##### `GUI_VNC_EnableKeyboardInput()`
Description
VNCを通したキーボード入力を有効/無効にします

シグネチャ
`void GUI_VNC_EnableKeyboardInput(int OnOff);`

引数

引数 | 内容
---|---
OnOff | 1の場合はキーボード入力が有効，0は無効

##### `GUI_VNC_GetNumConnections()`
Description
現在のサーバーとの接続数を返す

シグネチャ
`int GUI_VNC_GetNumConnections(void);`

返値
接続数

##### `GUI_VNC_Process()`
Description
送信と受信機能を有効にし，ビューワーとの通信を開始します

シグネチャ
`int GUI_VNC_Process(GUI_VNC_CONTEXT * pContext, GUI_tSend pfSend, GUI_tRecv pfReceive, void * pConnectInfo);`

引数

引数 | 内容
---|---
pContext | GUI_VNC_CONTEXT構造体のポインタ
pfSend | ビューワーにデータを送信するためにサーバーで使う関数のポインタ
pfReceive | ビューワーからのデータを読み込むためにサーバーで使う関数のポインタ
pConnectInfo | 送信・受信関数へ渡されるポインタ

追加情報
GUI_VNC_CONTEXT構造体は接続状態情報を保存するためにサーバーに使われます
送信及び受信関数はビューワーとの通信で送受信に成功したデータのバイト数を返します
ポインタpConnectInfoは送信もしくは受信処理に渡されます
接続情報を含む構造体にポインタやソケット番号を渡すために使われます
次のタイプは，ビューワーへの送受信の処理の関数ポインタとして使われます

```
typedef int (* GUI_tSend) (const U8 * pData, int len, void * pConnectInfo);
typedef int (* GUI_tReceive) (U8 * pData, int len, void * pConnectInfo);
Example

static GUI_VNC_CONTEXT _Context; /* Data area for server */
static int _Send(const U8* buf, int len, void * pConnectionInfo) {
  SOCKET Socket = (SOCKET)pConnectionInfo;
 }
static int _Recv(U8* buf, int len, void * pConnectionInfo) {
  SOCKET Socket = (SOCKET)pConnectionInfo;
  }
static void _ServerTask(void) {
  int Socket;
  ...
  GUI_VNC_Process(&_Context, _Send, _Recv, (void *)Socket);
  }
```

##### GUI_VNC_RingBell()
Description
クライアントがベルを持っていれば，ベルを鳴らします

シグネチャ
`void GUI_VNC_RingBell(void);`

##### `GUI_VNC_SetFS_API()`

Note
IP_FS_API構造体への次の記述はドキュメントUM07001 User & Reference Guide for embOS/IPの抜粋です．これはwww.segger.comでも参照できます

Description
ファイルアクセスに利用される関数テーブルを設定する
シグネチャ
`void GUI_VNC_SetFS_API(const IP_FS_API * pFS_API);`

引数

引数 | 内容
---|---
pFS_API | ファイルアクセス用の関数ポインタを含むIP_FS_API構造体のポインタ

追加情報
ファイル転送を有効にするために，この処理はGUI_VNC_X_StartServerFT()から呼ばれる必要があります
サンプルコードのSample\GUI_X\GUI_VNC_X_S tartServer.cも参照して下さい．ターゲット上でのファイル転送の有効化を説明しています

##### `GUI_VNC_SetLockFrame()`
Description
GUI描画処理を行っている間はディスプレイを読み込まないようにVNCサーバを設定します

シグネチャ
`void GUI_VNC_SetLockFrame(unsigned OnOff);`

引数

引数 | 内容
---|---
OnOff | eIf set to a value >0 frame locking will be enabled. デフォルトではフレームロックは有効です

追加情報
これはコンパイラへのスイッチによってコンパイル時に設定されます
GUI_VNC_LOCK_FRAME

##### `GUI_VNC_SetPassword()`
Description
サーバーと接続するのに必要なパスワードを設定します

シグネチャ
`void GUI_VNC_SetPassword(U8 * sPassword);`

引数

引数 | 内容
---|---
sPassword | サーバーとの接続に必要なパスワード

追加情報
　デフォルトではパスワードは必要ありません
パスワードが設定されるとサーバーは16バイトのランダムチャレンジを生成しDESを使って暗号化します
暗号化していないチャレンジがクライアントに送信され，暗号化されて帰ってきます
クライアントからのレスポンスが暗号のチャレンジにあっていたら認証は成功です

##### `GUI_VNC_SetProgName()`
Description
クライアント・ウィンドウのタイトルバーに表示されるタイトルを設定します

シグネチャ
`void GUI_VNC_SetProgName(const char * sProgName);`

引数

引数 | 内容
---|---
sProgName | クライアント・ウィンドウのタイトルバーに表示されるタイトル

##### `GUI_VNC_SetRetryCount()`
Description
データを書き込もうとしてエラーの時に，追加で何回再挑戦するかを設定します

シグネチャ
`void GUI_VNC_SetRetryCount(unsigned Cnt);`

引数

引数 | 内容
---|---
Cnt | エラーの場合，リトライする回数（デフォルトは0）

##### `GUI_VNC_SetSize()`
Description
クライアントに送信される画面サイズを設定します

シグネチャ
`void GUI_VNC_SetSize(unsigned xSize, unsigned ySize);`

引数

引数 | 内容
---|---
xSize | 使用されるXサイズ
ySize | 使用されるYサイズ

追加情報
　デフォルトではサーバーはレイヤーのサイズを使用します
関数に渡されるサイズは，実際の画面サイズより小さくても，大きくても大丈夫です

##### `GUI_VNC_X_StartServer()`
Description
　この関数は，接続を待つスレッドを開始しなくてはなりません
接続が確立されたら，実際のVNCサーバーGUI_VNC_Process()を実行しなければなりません
実装は使用するTCP/IPスタックと使用するOSに依存するため，カスタマーは関数を提供する必要があります
emWinにはサンプルの実装としてSample\GUI_X\GUI_VNC_X_StartServer.cが付属します
これは他のシステムへ適合させる開始点として使用できます

シグネチャ
`int GUI_VNC_X_StartServer(int LayerIndex,int ServerIndex);`

引数

引数 | 内容
---|---
LayerIndex | ビューワーに表示されるレイヤー
ServerIndex | サーバーインデックス

返値
返値0

追加情報
　シミュレーションやターゲット上でVNCサーバーを開始するのと違いはありません
どちらの場合でもこの関数を呼び出さなければなりません
シミュレーションは，この関数の実装を含みます，ハードウェアの実装はカスタマーによって行う必要があります

##### `GUI_VNC_X_StartServerFT()`
Description
　ファイル転送をサポートしたVNCサーバーを開始するために，カスタマーが実装しなければならない機能
サーバーのスレッドを開始するのに追加して関数は，GUI_VNC_EnableFileTransfer()を呼ぶことでファイル転送拡張を有効にしなければなりません．そしてGUI_VNC_SetFS_API()によってファイルアクセスするためファンクションテーブルを設定しなければなりません

シグネチャ
`int GUI_VNC_X_StartServerFT(int LayerIndex,int ServerIndex);`

引数

引数 | 内容
---|---
LayerIndex | ビューワーに表示されるレイヤー
ServerIndex | サーバーインデックス

返値
返値0

追加情報
Sample\GUI_X\GUI_VNC_X_StartServer.cは，embOS/IPとemFileの実装のサンプルです

#### データ構造
##### IP_FS_API
Description
テーブルはファイルアクセス用の関数ポインタを含みます
型の定義

```
typedef struct {
  void * (* pfOpenFile)              (const char  * sFilename,
                                      const char  * sOpenFlags             );
  int    (* pfCloseFile)             (      void  * hFile                  );
  int    (* pfReadAt)                (      void  * hFile,
                                            void  * pBuffer,
                                            U32     Pos,
                                            U32     NumBytes               );
  long   (* pfGetLen)                (      void  * hFile                  );
  void   (* pfForEachDirEntry)       (      void  * pContext,
                                      const char  * sDir,
                                            void (* pf) (void * pContext,
                                                         void * pFileEntry));
  void   (* pfGetDirEntryFileName)   (      void  * pFileEntry,
                                            char  * sFileName,
                                            U32     SizeOfBuffer           );
  U32    (* pfGetDirEntryFileSize)   (      void  * pFileEntry,
                                            U32   * pFileSizeHigh          );
  int    (* pfGetDirEntryFileTime)   (      void  * pFileEntry             );
  U32    (* pfGetDirEntryAttributes) (      void  * pFileEntry             );
  void * (* pfCreate)                (const char  * sFileName              );
  void * (* pfDeleteFile)            (const char  * sFilename              );
  int    (* pfRenameFile)            (const char  * sOldFilename,
                                      const char  * sNewFilename           );
  int    (* pfWriteAt)               (      void  * hFile,
                                            void  * pBuffer,
                                            U32     Pos,
                                            U32     NumBytes               );
  int    (* pfMKDir)                 (const char  * sDirName               );
  int    (* pfRMDir)                 (const char  * sDirName               );
  int    (* pfIsFolder)              (const char  * sPath                  );
  int    (* pfMove)                  (const char  * sOldFilename,
                                      const char  * sNewFilename           );
} IP_FS_API;
```

構造体メンバ

機能 | 内容
---|---
読み込み専用ファイルシステム関数(required) | 
pfOpenFile | ファイルを生成/開くための関数のポインタ．それらのファイルハンドラを返す
pfCloseFile | ファイルを閉じる関数のポインタ
pfReadAt | ファイルを読み込む関数のポインタ
pfGetLen | ファイルの長さを返す関数のポインタ
ディレクトリ query 操作 |
pfForEachDirEntry | 各ディレクトリエントリで呼び出される関数のポインタ
pfGetDirEntryFileName | ファイルエントリの名前を返す関数のポインタ
pfGetDirEntryFileSize | ファイルサイズを返す関数のポインタ

関数 | 内容
---|---
pfGetDirEntryFileTime | ファイルのタイムスタンプを返す関数のポインタ
pfGetDirEntryAttributes | ディレクトリエントリの属性を返す関数のポインタ
ファイル書き込み操作 | 
pfCreate | ファイルを作成する関数のポインタ
pfDeleteFile | ファイルを削除する関数のポインタ
pfRenameFile | ファイルの名前を変更する関数のポインタ
pfWriteAt | ファイルに書き込む関数のポインタ
追加のディレクトリ操作(optional) | 
pfMKDir | ディレクトリを作成する関数のポインタ
pfRMDir | ディレクトリを削除する関数のポインタ
追加操作(optional) | 
pfIsFolder | パスがフォルダかどうか確かめる関数のポインタ
pfMove | ファイルまたはディレクトリを移動させる関数のポインタ