先日秋葉原にいったら、こんなものが売られていました。
USBから電源のON/OFFができる電源タップです。
これいいな! と思ったけども、どうやらこの電源タップを操作できるソフトはWindows用のものしかないらしいです。
しかもこの製品自体、現在では製造されていないらしいのです。
Linuxユーザーの自分としては、これを我が家の自宅サーバーにつなげて、リモートからの操作ができるようになりたいと思っておるのです。
「ないんだったら、自分で作ればいいじゃない!」
と神の啓示をいただきました
調べてみると、これを操作するソフトを独自で作り上げていた猛者がすでにおりました。
PTU2F3 をバグったSDKなんて使わないで直接操作しよう
流石です。僕が作る必要もな
いえいえ、これは.Net Frameworkを使ってるらしいのでやっぱりLinuxでは使えそうにもありません。
wine使えば動くのかもしれないけど、それだとコンソールから動かせないしなぁ。
やっぱり自作の道でした。
上記のページにはPTU2F3でどういうメッセージのやり取りがされているのかも書かれてあったので、比較的簡単に作れそうな気がします。
しかし、そもそもなんですが僕はUSBのアーキテクチャなんて知らないもんですから、そこから勉強する必要があるわけでした。
USBの基本アーキテクチャ
めんどくさがりの自分でもさらっと理解できる程度のページを発見。
なるほど。USBデバイスの操作にはエンドポイントと呼ばれる論理情報が必要なわけか。
次は、PTU2F3からエンドポイントを調べます。
まずはPC(CentOS)にPTU2F3を接続し、以下のコマンドを打つ。
[root@YKHG01 ~]# lsusb
Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
Bus 002 Device 001: ID 1d6b:0001 Linux Foundation 1.1 root hub
Bus 003 Device 001: ID 1d6b:0001 Linux Foundation 1.1 root hub
Bus 004 Device 001: ID 1d6b:0001 Linux Foundation 1.1 root hub
Bus 005 Device 001: ID 1d6b:0001 Linux Foundation 1.1 root hub
Bus 003 Device 005: ID 0711:0028 Magic Control Technology Corp.
lsusbこまんどで、デバイスがどのポートに接続されているかを確認できます。
ルートハブというのがUSBポートそれ自身だと思ってください。
デバイスは一番下のBus003 Device005と書かれているものがPTU2F3であるという推測ができます。
次にこのデバイスの詳細を調べます。
[root@YKHG01 ~]# lsusb -v -s 003:005
Bus 003 Device 005: ID 0711:0028 Magic Control Technology Corp.
Device Descriptor:
bLength 18
bDescriptorType 1
bcdUSB 1.10
bDeviceClass 0 (Defined at Interface level)
bDeviceSubClass 0
bDeviceProtocol 0
bMaxPacketSize0 8
idVendor 0x0711 Magic Control Technology Corp. idProduct 0x0028 bcdDevice 2.01
iManufacturer 1 MCT Corp_
iProduct 3 0123456
iSerial 0
bNumConfigurations 1
Configuration Descriptor:
bLength 9
bDescriptorType 2
wTotalLength 41
bNumInterfaces 1
bConfigurationValue 1
iConfiguration 0
bmAttributes 0x80
(Bus Powered)
MaxPower 100mA
Interface Descriptor:
bLength 9
bDescriptorType 4
bInterfaceNumber 0
bAlternateSetting 0
bNumEndpoints 2
bInterfaceClass 3 Human Interface Device
bInterfaceSubClass 0 No Subclass
bInterfaceProtocol 0 None
iInterface 0
HID Device Descriptor:
bLength 9
bDescriptorType 33
bcdHID 1.10
bCountryCode 0 Not supported
bNumDescriptors 1
bDescriptorType 34 Report
wDescriptorLength 25
Report Descriptor: (length is 25)
Item(Global): Usage Page, data= [ 0x00 0xff ] 65280
(null)
Item(Local ): Usage, data= [ 0x01 ] 1
(null)
Item(Main ): Collection, data= [ 0x01 ] 1
Application
Item(Local ): Usage, data= [ 0x02 ] 2
(null)
Item(Global): Logical Minimum, data= [ 0x00 ] 0
Item(Global): Logical Maximum, data= [ 0xff 0x00 ] 255
Item(Global): Report Size, data= [ 0x08 ] 8
Item(Global): Report Count, data= [ 0x08 ] 8
Item(Main ): Input, data= [ 0x82 ] 130
Data Variable Absolute No_Wrap Linear
Preferred_State No_Null_Position Volatile Bitfield
Item(Local ): Usage, data= [ 0x03 ] 3
(null)
Item(Main ): Output, data= [ 0x82 ] 130
Data Variable Absolute No_Wrap Linear
Preferred_State No_Null_Position Volatile Bitfield
Item(Main ): End Collection, data=none
Endpoint Descriptor: bLength 7
bDescriptorType 5
bEndpointAddress 0x02 EP 2 OUT bmAttributes 3
Transfer Type Interrupt
Synch Type None
Usage Type Data
wMaxPacketSize 0x0008 1x 8 bytes bInterval 10
Endpoint Descriptor:
bLength 7
bDescriptorType 5
bEndpointAddress 0x81 EP 1 IN
bmAttributes 3
Transfer Type Interrupt
Synch Type None
Usage Type Data
wMaxPacketSize 0x0008 1x 8 bytes
bInterval 10
Device Status: 0x0000
(Bus Powered)
確認する場所は赤文字にしてある部分です。
まずは
idVendor 0x0711 Magic Control Technology Corp.
idProduct 0x0028
この2行で、USBポートに刺さっているデバイスを特定します。
idVendorがベンダー(製造者)IDで、idProductがプロダクト(製品)IDです。
Endpoint Descriptor:
ここから下にエンドポイントの情報が記されています。
bEndpointAddress 0x02 EP 2 OUT
エンドポイント(というかパイプ)は複数個作成でき、この値はこのデバイスのパイプを指定するためのアドレスになります。
EPをエンドポイントを表し、2はパイプ番号、OUTはデバイスへの出力(デバイスからの入力はIN)を表します。
wMaxPacketSize 0x0008 1x 8 bytes
デバイスとの通信でやり取りされる最大のパケットサイズです。
PTU2F3は8バイトのデータをやり取りしていることがわかりました。
これでPTU2F3の基本情報を確認することができました。
次にメインであるプログラミングをします。
LinuxでUSBデバイスの操作をするために、libusbというライブラリを利用することができます。
最初は一からコードを組もうと思いましたが、めんdサンプルの出来が良いので上記ページにあるサンプルコードをそのまま使わせていただきました。
で、メッセージの送信部分しか作ってないのでコードの解説は省略します。
とりあえず変更部分のソースを晒しておきます。
unsigned char writeStatus[8] = {2,0,0,0,0,0,0,0};
if(argc == 2){
switch(argv[1][0]){
case '1':
writeStatus[1] = 1;
break;
case '2':
writeStatus[1] = 2;
break;
case '3':
writeStatus[1] = 3;
break;
default:
break;
}
}
int result=usb_bulk_write(dh, 0x02, writeStatus, sizeof(writeStatus), TIMEOUT);
if(result<0){printf ("Control message error. (%d:%s)\n", result, usb_strerror());}
あ、一箇所だけ解説をば、
unsigned char writeStatus[8] = {2,0,0,0,0,0,0,0};
最初に紹介した人のページではパケットサイズは9バイトで、2バイト目に制御コードを入れていましたが、lsusbの結果から、こちらのほうが妥当だと判断しました。
(実際この制御コードでも動作しました)
で、完成したのがこちら。
とりあえずダウンロードしてコンパイルできれば動かせます。(要libusb-dev)
[root@YKHG01 ~]# gcc -o ptu2f3 main.c -lusb
第一引数にON/OFFしたいタップのポート番号を指定してください。
# ./ptf2f3 0 # 4,5ポート共にONにします。
# ./ptf2f3 1 # 4ポートOFF、5ポートON
# ./ptf2f3 2 # 4ポートON、5ポートOFF
# ./ptf2f3 3 # 4,5ポート共にOFFにします。
はい、こんな感じで動かすことができました。
これでサーバのターミナル上からUSBの制御をすることができるようになりました。
それじゃこれを何に使おうかっていう話ですが。
うちのラボ環境をリモートから制御できるようにしたいわけです。
基本的に商用ルータやスイッチには電源がないので。こういう電源の操作を直接できるタップは本当に役に立つわけです。
多分、このタップが話題にならなかったのはバグだらけでWindowsでしか動作しないSDKしかなかったからじゃないかなぁと思う。
サーバー用途とかで使えるものだと思います。
こんな感じで、うちのネット環境がまた一つ充実してしまった。そういうお話でした。
以上。
それじゃこれを何に使おうかっていう話ですが。
うちのラボ環境をリモートから制御できるようにしたいわけです。
基本的に商用ルータやスイッチには電源がないので。こういう電源の操作を直接できるタップは本当に役に立つわけです。
多分、このタップが話題にならなかったのはバグだらけでWindowsでしか動作しないSDKしかなかったからじゃないかなぁと思う。
サーバー用途とかで使えるものだと思います。
こんな感じで、うちのネット環境がまた一つ充実してしまった。そういうお話でした。
以上。
windowsの方を書いたrtiです。
返信削除これをlinuxに移植して libusbの操作がわからずにはまっていましたが、おかげで助かりました。
返信遅くなって申し訳ないです。コメントありがとうございます。
削除書いたものも下手で見せられるものではないのですが、なにか一つでも参考にすることができたなら幸いです。
これからもどうぞよろしくおねがいします。