USB keyboardのテスト

2008/08/28工作::USBimport

USB keyboardの話

HIDとして,キーボードとマウスは抑えておきたいところである.そこで,キーボードについて,仕様ではよくわからなかった動作について確認する.PCやOSに依存するかもしれないので,ここで記述する事項は実際に試したこと,推測(妄想)事項であることを明記しておく.
何らかの明確な動作に関する資料が開示されているのであれば,ポインタを教示いただきますと幸いです.

実験と確認

先日の疑問について,実装して確認する.
デバイス側のマイコンから,キーコード(usage ID)を送信し,PC側でどういう挙動を示すかを調べる.

(1)	{0x00, 0, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00 },
(2)	{0x01, 0, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00 },
(3)	{0x00, 0, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A },
(4)	{0x00, 0, 0x07, 0x08, 0x09, 0x0A, 0x05, 0x06 },
(5)	{0x00, 0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // nothing
(6)	{0x00, 0, 0x2C, 0x00, 0x00, 0x00, 0x00, 0x00 }, // space

	結果.
	"abcdefg "の繰り返しとなる.
	 456789a

	"押している"情報であることがわかる.
	(1)-(2)で 'a'を2回送っていることになるはず.(2回数はshift押下)
	(3),(4)で並びを変えてみたが, 反応ナシ.
	(5)で全部離したと認識して, "bcdefg"をinput.
	このとき,押下情報(3)の若い順に入力されたと考えられる.(並びを変えて確認要)

	また,別キーボードにてshiftを押下したところ,押下中は文字サイズが変わった.

# 教訓.スキップせずにコツコツと進みましょう:)

"abcdefg "....

(1)	{0x01, 0, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00 },
(2)	{0x00, 0, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00 },
(3)	{0x00, 0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // nothing
(4)	{0x00, 0, 0x07, 0x08, 0x09, 0x0A, 0x05, 0x06 },
(5)	{0x00, 0, 0x05, 0x06, 0x07, 0x08, 0x09, 0x00 },
(6)	{0x00, 0, 0x2C, 0x00, 0x00, 0x00, 0x00, 0x00 },

	"adefgbc "で繰り返された.
	(1) 'a'を押下,
	(2) 'a'を押下しながら shift押下
	(3) 'a'とshiftを同時に離す. 
	 → (shiftはキーの前後でon状態を保つ必要がある? 少なくとも入力時に同時か一つ前?)
	(4) d,e,f,g,b,c を押下
	(5) 'g'だけ離す...
	(6) b-fを離して, spaceを押す.


(1)	{0x01, 0, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00 },
(2)	{0x01, 0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // shift入れてみる
(3)	{0x01, 0, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00 },
(4)	{0x00, 0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // shift入れてみる
(5)	{0x00, 0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // nothing
(6)	{0x00, 0, 0x07, 0x08, 0x09, 0x00, 0x00, 0x00 },
(7)	{0x00, 0, 0x05, 0xC6, 0xC4, 0x00, 0x00, 0x00 },
(8)	{0x00, 0, 0x05, 0xC6, 0x00, 0x00, 0x00, 0x00 },
(9)	{0x00, 0, 0x05, 0xC6, 0xC4, 0x00, 0x00, 0x00 },
(A)	{0x00, 0, 0x2C, 0x00, 0x00, 0x00, 0x00, 0x00 },

	^a
	^a
	def
	0xC4/0xC6は無視されたぽいな..
	b
	<space>


!ここでReport descriptorのUsage Maxが 0x65なのに気づく.
0xE7とすることで,定義値全て有効になるはず..

(1)	{0x02, 0, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00 },
(2)	{0x02, 0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // shift入れてみる
(3)	{0x02, 0, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00 },
(4)	{0x00, 0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // shift入れてみる
(5)	{0x00, 0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // nothing
(6)	{0x00, 0, 0x07, 0x08, 0x09, 0x00, 0x00, 0x00 },
(7)	{0x00, 0, 0x05, 0xC6, 0xC4, 0x00, 0x00, 0x00 },
(8)	{0x00, 0, 0x05, 0xC6, 0x00, 0x00, 0x00, 0x00 },
(9)	{0x00, 0, 0x05, 0xC6, 0xC4, 0x00, 0x00, 0x00 },
(A)	{0x00, 0, 0x2C, 0x00, 0x00, 0x00, 0x00, 0x00 },

	ならなかったなぁ.
	AAdefb "Shift"は同時に離しても,跡で開放でも良いみたい.

min.max.を 0x80 - 0x7Fにしてみた.
	→値全部無視された.SHIFTのみに反応して,"固定キー機能"ダイアログが出てくる.

0x00 - 0x00E7にしてみたが,駄目だな. 
keypadになると,usage sub-IDが変わってくるので,無視されるのだろう.
table中,keyboard/keypadと明記されていたのはコレによるものと思われる.
分けてくれよ...

utility関数の作成

usage IDとASCIIコードとはテーブル引きするしかなさそう.US keyboardをベースにしているらしく,日本語keyboardとは異なるマップと考えるしかない.また,SHIFT/CTRL等の情報は文字とは別です.
前述の結果より,本I/FでPCが受信するのはキーの押下情報であり,入力された文字情報ではないです.文字入力の肩代わりをさせる場合,ほかのキーボードとの干渉を考慮する必要がありそうです.
ゲームの入力装置として考える場合は,押下情報であったことは良いことでしょう.同時押し6つまで認識してくれそうです.(SHIFT/ALT/CTRLは別腹で同時押し可)

ASCII文字 - 0x20を index0として,下記のIDを送ると良い.
ただし,"SHIFT+"は,SHIFTを押下しながら文字を入力した場合であり,単純に1倍との送信では実現できない.

0x2C, SHIFT+0x1E, SHIFT+0x34, SHIFT+0x20, SHIFT+0x21, SHIFT+0x22, SHIFT+0x24, 0x34, SHIFT+0x26, SHIFT+0x27, SHIFT+0x25, SHIFT+0x2E, 0x36, 0x2D, 0x37, 0x38,
	// 0x20~0x2F, → <SPC>!"#$%&'()*+,-./
0x27, 0x1E, 0x1F, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, SHIFT+0x33, 0x33, SHIFT+0x36, 0x2E, SHIFT+0x37, SHIFT+0x38
	// 0x30~0x3F, → 0123456789:;<=>?
SHIFT+0x1F, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12,
	// 0x40~0x4F, → @ABCDEFGHIJKLMNO
	// 0x89 : Keyboard International3(17) => '\'キー
0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x2F, 0x31 ,0x30, SHIFT+0x23, SHIFT+0x2D,
	// 0x50~0x5F, → PQRSTUVWXYZ[\]^_
0x34, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12,
	// 0x60~0x6F, → `abcdefghijklmno
0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, SHIFT+0x2F, SHIFT+0x31, SHIFT+0x30, SHIFT+0x32, 0x2A
	// 0x70~0x7F, → pqrstuvwxyz{|}~<DEL>


複合デバイスの作成

作り方

PSoC環境を使う限り,自動的にInterface数を把握して,standard requestに応答してくれる模様.便利ですな.. *1

  1. Descriptorにinterfaceを追加する.
  2. EPを追加する.
  3. Report descriptorを追加する.

メモ
PSoCのEPは,入出力で同じIDが使えない?simple IOの実装でEPを1/1または3/3としたときに,IN応答が無かった.OUTを受けてからIN transactionを起こしていたので,先に処理したモン勝ちか?詳細はPSoCのTRMで確認する予定.
【宿題】の結果,下記の記述が見つかりました.

PSoC TRM, Document No. 001-14463 Rev. **
34. Full-Speed USB

The SIE supports five endpoints including a control endpoint (endpoint 0) and four data endpoints (endpoint 1, 2, 3, and4).
The control endpoint can be configured to support SETUP, IN, and OUT requests.
The data endpoints can be individually configured to respond to Interrupt, Bulk, or Isochronous IN or OUT requests.

ということで,EP1~4は,INかOUTのいずれか1つしか取れません.したがって,インタフェースIN/OUTを2つ用いるデバイスでは,EPも2つ消費します.入出力対応しているEPであれば,EP数を削減できたのですが.まぁ,物理的な制約であり,仮に入出力OKでも,IDが経るなら同じなので,こんなもんなんでしょう.
キーボード,マウス,+α(入出力)とするならば,キーボードのLED出力は受け取れないということですね.

デバッグ・お試し時のメモ

PID/VIDが同じだと,Windows Device ManagerがInterfaceを覚えているようだ.
複合→単純に変えたとき,2度目以降は複合として扱われた.
Device Manager → USBコントローラ の 該当するVID/PIDの複合デバイスを削除することで,再度認識してくれるみたいです.


*1 : 仕組みを理解する上では,手抜きになってしまうなぁ.

参考サイト



wiki機能でコンテンツにしているけれども,まとまってないな...
日々書き散らかしてまとめていないからかなぁ.使い方間違ってる?w

HID Report Descriptor

2008/08/26未分類import

Descriptorメモ

階層だてて理解していく必要があるが,とりあえずはメモレベルで残す.

グローバルアイテムのタイプ @ USB complete 12-3

Usage Pageデータの使い方または機能の定義
論理的最小値アイテムがレポートする値の最小値
論理的最大値アイテムがレポートする値の最大値
物理的最小値論理的最小値を物理的最小値で示したもの
物理的最大値論理的最大値を物理的最大値で示したもの

HID Usage Tables,10/28/2004,Version 1.12

 3.1 HID Usage Table Conventions 
   32'hxxxx ::= { Usage Page(16bit) , Usage ID(16bit) } 
 
 3.3 Usages and Units 
 When declaring Units for a main item, 
 the Logical Minimum, Logical Maximum, Physical Minimum, Physical Maximum, and Unit Exponent items must also be declared. 
 
 
 3.4 Usage Types 
  control type( LC(Linear Control),OOC(On/Off Control),MC(Momentary Control)など)により, 
  Logical Min - Maxの範囲設定例と動作概要の説明 
 
 3.4.1 Usage Types (Controls) 
   Linear Control(LC) 
   On/Off Control(OOC) 
   Momentary Control(MC) 
   One Shot Control(OSC) 
   Re-trigger Control(RTC) 
 3.4.2 Usage Types (Data) 
Type Flags Description
Selector (Sel)ArrayContained in a Named Array (NAry).
Static Value (SV)Constant, Variable, AbsoluteA read-only multiple-bit value.
Static Flag (SF)Constant, Variable, AbsoluteA read-only single-bit value.
Dynamic Value (DV)Data, Variable, AbsoluteA read/write multiple-bit value.
Dynamic Flag (DF)Data, Variable, AbsoluteA read/write single-bit value.
 4 Generic Desktop Page (0x01) 
 |* Usage ID |* Usage Name |* Usage Type |* Section8 Hut1_12.pdf 
 
 4.3.1 Resolution Multiplier 

Effective Resolutiuon Multiplierは,以下の式で求められる.{( ( \frac{RMV - LMin}{LMax - LMin} * (PMax - PMin))  + PMin) * 10^{UnitExponent}}
where RMV = Resolution Multiplier Value, LMin = Logical Minimum, LMax = Logical Maximum, ssPMin = Physical Minimum, and PMax = Physical Maximum

Collection (Logical) 
Usage Page Generic Desktop (0x01) 
Usage Resolution Multiplier (0x48) 
Logical Minimum 0 
Logical Maximum 15 
Physical Minimum 1 
Physical Maximum 16 
Report Size 4 
Report Count 1 
Feature (Data, Var, Abs)		<- featureコマンドで, 1-16を受け付ける.  

Usage Page Generic Desktop (0x01) 
Usage (Wheel) (0x38) 
Logical Minimum -127 
Logical Maximum 127 
Report Count 1 
Report Size 8 
Input (Data, Var, Rel) 
End Collection 
||< 

*参考-usb.orgの仕様から HID Report Descriptorを消化してみる.
どう読めばよいか,という視点で確認.
[http://www.computer-engineering.org/index.php?title=USB_HID_Notes:ここ]も参考にした.

キーボードの例
>||
Usage Page (Generic Desktop),
Usage (Keyboard),
Collection (Application),
  Report Size (1),			
  Report Count (8),			
  Usage Page (Key Codes),	// KeyCodeを示すことを宣言
  Usage Minimum (224),		//ID224-231を size=1(bit) x 8個 に割り当てる.
  Usage Maximum (231),		//
  Logical Minimum (0),		//押下状態0/1を定義
  Logical Maximum (1),		//
  Input (Data, Variable, Absolute),     ;Modifier byte

  Report Count (1),			
  Report Size (8),			
  Input (Constant), ;Reserved byte

  Report Count (5),			// 5個
  Report Size (1),			// 1bit
  Usage Page (LEDs),		// 
  Usage Minimum (1),		// 1~5
  Usage Maximum (5),		// 
  Output (Data, Variable, Absolute),    ;LED report

  Report Count (1),			
  Report Size (3),			
  Output (Constant),                    ;LED report padding

  Report Count (6),		// 6個
  Report Size (8),			// 8bitサイズ
  Logical Minimum (0),		// 0~
  Logical Maximum(255),		// 255
  Usage Page (Key Codes),	// KeyCodeを示すことを宣言
  Usage Minimum (0),		// 0~
  Usage Maximum (255),		// 255 このUsage min/maxと冒頭のmin/maxでかなり意味が違う気がする. Array型だからいいように把握してくれるのかな..
  Input (Data, Array),		// 反映. 
End Collection

1バイト目でUsage Min/Maxを指定しているのは,下記押下状態を通知するためと考えられる(未確認)

Usage ID(Dec)Usage ID(Hex)Usage Name
224E0Keyboard LeftControl
225E1Keyboard LeftShift
226E2Keyboard LeftAlt
227E3Keyboard Left GUI
228E4Keyboard RightControl
229E5Keyboard RightShift
230E6Keyboard RightAlt
231E7Keyboard Right GUI

Usage(LED)'s valueは以下のとおり.これをデバイス側で受けて,LEDのon/off制御をおこなう..のだろう.

01Num Lock
02Caps Lock
03Scroll Lock
04Compose
05Kana

USB関連覚書

2008/08/26工作::USBimport

資料入手先等

仕様書関連

個人サイト等実装例

  • The HID Page, Jan Axelsonさん, [http://www.lvr.com/:Jan Axelson's
    ある意味総本山?ホスト側ソフトも充実していて,さらにリンクも良い.

Lakeview Research]

構想/妄想

2008/03/28工作::妄想import

製造ステップ

  1. リセット保持
指定回数のリセット検出で、resetoutpをLow levelに引き込む.
  1. USB挿抜自動化, GMT起動/script loadと実行(GMTにも手を入れたほうが良いか?)
  2. APL自動試験系への適応
Ydu.dllと、ソコで使っている関数を提供すれば、買い物+αをつかわずにすむはず。
障害ログの吸い上げ処理については依頼するしか無いかなぁ。

リセット保持

入出力双方向でレベル変換する必要がある.
相手は2.8V系なので, 駆動側電圧がソレを超える場合は単純にO.C.ではできない.(NPN Tr.を使う場合)

入力については, 高電圧側をPullUpして, TrのCollectorで引き落とすようにすれば良い.
ベース電流に気をつけないと、Iohを超えてしまうかもしれないので注意.

※RESETOUPは入力端子に分類され、外部は内部PullUpによる電位が見えている形になっている模様. 外部で吸い込むべき電流値はPU抵抗に依存か.
吊り上げはmin.で250k, 吊り下げはmax.で1kとのこと.(HWM rev2.0より)

ST2378EERによるレベル変換が入っている. ただし 1.8Vで出ている for ICE.

~1.8でも2.8でもロジックで受けるのはきつい. Trだと電流問題がでる. FETは在庫ではない.

ということで, マイコン内蔵コンパレータでいけるか検討する. reset直後のマイコン端子がoutputとか、inputだとしても漏れ電流がでかいとかいう問題がありそうならお手上げ.
クリアできれば, CORE DBG BOARDのJTAGコネクタで、1.8V変換後のRESETOUTPを取得・ドライブできる。

mega8のPort B,C,Dは, DDRとDともに'0'が初期値となっているので, Hi-Z状態となる.
コードを間違わない限りは大丈夫そう. コンパレータとして使用し, 他方に1.4V程度の電圧を印加しておけば良さそうだ. テキトウに版固定抵抗でもぶち込んでおけばいいだろう...


材料-マイコン

  • ATMEL AVR mega8
DIP 28pin package. ROM8k(4k step),RAM1kだが十分かな..
  • ATMEL AVR mega128
TQFP100pin package.

電気的特性(Vcc=5V)

VIH=0.6 Vccなので, RESETOUTPの最低保証2.0Vに対してはきつい.

3.3Vでマイコンを動かすか, レベル変換が必要.

→一本でよければアナログコンパレータを使うとか... 時間制限無ければADCで読み込むか.

材料-FT245RL使用

電気的特性(Vcc=5V/VccIO = 5 or 3.3)

入力レベルは低そうな... 特性図が無いのが難点だな.

photoMOS relay

Panasonicのデバイスを囲っている.
http://www.mew.co.jp/ac/control/relay/photomos/index.jsp?c=search