Again still WIP - but now have the Bluetooth object talking through a keyboard object...main
@@ -56,7 +56,7 @@ | |||
// your best effort to read chapter 4 before asking USB questions! | |||
//#define USBHOST_PRINT_DEBUG | |||
#define USBHOST_PRINT_DEBUG | |||
/************************************************/ | |||
/* Data Types */ | |||
@@ -516,6 +516,35 @@ protected: | |||
Device_t *mydevice = NULL; | |||
}; | |||
// Device drivers may inherit from this base class, if they wish to receive | |||
// HID input like data from Bluetooth HID device. | |||
class BluetoothController; | |||
class BTHIDInput { | |||
public: | |||
operator bool() { return (btdevice != nullptr); } | |||
uint16_t idVendor() { return (btdevice != nullptr) ? btdevice->idVendor : 0; } | |||
uint16_t idProduct() { return (btdevice != nullptr) ? btdevice->idProduct : 0; } | |||
const uint8_t *manufacturer() | |||
{ return ((btdevice == nullptr) || (btdevice->strbuf == nullptr)) ? nullptr : &btdevice->strbuf->buffer[btdevice->strbuf->iStrings[strbuf_t::STR_ID_MAN]]; } | |||
const uint8_t *product() | |||
{ return ((btdevice == nullptr) || (btdevice->strbuf == nullptr)) ? nullptr : &btdevice->strbuf->buffer[btdevice->strbuf->iStrings[strbuf_t::STR_ID_PROD]]; } | |||
const uint8_t *serialNumber() | |||
{ return ((btdevice == nullptr) || (btdevice->strbuf == nullptr)) ? nullptr : &btdevice->strbuf->buffer[btdevice->strbuf->iStrings[strbuf_t::STR_ID_SERIAL]]; } | |||
private: | |||
virtual bool claim_bluetooth(BluetoothController *driver, uint32_t bluetooth_class) {return false;} | |||
virtual bool process_bluetooth_HID_data(const uint8_t *data, uint16_t length) {return false;} | |||
virtual void release_bluetooth() {}; | |||
void add_to_list(); | |||
BTHIDInput *next; | |||
friend class BluetoothController; | |||
protected: | |||
Device_t *btdevice = NULL; | |||
}; | |||
/************************************************/ | |||
/* USB Device Drivers */ | |||
/************************************************/ | |||
@@ -655,7 +684,7 @@ private: | |||
//-------------------------------------------------------------------------- | |||
class KeyboardController : public USBDriver , public USBHIDInput { | |||
class KeyboardController : public USBDriver , public USBHIDInput, public BTHIDInput { | |||
public: | |||
typedef union { | |||
struct { | |||
@@ -673,7 +702,13 @@ public: | |||
KeyboardController(USBHost *host) { init(); } | |||
// Some methods are in both public classes so we need to figure out which one to use | |||
operator bool() { return (device != nullptr); } | |||
uint16_t idVendor(); | |||
uint16_t idProduct(); | |||
const uint8_t *manufacturer(); | |||
const uint8_t *product(); | |||
const uint8_t *serialNumber(); | |||
operator bool() { return ((device != nullptr) || (btdevice != nullptr)); } | |||
// Main boot keyboard functions. | |||
uint16_t getKey() { return keyCode; } | |||
uint8_t getModifiers() { return modifiers; } | |||
@@ -704,6 +739,12 @@ protected: | |||
void new_data(const Transfer_t *transfer); | |||
void init(); | |||
// Bluetooth data | |||
bool claim_bluetooth(BluetoothController *driver, uint32_t bluetooth_class); | |||
bool process_bluetooth_HID_data(const uint8_t *data, uint16_t length); | |||
void release_bluetooth(); | |||
protected: // HID functions for extra keyboard data. | |||
virtual hidclaim_t claim_collection(USBHIDParser *driver, Device_t *dev, uint32_t topusage); | |||
virtual void hid_input_begin(uint32_t topusage, uint32_t type, int lgmin, int lgmax); | |||
@@ -1546,12 +1587,15 @@ public: | |||
enum {MAX_ENDPOINTS=4, NUM_SERVICES=4, }; // Max number of Bluetooth services - if you need more than 4 simply increase this number | |||
enum {BT_CLASS_DEVICE= 0x0804}; // Toy - Robot | |||
static void driver_ready_for_bluetooth(BTHIDInput *driver); | |||
protected: | |||
virtual bool claim(Device_t *device, int type, const uint8_t *descriptors, uint32_t len); | |||
virtual void control(const Transfer_t *transfer); | |||
virtual void disconnect(); | |||
//virtual void timer_event(USBDriverTimer *whichTimer); | |||
BTHIDInput * find_driver(uint32_t device_type); | |||
private: | |||
static void rx_callback(const Transfer_t *transfer); | |||
static void rx2_callback(const Transfer_t *transfer); | |||
@@ -1580,38 +1624,6 @@ private: | |||
void inline sendHCIRemoteNameRequest(); | |||
//void inline sendHCIReadBufferSize(); | |||
//void inline sendHCIReadClassOfDevice(); | |||
//void inline sendHCIReadLocalSupportedCommands(); | |||
//void inline sendHCIReadLocalName(); | |||
//void inline sendHCIReadVoiceSettings(); | |||
//void inline sendHCICommandReadNumberSupportedIAC(); | |||
//void inline sendHCICommandReadCurrentIACLAP(); | |||
//void inline sendHCIClearAllEventFilters(); | |||
//void inline sendHCIWriteConnectionAcceptTimeout(); | |||
//void inline sendHCILEReadBufferSize(); | |||
//void inline sendHCILEReadLocalSupportedFeatures(); | |||
//void inline sendHCILEReadSupportedStates(); | |||
//void inline sendHCIWriteInquiryMode(); | |||
//void inline sendHCIReadInquiryResponseTransmitPowerLevel(); | |||
//void inline sendHCIReadLocalExtendedFeatures(uint8_t page); | |||
//void inline sendHCISetEventMask(); | |||
//void inline sendHCIReadStoredLinkKey(); | |||
//void inline sendHCIWriteDefaultLinkPolicySettings(); | |||
//void inline sendHCIReadPageScanActivity(); | |||
//void inline sendHCIReadPageScanType(); | |||
//void inline sendHCILESetEventMask(); | |||
//void inline sendHCILEReadADVTXPower(); | |||
//void inline sendHCIEReadWhiteListSize(); | |||
//void inline sendHCILEClearWhiteList(); | |||
//void inline sendHCIDeleteStoredLinkKey(); | |||
//void inline sendHCIWriteLocalName(); | |||
//void inline sendHCIWriteSSPMode(uint8_t ssp_mode); | |||
//void inline sendHCIWriteEIR(); | |||
//void inline sendHCIWriteLEHostSupported(); | |||
//void inline sendHCILESetAdvData () ; | |||
//void inline sendHCILESetScanRSPData(); | |||
void handle_hci_command_complete(); | |||
void handle_hci_command_status(); | |||
void handle_hci_inquiry_result(); | |||
@@ -1639,6 +1651,7 @@ private: | |||
void setHIDProtocol(uint8_t protocol); | |||
void handleHIDTHDRData(uint8_t *buffer); // Pass the whole buffer... | |||
static BTHIDInput *available_bthid_drivers_list; | |||
setup_t setup; | |||
@@ -1663,6 +1676,7 @@ private: | |||
const char *pair_pincode_; // What pin code to use for the pairing | |||
uint8_t my_bdaddr[6]; // The bluetooth dongles Bluetooth address. | |||
uint8_t features[8]; // remember our local features. | |||
BTHIDInput * device_driver_ = nullptr;; | |||
uint8_t device_bdaddr_[6];// remember devices address | |||
uint8_t device_ps_repetion_mode_ ; // mode | |||
uint8_t device_clock_offset_[2]; |
@@ -149,6 +149,42 @@ enum {PC_RESET = 1, PC_WRITE_CLASS_DEVICE, PC_READ_BDADDR, PC_READ_LOCAL_VERSION | |||
// Setup some states for the TX pipe where we need to chain messages | |||
enum {STATE_TX_SEND_CONNECT_INT=200, STATE_TX_SEND_CONECT_RSP_SUCCESS, STATE_TX_SEND_CONFIG_REQ}; | |||
// This is a list of all the drivers inherited from the BTHIDInput class. | |||
// Unlike the list of USBDriver (managed in enumeration.cpp), drivers stay | |||
// on this list even when they have claimed a top level collection. | |||
BTHIDInput * BluetoothController::available_bthid_drivers_list = NULL; | |||
void BluetoothController::driver_ready_for_bluetooth(BTHIDInput *driver) | |||
{ | |||
driver->next = NULL; | |||
if (available_bthid_drivers_list == NULL) { | |||
available_bthid_drivers_list = driver; | |||
} else { | |||
BTHIDInput *last = available_bthid_drivers_list; | |||
while (last->next) last = last->next; | |||
last->next = driver; | |||
} | |||
} | |||
// When a new top level collection is found, this function asks drivers | |||
// if they wish to claim it. The driver taking ownership of the | |||
// collection is returned, or NULL if no driver wants it. | |||
BTHIDInput * BluetoothController::find_driver(uint32_t device_type) | |||
{ | |||
Serial.printf("BluetoothController::find_driver"); | |||
BTHIDInput *driver = available_bthid_drivers_list; | |||
while (driver) { | |||
Serial.printf(" driver %x\n", (uint32_t)driver); | |||
if (driver->claim_bluetooth(this, device_type)) { | |||
Serial.printf(" *** Claimed ***\n"); | |||
return driver; | |||
} | |||
driver = driver->next; | |||
} | |||
return NULL; | |||
} | |||
/************************************************************/ | |||
// Initialization and claiming of devices & interfaces | |||
/************************************************************/ | |||
@@ -265,6 +301,11 @@ bool BluetoothController::claim(Device_t *dev, int type, const uint8_t *descript | |||
void BluetoothController::disconnect() | |||
{ | |||
Serial.printf("Bluetooth Disconnect"); | |||
if (device_driver_) { | |||
device_driver_->release_bluetooth(); | |||
device_driver_ = nullptr; | |||
} | |||
} | |||
@@ -739,6 +780,8 @@ void BluetoothController::handle_hci_inquiry_result() | |||
// BUGBUG, lets hard code to go to new state... | |||
for (uint8_t i = 0; i < 6; i++) device_bdaddr_[i] = rxbuf_[index_bd+i]; | |||
device_class_ = bluetooth_class; | |||
device_driver_ = find_driver(device_class_); | |||
device_ps_repetion_mode_ = rxbuf_[index_ps]; // mode | |||
device_clock_offset_[0] = rxbuf_[index_clock_offset]; | |||
device_clock_offset_[1] = rxbuf_[index_clock_offset+1]; | |||
@@ -777,6 +820,7 @@ void BluetoothController::handle_hci_incoming_connect() { | |||
DBGPrintf(" Peripheral device\n"); | |||
if (class_of_device & 0x80) DBGPrintf(" Mouse\n"); | |||
if (class_of_device & 0x40) DBGPrintf(" Keyboard\n"); | |||
device_driver_ = find_driver(class_of_device); | |||
// We need to save away the BDADDR and class link type? | |||
for(uint8_t i=0; i<6; i++) device_bdaddr_[i] = rxbuf_[i+2]; | |||
@@ -826,6 +870,14 @@ void BluetoothController::handle_hci_disconnect_complete() | |||
//5 4 0 48 0 13 | |||
DBGPrintf(" Event: HCI Disconnect complete(%d): handle: %x, reason:%x\n", rxbuf_[2], | |||
rxbuf_[3]+(rxbuf_[4]<<8), rxbuf_[5]); | |||
if (device_driver_) { | |||
device_driver_->release_bluetooth(); | |||
device_driver_ = nullptr; | |||
} | |||
// Probably should clear out connection data. | |||
device_class_ = 0; | |||
memset(device_bdaddr_, 0, sizeof(device_bdaddr_)); | |||
//... | |||
} | |||
void BluetoothController::handle_hci_authentication_complete() | |||
@@ -1249,7 +1301,8 @@ void BluetoothController::process_l2cap_config_response(uint8_t *data) { | |||
data[8]+((uint16_t)data[9] << 8), data[10]+((uint16_t)data[11] << 8)); | |||
if (scid == control_dcid_) { | |||
// Set HID Boot mode | |||
setHIDProtocol(HID_BOOT_PROTOCOL); | |||
//setHIDProtocol(HID_BOOT_PROTOCOL); // | |||
setHIDProtocol(HID_RPT_PROTOCOL); //HID_RPT_PROTOCOL | |||
if (do_pair_device_) { | |||
// Tell system we will next need to setup connection for the interrupt | |||
pending_control_tx_ = STATE_TX_SEND_CONNECT_INT; | |||
@@ -1276,18 +1329,21 @@ void BluetoothController::handleHIDTHDRData(uint8_t *data) { | |||
DBGPrintf("HID HDR Data: len: %d, Type: %d\n", len, data[9]); | |||
// ??? How to parse??? Use HID object??? | |||
switch (data[9]) { | |||
case 1: | |||
DBGPrintf(" Keyboard report type\n"); | |||
break; | |||
case 2: | |||
DBGPrintf(" Mouse report type\n"); | |||
break; | |||
case 3: | |||
DBGPrintf(" Combo keyboard/pointing\n"); | |||
break; | |||
default: | |||
DBGPrintf(" Unknown report\n"); | |||
if (device_driver_) { | |||
device_driver_->process_bluetooth_HID_data(&data[9], len-1); // We skip the first byte... | |||
} else { | |||
switch (data[9]) { | |||
case 1: | |||
DBGPrintf(" Keyboard report type\n"); | |||
break; | |||
case 2: | |||
DBGPrintf(" Mouse report type\n"); | |||
break; | |||
case 3: | |||
DBGPrintf(" Combo keyboard/pointing\n"); | |||
break; | |||
default: | |||
DBGPrintf(" Unknown report\n"); | |||
} | |||
} | |||
} |
@@ -92,6 +92,44 @@ keycode_numlock_t keycode_numlock[] = { | |||
#define print USBHost::print_ | |||
#define println USBHost::println_ | |||
uint16_t KeyboardController::idVendor() | |||
{ | |||
if (device != nullptr) return device->idVendor; | |||
if (btdevice != nullptr) return btdevice->idVendor; | |||
return 0; | |||
} | |||
uint16_t KeyboardController::idProduct() | |||
{ | |||
if (device != nullptr) return device->idProduct; | |||
if (btdevice != nullptr) return btdevice->idProduct; | |||
return 0; | |||
} | |||
const uint8_t *KeyboardController::manufacturer() | |||
{ | |||
if ((device != nullptr) && (device->strbuf != nullptr)) return &device->strbuf->buffer[device->strbuf->iStrings[strbuf_t::STR_ID_MAN]]; | |||
if ((btdevice != nullptr) && (btdevice->strbuf != nullptr)) return &btdevice->strbuf->buffer[btdevice->strbuf->iStrings[strbuf_t::STR_ID_MAN]]; | |||
return nullptr; | |||
} | |||
const uint8_t *KeyboardController::product() | |||
{ | |||
if ((device != nullptr) && (device->strbuf != nullptr)) return &device->strbuf->buffer[device->strbuf->iStrings[strbuf_t::STR_ID_PROD]]; | |||
if ((btdevice != nullptr) && (btdevice->strbuf != nullptr)) return &btdevice->strbuf->buffer[btdevice->strbuf->iStrings[strbuf_t::STR_ID_PROD]]; | |||
return nullptr; | |||
} | |||
const uint8_t *KeyboardController::serialNumber() | |||
{ | |||
if ((device != nullptr) && (device->strbuf != nullptr)) return &device->strbuf->buffer[device->strbuf->iStrings[strbuf_t::STR_ID_SERIAL]]; | |||
if ((btdevice != nullptr) && (btdevice->strbuf != nullptr)) return &btdevice->strbuf->buffer[btdevice->strbuf->iStrings[strbuf_t::STR_ID_SERIAL]]; | |||
return nullptr; | |||
} | |||
void KeyboardController::init() | |||
{ | |||
contribute_Pipes(mypipes, sizeof(mypipes)/sizeof(Pipe_t)); | |||
@@ -99,6 +137,7 @@ void KeyboardController::init() | |||
contribute_String_Buffers(mystring_bufs, sizeof(mystring_bufs)/sizeof(strbuf_t)); | |||
driver_ready_for_device(this); | |||
USBHIDParser::driver_ready_for_hid_collection(this); | |||
BluetoothController::driver_ready_for_bluetooth(this); | |||
} | |||
bool KeyboardController::claim(Device_t *dev, int type, const uint8_t *descriptors, uint32_t len) | |||
@@ -323,8 +362,13 @@ void KeyboardController::LEDS(uint8_t leds) { | |||
void KeyboardController::updateLEDS() { | |||
// Now lets tell keyboard new state. | |||
mk_setup(setup, 0x21, 9, 0x200, 0, sizeof(leds_.byte)); // hopefully this sets leds | |||
queue_Control_Transfer(device, &setup, &leds_.byte, this); | |||
if (device != nullptr) { | |||
// Only do it this way if we are a standard USB device | |||
mk_setup(setup, 0x21, 9, 0x200, 0, sizeof(leds_.byte)); // hopefully this sets leds | |||
queue_Control_Transfer(device, &setup, &leds_.byte, this); | |||
} else { | |||
// Bluetooth, need to setup back channel to Bluetooth controller. | |||
} | |||
} | |||
//============================================================================= | |||
@@ -426,3 +470,51 @@ void KeyboardController::hid_input_end() | |||
hid_input_begin_ = false; | |||
} | |||
} | |||
bool KeyboardController::claim_bluetooth(BluetoothController *driver, uint32_t bluetooth_class) | |||
{ | |||
Serial.printf("Keyboard Controller::claim_bluetooth - Class %x\n", bluetooth_class); | |||
if ((((bluetooth_class & 0xff00) == 0x2500) || (((bluetooth_class & 0xff00) == 0x500))) && (bluetooth_class & 0x40)) { | |||
Serial.printf("KeyboardController::claim_bluetooth TRUE\n"); | |||
//btdevice = driver; | |||
return true; | |||
} | |||
return false; | |||
} | |||
bool KeyboardController::process_bluetooth_HID_data(const uint8_t *data, uint16_t length) | |||
{ | |||
// Example DATA from bluetooth keyboard: | |||
// 0 1 2 3 4 5 6 7 8 910 1 2 3 4 5 6 7 | |||
// LEN D | |||
//BT rx2_data(18): 48 20 e 0 a 0 70 0 a1 1 2 0 0 0 0 0 0 0 | |||
//BT rx2_data(18): 48 20 e 0 a 0 70 0 a1 1 2 0 4 0 0 0 0 0 | |||
//BT rx2_data(18): 48 20 e 0 a 0 70 0 a1 1 2 0 0 0 0 0 0 0 | |||
// So Len=9 passed in data starting at report ID=1... | |||
Serial.printf("KeyboardController::process_bluetooth_HID_data\n"); | |||
if (data[0] != 1) return false; | |||
print(" KB Data: "); | |||
print_hexbytes(data, length); | |||
for (int i=2; i < length; 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 = data[i]; | |||
if (key >= 4 && !contains(key, prev_report)) { | |||
key_press(data[1], key); | |||
} | |||
} | |||
// Save away the data.. But shift down one byte... Don't need the report number | |||
memcpy(prev_report, &data[1], 8); | |||
return true; | |||
} | |||
void KeyboardController::release_bluetooth() | |||
{ | |||
//btdevice = nullptr; | |||
} | |||