JavaからUSBランプを光らせてみる

続編あります。

2013/2/14追記: WindowsサービスでWebmail Notifierを制御するユーティリティを作ったけど半年以上忘れてたので紹介 - ka-ka_xyzの日記


Webmail windowというUSB接続のLEDランプを制御するプログラムを作りました - ashelの日記 Webmail windowというUSB接続のLEDランプを制御するプログラムを作りました - ashelの日記

↑を読んでて、便利そうだったので早速WebMail Notifierを購入してみました。

WebMail Notifierを購入する

こういうUSB接続のちょっと微妙なガジェットといえばこちら。

All about USB | USB 3.0, USB Gaming, USB Lifestyle | Brando Workshop

"Webmail"で商品検索するとあっけなくヒットします。
とりあえず、ランプ単体版とUSBハブ機能付き版があったので、下記のハブ機能付き版を購入。
All about USB | USB 3.0, USB Gaming, USB Lifestyle | Brando Workshop : USB Webmail Notifier + 4-Port Hub Cable

まあ、最悪使えなくてもUSBハブにできればいくらか投資を回収できるかな。(実はこの時点で罠が潜んでいたのですが、詳細については後述)

libusb-win32の導入

さて、JavaからUSBデバイスを制御するといえば、JSRであるにも関わらず誰からも注目されていないJSR-80実装は無視して、libusb-win32と、libusb / libusb-win32 wrapperの組み合わせで行ってみます。環境はwin7 64bit。
Linux環境はとりあえず置きで。

手順1 libusb-win32関連dllのインストール

http://sourceforge.net/projects/libusb-win32/files/libusb-win32-releases/1.2.6.0/libusb-win32-bin-1.2.6.0.zip/download

↑から、libusb-win32 v1.2.0.6(現時点での最新版リリース)をダウンロードします。
binフォルダの下にあるreadme.txtに従い、libusb0.dllおよびlibusb0.sysをコピーします。32bitと64bit(amd64)アーキテクチャでのコピー方法を引用します。

ALL ARCHITECTURES:
x86\libusb0_x86.dll: x86 32-bit library. Must be renamed to libusb0.dll
On 64 bit, Installs to Windows\syswow64\libusb0.dll.
On 32 bit, Installs to Windows\system32\libusb0.dll.

x86\inf-wizard.exe: inf-wizard application with embedded libusb-win32
v1.2.6.0 binaries.

X86 ONLY ARCHITECTURES:
x86\libusb0.sys: x86 32-bit driver.
Installs to Windows\system32\drivers\libusb0.sys

AMD64-INTEL64 ONLY ARCHITECTURES:
amd64\libusb0.sys: x64 64-bit driver.
Installs to Windows\system32\drivers\libusb0.sys

amd64\libusb0.dll: x64 64-bit library.
Installs to Windows\system32\libusb0.dll

32bit版と64bit版でコピー元のディレクトリが違う(32bit版はbin/x86、64bit版はbin/amd64)ので注意。

infファイルの作成

Webmail Notifierを刺した状態でbin/inf-wizard.exeを起動します。
OSが認識しているUSBデバイス一覧が出てくるので、下記の条件に当てはまるものを選択。

VenderID 0x1294
ProductID 0x1320

libusb用のINF ファイルを生成してくれるので、適当な場所に保存します。
次に、WindowsのデバイスマネージャーからWebmail Notifierを探してきて、「プロパティ」->「ドライバーの更新」から、「コンピュータを参照してドライバソフトウェアの検索」->「コンピュータ上のデバイスドライバの一覧から選択します」->「ディスク使用」という流れで、上で作成したinfファイルを指定し、ドライバをインストールします。
inf-wizard.exeのダイアログにある「install now」ボタンをクリックすると自動でインストールしてくれます。

正常にインストールが終了すると、Windowsデバイスマネージャーの該当デバイスプロパティから「ドライバーの詳細」ボタンをクリックすると下記のように表示されるはず。

C:\windows\system32\drivers\libusb0.sys
C:\windows\system32\libusb0.dll
C:\windows\syswow64\libusb0.dll

最後に、libusb-win32のbin/x86/testlibusb-win.exeを実行して以下のようなダイアログが表示されればインストールは成功です。

DLL version: 1.2.6.0
Driver version: 1.2.6.0

bus/device idVendor/idProduct
bus-0/\\.\libusb0-0001--0x1294-0x1320 1294/1320

  • Unable to fetch manufacturer string
  • Unable to fetch product string

bLength: 18
bDescriptorType: 01h
bcdUSB: 0110h
bDeviceClass: 00h
bDeviceSubClass: 00h
bDeviceProtocol: 00h
bMaxPacketSize0: 08h
idVendor: 1294h
idProduct: 1320h
bcdDevice: 0100h
iManufacturer: 1
iProduct: 2
iSerialNumber: 0
bNumConfigurations: 1
wTotalLength: 41
bNumInterfaces: 1
bConfigurationValue: 1
iConfiguration: 4
bmAttributes: 80h
MaxPower: 100
bInterfaceNumber: 0
bAlternateSetting: 0
bNumEndpoints: 2
bInterfaceClass: 3
bInterfaceSubClass: 0
bInterfaceProtocol: 0
iInterface: 0
bEndpointAddress: 83h
bmAttributes: 03h
wMaxPacketSize: 8
bInterval: 10
bRefresh: 0
bSynchAddress: 0
bEndpointAddress: 04h
bmAttributes: 03h
wMaxPacketSize: 5
bInterval: 10
bRefresh: 0
bSynchAddress: 0

(赤字部分は後で使用)

wrapperのインストール

ダウンロードサイトからdllファイルおよびjarファイルを入手します。
LibusbJava.dllをwindows/system32へコピー。
32bit版LibusbJava.dllをwindows/syswow64へコピー。

テストアプリの起動

jarファイルをダウンロードしたフォルダで、jarに含まれるテストアプリを起動してみます。インストールに問題なければ、webmail notifierのUSBデバイス情報が表示されるはずです。

java -jar ch.ntb.usb-0.5.9.jar

ただし、64bit版JVMから起動するとjava.lang.UnsatisfiedLinkErrorが出て起動に失敗します。原因はわかりませんが、32bit版JVMから起動するようにしてください。

javaプログラムの実行

ch.ntb.usb-0.5.9.jarをクラスパスに入れて、以下のコードを実行します。
問題がなければ、一秒間だけ赤色LEDが点灯し、その後消灯するはずです。

package jp.gr.java_conf.ka_ka_xyz.usb;

import ch.ntb.usb.Device;
import ch.ntb.usb.USB;
import ch.ntb.usb.USBException;

public class UsbMain {
	
	public static void main(String[] args){
		UsbMain usbMain = new UsbMain();
		usbMain.firstLight();
	}
	
	public UsbMain(){}
	
	public void firstLight(){
		/*
		 * testlibusb-win.exe実行結果にあるベンダIDとプロダクトIDでUSBデバイスを指定
		 * ベンダID: 0x1294
		 * プロダクトID: 0x1320
		 * */
		Device dev = USB.getDevice((short) 0x1294, (short) 0x1320);
		if(dev == null){
			System.out.println("failed to open USB device!");
			System.exit(1);
		}
		try {
			dev.open(1, 0, -1);
			//RED light
			final byte[] red = {1, 0, 0, 0, 0,};
			System.out.println("result: " + dev.writeInterrupt(0x04, red, red.length, 100, true));
			try {
				//一秒待ち
				Thread.sleep(1000);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			//ライトを消す
			final byte[] lightOff = {0, 0, 0, 0, 0};
			//0x04: testlibusb-win.exe実行結果中のEndpoint値
			dev.writeInterrupt(0x04, lightOff, lightOff.length, 100, true);
			
			dev.close();
			
		} catch (USBException e) {
			e.printStackTrace();
		}
		
	}
}

赤色LEDしか点かないんだが・・・・

以下の配列で、先頭部分の値を1〜7に変えることで色が変わるはずだと思っていましたが・・・値を変えても何故か赤色のまま。

final byte[] red = {1, 0, 0, 0, 0,};

で、Webmail Notifierを分解してみたわけです。
中には3つのLEDが入っており、値を1〜7に変えて実行してやると確かに点灯するLEDのパターンが変わりますが・・・3つとも全部赤色LEDじゃねーか。

何なの!? HOI3で真っ先にソ連プレイした祟りなの? それとも生産工場に文化大革命並みに「赤以外の使用はまかりならん」とか政治的指導が入ったの?シベリアに飛ばされちゃうの?

とか思ってましたが、バカなのは自分でした。

USBハブ機能の無いWebmail Notifierの製品紹介ページには

Soft Illuminated Blue, Red, Green indicator

と書いていますが、USBハブ機能付きWebmail Notifierの製品紹介ページには

Soft Illuminated Red indicator

としか書かれていません。
ぐぬぅ。これが孔明の罠ってやつか。

とりあえず、ハブ無し版Webmail Notifierをオーダーして、多色発光がうまくいくか試してみます。
まあ、最終的にはHTMLパーサーと組み合わせてテスト自動化サーバーや職場のWebアプリと連携していろいろする予定。