[トップページへ戻る]

V-USB ホスト側アプリとAVR-HID/IO


(C) Objective Development Software

2012年4月
前回の記事「V-USBを利用してHIDデバイスを作る」はハードウェア編でした。
今回はホスト(PC)側のソフトを紹介します。C#でHIDデバイスを操作するライブラリです。
また、汎用I/OデバイスAVR-HID/IOとそれを操作するアプリを作成したので、ハードともども紹介します。


なぜ自作ライブラリなのか
PCからUSB/HIDデバイスを操作するにはWindows APIを使います。必要なAPIはhid.dll, setupapi.dll, kernel32.dllに含まれています。これらを使ってイチから自分で組むのも一興ですが、libusbを使う方が簡単です。libusbはUSBデバイス操作の汎用ライブラリで(HIDデバイスに限らない)、libusb0.sys(ドライバ)とlibusb0.dll(ライブラリ)から成っています。
libusb http://libusb.org

WinUSB APIを使ったドライバ開発の方法もあります。この場合Windowsに含まれるwinusb.sys/winusb.dllを利用するのですが、これらはWindowsXP/SP1以前には含まれていません。MicrosoftUpdateでSP2以上にアップデートしても追加されません。※手元の開発機WindowsXP/SP3(SP1からアップデート)には入っていないので、WinUSBを使った開発の線はここで消える。

libusbを使用したアプリの実行にはlibusb0.dllが必要です。アプリのexeファイルと同梱して配布するか、アプリ利用者に別途用意してもらうことになります。後者の場合、「DLLのバージョンによってアプリの動作が異なることがある」という、よくある心配事が付いてきます。
ここで、本シリーズ記事がHIDデバイスを開発している理由は、「デバイスとアプリを利用するのに、ドライバのインストールが不要だから」です。というわけで、libusbも使わずホスト側アプリを開発しました。
※C#で開発したい、自分で好きなように作れる、というのも理由。

今回作成したライブラリはUSB汎用ではなく、V-USBを利用したHIDデバイスを操作するためのものです。多様なUSBデバイスを制御するためのものではありません。

C#でソフト開発しない人には、本記事の見所は特にないかもしれません。
C#のプログラミングに興味がある人には、USBやHIDのこととは関係なしに、プログラミング技術の面で参考になることがあるかもしれません。本ライブラリではCで組まれたDLL内のAPIを呼び出しています。マーシャリング、アンマネージ領域のメモリ操作、それを含むスレッド処理などは、マネージコードだけのプログラミングとはちょっと違うコツがあります。ソース内のコメントを参照してください。

USB HIDライブラリ
ソース(UsbHidLib.cs)は次章「AVR-HID/IO」でダウンロードできます。
使用例として、前記事のテストプログラムhiddevc.exeのProgram.csをここに示します※下図は概略。

hiddevc.exe実行画面

プロジェクトの準備
1. プロジェクトに「UsbHidLib.cs」を追加する。
2. ソースに「using UsbHid;」を記述する。

ソース記述の手順
1. HidDeviceMgrオブジェクトを生成する。
2. HidDeviceMgr.GetDeviceList()でデバイス一覧を取得する。
3. HidDeviceMgr.TargetDevice()で目的のデバイスを決定する。HidDeviceオブジェクトが返る。
4. 以降、HidDeviceオブジェクトを通してデバイスを操作する。

同種のデバイスを複数台接続した場合、手順2の一覧に全て含まれます。それぞれのシリアル番号やデバイス名を見て目的のデバイスを選びます。または、それら一つ一つを手順3で決定し(それぞれのHidDeviceオブジェクトを取得し)、個別に操作することもできます。

class HidDevice HIDデバイスを個別に操作する
コンストラクタ
public HidDevice(HidDeviceInfo devInfo)
ユーザーアプリ内からコンストラクタを呼び出すことはしない。
インスタンスはHidDeviceMgr.TargetDevice()で取得すること。
publicメソッド
コントロール転送でFeatureReportを取得する
byte[] GetFeatureReport(int dataLength)
dataLength: 取得するデータの長さ。レポートIDを含まない長さ。
byte[] GetFeatureReport(byte reportID, int reportLength, bool cutReportIdByte)
reportID: レポートID。
reportLength: 取得するレポートの長さ。レポートIDの分1byteを含めた長さであること。
cutReportIdByte: 取得したbyte配列からレポートIDの要素をカットするかどうか。
コントロール転送でFeatureReportをセットする
bool SetFeatureReport(byte[] dataBytes)
dataBytes: 送信するデータ。レポートIDを含まないデータであること。
bool SetFeatureReport(byte reportID, byte[] dataBytes, bool addReportIdByte)
reportID: レポートID。
dataBytes: 送信するデータ。下記備考参照。
addReportIdByte: dataBytesの先頭にレポートIDを加えるかどうか。
備考
addReportIdByteをtrueとするとき、dataBytesはレポートIDを含まないbyte配列であること。
addReportIdByteをfalseとするとき、dataBytesはレポートIDを含んだbyte配列であること。
コントロール転送でInputReportを取得する
byte[] GetInputReport(int dataLength)
dataLength: 取得するデータの長さ。レポートIDを含まない長さ。
byte[] GetInputReport(byte reportID, int reportLength, bool cutReportIdByte)
reportID: レポートID。
reportLength: 取得するレポートの長さ。レポートIDの分1byteを含めた長さであること。
cutReportIdByte: 取得したbyte配列からレポートIDの要素をカットするかどうか。
コントロール転送でOutputReportをセットする
bool SetOutputReport(byte[] dataBytes)
dataBytes: 送信するデータ。レポートIDを含まないデータであること。
bool SetOutputReport(byte reportID, byte[] dataBytes, bool addReportIdByte)
reportID: レポートID。
dataBytes: 送信するデータ。下記備考参照。
addReportIdByte: dataBytesの先頭にレポートIDを加えるかどうか。
備考
addReportIdByteをtrueとするとき、dataBytesはレポートIDを含まないbyte配列であること。
addReportIdByteをfalseとするとき、dataBytesはレポートIDを含んだbyte配列であること。
インタラプト転送(IN)の受信スレッドを開始する
bool InterruptInStart(InterruptInCB callbackMethod)
callbackMethod: ユーザーアプリ内で用意したstaticなメソッド。
インタラプト転送(IN)の受信スレッドを停止/破棄する
void InterruptInStop()
InterruptInStart()を使用した場合、ユーザーアプリ終了時までに呼び出す。

AVR-HID/IO
ダウンロード hidio_v110.zip V-USB HIDライブラリ (UsbHidLib.cs)
AVR-HID/IOコントローラ (UsbHidIOCtrl.cs)
ファームウェアと
サンプルプログラムを含む。
2012/08 更新(v1.10) 動作確認環境: WindowsXP(32bit)/SP3, Windows7(64bit)/SP1

前回の記事で目標としていた、AVR-CDC/IOと同様のデバイスAVR-HID/IOを作りました。
ATmega48シリーズ版とATtiny2313版があります。
回路はどちらもV-USBの基本回路の通りです。フラッシュ容量の都合によりATtiny2313版は機能を削減しています。
ソフトの組み方・ライブラリの使い方は、上記ZIPに同梱のサンプルプログラムを見てください。※下図は概略。


ATmega48シリーズ版(48/88/168/328)

テスト中の様子。
PORTCを読み取る場面。

サポートしている操作
class HidIOCtrl
レジスタ操作 EEPROM操作
int Get(SFR register) byte EEPRomReadByte(int adrs)
bool Set(SFR register, int byteValue) bool EEPRomWriteByte(int adrs, int byteValue)
bool AndSet(SFR register, int byteValue) int EEPRomReadWord(int adrs)
bool OrSet(SFR register, int byteValue) bool EEPRomWriteWord(int adrs, int nValue)
bool XorSet(SFR register, int byteValue)
割り込みに対応。コールバック関数にベクタ番号が上がってくる。※番号と内容の対応はデータシートを参照。
ただし、1番(リセット割り込み),2番(INT0割り込み),3番(INT1割り込み)は無い。

ATtiny2313版

サポートしている操作
class HidIOCtrl
レジスタ操作 EEPROM操作
int Get(SFR register) byte EEPRomReadByte(int adrs)
bool Set(SFR register, int byteValue) bool EEPRomWriteByte(int adrs, int byteValue)
bool AndSet(SFR register, int byteValue) int EEPRomReadWord(int adrs) なし
bool OrSet(SFR register, int byteValue) bool EEPRomWriteWord(int adrs, int nValue) なし
bool XorSet(SFR register, int byteValue)
割り込みには対応していない。

AVR-HID/IOの応用について
AVR-CDCシリーズにはAVR-CDC/IOの他、AVR-CDC/232やAVR-CDC/SPIがあります。今回製作したAVR-HID/IOは外から見れば汎用I/Oデバイスですが、内部的にはAVRのレジスタ操作デバイスです。レジスタを適切に設定すれば、AVR-CDC/232やAVR-CDC/SPIと似たような動作をさせることもできます。ですがAVR-HID/IOの原型を維持しようとせず、目的の製作物に合わせて独自に作り替えた方が扱いやすいものになります。

AVR-HID/IOはUSBロー・スピード・デバイスなので仕様上1.5Mbps出せます。ホストとの通信速度で困ることはあまり無いと思います。それよりも、SRAM上に送受信バッファをどれだけ取るか、インタラプト転送(IN)を使うか連続したコントロール転送(IN)で処理するか、それで速さと処理量が見合うのか、細かいレジスタ制御が必要になるのか、といったことが考えどころになるでしょう。


◆ ◆ ◆
V-USBを利用してHIDデバイスを作り、ホスト側アプリにlibusbを使わず、C#で開発したい。
…という場合に本記事のアプリが参考になれば幸いです。かなり限定された向きの話です。


(C) 『昼夜逆転』工作室 [トップページへ戻る]
inserted by FC2 system