// your best effort to read chapter 4 before asking USB questions! | // your best effort to read chapter 4 before asking USB questions! | ||||
#define USBHOST_PRINT_DEBUG | |||||
// #define USBHOST_PRINT_DEBUG | |||||
/************************************************/ | /************************************************/ | ||||
/* Data Types */ | /* Data Types */ | ||||
public: | public: | ||||
KeyboardController(USBHost &host) { init(); } | KeyboardController(USBHost &host) { init(); } | ||||
KeyboardController(USBHost *host) { init(); } | KeyboardController(USBHost *host) { init(); } | ||||
int available(); | |||||
int read(); | |||||
uint8_t getKey(); | |||||
uint8_t getModifiers(); | |||||
uint8_t getOemKey(); | |||||
void attachPress(void (*keyPressed)()); | |||||
void attachRelease(void (*keyReleased)()); | |||||
int available(); | |||||
int read(); | |||||
uint16_t getKey() { return keyCode; } | |||||
uint8_t getModifiers() { return modifiers; } | |||||
uint8_t getOemKey() { return keyOEM; } | |||||
void attachPress(void (*f)(int unicode)) { keyPressedFunction = f; } | |||||
void attachRelease(void (*f)(int unicode)) { keyReleasedFunction = f; } | |||||
protected: | protected: | ||||
virtual bool claim(Device_t *device, int type, const uint8_t *descriptors, uint32_t len); | virtual bool claim(Device_t *device, int type, const uint8_t *descriptors, uint32_t len); | ||||
virtual void control(const Transfer_t *transfer); | virtual void control(const Transfer_t *transfer); | ||||
void new_data(const Transfer_t *transfer); | void new_data(const Transfer_t *transfer); | ||||
void init(); | void init(); | ||||
private: | private: | ||||
void (*keyPressedFunction)(); | |||||
void (*keyReleasedFunction)(); | |||||
void update(); | |||||
uint16_t convert_to_unicode(uint32_t mod, uint32_t key); | |||||
void key_press(uint32_t mod, uint32_t key); | |||||
void key_release(uint32_t mod, uint32_t key); | |||||
void (*keyPressedFunction)(int unicode); | |||||
void (*keyReleasedFunction)(int unicode); | |||||
Pipe_t *datapipe; | Pipe_t *datapipe; | ||||
setup_t setup; | setup_t setup; | ||||
uint8_t report[8]; | uint8_t report[8]; | ||||
uint16_t keyCode; | |||||
uint8_t modifiers; | |||||
uint8_t keyOEM; | |||||
uint8_t prev_report[8]; | |||||
Pipe_t mypipes[2] __attribute__ ((aligned(32))); | Pipe_t mypipes[2] __attribute__ ((aligned(32))); | ||||
Transfer_t mytransfers[4] __attribute__ ((aligned(32))); | Transfer_t mytransfers[4] __attribute__ ((aligned(32))); | ||||
}; | }; |
USBHS_USBCMD |= USBHS_USBCMD_IAA; | USBHS_USBCMD |= USBHS_USBCMD_IAA; | ||||
if (rootdev) print(rootdev->control_pipe); | if (rootdev) print(rootdev->control_pipe); | ||||
#endif | #endif | ||||
keyboard1.attachPress(press); | |||||
keyboard2.attachPress(press); | |||||
midi1.setHandleNoteOff(OnNoteOff); | midi1.setHandleNoteOff(OnNoteOff); | ||||
midi1.setHandleNoteOn(OnNoteOn); | midi1.setHandleNoteOn(OnNoteOn); | ||||
midi1.setHandleControlChange(OnControlChange); | midi1.setHandleControlChange(OnControlChange); | ||||
digitalWriteFast(30, LOW); | digitalWriteFast(30, LOW); | ||||
} | } | ||||
void press(int key) | |||||
{ | |||||
Serial.print("key "); | |||||
Serial.println(key); | |||||
//Serial.print("key "); | |||||
//Serial.print((char)keyboard1.getKey()); | |||||
//Serial.print(" "); | |||||
//Serial.print((char)keyboard2.getKey()); | |||||
//Serial.println(); | |||||
} | |||||
void OnNoteOn(byte channel, byte note, byte velocity) | void OnNoteOn(byte channel, byte note, byte velocity) | ||||
{ | { | ||||
Serial.print(channel); | Serial.print(channel); | ||||
Serial.print(", note="); | Serial.print(", note="); | ||||
Serial.print(note); | Serial.print(note); | ||||
Serial.print(", velocity="); | |||||
Serial.print(velocity); | |||||
//Serial.print(", velocity="); | |||||
//Serial.print(velocity); | |||||
Serial.println(); | Serial.println(); | ||||
} | } | ||||
#include <Arduino.h> | #include <Arduino.h> | ||||
#include "USBHost_t36.h" // Read this header first for key info | #include "USBHost_t36.h" // Read this header first for key info | ||||
#include "keylayouts.h" // from Teensyduino core library | |||||
void KeyboardController::init() | void KeyboardController::init() | ||||
void KeyboardController::callback(const Transfer_t *transfer) | void KeyboardController::callback(const Transfer_t *transfer) | ||||
{ | { | ||||
println("KeyboardController Callback (static)"); | |||||
//println("KeyboardController Callback (static)"); | |||||
if (transfer->driver) { | if (transfer->driver) { | ||||
((KeyboardController *)(transfer->driver))->new_data(transfer); | ((KeyboardController *)(transfer->driver))->new_data(transfer); | ||||
} | } | ||||
} | } | ||||
void KeyboardController::disconnect() | |||||
{ | |||||
// TODO: free resources | |||||
} | |||||
// Arduino defined this static weak symbol callback, and their | |||||
// examples use it as the only way to detect new key presses, | |||||
// so unfortunate as static weak callbacks are, it probably | |||||
// needs to be supported for compatibility | |||||
extern "C" { | |||||
void __keyboardControllerEmptyCallback() { } | |||||
} | |||||
void keyPressed() __attribute__ ((weak, alias("__keyboardControllerEmptyCallback"))); | |||||
void keyReleased() __attribute__ ((weak, alias("__keyboardControllerEmptyCallback"))); | |||||
static bool contains(uint8_t b, const uint8_t *data) | |||||
{ | |||||
if (data[2] == b || data[3] == b || data[4] == b) return true; | |||||
if (data[5] == b || data[6] == b || data[7] == b) return true; | |||||
return false; | |||||
} | |||||
void KeyboardController::new_data(const Transfer_t *transfer) | void KeyboardController::new_data(const Transfer_t *transfer) | ||||
{ | { | ||||
println("KeyboardController Callback (member)"); | println("KeyboardController Callback (member)"); | ||||
print(" KB Data: "); | print(" KB Data: "); | ||||
print_hexbytes(transfer->buffer, 8); | print_hexbytes(transfer->buffer, 8); | ||||
// TODO: parse the new data | |||||
for (int i=2; i < 8; i++) { | |||||
uint32_t key = prev_report[i]; | |||||
if (key >= 4 && !contains(key, report)) { | |||||
key_release(prev_report[0], key); | |||||
} | |||||
} | |||||
for (int i=2; i < 8; i++) { | |||||
uint32_t key = report[i]; | |||||
if (key >= 4 && !contains(key, prev_report)) { | |||||
key_press(report[0], key); | |||||
} | |||||
} | |||||
memcpy(prev_report, report, 8); | |||||
queue_Data_Transfer(datapipe, report, 8, this); | queue_Data_Transfer(datapipe, report, 8, this); | ||||
} | } | ||||
void KeyboardController::disconnect() | |||||
void KeyboardController::key_press(uint32_t mod, uint32_t key) | |||||
{ | { | ||||
// TODO: free resources | |||||
// TODO: queue events, perform callback from Task | |||||
println(" press, key=", key); | |||||
modifiers = mod; | |||||
keyOEM = key; | |||||
keyCode = convert_to_unicode(mod, key); | |||||
println(" unicode = ", keyCode); | |||||
if (keyPressedFunction) { | |||||
keyPressedFunction(keyCode); | |||||
} else { | |||||
keyPressed(); | |||||
} | |||||
} | |||||
void KeyboardController::key_release(uint32_t mod, uint32_t key) | |||||
{ | |||||
// TODO: queue events, perform callback from Task | |||||
println(" release, key=", key); | |||||
modifiers = mod; | |||||
keyOEM = key; | |||||
keyCode = convert_to_unicode(mod, key); | |||||
if (keyReleasedFunction) { | |||||
keyReleasedFunction(keyCode); | |||||
} else { | |||||
keyReleased(); | |||||
} | |||||
} | } | ||||
uint16_t KeyboardController::convert_to_unicode(uint32_t mod, uint32_t key) | |||||
{ | |||||
// TODO: special keys | |||||
// TODO: caps lock | |||||
// TODO: dead key sequences | |||||
if ((mod & 0x02) || (mod & 0x20)) key |= SHIFT_MASK; | |||||
for (int i=0; i < 96; i++) { | |||||
if (keycodes_ascii[i] == key) return i + 32; | |||||
} | |||||
#ifdef ISO_8859_1_A0 | |||||
for (int i=0; i < 96; i++) { | |||||
if (keycodes_iso_8859_1[i] == key) return i + 160; | |||||
} | |||||
#endif | |||||
return 0; | |||||
} | |||||