Blog


Bluetoothでデバイスと通信するには

Rfcomm

WindowsRuntimeではBluetoothの通信プロファイルの一つである、Rfcommをサポートしています。

Rfcommとは、通信上はBluetoothで接続されているデバイスと通信を行いますが、見かけ上はただのシリアル通信としてプログラミングできるプロファイルです。

 

シリアル通信とはCOMポートを使って有線で通信を行う方法ですが、RfcommではBluetoothで繋がったデバイスに仮想的なCOMポートを提供し、そのCOMポートにむかってシリアル通信をするだけで見かけ上のシリアル通信を無線で実現することができます。

73

 

RBT-001

今回は接続するデバイスとして、ArduinoとRBT-001というBluetoothモジュールを用いて通信を行います。

回路図はこんな感じです。

ArduinoのRXソケットをRBT-001のTXソケットに、TXソケットをRXソケットにつなぎます。

74

73

 

 

あらかじめArduino側にプログラムを書き込んでおきます。

シリアル通信でデータが流れてくるとそのままデータをシリアル通信で流し、LEDを1秒光らせる単純なものです。

ここまでできると、RBT-001からBluetoothの電波が飛ぶのでWindows側から認識できます。

ペアリングしておきましょう。PINコードはデフォルトで「0000」です。

 

SeviceGUID

RBT-001でRfcommを使うとき、サービスを一意に特定するためにGUID値を利用します。

これはあらかじめRBT-001が提供するGUID値を使います。

 

コントロールパネルからEasyBTのプロパティを見ます。

ハードウエアのタブからBluetoothリンク経由の標準シリアルを選択し、「プロパティ」を押します。

 

75

 

詳細タブを開き、BluetoothサービスGUIDを見るとGUIDを取得できます。

このGUIDを使用するのでコピ-しておきます。

 

マニフェストファイルに書き込む

Rfcommで通信するにはマニフェストファイルに書き込まなければいけません。

Package.manifestファイルを右クリックして「コードを表示」をおしましょう。

37

 

Capabilityタグ内に以下のタグを追加します。

m2:FunctionタグのType属性値は先ほど取得したGUIDに置き換えてください

 

 

RfcommDeviceService

WindowsRuntimeでRfcommを使うにはRfcommDeviceServiceAPIを使います。

まずBluetoothデバイスを特定しましょう。

先ほどのGUID値を使うので変数として宣言しておきます。

GUID値を先ほどコピーしたものと置き換えてください。

 

RfcommDeviceServiceクラスのGetDeviceSelectorメソッドを使ってセレクターを作ります。

セレクターを使ってDeviceInformationのFromAsyncメソッドでデバイスを特定します。

あとはDeviceInformationのIDからRfcommDeviceServiceクラスを初期化します。

 

次に作成したRfcommDeviceServiceクラスのConnectHostNameとConnectServiceNameを使ってStreamSocketを作ります。

StreamSocketができたらOutputStreamとInputStreamを使ってDataWriterとDataReaderを作ります。

 

 

データを送信する

先ほど作ったDataWriterを使用してbyte値を書き込みます。

これでBluetoothを経由してArduinoのシリアルポートにデータが送られます。

 

データを受信する

先ほど作ったDataReaderを使用してbyte値を読み込みます。

ArduinoからBluetooth経由で仮想COMポートに送られてくるデータを取得することができます。

 

サンプルコード

 




WinUSBデバイスとシリアル通信するには

WinUSB

WindowsRuntimeでは、サードパーティー製のドライバで接続されたデバイスとのシリアル通信が禁止されています。

基本的にWindowsストアアプリなどからUSBデバイスとシリアル通信を行うには、USBデバイスが「WinUSB.sys」というドライバで認識されていなければいけません。

たとえばエレコムのUC-SGTなどは、RS232C→USBの変換ケーブルですが、公式でWinUSBをインストールするドライバパッケージ(中身はinfファイル)が提供されているのでドライバを入れれば、UC-SGTで接続されたデバイスはWindowsストアアプリからシリアル通信が可能となります。

とにかく、WindowsRuntimeでシリアル通信を行うには、デバイスをWinUSBというドライバで認識できなければ使うことができません。

 

デバイスをWinUSBとして認識させる2つの方法

デバイスをWinUSBとして認識させるには2つの方法があります。

  1. カスタムinfファイルを作成する方法 (条件 端末に物理キーボードが付いている場合)
  2. レジストリにGUIDを登録する方法 (条件 レジストリをいじっても問題無い場合)

 

1番目のカスタムinfファイルを作成する方法は、端末に物理キーボードが付いていることが条件になります。

なぜなら、オリジナルなinfファイルをつくり、インストールするためデジタル証明の無いドライバーをインストールする許可を端末に与えなければいけません。

Windows8.1でデジタル証明のないドライバをインストールする許可を与えるには、PCの設定→保守と管理→回復→PCの起動をカスタマイズする→トラブルシューティング→詳細オプション→その他の修復オプションを表示→スタートアップ設定に行き、

「7キー」を押してドライバー署名の強制を無効にするを押さなければいけません。

20140923_072229394_iOS

 

 

しかし端末に物理キーボードなどがついていない場合、7キーを押すことができません。USBキーボードを接続しても認識しない場合が多いので、ラップトップなど、PCに物理キーボードが標準で付いている場合はこちらのカスタムinfファイルを作成する方法をとれますが、端末に物理キーボードがついていない場合、レジストリをいじる必要があります。

 

2番目のレジストリにGUIDを登録する方法は、端末に物理キーボードがついていない場合使用します。

そもそもすべてのデバイスはデバイスマネージャからWinUSBドライバをドライバとして選択すればドライバを適用できます。

しかし、認識するときにシステムが登録されているGUIDにデバイスと一致するものがあるかどうか見に行くのですがその時にデバイスのGUIDがなくて認識できません。

そこで、レジストリにデバイスのGUIDを登録することでデバイスを認識することができます。

GUIDとはGlobally Unique Identifierの略でなにかを一意に決定する識別子(ID)です。

このような形をしています。{d53fa365-5ag4-4436-938b-9db4734c6ca3}

 

Arduinoを接続してみる

Arduinoマイコンとは様々IOが標準で搭載されたAVRマイコンで非常に使い勝手がよく、シリアル通信をすることもできます。

今回はArduino UNOを接続してみたいと思います。

20140923_114511201_iOS

 

カスタムinfファイルを作成する方法

こちらの方法でデバイスが認識できればGUIDを追加する方法はしなくてもよいです。

infファイルとは、Windowsのソフトウエアをインストール用の設定が記述されたファイルのことです。

事前にOSにinfファイルをインストールしておくと、デバイスが接続されたときそのinfファイルを仲介してWinUSBドライバを読み込んでくれます。

40

カスタムinfファイルとは、そのinfファイルを自分で記述して事前にインストールしておくことを指します。

 

ではカスタムinfファイルを作成してみましょう。

以下のテキストデータをテキストエディタで書き込みます。

編集すべきところは

%DeviceName% = と [Dev_AddReg] と ManufacturerName= と DeviceName= の4つです。

 

%DeviceName% =

ここではVendorIDとProductIDを指定します。

ArduinoのVendorIDとProductIDの取得方法は、通常の方法でArduinoのドライバーをインストールしてデバイスマネージャからプロパティを表示します。

41

 

ハードウエアIDの項目を見るとVID_****とPID_****が書かれています。

 

42

 

コレをさきほどの%DeviceName% =USB_Install, USB\以降に書きます。

おそらく同じArduinoUNOを使っているとVIDとPIDは同じ値になるはずです。

[Dev_AddReg]

ここではオリジナルのGUIDを作成して書き込みます。

GUIDの作成は、VisualStudioのGUID作成ツールで行います。

VisualStudioのメニューバーの[ツール]→[GUIDの作成]を押します。

43

 

GUID形式はレジストリ形式を選択し、[新規GUIDの作成]をしてコピーします。

44

 

GUIDをコピーしたら

[Dev_AddReg]
HKR,,DeviceInterfaceGUIDs,0x10000,”*************”

の「*」の部分に貼り付けます。

 

ManufacturerName=

個々にはデバイスドライバの製造者名を書き込みます。なんでも大丈夫です

DeviceName=

個々には表示されるデバイス名を書き込みます。

ここに書いた値がデバイスマネージャに表示されます。

 

ここまでできたら拡張子を.infとしてファイルを保存しておきましょう。

45

 

デジタル署名の無いinfファイルのインストールを許可する

設定チャーム→PCの設定→保守と管理→回復→PCの起動をカスタマイズするで[今すぐ再起動をする]を押します。

そして青い画面で、トラブルシューティング→詳細オプション→その他の修復オプションを表示→スタートアップ設定に行き、

「7キー」を押します。

これでデジタル署名の無いinfファイルのインストールが許可されます。

 カスタムinfファイルをインストールする

では先ほど作成したinfファイルを右クリックして[インストール]を押しましょう。

49

 

[このドライバーソフトウエアをインストールします]をクリックします。

53

 

このダイアログが出れば成功です。

54

 

Arduinoの標準ドライバをアンインストールする。

カスタムinfファイルをインストールできたら現在インストールしている標準のArduinoドライバをアンインストールしましょう。

デバイスマネージャからArduinoUNOを削除します。

46

 

このデバイス・ドライバーソフトウエアを削除するにチェックをいれ、OKを押します。

47

 

できたら一度、Arduinoを抜き差ししましょう。

デバイスマネージャのユニバーサル・シリアル・バスデバイスの項目に自分がinfファイルに設定した名前と同じ名前でArduinoが認識できていれば成功です。

55

もし認識できていない場合は、不明なデバイスのどれかがArduinoなので、プロパティからVendorIDとProductIDで特定しましょう。

特定できたら、ドライバーソフトウエアの更新を押します。

57

 

コンピュータを参照してドライバーソフトウエアを検索します。を押します。

58

 

コンピュータ上のデバイス・ドライバーの一覧から選択します。を押します。

 

59

 

ユニバーサルシリアルバスデバイスを選択し、次へを押します。

 

60

 

正しくinfファイルがインストールされていればこの中の項目に自分の作成したinfファイルと同一名のものがあるのでそれを選択し、次へを押します。

62

 

 

ドライバーのインストールが完了すれば成功です。

64

カスタムinfファイルを作成する方法は以上で終わりです。

あとはWinUSBのAPIを利用することでシリアル通信が可能となります。

WinUSBのインストール

 

レジストリにGUIDを追加する方法

こちらの方法でデバイスが認識できればカスタムinfの方法はしなくても大丈夫です。

こちらの方法はレジストリを編集するので注意して編集してください。

もしレジストリを編集してお使いのPCの動作が不安定になっても私は責任を負いません。

 

レジストリにGUIDを追加する方法は、一度ArduinoをWinUSBドライバで読み込ませます。

現在インストールしているArduinoのドライバを一度削除します。

46

 

このデバイスのドライバーソフトウエアを削除するにチェックを入れ、[OK]を押します。

 

47

 

できたら一度、ハードウエアの変更のスキャンを押しましょう。

 

48

 

続いて[ほかのデバイス]の中から不明なデバイスのどれか1つがArduinoなのでプロパティを見てVendorIDとProductIDで特定しましょう。

特定できたらドライバーソフトウエアの更新を押します。

57

 

コンピュータを参照してドライバーソフトウエアを検索します。を押します。

58

コンピュータ上のデバイス・ドライバーの一覧から選択します。を押します。

59

ユニバーサルシリアルバスデバイスを選択し、次へを押します。

60

Microsoftの中に、WinUSBデバイスがあるのでそれを選択します。

61

ドライバーのインストールが完了すれば成功です。

63

 

GUIDを生成する

VisualStudioのGUID生成ツールを使ってGUIDを作りましょう。

VisualStudioのメニューバーの[ツール]→[GUIDの作成]を押します。

43

 

GUID形式はレジストリ形式を選択し、[新規GUIDの作成]をしてコピーします。

44

 

ではレジストリを編集します。

ファイル名を指定して実行で「regedit」と入力し、レジストリエディタを立ち上げます。

65

 

HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Enum\USB\<VID_****&PID_*****>の下の更に下の改装にDevice Parametersがあるので、その中に新規で文字列を追加しましょう。

↑(****はArduinoのVendorIDとProductIDに対応)

 

名前は[DeviceInterfaceGUIDs]で値に先ほど作成したGUIDを設定します。

68

 

以上でGUIDを追加する方法は完了です。

あとはWinUSBのAPIから呼び出すとシリアル通信をすることができます。

 

USBシリアル通信の準備

では実際にUSBで接続されたデバイスとシリアル通信を行ってみましょう。

 

まずはPackage.manifestファイルを編集します。

Package.manifestファイルを右クリック→[コードの表示]を押しましょう。

37

Packageタグにwc属性を追加しましょう。

Capabilityタグの要素に以下を追加します。

wc:DeviceタグのId属性はVendorIDとProductIDを接続したいデバイスに置き換えてください。

m2:FunctionタグのType属性に関してはCDCコントロールは02 * *で共通です。

詳しくはWindowsデベロッパーセンターに載っています。

 

続いて以下のUsbSerialPortクラスをコピペして新しいクラスとして追加しましょう。

Usbシリアル通信はUsbDeviceクラスからUsbInterfaceクラスでインターフェースを指定してDataWriterとDataReaderで通信を行いますが、結構めんどくさいので以下のクラスを使ってシリアル通信をします。

 

USBSerialPortクラスを使う

では先ほどのUsbSerialPortクラスを使ってみましょう。

UsbDeviceクラスのGetDeviceSelectorメソッドにVendorIdとProductIdを指定してselectorを取得します。

その後、DeviceInformationのFindAllAsyncメソッドを使ってデバイスを取得します。

取得したDeviceのIdを使って、UsbDeviceを取得します。

そしてUsbDeviceを使ってUsbSerialPortクラスを初期化します。

 

UsbSerialPortを初期化したらOpenAsyncでポートをオープンします。

通信速度は9600とします。

 

データを受信した時のイベントをハンドルしておきます。

データのリッスンを開始します。

引数で指定したバイト数だけ読み込みます。

もしデータが流れてきた場合ListenDataReceivedイベントが発動します。

 

データを書き込みます。

今回は2という数字をバイトデータとして送ります。

 

Arduino側のプログラム

Arduinoはドライバを変更してしまったので別のPCでArduinoIDEを使ってプログラムを書き込む必要があります。

Arduino側のプログラムはシリアルポートにデータが流れてきたらそのままデータを返して13番のLEDを100ミリ秒点灯させます。

20140923_164841269_iOS

これでArduinoとタブレットをつないでプログラムを実行するとシリアル通信できます。

 




ヒューマンインタフェイスデバイス(HID)を使うには

ヒューマンインターフェイスデバイス

ヒューマンインターフェイスデバイス(HID)とは、マウスやキーボードなど、人とPCとの基本的なやりとりをする装置を統一的なプロファイルで表したもので、HID対応デバイスならばどのようなデバイスであっても統一的な処理でアクセスすることができます。

 

どのようなHIDデバイスがあるのかはUSB.orgのサイトにあるHID Usage tableのPDFを見るとわかります。

非常に沢山あり、KeyboardやGame ControlsからVR Controlsまで、様々なデバイスをサポートしています。

自分のPCにどのようなHIDデバイスがあるのかは、デバイスマネージャーからヒューマンインターフェイスデバイスの項目を見るとわかります。

34

 

 

WindowsRuntimeでは標準でHIDデバイスの入出力をサポートしており、HIDDeviceクラスによって扱うことができます。

今回はHIDデバイスの一つであるXBOX360のコントローラを使って入力値をとってみたいと思います。

20140922_203400705_iOS

 

デバイスを特定するID

HID対応のデバイスを特定するには4つのIDが必要となっています。

  • UsagePage(デバイスのカテゴリID)
  • UsageId(デバイスの種類ID)
  • VendorId(デバイスの製造者ID)
  • ProductId(デバイスの製品ID)

の4つが必要となります。

 

UsagePageとUsageIdについてはUSB.orgのサイトにあるHID Usage tableのPDFを見て調べます。

GamePadはGeneric DesktopPage(0x01)のGame Pad(0x05)なので

UsagePageは0x01、UsageIdは0x05となります。

 

続いてVendorIdとProductIdです。

これはデバイスのプロパティを見るとわかる場合が多いです。

デバイスマネージャーからXBox360コントローラのプロパティを見て、詳細タブのプロパティからハードウエアIDの項目を見ると、VIDとPIDがわかります。

36

したがってこの場合、VendorIDはVIDのところを見て、0x045E、ProductIDはPIDのところを見て0x028Eということがわかります。

 

もしこの方法でVendorIDとProductIDが取得できない場合、取得ツールが公開されているのでMicrosoftの太田さんの記事を呼んでVendorIDとProductIDを取得してください。

WindowsストアアプリからHIDデバイスを制御する

 

マニフェストファイルを編集する

4つのIDを取得できたら、マニフェストファイルに4つのIDを書いておく必要があります。

ソリューションエクスプローラーからPackage.manifestファイルを右クリックして、コードを表示します。

37

 

Packageタグにxmlns:wb=”http://schemas.microsoft.com/appx/2013/manifest”属性を追加します。

そしてCapabilityタグ内に<wb:DeviceCapability>タグを追加します。

DeviceタグのId属性には”vidpid:{vendorId} {productID}”の形式でVendorIDとProductIDを入力します。

FunctionタグのType属性には”usage:{UsagePage} {UsageId}”の形でUsagePageとUsageIDを指定します。

 

 

今回の場合Package.manifestファイルはこのようになりました。

 

デバイスを取得する

デバイスを取得するには、HidDeviceのGetDeviceSelectorメソッドで、UsagePageとUsageIdとVendorIdとProductIdを指定します。

そしてDeviceInformationクラスのFindAllAsyncメソッドでデバイスリストを取得します。

もしIDが間違っているか、デバイスが接続されていない場合、取得できるリストの数が0になるのでそれで判断します。

デバイスを決定することができたらHidDeviceクラスのFromIdAsyncメソッドでIdとアクセスモードを指定してHidDeviceクラスを初期化します。

デバイスからの入力を検知するにはInputReportReceivedイベントを取得します。

入力として受け取ったデータをDataReaderでバイトデータを読み込みます。

ゲームコントローラーは15byteずつデータが来ました。

各バイトデータは8bitずつあるので2^8で0~255の値で各ボタンやスティックのデータが送られてきました。

38

 

 

各バイト値が取りうる値はこんな感じでした。

39

 

各ボタンに関しては、図の右下にあるような値の和が12バイト目で取得できます。

各ボタンはすべて2^nの値が設定されていて、2^nの和というのは、必ず加算する前の両辺に分解することができます。

つまり12バイト目は押しているボタンの加算値であり、それらはすべて2^nで値が設定されているのでどのボタンを押しているのかが決定できます。

 




スキャナーを使ってスキャンするには

スキャナーを取得する

WindowsRuntimeではイメージスキャナーを標準でサポートしています。

使用するスキャナーを決定するためにはDeviceInformationクラスのFindAllAsyncでDeviceClass列挙体のImageScannerを渡してスキャナーを列挙します。

 

コレクションからどのスキャナーを使うかを決定し、そのIdをImageScannerクラスのFromIdAsyncメソッドに渡してImageScannerを初期化します。

 

DeviceClassを使いましたがImageScannerのGetDeviceSelectorをFindAllAsyncメソッドにわたすことでフィルタリングも可能です。

 

スキャンしてStorageFileに保存する

スキャナーが決定できたらScanFileToStorageFolderAsyncメソッドによってスキャンを開始することができます。

今回は画像ライブラリに保存するのでマニフェストファイルの機能→画像ライブラリにチェックを入れましょう。

 

スキャンしてプレビューする

プレビュー機能のあるスキャナーならばスキャン結果をプレビューすることが可能です。

IsPreviewSupportedメソッドをつかって、プレビュー機能をスキャナーがサポートするかを判断し、

ScanPreviewToStreamAsyncメソッドつかってストリームにプレビューデータを流します。

あとはInMemoryRandomAccessStreamをつかってImageコントロールにストリームを流します。

 

サンプルコード

XAML

C#

 




プリンターを使って印刷するには

プリンターへのアクセス

WindowsRuntimeでは周辺機器へのアクセスはDeviceInformationクラスでデバイスを列挙して特定しますが、プリンターの場合はチャームのデバイス→印刷を表示することで現在アクセス可能なプリンター一覧が表示され、ユーザーが任意のプリンターを選択するという形になります。

32

 

したがって、プリンターで印刷をするために開発者側がすることは、プリントしたいドキュメントをPrintManagerクラスに投げるだけです。

どのプリンターで印刷するか、印刷をするかどうかはユーザーの選択に任せることになっています。

 

印刷用ページの作成

WindowsRuntimeで印刷を行うことができるものは、UIElementとそれを継承するクラスです。

UIElementはほとんどのXAMLコントロールの基底となるクラスですのでほとんどのコントロールは印刷が可能です。

したがって、画像やドキュメントなどを印刷したい場合、一度XAMLコントロール上に置きます。

 

今回は3ページ印刷するために一つ一つのページをCanvasコントロールで定義します。

 

XAMLでページが定義できたら、一度コンストラクタでUIElementのコレクションに入れておきましょう。

ページは複数(今回は3ページ)なのでUIElementのコレクションにいれることで扱いやすくなります。

 PrintDocumentの作成

印刷するドキュメントはPrintDocumentというクラスで定義されます。

このクラスは少し特殊で、何かしらの要求が来た時、そのイベントを使って印刷するコンテンツを追加します。

33

 

PrintDocumentを使うには、まずPrintDocumentをnewします。

 

つづいて、プレビュー要求がきたときのイベントを処理します。

Paginateイベントはプレビュー要求がきたときにプレビューページの最大数を設定する必要があります。

GetPreviewPageイベントはプレビュー要求がきたときにプレビューページをすべて設定します。

AddPagesイベントは印刷要求がきたときに印刷したいページをすべてAddPageします。

すべてAddできたらAddPagesCompleteメソッドを最後に呼んで印刷ページの追加を完了します。

これでPrintDocumentの処理は完了です。

PrintMangerでチャームに登録

先ほど作成したPrintDocumentをチャームに登録するにはPrintManagerクラスを使います。

このクラスもPrintDocument同様、要求イベントが来た時に応じで処理をします。

 

PrintTaskRequestedイベントはユーザーがチャームの印刷を押した時に発生します。

ここでCreatePrintTaskメソッドによってPrintDocumentのDocumentSourceプロパティを渡します。

CreatePrintTaskは別スレッドで呼び出されるのでDispatcher.RunAsyncメソッドでUIスレッドに戻します。

 

また、CreatePrintTaskメソッドは第一引数で印刷Paneに表示されるタイトルをかえることができます。

印刷する

以上で印刷ドキュメントの登録は完了しました。

あとは端末をプリンターに接続し、アプリからチャーム→デバイス→印刷を押すと印刷することができます。

 

印刷チャームを表示する

印刷チャームを表示することでユーザーに印刷を促すこともできます。

印刷チャームを表示するにはPrintMangerのShowPrintUIAsyncメソッドを使います。

 

サンプルコード

XAML

C#

 

EpsonのPX-046Aで印刷してみました。

20140922_192016764_iOS

印刷できました

20140922_192159799_iOS

目次