まごころせいじつ堂

浜町庄金 研究開発  マイコンで遊んでばっかりで

Leonardo

Arduinoで任意のUSBコードを送る 解決編

 Arduino Leonardo/MicroはUSBキーボードとして使えるが、Usageコードが101より大きいものは無視されるという問題があった。
PS/2キーボード変換器の製作(18) USBキーボードの無視されるキーについて
対策箇所はわかっていたが、当時はバイナリにパッチするという手段しか思いつかず強引にやっていた。
PS/2キーボード変換器の製作(19) HEXファイルにパッチを当てる
 この後、Arduino IDEのフォルダ内にあるソースをいじると反映されることを知った。Arduino IDEは毎回ソースから全部ビルドしてたのか!コアな部分はコンパイル済と勝手に思っていた。
Turning an Arduino Leonardo into a joystick.(Imarginary Industries)
 この記事ではUSBAPI.h、HID.cppを修正することによりジョイスティックのUSB-HIDを追加している。ということはArduino IDEにあるHID.cppのHID Report Descripterを修正することで日本語キーボードの機種で¥マークなどを入力できるようになるはずだ。
MacOSXだと修正対象のソースはContents/Resources/Java/hardware/arduino/cores/arduino/以下にある。
https://gist.github.com/houmei/2ad9f7a713f46149e72f

HID.cppを差し替え、ライブラリを組み込む。このライブラリはHID.cpp/USBAPI.hと一体化もできると思うが以前作ったのをそのまま流用しているのでこうなっている。

2014shot1
 これはDavinciにArduino Microのファームウェアを書き込んだもの。pin4にスイッチを付けてフリスクの大きめのケースに入れてみた。たったこれだけ。日本語キーボードがついてるものがWindowsXPの古いノートPCしかなかったのでそれに接続して¥マークが入力できることを確認した。

https://gist.github.com/houmei/0ac6873618caa02f22b4

 USBキーボードのUsageコードについては以下からどうぞ。注意点としてUSキーボードのレイアウトが基準。
USB HID to PS/2 Scan Code Translation Table

 ああ、これで数年悩んでた問題が解決だ。変なバイナリパッチ作った時点で誰も突っ込んでくれないのね。


 ついでにPrint ScreenのUsageコード(0x46)を設定して最近話題のエビデンス画面スクリーンショット用ボタンにしてみた。これでハードコピー取り放題よ。
2014shot2

 

Adafruit 1.8" TFT ShieldをLeonardoで使う(SoftSPI)

※サンプルスケッチをしばらく実行しているとハングします※
→解決 microSDカードのせい http://blog.livedoor.jp/hardyboy/archives/7270159.html

 TFTシールドの続き。Arduino UNOではそのまま動くがLeonardoでは動かない。シールドの端子がハードウェアSPIに決め打ちになっているせい。これをソフトウェアSPIでやった。

Adafruit 1.8" 18-bit Color TFT Shield w/microSD and Joystick

シールドでの端子は以下の様になっている。
#define sclk 13
#define mosi 11
#define cs   10
#define dc   8
#define rst  0
#define sd_cs 4
ジョイスティックはアナログポートA3。


さて、以下のように書くとエラーになってしまう。TFT.hとTFT.cppはAdafruit_ST7735.hを呼び出しているが、ソフトウェアSPIを呼び出す5引数の部分の記述がないから。
TFT screen = TFT(TFT_CS, TFT_DC, TFT_MOSI, TFT_SCLK, TFT_RST);
以下に差し替え用のTFT.hとTFT.cpp、画面に線を引くサンプルを作った。

https://gist.github.com/houmei/1ec877f60f20c9d45a6e

 ソフトによるSPIは遅そうなので描画時間を測定した。線1本を引く時間はこのような差があった。

 Arduino UNO / ハードウェアSPI 8.65ms
Arduino Leonardo / ソフトウェアSPI 39.5ms 

2014SPIline 

追記:サンプルのスケッチ、Leonardo用はSerialコンソールを開いてないと先に進みません
ー以下解決ー
追記2:Arduino IDE1.5.6-r2にてMEGA2560互換機(Sinesmart)、Arduino DueはソフトSPIにて動作。
ただし両方共しばらく経つとハングする。(Leonardoも)

 ハングするとこうなる。Arduino Leonardoで4分46秒後に発生。
 Arduino UNO / ハードウェアによるSPIでも約1分で発生し、再起動するような挙動。TFTライブラリ?
2014softTFThang
 

Leonardo互換のSeeeduino LiteとGrove OLEDテスト


 Seeeduino Lite (スイッチサイエンス) 1995円。同社扱いのArduino Leonardo 2835円とくらべて安い。
黄色いコネクタと白いGrove用コネクタは自分でハンダ付けする。
特徴として、3.3V/5V切り替え、I2CとシリアルのGroveコネクタ、半ピンずらしたコネクタ取り付けのパターンあり。

 MacOSX 10.9.1 + Arduino IDE 1.0.5で動作確認。

 Seeeduino Lite Wiki
2014leo



 このままだとちょっとつまらないのでGroveを使ってみる。Groveは4ピンコネクタを使用するセンサ類を接続するSeeedStudio独自の規格。最初、右側のシリアル端子にシリアル用LCDを接続して試してみたが、Seeeduino Liteでは1,2番ピンに接続されている。これはATMega32U4のハードウェアシリアル端子なので、ライブラリに付属しているexamplesでは動かないようだ。
 そこで左側のI2C接続端子に128x64 OLEDを接続してみた。

GROVE System

Grove - OLED Display 0.96"

2014leo2 

 これは簡単、ライブラリをインストールしてArduino IDEを再起動、サンプルスケッチを呼び出してみただけ。
 

Arduino Leonardo用 USB-HIDの書き換えメモ、その他

 この記事、Arduino Leonardoでどうやって標準ではないUSB-HIDジョイスティックを入力可能にしているのかと思っていたら:
ゲームコントローラー cubic9.com

Turning an Arduino Leonardo into a joystick.

USBAPI.hとHID.cppを差し替えるだけだったのか! バイナリにパッチ当ててたよ……


以下、今月のメモ
HID-class USB Serial communication for AVRs using V-USB

Arduinoで物足りなくなっちゃった方へ。Cypress CY8CKIT-042 PSoC 4 PIONEER KIT
DA4121 PSoC 4 PIONEER KIT 共立エレショップ
Fubarino SD Development Board MICROCHIP PIC32MXのボード

mbed LPC1114FN28で8桁7セグLEDモジュールを制御してみた きょうのかんぱぱ
AVR用ISP変換ケーブルふたたび ikkei blog
Raspberry Piクイックスタートアップガイド (日本語) 
日本語音声認識  cubic9.com
ATmega32U2でArduinoモドキを作る  kosaka lab
Freescale,ノイズ耐性などに優れた5V電源仕様のARM Cortex-M0+マイコンを発売  5V系ARM
FRDM-KE02Z: Kinetis EシリーズFreedom開発プラットフォーム 
Cyclone V GX Starter Kit $179。DE0の次はこれか?
VFDとは
3V-5V switchable I2C Real Time Clock Shield
Marcelo Barros / This repository is a program ArduinoShieldSPI
ASOOVU USB

たぶん最後のカイゼン LEDのチラつきをなくしキー入力を確実に

 以下の続き。

 カイゼンCookieClicker用自動マウスクリック(TimerOne割り込みによるキー読み取り)  

Arduino Leonardoでマウスクリック/クッキーを自動的に焼く装置(マウスクリック99回/秒、設定変更可能)

 残り、気になっている点は7セグメントLEDのチラつきと、クリック送出開始・送出終了のキー反応が敏感すぎること。一回確実に押しっぱなしにしてON、離してから次に押しっぱなしにしてOFFのような動作にしたい。

 LEDのチラつきは表示を消してから書いているためで、値が変わらなければ表示の更新もしないことで解決。BASICでゲーム作る時は移動先にキャラクタを描いてから元のキャラクタを消さないとちらついてましたね。

 送出開始・終了は、割り込みルーチン内で直前は押していない、現在は押している状態を認識させればよい。押しっぱなしでも記録されるのは1回だけ。これでかなり操作性が良くなった。
 なおディレイ間隔の増減は押しっぱなしで連続的に変化してもらいたいためそのままとした。

  key=digitalRead(CBTN);
  if (key==LOW && Psend==HIGH) Send=1; // Press
  Psend=key;
 
ソースはこちら:
https://gist.github.com/houmei/6627272

現在、4.5GcpsでUncannyClickerのarchivementを得た。
 

カイゼンCookieClicker用自動マウスクリック(TimerOne割り込みによるキー読み取り)

前回作った
Arduino Leonardoでマウスクリック/クッキーを自動的に焼く装置(マウスクリック99回/秒、設定変更可能)
が大変雑だったので、スケッチを作りなおした。

 どのへんが雑だったかというと:
(1)ループ内でキーを読み込んでいるため、ループ回数などが簡単にいじれずキーの反応も悪い。
(2)1000回ループのうち指定した回数を最初の方に1ms間隔でマウスクリックを押し込めたのでどうもよろしくない(ブラウザが固まることがある)

 特に操作感が悪かったのでキー入力を取りこぼさないようタイマ割り込みで読み取り、グローバル変数に結果を置き、メインのループでそれを参照するようにした。また、マウスクリック(1ms)+指定したms何もしないで待つ、という動作を繰り返すようにしてなるべくマウスクリックを一定間隔にあけられるようにした。このため、7セグLEDでの表示は待ち時間のmsに変更。つまり数値が小さいほど時間あたりのクリック数は多い。

ソースはこちら:
https://gist.github.com/houmei/6611030 

 タイマ割り込みについてはTimerOneライブラリを使用する。これはArduino Leonardoにも対応している。動作は簡単に言うとBASICのON TIME GOSUB 行番号。通じた?

 TimeOneライブラリを使用するにはsetup()内で初期化する。

  Timer1.initialize();
  Timer1.attachInterrupt(readkey,30000); // 30ms 

これで30ms間隔でreadkey()関数を呼び出す。

 readkey()関数はプッシュボタンの状態を呼び出す。直前のボタンの状態と比較し、押されていたらグローバル変数Up,Down,Sendを1に設定する。これはボタンのチャタリングを除去するため。Up,Down,Sendはloop()内で読み出したら0にクリアする。

volatile int Send=0;
volatile int Up=0;
volatile int Down=0;

volatile int Psend=0;
volatile int Pup=0;
volatile int Pdown=0;

void readkey() {
  int key;
  key=digitalRead(ABTN);
  if (key==LOW && Pdown==LOW) Down=1;
  Pdown=key;
  key=digitalRead(BBTN);
  if (key==LOW && Pup==LOW) Up=1;
  Pup=key;
  key=digitalRead(CBTN);
  if (key==LOW && Psend==LOW) Send=1;
  Psend=key;
}

 さて、ちょっとはまったのが noInterrupts()と interrupts()。これらは割り込みを抑止/許可するのだが、Mouse.click()以前にnoIntterrupts()状態だとクリックが送出されない。つまり、USBのHIDマウス/キーボードを使うときには割り込みを許可しておかなければならない。
 
 で、だいぶ操作感は改善されましたよ。

2013cookieclick3




現在3.5Gcps (cookies per second)

http://orteil.dashnet.org/cookieclicker/ 



Arduino Leonardo (ソケット・ヘッダ付き)Arduino Leonardo (ソケット・ヘッダ付き)

Arduino
売り上げランキング : 38773

Amazonで詳しく見る
by G-Tools

Arduino Leonardoでマウスクリック/クッキーを自動的に焼く装置(マウスクリック99回/秒、設定変更可能)

 なぜか今日ツイッターの自分のTLで突然流行り始めたクッキークリッカー。最初はクッキーをクリックするだけだったのが……
http://orteil.dashnet.org/cookieclicker/

 常にクリックするのも面倒なので、勝手に連続クリックするのを作ってみた。マウスクリックの代わりはArduino Leonardoを使えば簡単にできそうだ、ということでその辺にある物で作ってみた。

https://gist.github.com/houmei/6572149

2013cookie


 Pin8,9,10にタクトスイッチを接続。もう片方はGNDへ。
 表示はシリアル接続7セグメント4桁LED(赤)を使ったけどクリック動作には直接関係ない。約1秒あたりのクリック数を表示させる。これはArduino Leonardoのハードウェアシリアル機能を使うのでPin2をモジュールのRXに接続する。以前ちょっと試した。
シリアル接続7セグメント4桁LEDとUSB-TTLシリアルコンバータケーブル
 8,9に接続したボタンでクリックする数を増減させる。10に接続したボタンでクリックの開始と停止。これはメインのループ内でポーリングしているだけなので応答が悪い。クリックを送出している時はLeonardo上のLEDを点灯させる。ま、TXランプが点滅するのでわかるんだけど。
 やってみたら1秒あたり100回ぐらい、もっと増やすとブラウザ側が応答できなくなってくる。

 こんな感じでスクリプト言語を使ってるみたいに思いついたものを作りたいんだけど、物理的な部品と使い方のストックが必要なのよねー 
 

ArduinoIDE1.0.3 USB-HID特に変わらず

やっと今日Arduino1.0.3のソースがダウンロードできたので、USB0-HIDのキーボード部分をチェックした。

// Keyboard
    0x05, 0x01,                    // USAGE_PAGE (Generic Desktop)	// 47
    0x09, 0x06,                    // USAGE (Keyboard)
    0xa1, 0x01,                    // COLLECTION (Application)
    0x85, 0x02,                    //   REPORT_ID (2)
    0x05, 0x07,                    //   USAGE_PAGE (Keyboard)
   
	0x19, 0xe0,                    //   USAGE_MINIMUM (Keyboard LeftControl)
    0x29, 0xe7,                    //   USAGE_MAXIMUM (Keyboard Right GUI)
    0x15, 0x00,                    //   LOGICAL_MINIMUM (0)
    0x25, 0x01,                    //   LOGICAL_MAXIMUM (1)
    0x75, 0x01,                    //   REPORT_SIZE (1)
    
	0x95, 0x08,                    //   REPORT_COUNT (8)
    0x81, 0x02,                    //   INPUT (Data,Var,Abs)
    0x95, 0x01,                    //   REPORT_COUNT (1)
    0x75, 0x08,                    //   REPORT_SIZE (8)
    0x81, 0x03,                    //   INPUT (Cnst,Var,Abs)
    
	0x95, 0x06,                    //   REPORT_COUNT (6)
    0x75, 0x08,                    //   REPORT_SIZE (8)
    0x15, 0x00,                    //   LOGICAL_MINIMUM (0)
    0x25, 0x65,                    //   LOGICAL_MAXIMUM (101)
    0x05, 0x07,                    //   USAGE_PAGE (Keyboard)
    
	0x19, 0x00,                    //   USAGE_MINIMUM (Reserved (no event indicated))
    0x29, 0x65,                    //   USAGE_MAXIMUM (Keyboard Application)
    0x81, 0x00,                    //   INPUT (Data,Ary,Abs)
    0xc0,                          // END_COLLECTION

そんなわけで LOGICAL_MAXIMUM(101) 、USAGE_MAXIMUM(101) →0x65 で変わらず。
なんで毎回制限してんだろ?日本語キーボードなど国際化無視?
 

Arduino IDE1.0.2 1.0.1との違い調査

Arduino IDE 1.0.2がリリースされた。
Download the Arduino Software

 リリースノートが和訳されている。
2012/11/5 Arduino-1.0.2リリース

 Arduino IDE 1.0.1でいじって気付いたLeonardo周りについて変化がないか確認した。

(1)USB HIDキーボードの送出可能コード範囲
ソースのHID.cppから該当箇所を確認。送出可能なコードの指定部分は0x65(101)で以前と変わらない。

(2)割込み
Arduino Leonardoの外部割り込み番号とピンの割り当てが異なる

これも変わらなかった。
PIN2かPIN3にスイッチを付けてGNDに落とし、割込みがかかるか調べる。

Arduino UNO R3:
INTNUM=0,INTPIN=2でPIN2○ PIN3×
INTNUM=0,INTPIN=3でPIN2○ PIN3△ (保証外動作)
INTNUM=1,INTPIN=2でPIN2× PIN3○ (保証外動作)
INTNUM=1,INTPIN=3でPIN2× PIN3○ 

Arduino Leonardo:
INTNUM=0,INTPIN=2でPIN2× PIN3△
INTNUM=0,INTPIN=3でPIN2× PIN3○
INTNUM=1,INTPIN=2でPIN2○ PIN3×
INTNUM=1,INTPIN=3でPIN2△ PIN3△ (不安定)

今後の実験はArduino IDE 1.0.2に移行する。

PS/2キーボード変換器の製作(19) HEXファイルにパッチを当てる

前回、Arduino LeonardoではUSBキーボードに関するHID Report Descriptorではふつうの日本語キーボード等とは違い、キーの上限を101に制限していることがわかった。これが原因で日本語キーボードの[¥]や[ろ]に対応するコードを送っても無視されていた。
 このHID Report Descriptorの記述はArduino IDE1.0.1のソースにあるHID.cppの中で定義されてある。これはコンパイル済みなのでいじれない。そこでArduino IDEが生成する、マイコンに書き込むイメージファイルである.HEXファイルにパッチを当てることにした。

 Arduino IDE1.0.1でコンパイル時に生成される.hexファイルの所在は以下の方法で知ることが出来る。
Arduino開発環境が使えなくなってハマった件

例えばこのようなディレクトリの中に生成される。(MacOSX)
/var/folders/r5/h8nsfjps4kzdltsm9t4p0qr00000gn/T/build2978712088924621678.tmp/sketch_oct06a.cpp.hex

.hexファイルはひとつしかないので、これをコピーして以下のパッチを当てる。
25行目、
:100180008103950675081500256505071900296581
 ↓
:10018000810395067508150025FE0507190029FE4F

 パッチ当て後はチェックサムも変更しなければならないのでawkで作ったツールで確認した。
[awk]インテルHEXフォーマットのチェッカ

 こうやって作った.hexファイルを書き込む。色々試行錯誤して、結局AVRISPmkIIを使った。
 
$ /Applications/Arduino1.0.1.app/Contents/Resources/Java/hardware/tools/avr/bin/avrdude -C/Applications/Arduino1.0.1.app/Contents/Resources/Java/hardware/tools/avr/etc/avrdude.conf -v -patmega32u4 -cavrispmkII -Pusb -b57600 -e -Uflash:w:ok.hex:i

書き込み用ツールavrdudeはArduinoIDE内のものを、confファイルも同様。ここでは-eでフラッシュメモリを消去してから書き込んでいる。-Uオプションで消去をスキップしたらverifyでエラーが出たため。

以下、ログ
avrdude: Version 5.11, compiled on Sep  2 2011 at 18:52:52
         Copyright (c) 2000-2005 Brian Dean, http://www.bdmicro.com/
         Copyright (c) 2007-2009 Joerg Wunsch

         System wide configuration file is "/Applications/Arduino1.0.1.app/Contents/Resources/Java/hardware/tools/avr/etc/avrdude.conf"
         User configuration file is "/Users/takesita/.avrduderc"
         User configuration file does not exist or is not a regular file, skipping

         Using Port                    : usb
         Using Programmer              : avrispmkII
         Overriding Baud Rate          : 57600
avrdude: usbdev_open(): Found AVRISP mkII, serno: 000200081404
         AVR Part                      : ATmega32U4
         Chip Erase delay              : 9000 us
         PAGEL                         : PD7
         BS2                           : PA0
         RESET disposition             : dedicated
         RETRY pulse                   : SCK
         serial program mode           : yes
         parallel program mode         : yes
         Timeout                       : 200
         StabDelay                     : 100
         CmdexeDelay                   : 25
         SyncLoops                     : 32
         ByteDelay                     : 0
         PollIndex                     : 3
         PollValue                     : 0x53
         Memory Detail                 :

                                  Block Poll               Page                       Polled
           Memory Type Mode Delay Size  Indx Paged  Size   Size #Pages MinW  MaxW   ReadBack
           ----------- ---- ----- ----- ---- ------ ------ ---- ------ ----- ----- ---------
           eeprom        65    10     8    0 no       1024    8      0  9000  9000 0x00 0x00
           flash         65     6   128    0 yes     32768  128    256  4500  4500 0x00 0x00
           lfuse          0     0     0    0 no          1    0      0  9000  9000 0x00 0x00
           hfuse          0     0     0    0 no          1    0      0  9000  9000 0x00 0x00
           efuse          0     0     0    0 no          1    0      0  9000  9000 0x00 0x00
           lock           0     0     0    0 no          1    0      0  9000  9000 0x00 0x00
           calibration    0     0     0    0 no          1    0      0     0     0 0x00 0x00
           signature      0     0     0    0 no          3    0      0     0     0 0x00 0x00

         Programmer Type : STK500V2
         Description     : Atmel AVR ISP mkII
         Programmer Model: AVRISP mkII
         Hardware Version: 1
         Firmware Version Master : 1.10
         Vtarget         : 5.0 V
         SCK period      : 8.00 us

avrdude: AVR device initialized and ready to accept instructions

Reading | ################################################## | 100% 0.01s

avrdude: Device signature = 0x1e9587
avrdude: safemode: lfuse reads as FF
avrdude: safemode: hfuse reads as D8
avrdude: safemode: efuse reads as CB
avrdude: erasing chip
avrdude: reading input file "ok.hex"
avrdude: writing flash (6676 bytes):

Writing | ################################################## | 100% 2.75s

avrdude: 6676 bytes of flash written
avrdude: verifying flash memory against ok.hex:
avrdude: load data flash data from input file ok.hex:
avrdude: input file ok.hex contains 6676 bytes
avrdude: reading on-chip flash data:

Reading | ################################################## | 100% 2.01s

avrdude: verifying ...
avrdude: 6676 bytes of flash verified

avrdude: safemode: lfuse reads as FF
avrdude: safemode: hfuse reads as D8
avrdude: safemode: efuse reads as CB
avrdude: safemode: Fuses OK

avrdude done.  Thank you.


 これで書き込んだLeonardo(Davinci)をPCに接続し、前回のキー入力テストを行うと、ちゃんと¥マークが入力できた。成功!

 なお、Arduino IDEのソース中ではLEDの状態を受信する部分は定義されていないので、USB経由の指示で、接続したPS/2キーボードのLEDを制御することができないようだ。

PS/2キーボード変換器の製作(18) USBキーボードの無視されるキーについて

正確にはArduino Leonardoで送信するキーのコードの一部が無視される現象について。

 WindowsXPで日本語キーボードが使える状態にして[¥]、[ろ]キーに対応するUsageコード0x89,0x87を送信する。普通の日本語キーボードでは期待通りの表示。だがArduino Leonardoから対応するコード0x89,0x87を送信しても無視される。この動作はUbuntu12.04をインストールした日本語キーボード接続のPCでも同様。
 USBlyzer というのを使ってパケットを監視してみた。これは有料だがお試し期間がある。
すると、日本語キーボードを接続したときは0x89を含むパケットにInternational3、0x87を含むパケットにInternational1の注釈がはいる。 しかしArduino Leonardoの場合は0x89、0x87とも注釈がApplicationとなっている。おなじキーボードデバイスなのに違う扱いを受けているようだ。どこかに違いがあるはずだが、ディスクリプタをよく理解していないので時間がかかりそう。キーボードに種別があるような記述は見つけていないし、ディスクリプタ中に現れるbCountrycodeは日本語キーボードでも0だったため、使われる地域の指定は無関係だった。他にあるのか。

 なお、調査中にわかったのだが、日本語キーボードの全角/半角キーはUsage 0x94にコードが割り当てられているが、実際に全角/半角の動作に切り替わるのは0x35[`]だった。

追記:なんとなくわかってきた。

https://gist.github.com/3854088

普通の日本語キーボードのHID Report Descriptorでは

Logical Minimum 0
Logical Maxmum 255
Usage Minimum (Undefined)
Usage Maximum 255

だけど、Arduino Leonardoは

Logical Minimum 0
Logical Maxmum 101
Usage Minimum (Undefined)
Usage Maximum 101 (アプリケーションキーまで)

となっている。0x89や0x87のコードを送っても無視されるのは多分このせい。

これらの記述はHID.cppの最初の方にある。これは……パッチを当てるしかないのか?


以下、資料: 
USB Descriptor
マウス付きUSBキーボードのディスクリプタ構成を調べる
HIDクラス
http://linux.die.net/Mobile-Guide/mobile-guide-p2c1s6-keyboard.html
USBキーボードのキーコード
アーカイブ: HID デバイスのハードウェア ID
Device Class Definition for Human Interface Devices (HID) [pdf]
HID Usage Tables[pdf]HID Usage Tables

PS/2キーボード変換器の製作(17) USBキーボードの任意コードの送出

Arduino Leonardo+IDE1.0.1ではKeyboard.press() / release()でUSB HIDキーボードのキーを押したような動作ができるが、引数としてアルファベットはASCIIコードを受け付け、HID Usage IDに変換してから送出しているので送れないキーがある。できれば余計な変換なしでHID Usage IDをそのまま送りたい。
 キーボードのコードを送信している部分 HID.cpp内のKeyboard_::sendReport(KeyReport* keys)はUSBAPI.hではprivateで宣言されている。USBAPI.hをコピーしてここだけpublic宣言にすればダマせるかなとやってみたがそんなのは通用しなかった。ここはコンパイル済で提供されているのでいじると大げさだしそんな実力はない。ということで、sendReport()内で呼び出してるHID_SendReport()は隠されてないのでこれを呼び出すArduinoライブラリを作ってみた。

https://gist.github.com/2ad9f7a713f46149e72f

ほぼHID.cppからのコピペですよ。

PS/2キーボード変換器の製作(16) ArduinoIDE1.0.1

Bootloaderメモ:
ArduinoのブートローダをいじってHIDのみホストに認識させることはできないだろうか?
dfu-programmer

ATmega 32u4 bootloader without ISP connection

USBメモ:
Arduino Leonardoを使ってUSBキーボード相当を実現しようとすると日本語キーボードの一部(¥、_)に対応するコードが送信できない。keyboard.press()を実現している部分をArduinoIDE1.0.1のソースから持ってきてそのままのコードを送れるように書き換えた。
ただしコンパイルが通った程度&汚いのでとりあえず置いとく。今週ちゃんと書きなおす。

https://gist.github.com/3827425

PS/2キーボード変換器の製作(15) US配列→JP配列の問題点

US配列から日本語配列に変換する部分を作成した。
Arduino用のスケッチは以下のとおり。これはUSB HIDキーボードに文字を出力すると共にシリアルポートにデバッグ情報を流す。
https://gist.github.com/3464019
ライブラリ(ps2kybd.h、ps2kybd.cpp)は前回から修正なし。
https://gist.github.com/ab100bfb33a78ddf067d



記号の置き換えは、以下のパターンで行う。
(1)SHIFTを押していない状態でSHIFTを押したような入力……右シフトキーpress、置き換えコード、右シフトキーrelease
(2)SHIFTを押していない状態で記号の置き換え……置き換えコード
(3)SHIFTを押した状態でSHIFTを押したような入力……置き換えコード
(4)SHIFTを押した状態でSHIFTを押さないような入力……左右のシフトキーをrelease、置き換えコード、元のシフトキーをpress

ALTキーを押した状態では、[`~]キーは変換せずにそのまま出力することで[ALT]+[漢字]と同じ操作になる。

 これで記号の置き換え、漢字入力のON/OFFができた。

 残った問題点。
(1)CapsLockの扱い。CapsLockはUSキーではSHIFT併用だが、日本語キーではそのまま。
→Capsフラグはライブラリ側にまかせているが、これをスケッチ側で対処
(2)[¥_]が入力できない →Arduino LeonardoはいったんASCIIコードで受けて内部で変換しUSB HIDコードを送っている。USキーのレイアウトを前提にしているため、日本語配列の[¥_]は対応するものがない。
(3)このアダプタをWindowsXPに接続するたびにデバイスドライバの確認ダイアログが登場する。

(2)、(3)は非常に大きな問題。

(2)はUSB HIDを直接送出する方法を調べなければならない。
(3)はArduinoのブートローダを置き換えなければならない。

うーん、これはけっこう難しいぞ……

スイッチサイエンス32U4ブレークアウトボードとAVRISPmkII

スイッチサイエンスの32U4ブレークアウトボードをArduino Leonardo化した。

SWITCH SCIENCE 32U4ブレークアウトボード

AVR ISPmkIIでArduinoブートローダを書き込むための端子は以下。

SCK (2).B1
MOSI (3).B2
MISO (4).B3
RST (5)
Vcc (6)
GND (21)

ACR ISPmkIIのICSP端子を上から見た図
AVRISPmkIIcon

ブレッドボード上で書き込み用の接続。32U4ブレークアウトボードはひっくり返して載せてる。また、AVR ISPmkIIのICSPコネクタは写真では上を向けているのでVccが左上に見える(赤い線)。
AVRISPmkII-32U4
 
 Arduino IDEから[ツール]→[書込装置]でAVRISPmkIIを選択し、[ツール]→[ブートローダを書き込む]でしばらく待つと青いLEDが点滅するようになる。これでOK。

参考:
AVRC Programming-Programmer

記事タイトルPS/2キーボード変換器の製作(14) US配列でPS/2→USB変換OK

PS/2のスキャンコードをUSB UserIDまで変換できた。次にArduino Leonardoで扱っているコードに変換する。変換方法はほぼ同じで、テーブルを別に用意する。

https://gist.github.com/ab100bfb33a78ddf067d

PrtScr / ScrLock / Break まわりが難航した。ここはスキャンコードが面倒。
USBのコードをKeyboard.press()やKeyboard.release()で操作する時には充分に注意しないとスケッチの修正ができなくなる。Arduino IDEからソースをコンパイルする時にスケッチ画面に文字がタイプされてしまうからだ。

・Windows7(64bit)(英語キーボード配列の設定)に本アダプタと英語キーボードを接続し確認
・WindowsXP(日本語キーボード配列の設定)に本アダプタと日本語キーボードを接続し確認

○(1)PrintScreen / ALT+PrintScreen 正常動作
○(2)ScrLock正常動作(Excelで確認)
○(3)[目](App)キー正常動作
○(4)日本語入力/英数入力切り換え確認OK
○(5)接続したままPC本体電源ONでも動作OK。Windows7のパスワード入力も確認
×(6)[\ろ] キーと[¥]キーを\に対応させたいのだがうまくいかない(日本語キーボード接続時)
→これは無視してもよいか?

Arduino Leonardoのライブラリの制限で、PC側の[無変換][変換][かな]キーに対応するコードを送ることができない。外付けキーボードの[無変換][変換][かな]キーを別のキーに割り当てることは可能。

その他の問題点:
(a)アダプタを接続するたびにデバイスマネージャがデバイスドライバを探す。(WindowsXP)
Windows7ではドライバがインストールできなかったことを通知。でも気持ち悪い。
→できればArduino用のドライバを入れずに動かしたい

(b)キーボードのステータスがわからない。
→PC本体からの指示を受け取る手段がない。PS/2キーボード側に送信するプログラムを書いていない。
※本体接続のキーボードのランプは点灯する。

しばらく英語キーボード配列のPCに接続して使ってみる。並行してUS→JP変換のテーブルを作成。

追記:
(6)は日本語キーボードのみの問題で、キーに対応するコードがArduino Leonardoから送れないため。
(a)はブートローダ差し替えでできそう。32U4はHWB端子を見てブートローダを起動するかどうかを判断するが、Arduinoのブートローダは関連するフューズビットを設定していないらしい。 

Arduino Leonardoの外部割り込み番号とピンの割り当てが異なる

PS/2キーボードのライブラリ改造を行なっていたら、Arduino Leonardoで動作がおかしい。Arduino UNO R3だと期待通りに動作する。どちらもマイコンからはピンが直接出ているので何が違うのか調べていたら、外部割り込みの番号とピン番号のアサインが違うことがわかった。

参考:Arduinoリファレンス attachinterrupt()

 再現環境を作った。(Arduino IDE 1.0.1、MacOSX)
 201207leonardo

以下のスケッチを使う。
// 20120703 Arduino IDE1.0.1
// Arduino UNO R3   INT_NUM=0,PIN=2 / INT_NUM=1,PIN=3
// Arduino Leonardo INT_NUM=0,PIN=3 / INT_NUM=1,PIN=2 (wrong)


#define INT_NUM 1
#define INT_PIN 3

int led = 13;
volatile int state = LOW;

void setup()
{
  pinMode(led, OUTPUT);
  pinMode(INT_PIN, INPUT_PULLUP);
  attachInterrupt(INT_NUM, blink, CHANGE);
}

void loop()
{
  digitalWrite(led, state);
}

void blink()
{
  state = !state;
}
 ピン2またはピン3に押ボタンを接続して、設定通りだとボタンを押せばLEDが反転する(チャタリングはとりあえず無視して)。
 Arduino UNO R3の場合は割り込み番号0、ピン2/割り込み番号1、ピン3の組み合わせで動作。
 Arduino Leonardoの場合は割り込み番号1、ピン2/割り込み番号0、ピン3の組み合わせで動作する。

この様に食い違っている。

PS/2キーボード変換器の製作(10) 整理

・PS/2キーボード→USB接続、US配列を日本語配列に変換する。工程整理。

■開発環境とマイコンは確定
・ArduinoIDE1.0.1とArduino Leonardo(互換品)で作成。オープンソース。再現性高い。
・送り返して書きなおしたりしなくても、先方でアップデート可能

☆印は優先、これらが出来れば最低限動作

□ハードウェア
□マイコン選定(AVR ATmega32U4搭載 Arduino Leonard互換ボード、複数の選択肢があることは重要)
 ※sparkfun ATmega32U4モジュール 今回は使わない http://www.switch-science.com/products/detail.php?product_id=982
☆PS/2ポートのPullUp抵抗無くせるか 設定確認
□ケース組み込み

□ソフトウェア
■構造
 ■PS/2キーボード入出力はArduinoのライブラリとして構成 → arduino.cc playgroundのps2keyboard/ps2keyboardext2を参考
 ■USB HIDキーボード出力はArduinoIDE1.0.1の機能を利用
 ■スキャンコード→USBのコードへの変換はスケッチで行う

・ライブラリ
□PS/2キーボード入力
 ■PS/2キーボードのスキャンコード Type2決め打ちでOK(Type1は古い機種、Type3は特殊で使われない)
 ☆スキャンコードを直接扱うrawread()を追加→作成済、未確認
 ☆スキャンコードをFIFOに入れる→キー取りこぼし対策
 ☆PrintScreen/Alt+PrintScreen
 □Pause(ただしPrintScreenができればたいしたことはない)
 □NumLock時挙動 キーパッド部分
□PS/2キーボード出力
 □コマンド送出 キーボード本体のLED制御
 □コマンド送出 キーボードリピート設定

・スケッチ
☆スキャンコード PS/2-US→USB-HID変換
□スキャンコード マルチメディア系の追加キー
☆make/release制御 USBは同時押し6個まで、PS/2は無制限 この調整

Arduino Leonardo USBキーの英語/日本語配列確認

Arduino Leonardoのkeyboard.press()でシフトキーを押した時の記号について。
以下のスケッチを使う。ピン2とGNDに繋いだスイッチを押すと[SHIFT]+[2]が出力される。


/*
 This example code is in the public domain.
 
 http://www.arduino.cc/en/Tutorial/Button
 */

// constants won't change. They're used here to 
// set pin numbers:
const int buttonPin = 2;     // the number of the pushbutton pin
const int keymacroPin = 3;
const int ledPin =  13;      // the number of the LED pin

// variables will change:
int buttonState = 0;         // variable for reading the pushbutton status

void setup() {
  // initialize the LED pin as an output:
  pinMode(ledPin, OUTPUT);      
  // initialize the pushbutton pin as an input:
  pinMode(buttonPin, INPUT_PULLUP);
  pinMode(keymacroPin, INPUT_PULLUP);

  Keyboard.begin();
}

void loop(){
  if (digitalRead(keymacroPin)==LOW) {
    // not implemented
  }

  // read the state of the pushbutton value:
  buttonState = digitalRead(buttonPin);

  // check if the pushbutton is pressed.
  // if it is, the buttonState is HIGH:
  if (buttonState == LOW) {     
    // turn LED on:    
    digitalWrite(ledPin, HIGH); 
    delay(30);
    while(buttonState == LOW){
      buttonState = digitalRead(buttonPin);
      Keyboard.press(KEY_LEFT_SHIFT);
      Keyboard.press('2');
    }
  } 
  else {
    // turn LED off:
    digitalWrite(ledPin, LOW); 
    Keyboard.release('2');
    Keyboard.release(KEY_LEFT_SHIFT);
  }
  delay(100);
}


 これを以下の環境で確認した。SHIFT+2では……
MacOSX Lion/PowerBookPro13インチ 日本語キーボード : @マーク
Windows7 32bit DELL PRECISION4300 英語キーボード : @マーク
WindowsXP DELL Latitude D630 日本語キーボード : ”マーク
 
 Windows環境では本体のキーボードを押すのと同じ様に入力された。
 MacOSXではLeonardoをUSBで接続した時にHIDキーボードの識別をする画面が出るが、これをキャンセルすると英語配列として扱うようだ。

ArduinoIDE1.0.1/Leonardoで足らないキーを追加する 続き

前回の続き。
 Arduino LeonardoではHID USB Keyboardとしてkey.press()でキーボードのように振る舞うことが出来る。これはArduino IDE1.0.1ソース中の
hardware/arduino/cores/arduino 以下にある
HID.cpp
USBAPI.h
で定義されている。

 USBAPI.hで定義されていないキーを、以下にまとめた。

参考:Universal Serial Bus(USB) HID Usage Tables
USBキーボードのコード 


#define KEY_PRINTSCREEN		0xCE
#define KEY_SCROLL_LOCK		0xCF
#define KEY_PAUSE			0xD0

#define KEYPAD_NUM_LOCK		0xDB
#define KEYPAD_SLASH		0xDC
#define KEYPAD_ASTERISK		0xDD
#define KEYPAD_MINUS		0xDE
#define KEYPAD_PLUS			0xDF
#define KEYPAD_ENTER		0xE0
#define KEYPAD_1			0xE1
#define KEYPAD_2			0xE2
#define KEYPAD_3			0xE3
#define KEYPAD_4			0xE4
#define KEYPAD_5			0xE5
#define KEYPAD_6			0xE6
#define KEYPAD_7			0xE7
#define KEYPAD_8			0xE8
#define KEYPAD_9			0xE9
#define KEYPAD_0			0xEA
#define KEYPAD_DOT			0xEB
#define KEYPAD_NONUS_BACKSLASH	0xEC
#define KEYPAD_APPRICATION	0xED
#define KEYPAD_POWER		0xEE
#define KEYPAD_EQUAL		0xEF
#define KEY_F13				0xF0
#define KEY_F14				0xF1
#define KEY_F15				0xF2
#define KEY_F16				0xF3
#define KEY_F17				0xF4
#define KEY_F18				0xF5
#define KEY_F19				0xF6
#define KEY_F20				0xF7
#define KEY_F21				0xF8
#define KEY_F22				0xF9
#define KEY_F23				0xFA
#define KEY_F24				0xFB
#define KEY_EXECUTE			0xFC
#define KEY_HELP			0xFD
#define KEY_MENU			0xFE
#define KEY_SELECT			0xFF
#define KEY_STOP			0x100
#define KEY_AGAIN			0x101
#define KEY_UNDO			0x102
#define KEY_CUT				0x103
#define KEY_COPY			0x104
#define KEY_PASTE			0x105
#define KEY_FIND			0x106
#define KEY_MUTE			0x107
#define KEY_VOLUP			0x108
#define KEY_VOLDOWN			0x109
#define KEY_LOCKING_CAPS_LOCK	0x10A
#define KEY_LOCKING_NUM_LOCK		0x10B
#define KEY_LOCKING_SCROLL_LOCK		0x10C
#define KEYPAD_COMMA		0x10D
#define KEYPAD_EQUALSIGN	0x10E
#define KEY_INTERNATIONAL1	0x10F
#define KEY_BACKSLASH	0x10F
#define KEY_INTERNATIONAL2	0x110
#define KEY_KANA	0x110
#define KEY_INTERNATIONAL3	0x111
#define KEY_YEN		0x111
#define KEY_INTERNATIONAL4	0x112
#define KEY_XFER	0x112
#define KEY_INTERNATIONAL5	0x113
#define KEY_NFER	0x113
#define KEY_INTERNATIONAL6	0x114
#define KEY_PC98_COMMA	0x114
#define KEY_INTERNATIONAL7	0x115
#define KEY_INTERNATIONAL8	0x116
#define KEY_INTERNATIONAL9	0x117
#define KEY_LANG1			0x118
#define KEY_LANG2			0x119
#define KEY_LANG3			0x11A
#define KEY_KATAKANA		0x11A
#define KEY_LANG4			0x11B
#define KEY_HIRAGANA		0x11B
#define KEY_LANG5			0x11C
#define KEY_ZENHAN			0x11C
#define KEY_LANG6			0x11D
#define KEY_LANG7			0x11E
#define KEY_LANG8			0x11F
#define KEY_LANG9			0x120
#define KEY_ALT_ERASE		0x121
#define KEY_SYSREQ			0x122
#define KEY_CANCEL			0x123
#define KEY_CLEAR			0x124
#define KEY_PRIOR			0x125
#define KEY_RETURN2			0x126
#define KEY_SEPARATOR		0x127
#define KEY_OUT				0x128
#define KEY_OPER			0x129
#define KEY_CLEAR_AGAIN		0x12A
#define KEY_CLRSEL			0x12B
#define KEY_EXSEL			0x12C

#define KEYPAD_00			0x138
#define KEYPAD_000			0x139
#define KEYPAD_THOUSANDS_SEPARATOR	0x13A
#define KEYPAD_DECIMAL_SEPARATOR	0x13B
#define KEYPAD_CURRENCY_UNIT	0x13C
#define KEYPAD_CURRENCY_SUBUNIT	0x13D
#define KEYPAD_LEFT_PAREN	0x13E
#define KEYPAD_RIGHT_PAREN	0x13F
#define KEYPAD_LEFT_BRACE	0x140
#define KEYPAD_RIGHT_BRACE	0x141
#define KEYPAD_TAB			0x142
#define KEYPAD_BACKSPACE	0x143
#define KEYPAD_A			0x144
#define KEYPAD_B			0x145
#define KEYPAD_C			0x146
#define KEYPAD_D			0x147
#define KEYPAD_E			0x148
#define KEYPAD_F			0x149
#define KEYPAD_XOR			0x14A
#define KEYPAD_CARET		0x14B
#define KEYPAD_PERCENT		0x14C
#define KEYPAD_LESSTHAN		0x14D
#define KEYPAD_GREATERTHAN	0x14E
#define KEYPAD_AND			0x14F
#define KEYPAD_LOGICAL_AND	0x150
#define KEYPAD_OR			0x151
#define KEYPAD_LOGICAL_OR	0x152
#define KEYPAD_COLON		0x153
#define KEYPAD_HASH			0x154
#define KEYPAD_SPACE		0x155
#define KEYPAD_ATMARK		0x156
#define KEYPAD_EXCLAMATION	0x157
#define KEYPAD_MS			0x158
#define KEYPAD_MR			0x159
#define KEYPAD_MC			0x15A
#define KEYPAD_MADD			0x15B
#define KEYPAD_MSUB			0x15C
#define KEYPAD_MMUL			0x15D
#define KEYPAD_MDIV			0x15E
#define KEYPAD_SIGN			0x15F
#define KEYPAD_CLEAR		0x160
#define KEYPAD_CLEARENTRY	0x161
#define KEYPAD_BIN			0x162
#define KEYPAD_OCT			0x163
#define KEYPAD_DEC			0x164
#define KEYPAD_HEX			0x165


問題点:0x100以上のコードは正しく扱われない。HID.cpp中のKeyboard_::press()が8bitの範囲内でしか扱っていないためと思われる。コードの修正も必要になる。

 MacOSXに接続して、Arduino Leonardoに繋いだボタンを押すとシャットダウン画面が出るものを作ってみた。また、pinmode(buttonPin,INPUT_PULLUP); で明示的なプルアップ指示をしてみた。これはArduino IDE 1.0.1からの機能。

/*
 This example code is in the public domain.
 
 http://www.arduino.cc/en/Tutorial/Button
 */

// constants won't change. They're used here to 
// set pin numbers:
const int buttonPin = 2;     // the number of the pushbutton pin
const int keymacroPin = 3;
const int ledPin =  13;      // the number of the LED pin

// variables will change:
int buttonState = 0;         // variable for reading the pushbutton status

#define KEY_PRINTSCREEN         0xCE
#define KEY_SCROLLLOCK          0xCF
#define KEY_PAUSE               0xD0
#define KEYPAD_POWER		0xEE
#define KEY_VOLUP			0x108
#define KEY_VOLDOWN			0x109

void setup() {
  // initialize the LED pin as an output:
  pinMode(ledPin, OUTPUT);      
  // initialize the pushbutton pin as an input:
  pinMode(buttonPin, INPUT_PULLUP);
  pinMode(keymacroPin, INPUT_PULLUP);

  Keyboard.begin();
}

void loop(){
  if (digitalRead(keymacroPin)==LOW) {
    // not implemented
  }

  // read the state of the pushbutton value:
  buttonState = digitalRead(buttonPin);

  // check if the pushbutton is pressed.
  // if it is, the buttonState is HIGH:
  if (buttonState == LOW) {     
    // turn LED on:    
    digitalWrite(ledPin, HIGH); 
    delay(30);
    while(buttonState == LOW){
      buttonState = digitalRead(buttonPin);
      // Keyboard.press(ctrlKey);
      Keyboard.press(KEYPAD_POWER);
    }
  } 
  else {
    // turn LED off:
    digitalWrite(ledPin, LOW); 
    Keyboard.release(KEYPAD_POWER);
  }
  delay(100);
}


Arduino Leonardo
記事検索
プロフィール

hardyboy

カテゴリ別アーカイブ
月別アーカイブ
QRコード
QRコード
  • ライブドアブログ