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; | |||
| } | |||