Arduino UNOでPCをスリープ
Arduino UNOを使って、ある条件の時にPCをスリープさせたいと思いました。 しかし、どうやらキーボード用のファームウェア(Arduino-keyboard.hex)を焼いてもスリープのコマンドは送れないらしい。
なので自分でファームウェアを書き換えて作ってみた。 今回はとりあえずスリープさえ出来ればいいと思って作ったので、キーボードと併用とかはできないです。
準備
必要なパッケージ
以下のものをaptでインストールします。
- avr-libc(avr-gccも一緒にインストールされます)
- dfu-programmer
ファームウェア書き換え
ファームウェア一式をダウンロードし、4箇所書き換えます。 今回はキーボード用のファームウェアをベースに書き換えます。
LUFA/Drivers/USB/Class/Common/HID.h
レポートデータの構造体を編集します。
typedef struct { uint8_t Modifier; /**< Keyboard modifier byte, indicating pressed modifier keys (a combination of * HID_KEYBOARD_MODIFER_* masks). */ uint8_t Reserved; /**< Reserved for OEM use, always set to 0. */ uint8_t KeyCode[6]; /**< Key codes of the currently pressed keys. */ } USB_KeyboardReport_Data_t;
↓
typedef struct { uint8_t ReportId; uint8_t Data; } USB_KeyboardReport_Data_t;
firmwares/arduino-keyboard/Arduino-keyboard.c
レポートデータのサイズが2になったので、8
を2
に変更します。
uint8_t keyboardData[8] = { 0 };
↓
uint8_t keyboardData[2] = { 0 };
if (BufferCount >= 8) { for (ind=0; ind<8; ind++) { keyboardData[ind] = RingBuffer_Remove(&USARTtoUSB_Buffer); }
↓
if (BufferCount &>= 2) { for (ind=0; ind<2; ind++) { keyboardData[ind] = RingBuffer_Remove(&USARTtoUSB_Buffer); }
Serial_TxByte(ledReport); } for (ind=0; ind<8; ind++) { datap[ind] = keyboardData[ind]; }
↓
Serial_TxByte(ledReport); } for (ind=0; ind<2; ind++) { datap[ind] = keyboardData[ind]; }
firmwares/arduino-keyboard/Descriptors.c
レポートディスクリプタを書き換えます。
const USB_Descriptor_HIDReport_Datatype_t PROGMEM KeyboardReport[] = { 0x05, 0x01, /* Usage Page (Generic Desktop) */ 0x09, 0x06, /* Usage (Keyboard) */ 0xa1, 0x01, /* Collection (Application) */ 0x75, 0x01, /* Report Size (1) */ 0x95, 0x08, /* Report Count (8) */ 0x05, 0x07, /* Usage Page (Key Codes) */ 0x19, 0xe0, /* Usage Minimum (Keyboard LeftControl) */ 0x29, 0xe7, /* Usage Maximum (Keyboard Right GUI) */ 0x15, 0x00, /* Logical Minimum (0) */ 0x25, 0x01, /* Logical Maximum (1) */ 0x81, 0x02, /* Input (Data, Variable, Absolute) */ 0x95, 0x01, /* Report Count (1) */ 0x75, 0x08, /* Report Size (8) */ 0x81, 0x03, /* Input (Const, Variable, Absolute) */ 0x95, 0x05, /* Report Count (5) */ 0x75, 0x01, /* Report Size (1) */ 0x05, 0x08, /* Usage Page (LEDs) */ 0x19, 0x01, /* Usage Minimum (Num Lock) */ 0x29, 0x05, /* Usage Maximum (Kana) */ 0x91, 0x02, /* Output (Data, Variable, Absolute) */ 0x95, 0x01, /* Report Count (1) */ 0x75, 0x03, /* Report Size (3) */ 0x91, 0x03, /* Output (Const, Variable, Absolute) */ 0x95, 0x06, /* Report Count (6) */ 0x75, 0x08, /* Report Size (8) */ 0x15, 0x00, /* Logical Minimum (0) */ 0x26, 231, 0, /* Logical Maximum (231) */ 0x05, 0x07, /* Usage Page (Keyboard) */ 0x19, 0x00, /* Usage Minimum (Reserved (no event indicated)) */ 0x29, 231, /* Usage Maximum (Keyboard Application) */ 0x81, 0x00, /* Input (Data, Array, Absolute) */ 0xc0 /* End Collection */ };
↓
const USB_Descriptor_HIDReport_Datatype_t PROGMEM KeyboardReport[] = { 0x05, 0x0c, // USAGE_PAGE (Consumer Devices) 0x09, 0x01, // USAGE (Consumer Control) 0xa1, 0x01, // COLLECTION (Application) 0x85, 0x01, // REPORT_ID (1) 0x15, 0x00, // LOGICAL_MINIMUM (0) 0x25, 0x01, // LOGICAL_MAXIMUM (1) 0x75, 0x01, // REPORT_SIZE (1) 0x95, 0x10, // REPORT_COUNT (16) 0x09, 0xe2, // USAGE (Mute) 0x01 0x09, 0xe9, // USAGE (Volume Up) 0x02 0x09, 0xea, // USAGE (Volume Down) 0x03 0x09, 0xcd, // USAGE (Play/Pause) 0x04 0x09, 0xb7, // USAGE (Stop) 0x05 0x09, 0xb6, // USAGE (Scan Previous Track) 0x06 0x09, 0xb5, // USAGE (Scan Next Track) 0x07 0x0a, 0x8a, 0x01, // USAGE (Mail) 0x08 0x0a, 0x92, 0x01, // USAGE (Calculator) 0x09 0x0a, 0x21, 0x02, // USAGE (www search) 0x0a 0x0a, 0x23, 0x02, // USAGE (www home) 0x0b 0x0a, 0x2a, 0x02, // USAGE (www favorites) 0x0c 0x0a, 0x27, 0x02, // USAGE (www refresh) 0x0d 0x0a, 0x26, 0x02, // USAGE (www stop) 0x0e 0x0a, 0x25, 0x02, // USAGE (www forward) 0x0f 0x0a, 0x24, 0x02, // USAGE (www back) 0x10 0x81, 0x62, // INPUT (Data,Var,Abs,NPrf,Null) 0xc0, // System Control Descriptor 0x05, 0x01, /* Usage Page (Generic Desktop) */ 0x09, 0x80, /* Usage (System Control) */ 0xA1, 0x01, /* Collection (Application) */ 0x85, 0x02, /* Report ID 0x02 [SYSTEM CTRL] */ 0x19, 0x82, /* Usage minimum (System Sleep) */ 0x29, 0x83, /* Usage maximum (System Wake up) */ 0x95, 0x02, /* Report count (2) */ 0x81, 0x06, /*Input (data, variable, relative, Preferred) */ 0x95, 0x06, /* Report count (6) */ 0x81, 0x01, /*Input (Constant) */ 0xC0 /*End Collection */ };
firmwares/arduino-keyboard/makefile
Arduino UNOのR3だとmakefileを書き換える必要があるみたいです。
MCU = atmega8u2 MCU_AVRDUDE = at90usb82 MCU_DFU = at90usb82 #MCU = atmega16u2 #MCU_AVRDUDE = atmega16u2 #MCU_DFU = atmega16u2
↓
#MCU = atmega8u2 #MCU_AVRDUDE = at90usb82 #MCU_DFU = at90usb82 MCU = atmega16u2 MCU_AVRDUDE = atmega16u2 MCU_DFU = atmega16u2
コンパイル&ファームウェア書き換え
ArduinoをDFUモードで繋いでおいてください
$ make $ make dfu
サンプルを動かしてみる
接続して認識されるとスリープします。(Windowsで動作確認)
uint8_t buf[2] = { 0 }; /* Report buffer 8Byte */ void setup() { Serial.begin(9600); delay(200); } void loop() { sleep(); while(1) { delay(1000); } } void sleep() { buf[0] = 2; buf[1] = 1; Serial.write(buf,2); delay(200); // これを送らないとブルースクリーンになる buf[0] = 0; buf[1] = 0; Serial.write(buf,2); }
最後に
レポートディスクリプタを正しく書いて、正しくデータを送ってあげれば用意されているファームウェアではできないこともできるようになるかな。 今回はスリープだけでしたが、拡張することで同じファームでキーボードの入力や、ボリューム調整キーの追加なども可能になると思います。
参考
サインスマート UNO 互換ボード for Arduino*USBケーブル付き*
- 出版社/メーカー: サインスマート(SainSmart)
- メディア: エレクトロニクス
- この商品を含むブログを見る