mirror of
https://github.com/felis/USB_Host_Shield_2.0.git
synced 2024-03-22 11:31:26 +01:00
Use the HIDBoot class to parse the incoming data
This commit is contained in:
parent
f783b97cb9
commit
aba004b047
5 changed files with 186 additions and 80 deletions
56
BTHID.cpp
56
BTHID.cpp
|
@ -18,18 +18,14 @@
|
||||||
#include "BTHID.h"
|
#include "BTHID.h"
|
||||||
// To enable serial debugging see "settings.h"
|
// To enable serial debugging see "settings.h"
|
||||||
//#define EXTRADEBUG // Uncomment to get even more debugging data
|
//#define EXTRADEBUG // Uncomment to get even more debugging data
|
||||||
//#define PRINTREPORT // Uncomment to print the report send by the Wii controllers
|
//#define PRINTREPORT // Uncomment to print the report send by the HID device
|
||||||
|
|
||||||
const uint8_t BUTTONS[] PROGMEM = { // Mouse buttons
|
|
||||||
0x04, // MIDDLE
|
|
||||||
0x02, // RIGHT
|
|
||||||
0, // Skip
|
|
||||||
0x01, // LEFT
|
|
||||||
};
|
|
||||||
|
|
||||||
BTHID::BTHID(BTD *p, bool pair, const char *pin) :
|
BTHID::BTHID(BTD *p, bool pair, const char *pin) :
|
||||||
pBtd(p) // pointer to USB class instance - mandatory
|
pBtd(p) // pointer to USB class instance - mandatory
|
||||||
{
|
{
|
||||||
|
for(uint8_t i = 0; i < epMUL; i++)
|
||||||
|
pRptParser[i] = NULL;
|
||||||
|
|
||||||
if (pBtd)
|
if (pBtd)
|
||||||
pBtd->registerServiceClass(this); // Register it as a Bluetooth service
|
pBtd->registerServiceClass(this); // Register it as a Bluetooth service
|
||||||
|
|
||||||
|
@ -196,22 +192,21 @@ void BTHID::ACLData(uint8_t* l2capinbuf) {
|
||||||
if (l2capinbuf[8] == 0xA1) { // HID_THDR_DATA_INPUT
|
if (l2capinbuf[8] == 0xA1) { // HID_THDR_DATA_INPUT
|
||||||
switch (l2capinbuf[9]) {
|
switch (l2capinbuf[9]) {
|
||||||
case 0x01: // Keyboard events
|
case 0x01: // Keyboard events
|
||||||
|
if (pRptParser[KEYBOARD_PARSER_ID]) {
|
||||||
|
uint16_t length = ((uint16_t)l2capinbuf[5] << 8 | l2capinbuf[4]);
|
||||||
|
pRptParser[KEYBOARD_PARSER_ID]->Parse((HID*)this, 0, (uint8_t) length, &l2capinbuf[10]);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 0x02: // Mouse events
|
case 0x02: // Mouse events
|
||||||
case 0x1A:
|
case 0x1A:
|
||||||
ButtonState = l2capinbuf[10];
|
if (pRptParser[MOUSE_PARSER_ID]) {
|
||||||
/*xAxis = l2capinbuf[11] | ((int16_t)l2capinbuf[12] << 8);
|
uint16_t length = ((uint16_t)l2capinbuf[5] << 8 | l2capinbuf[4]);
|
||||||
yAxis = l2capinbuf[13] | ((int16_t)l2capinbuf[14] << 8);
|
pRptParser[MOUSE_PARSER_ID]->Parse((HID*)this, 0, (uint8_t) length, &l2capinbuf[10]);
|
||||||
scroll = l2capinbuf[15] | ((int16_t)l2capinbuf[16] << 8);*/
|
|
||||||
|
|
||||||
if (ButtonState != OldButtonState) {
|
|
||||||
ButtonClickState = ButtonState & ~OldButtonState; // Update click state variable
|
|
||||||
OldButtonState = ButtonState;
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 0x03:
|
case 0x03:
|
||||||
#ifdef DEBUG_USB_HOST
|
#ifdef EXTRADEBUG
|
||||||
Notify(PSTR("\r\nChange mode event: "), 0x80);
|
Notify(PSTR("\r\nChange mode event: "), 0x80);
|
||||||
D_PrintHex<uint8_t > (l2capinbuf[11], 0x80);
|
D_PrintHex<uint8_t > (l2capinbuf[11], 0x80);
|
||||||
#endif
|
#endif
|
||||||
|
@ -246,7 +241,7 @@ void BTHID::ACLData(uint8_t* l2capinbuf) {
|
||||||
|
|
||||||
void BTHID::L2CAP_task() {
|
void BTHID::L2CAP_task() {
|
||||||
switch (l2cap_state) {
|
switch (l2cap_state) {
|
||||||
/* These states are used if the Wiimote is the host */
|
/* These states are used if the HID device is the host */
|
||||||
case L2CAP_CONTROL_SUCCESS:
|
case L2CAP_CONTROL_SUCCESS:
|
||||||
if (l2cap_config_success_control_flag) {
|
if (l2cap_config_success_control_flag) {
|
||||||
#ifdef DEBUG_USB_HOST
|
#ifdef DEBUG_USB_HOST
|
||||||
|
@ -382,29 +377,6 @@ void BTHID::Run() {
|
||||||
/* HID Commands */
|
/* HID Commands */
|
||||||
/************************************************************/
|
/************************************************************/
|
||||||
void BTHID::setProtocol() {
|
void BTHID::setProtocol() {
|
||||||
uint8_t command = 0x71; // Set Protocol to "Report Protocol Mode", see HID specs page 33
|
uint8_t command = 0x70 | protocolMode; // Set Protocol, see HID specs page 33
|
||||||
pBtd->L2CAP_Command(hci_handle, &command, 1, control_scid[0], control_scid[1]);
|
pBtd->L2CAP_Command(hci_handle, &command, 1, control_scid[0], control_scid[1]);
|
||||||
}
|
}
|
||||||
|
|
||||||
/************************************************************/
|
|
||||||
/* BT HID Commands */
|
|
||||||
/************************************************************/
|
|
||||||
|
|
||||||
bool BTHID::getButtonPress(Button b) { // Return true when a button is pressed
|
|
||||||
return (bool)((ButtonState & pgm_read_byte(&BUTTONS[(uint8_t)b])));
|
|
||||||
}
|
|
||||||
|
|
||||||
bool BTHID::getButtonClick(Button b) { // Only return true when a button is clicked
|
|
||||||
uint8_t button = pgm_read_byte(&BUTTONS[(uint8_t)b]);
|
|
||||||
bool click = (ButtonClickState & button);
|
|
||||||
ButtonClickState &= ~button; // Clear "click" event
|
|
||||||
return click;
|
|
||||||
}
|
|
||||||
|
|
||||||
void BTHID::onInit() {
|
|
||||||
if (pFuncOnInit)
|
|
||||||
pFuncOnInit(); // Call the user function
|
|
||||||
else {
|
|
||||||
// Do nothing
|
|
||||||
}
|
|
||||||
}
|
|
52
BTHID.h
52
BTHID.h
|
@ -20,6 +20,7 @@
|
||||||
|
|
||||||
#include "BTD.h"
|
#include "BTD.h"
|
||||||
#include "controllerEnums.h"
|
#include "controllerEnums.h"
|
||||||
|
#include "hidboot.h"
|
||||||
|
|
||||||
/* Bluetooth L2CAP states for L2CAP_task() */
|
/* Bluetooth L2CAP states for L2CAP_task() */
|
||||||
#define L2CAP_WAIT 0
|
#define L2CAP_WAIT 0
|
||||||
|
@ -59,6 +60,10 @@
|
||||||
#define l2cap_connection_request_control_flag (l2cap_event_flag & L2CAP_FLAG_CONNECTION_CONTROL_REQUEST)
|
#define l2cap_connection_request_control_flag (l2cap_event_flag & L2CAP_FLAG_CONNECTION_CONTROL_REQUEST)
|
||||||
#define l2cap_connection_request_interrupt_flag (l2cap_event_flag & L2CAP_FLAG_CONNECTION_INTERRUPT_REQUEST)
|
#define l2cap_connection_request_interrupt_flag (l2cap_event_flag & L2CAP_FLAG_CONNECTION_INTERRUPT_REQUEST)
|
||||||
|
|
||||||
|
#define KEYBOARD_PARSER_ID 0
|
||||||
|
#define MOUSE_PARSER_ID 1
|
||||||
|
#define epMUL 2
|
||||||
|
|
||||||
/** This BluetoothService class implements support for the HID keyboard and mice. */
|
/** This BluetoothService class implements support for the HID keyboard and mice. */
|
||||||
class BTHID : public BluetoothService {
|
class BTHID : public BluetoothService {
|
||||||
public:
|
public:
|
||||||
|
@ -84,38 +89,27 @@ public:
|
||||||
virtual void disconnect();
|
virtual void disconnect();
|
||||||
/**@}*/
|
/**@}*/
|
||||||
|
|
||||||
|
HIDReportParser *GetReportParser(uint8_t id) {
|
||||||
|
return pRptParser[id];
|
||||||
|
};
|
||||||
|
|
||||||
|
bool SetReportParser(uint8_t id, HIDReportParser *prs) {
|
||||||
|
pRptParser[id] = prs;
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
|
void setProtocolMode(uint8_t mode) {
|
||||||
|
protocolMode = mode;
|
||||||
|
};
|
||||||
|
|
||||||
/** True if a device is connected */
|
/** True if a device is connected */
|
||||||
bool connected;
|
bool connected;
|
||||||
|
|
||||||
/** @name HID mouse functions */
|
|
||||||
/**
|
|
||||||
* getButtonPress(Button b) will return true as long as the button is held down.
|
|
||||||
*
|
|
||||||
* While getButtonClick(Button b) will only return it once.
|
|
||||||
*
|
|
||||||
* So you instance if you need to increase a variable once you would use getButtonClick(Button b),
|
|
||||||
* but if you need to drive a robot forward you would use getButtonPress(Button b).
|
|
||||||
*/
|
|
||||||
bool getButtonPress(Button b);
|
|
||||||
bool getButtonClick(Button b);
|
|
||||||
/**@}*/
|
|
||||||
/** @name HID mouse functions */
|
|
||||||
/*int16_t getXaxis() {
|
|
||||||
return xAxis;
|
|
||||||
}
|
|
||||||
int16_t getYaxis() {
|
|
||||||
return yAxis;
|
|
||||||
}
|
|
||||||
int16_t getScroll() {
|
|
||||||
return scroll;
|
|
||||||
}*/
|
|
||||||
/**@}*/
|
|
||||||
|
|
||||||
/** Call this to start the paring sequence with a controller */
|
/** Call this to start the paring sequence with a controller */
|
||||||
void pair(void) {
|
void pair(void) {
|
||||||
if (pBtd)
|
if (pBtd)
|
||||||
pBtd->pairWithHID();
|
pBtd->pairWithHID();
|
||||||
}
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Used to call your own function when the controller is successfully initialized.
|
* Used to call your own function when the controller is successfully initialized.
|
||||||
|
@ -128,15 +122,21 @@ public:
|
||||||
private:
|
private:
|
||||||
BTD *pBtd; // Pointer to BTD instance
|
BTD *pBtd; // Pointer to BTD instance
|
||||||
|
|
||||||
|
HIDReportParser *pRptParser[epMUL];
|
||||||
|
|
||||||
/** Set report protocol. */
|
/** Set report protocol. */
|
||||||
void setProtocol();
|
void setProtocol();
|
||||||
|
uint8_t protocolMode;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called when the controller is successfully initialized.
|
* Called when the controller is successfully initialized.
|
||||||
* Use attachOnInit(void (*funcOnInit)(void)) to call your own function.
|
* Use attachOnInit(void (*funcOnInit)(void)) to call your own function.
|
||||||
* This is useful for instance if you want to set the LEDs in a specific way.
|
* This is useful for instance if you want to set the LEDs in a specific way.
|
||||||
*/
|
*/
|
||||||
void onInit();
|
void onInit() {
|
||||||
|
if (pFuncOnInit)
|
||||||
|
pFuncOnInit(); // Call the user function
|
||||||
|
}
|
||||||
void (*pFuncOnInit)(void); // Pointer to function called in onInit()
|
void (*pFuncOnInit)(void); // Pointer to function called in onInit()
|
||||||
|
|
||||||
void L2CAP_task(); // L2CAP state machine
|
void L2CAP_task(); // L2CAP state machine
|
||||||
|
|
|
@ -6,32 +6,42 @@
|
||||||
|
|
||||||
#include <BTHID.h>
|
#include <BTHID.h>
|
||||||
#include <usbhub.h>
|
#include <usbhub.h>
|
||||||
|
#include "KeyboardParser.h"
|
||||||
|
#include "MouseParser.h"
|
||||||
|
|
||||||
USB Usb;
|
USB Usb;
|
||||||
//USBHub Hub1(&Usb); // Some dongles have a hub inside
|
//USBHub Hub1(&Usb); // Some dongles have a hub inside
|
||||||
|
|
||||||
BTD Btd(&Usb); // You have to create the Bluetooth Dongle instance like so
|
BTD Btd(&Usb); // You have to create the Bluetooth Dongle instance like so
|
||||||
|
|
||||||
/* You can create the instance of the class in two ways */
|
/* You can create the instance of the class in two ways */
|
||||||
BTHID hid(&Btd, PAIR, "0000"); // This will start an inquiry and then pair with your Wiimote - you only have to do this once
|
// This will start an inquiry and then pair with your device - you only have to do this once
|
||||||
//BTHID hid(&Btd); // After that you can simply create the instance like so and then press any button on the Wiimote
|
// If you are using a Bluetooth keyboard, then you should type in the password on the keypad and then press enter
|
||||||
|
BTHID hid(&Btd, PAIR, "0000");
|
||||||
|
|
||||||
|
// After that you can simply create the instance like so and then press any button on the device
|
||||||
|
//BTHID hid(&Btd);
|
||||||
|
|
||||||
|
KbdRptParser keyboardPrs;
|
||||||
|
MouseRptParser mousePrs;
|
||||||
|
|
||||||
void setup() {
|
void setup() {
|
||||||
Serial.begin(115200);
|
Serial.begin(115200);
|
||||||
while (!Serial); // Wait for serial port to connect - used on Leonardo, Teensy and other boards with built-in USB CDC serial connection
|
while (!Serial); // Wait for serial port to connect - used on Leonardo, Teensy and other boards with built-in USB CDC serial connection
|
||||||
if (Usb.Init() == -1) {
|
if (Usb.Init() == -1) {
|
||||||
Serial.print(F("\r\nOSC did not start"));
|
Serial.print(F("\r\nOSC did not start"));
|
||||||
while (1); //halt
|
while (1); // Halt
|
||||||
}
|
}
|
||||||
|
|
||||||
|
hid.SetReportParser(KEYBOARD_PARSER_ID, (HIDReportParser*)&keyboardPrs);
|
||||||
|
hid.SetReportParser(MOUSE_PARSER_ID, (HIDReportParser*)&mousePrs);
|
||||||
|
|
||||||
|
// If "Boot Protocol Mode" does not work, then try "Report Protocol Mode"
|
||||||
|
// If that does not work either, then uncomment PRINTREPORT in BTHID.cpp to see the raw report
|
||||||
|
hid.setProtocolMode(HID_BOOT_PROTOCOL); // Boot Protocol Mode
|
||||||
|
//hid.setProtocolMode(HID_RPT_PROTOCOL); // Report Protocol Mode
|
||||||
|
|
||||||
Serial.print(F("\r\nHID Bluetooth Library Started"));
|
Serial.print(F("\r\nHID Bluetooth Library Started"));
|
||||||
}
|
}
|
||||||
void loop() {
|
void loop() {
|
||||||
Usb.Task();
|
Usb.Task();
|
||||||
if (hid.connected) {
|
|
||||||
if (hid.getButtonClick(LEFT)) // Print mouse buttons
|
|
||||||
Serial.println(F("Left"));
|
|
||||||
if (hid.getButtonClick(RIGHT))
|
|
||||||
Serial.println(F("Right"));
|
|
||||||
if (hid.getButtonClick(MIDDLE))
|
|
||||||
Serial.println(F("Middle"));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
78
examples/Bluetooth/BTHID/KeyboardParser.h
Normal file
78
examples/Bluetooth/BTHID/KeyboardParser.h
Normal file
|
@ -0,0 +1,78 @@
|
||||||
|
#ifndef __kbdrptparser_h_
|
||||||
|
#define __kbdrptparser_h_
|
||||||
|
|
||||||
|
class KbdRptParser : public KeyboardReportParser {
|
||||||
|
private:
|
||||||
|
void PrintKey(uint8_t mod, uint8_t key);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
virtual void OnControlKeysChanged(uint8_t before, uint8_t after);
|
||||||
|
virtual void OnKeyDown(uint8_t mod, uint8_t key);
|
||||||
|
virtual void OnKeyUp(uint8_t mod, uint8_t key);
|
||||||
|
virtual void OnKeyPressed(uint8_t key);
|
||||||
|
};
|
||||||
|
|
||||||
|
void KbdRptParser::PrintKey(uint8_t m, uint8_t key) {
|
||||||
|
MODIFIERKEYS mod;
|
||||||
|
*((uint8_t*)&mod) = m;
|
||||||
|
Serial.print((mod.bmLeftCtrl == 1) ? F("C") : F(" "));
|
||||||
|
Serial.print((mod.bmLeftShift == 1) ? F("S") : F(" "));
|
||||||
|
Serial.print((mod.bmLeftAlt == 1) ? F("A") : F(" "));
|
||||||
|
Serial.print((mod.bmLeftGUI == 1) ? F("G") : F(" "));
|
||||||
|
|
||||||
|
Serial.print(F(" >"));
|
||||||
|
PrintHex<uint8_t>(key, 0x80);
|
||||||
|
Serial.print(F("< "));
|
||||||
|
|
||||||
|
Serial.print((mod.bmRightCtrl == 1) ? F("C") : F(" "));
|
||||||
|
Serial.print((mod.bmRightShift == 1) ? F("S") : F(" "));
|
||||||
|
Serial.print((mod.bmRightAlt == 1) ? F("A") : F(" "));
|
||||||
|
Serial.println((mod.bmRightGUI == 1) ? F("G") : F(" "));
|
||||||
|
};
|
||||||
|
|
||||||
|
void KbdRptParser::OnKeyDown(uint8_t mod, uint8_t key) {
|
||||||
|
Serial.print(F("DN "));
|
||||||
|
PrintKey(mod, key);
|
||||||
|
uint8_t c = OemToAscii(mod, key);
|
||||||
|
|
||||||
|
if (c)
|
||||||
|
OnKeyPressed(c);
|
||||||
|
}
|
||||||
|
|
||||||
|
void KbdRptParser::OnControlKeysChanged(uint8_t before, uint8_t after) {
|
||||||
|
MODIFIERKEYS beforeMod;
|
||||||
|
*((uint8_t*)&beforeMod) = before;
|
||||||
|
|
||||||
|
MODIFIERKEYS afterMod;
|
||||||
|
*((uint8_t*)&afterMod) = after;
|
||||||
|
|
||||||
|
if (beforeMod.bmLeftCtrl != afterMod.bmLeftCtrl)
|
||||||
|
Serial.println(F("LeftCtrl changed"));
|
||||||
|
if (beforeMod.bmLeftShift != afterMod.bmLeftShift)
|
||||||
|
Serial.println(F("LeftShift changed"));
|
||||||
|
if (beforeMod.bmLeftAlt != afterMod.bmLeftAlt)
|
||||||
|
Serial.println(F("LeftAlt changed"));
|
||||||
|
if (beforeMod.bmLeftGUI != afterMod.bmLeftGUI)
|
||||||
|
Serial.println(F("LeftGUI changed"));
|
||||||
|
|
||||||
|
if (beforeMod.bmRightCtrl != afterMod.bmRightCtrl)
|
||||||
|
Serial.println(F("RightCtrl changed"));
|
||||||
|
if (beforeMod.bmRightShift != afterMod.bmRightShift)
|
||||||
|
Serial.println(F("RightShift changed"));
|
||||||
|
if (beforeMod.bmRightAlt != afterMod.bmRightAlt)
|
||||||
|
Serial.println(F("RightAlt changed"));
|
||||||
|
if (beforeMod.bmRightGUI != afterMod.bmRightGUI)
|
||||||
|
Serial.println(F("RightGUI changed"));
|
||||||
|
}
|
||||||
|
|
||||||
|
void KbdRptParser::OnKeyUp(uint8_t mod, uint8_t key) {
|
||||||
|
Serial.print(F("UP "));
|
||||||
|
PrintKey(mod, key);
|
||||||
|
}
|
||||||
|
|
||||||
|
void KbdRptParser::OnKeyPressed(uint8_t key) {
|
||||||
|
Serial.print(F("ASCII: "));
|
||||||
|
Serial.println((char)key);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
46
examples/Bluetooth/BTHID/MouseParser.h
Normal file
46
examples/Bluetooth/BTHID/MouseParser.h
Normal file
|
@ -0,0 +1,46 @@
|
||||||
|
#ifndef __mouserptparser_h__
|
||||||
|
#define __mouserptparser_h__
|
||||||
|
|
||||||
|
class MouseRptParser : public MouseReportParser {
|
||||||
|
protected:
|
||||||
|
virtual void OnMouseMove(MOUSEINFO *mi);
|
||||||
|
virtual void OnLeftButtonUp(MOUSEINFO *mi);
|
||||||
|
virtual void OnLeftButtonDown(MOUSEINFO *mi);
|
||||||
|
virtual void OnRightButtonUp(MOUSEINFO *mi);
|
||||||
|
virtual void OnRightButtonDown(MOUSEINFO *mi);
|
||||||
|
virtual void OnMiddleButtonUp(MOUSEINFO *mi);
|
||||||
|
virtual void OnMiddleButtonDown(MOUSEINFO *mi);
|
||||||
|
};
|
||||||
|
|
||||||
|
void MouseRptParser::OnMouseMove(MOUSEINFO *mi) {
|
||||||
|
Serial.print(F("dx="));
|
||||||
|
Serial.print(mi->dX, DEC);
|
||||||
|
Serial.print(F(" dy="));
|
||||||
|
Serial.println(mi->dY, DEC);
|
||||||
|
};
|
||||||
|
|
||||||
|
void MouseRptParser::OnLeftButtonUp(MOUSEINFO *mi) {
|
||||||
|
Serial.println(F("L Butt Up"));
|
||||||
|
};
|
||||||
|
|
||||||
|
void MouseRptParser::OnLeftButtonDown(MOUSEINFO *mi) {
|
||||||
|
Serial.println(F("L Butt Dn"));
|
||||||
|
};
|
||||||
|
|
||||||
|
void MouseRptParser::OnRightButtonUp(MOUSEINFO *mi) {
|
||||||
|
Serial.println(F("R Butt Up"));
|
||||||
|
};
|
||||||
|
|
||||||
|
void MouseRptParser::OnRightButtonDown(MOUSEINFO *mi) {
|
||||||
|
Serial.println(F("R Butt Dn"));
|
||||||
|
};
|
||||||
|
|
||||||
|
void MouseRptParser::OnMiddleButtonUp(MOUSEINFO *mi) {
|
||||||
|
Serial.println(F("M Butt Up"));
|
||||||
|
};
|
||||||
|
|
||||||
|
void MouseRptParser::OnMiddleButtonDown(MOUSEINFO *mi) {
|
||||||
|
Serial.println(F("M Butt Dn"));
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
Loading…
Reference in a new issue