void USB_GetNextDescriptorOfTypeAfter(uint16_t* const BytesRem, void** const CurrConfigLoc, const uint8_t Type, const uint8_t AfterType) { USB_GetNextDescriptorOfType(BytesRem, CurrConfigLoc, AfterType); if (*BytesRem) USB_GetNextDescriptorOfType(BytesRem, CurrConfigLoc, Type); }
uint8_t USB_Host_GetDeviceConfigDescriptor(uint8_t ConfigNumber, uint16_t* const ConfigSizePtr, void* BufferPtr, uint16_t BufferSize) { uint8_t ErrorCode; uint8_t ConfigHeader[sizeof(USB_Descriptor_Configuration_Header_t)]; USB_ControlRequest = (USB_Request_Header_t) { .bmRequestType = (REQDIR_DEVICETOHOST | REQTYPE_STANDARD | REQREC_DEVICE), .bRequest = REQ_GetDescriptor, .wValue = ((DTYPE_Configuration << 8) | (ConfigNumber - 1)), .wIndex = 0, .wLength = sizeof(USB_Descriptor_Configuration_Header_t), }; Pipe_SelectPipe(PIPE_CONTROLPIPE); if ((ErrorCode = USB_Host_SendControlRequest(ConfigHeader)) != HOST_SENDCONTROL_Successful) return ErrorCode; *ConfigSizePtr = DESCRIPTOR_CAST(ConfigHeader, USB_Descriptor_Configuration_Header_t).TotalConfigurationSize; if (*ConfigSizePtr > BufferSize) return HOST_GETCONFIG_BuffOverflow; USB_ControlRequest.wLength = *ConfigSizePtr; if ((ErrorCode = USB_Host_SendControlRequest(BufferPtr)) != HOST_SENDCONTROL_Successful) return ErrorCode; if (DESCRIPTOR_TYPE(BufferPtr) != DTYPE_Configuration) return HOST_GETCONFIG_InvalidData; return HOST_GETCONFIG_Successful; } #endif void USB_GetNextDescriptorOfType(uint16_t* const BytesRem, void** const CurrConfigLoc, const uint8_t Type) { while (*BytesRem) { USB_GetNextDescriptor(BytesRem, CurrConfigLoc); if (DESCRIPTOR_TYPE(*CurrConfigLoc) == Type) return; } } void USB_GetNextDescriptorOfTypeBefore(uint16_t* const BytesRem, void** const CurrConfigLoc, const uint8_t Type, const uint8_t BeforeType) { while (*BytesRem) { USB_GetNextDescriptor(BytesRem, CurrConfigLoc); if (DESCRIPTOR_TYPE(*CurrConfigLoc) == Type) { return; } else if (DESCRIPTOR_TYPE(*CurrConfigLoc) == BeforeType) { *BytesRem = 0; return; } } } void USB_GetNextDescriptorOfTypeAfter(uint16_t* const BytesRem, void** const CurrConfigLoc, const uint8_t Type, const uint8_t AfterType) { USB_GetNextDescriptorOfType(BytesRem, CurrConfigLoc, AfterType); if (*BytesRem) USB_GetNextDescriptorOfType(BytesRem, CurrConfigLoc, Type); }
/** Reads and processes an attached device's descriptors, to determine compatibility and pipe configurations. This * routine will read in the entire configuration descriptor, and configure the hosts pipes to correctly communicate * with compatible devices. * * This routine searches for a BT interface descriptor containing bulk IN and OUT data endpoints. * * \return An error code from the \ref BluetoothHost_GetConfigDescriptorDataCodes_t enum. */ uint8_t ProcessConfigurationDescriptor(void) { uint8_t ConfigDescriptorData[512]; void* CurrConfigLocation = ConfigDescriptorData; uint16_t CurrConfigBytesRem; USB_Descriptor_Endpoint_t* DataINEndpoint = NULL; USB_Descriptor_Endpoint_t* DataOUTEndpoint = NULL; USB_Descriptor_Endpoint_t* EventsEndpoint = NULL; /* Retrieve the entire configuration descriptor into the allocated buffer */ switch (USB_Host_GetDeviceConfigDescriptor(1, &CurrConfigBytesRem, ConfigDescriptorData, sizeof(ConfigDescriptorData))) { case HOST_GETCONFIG_Successful: break; case HOST_GETCONFIG_InvalidData: return InvalidConfigDataReturned; case HOST_GETCONFIG_BuffOverflow: return DescriptorTooLarge; default: return DevControlError; } /* The Bluetooth USB transport addendum mandates that the data (not streaming voice) endpoints be in the first interface descriptor (interface 0) */ USB_GetNextDescriptorOfType(&CurrConfigBytesRem, &CurrConfigLocation, DTYPE_Interface); /* Ensure that an interface was found, and the end of the descriptor was not reached */ if (!(CurrConfigBytesRem)) return NoCompatibleInterfaceFound; while (!(DataINEndpoint) || !(DataOUTEndpoint)) { /* Get the next Bluetooth interface's data endpoint descriptor */ if (USB_GetNextDescriptorComp(&CurrConfigBytesRem, &CurrConfigLocation, DComp_NextInterfaceBluetoothDataEndpoint) != DESCRIPTOR_SEARCH_COMP_Found) { /* Data endpoints not found within the first bluetooth device interface, error out */ return NoCompatibleInterfaceFound; } /* Retrieve the endpoint address from the endpoint descriptor */ USB_Descriptor_Endpoint_t* EndpointData = DESCRIPTOR_PCAST(CurrConfigLocation, USB_Descriptor_Endpoint_t); /* If the endpoint is a IN type endpoint */ if ((EndpointData->EndpointAddress & ENDPOINT_DIR_MASK) == ENDPOINT_DIR_IN) { /* Check if the found endpoint is a interrupt or bulk type descriptor */ if ((EndpointData->Attributes & EP_TYPE_MASK) == EP_TYPE_INTERRUPT) EventsEndpoint = EndpointData; else DataINEndpoint = EndpointData; } else { DataOUTEndpoint = EndpointData; } } /* Configure the Bluetooth data IN pipe */ Pipe_ConfigurePipe(BLUETOOTH_DATA_IN_PIPE, EP_TYPE_BULK, PIPE_TOKEN_IN, DataINEndpoint->EndpointAddress, DataINEndpoint->EndpointSize, PIPE_BANK_SINGLE); /* Configure the Bluetooth data OUT pipe */ Pipe_ConfigurePipe(BLUETOOTH_DATA_OUT_PIPE, EP_TYPE_BULK, PIPE_TOKEN_OUT, DataOUTEndpoint->EndpointAddress, DataOUTEndpoint->EndpointSize, PIPE_BANK_SINGLE); /* Configure the Bluetooth events pipe */ Pipe_ConfigurePipe(BLUETOOTH_EVENTS_PIPE, EP_TYPE_INTERRUPT, PIPE_TOKEN_IN, EventsEndpoint->EndpointAddress, EventsEndpoint->EndpointSize, PIPE_BANK_SINGLE); Pipe_SetInterruptPeriod(EventsEndpoint->PollingIntervalMS); /* Valid data found, return success */ return SuccessfulConfigRead; }
/** Attempts to configure the system pipes for the attached Bluetooth adapter. * * \param[in] DeviceDescriptor Pointer to the Device Descriptor read from the attached device * \param[in] ConfigDescriptorSize Size of the retrieved Configuration Descriptor from the device * \param[in] ConfigDescriptorData Pointer to the Configuration Descriptor read from the attached device * * \return Boolean true if a valid Bluetooth interface was found, false otherwise. */ bool BluetoothAdapter_ConfigurePipes(USB_Descriptor_Device_t* const DeviceDescriptor, uint16_t ConfigDescriptorSize, void* ConfigDescriptorData) { USB_Descriptor_Endpoint_t* DataINEndpoint = NULL; USB_Descriptor_Endpoint_t* DataOUTEndpoint = NULL; USB_Descriptor_Endpoint_t* EventsEndpoint = NULL; BluetoothAdapter_IsActive = false; /* Validate returned device Class, SubClass and Protocol values against the Bluetooth spec values */ if ((DeviceDescriptor->Class != BLUETOOTH_DEVICE_CLASS) || (DeviceDescriptor->SubClass != BLUETOOTH_DEVICE_SUBCLASS) || (DeviceDescriptor->Protocol != BLUETOOTH_DEVICE_PROTOCOL)) { return false; } /* The Bluetooth USB transport addendum mandates that the data (not streaming voice) endpoints be in the first interface descriptor (interface 0) */ USB_GetNextDescriptorOfType(&ConfigDescriptorSize, &ConfigDescriptorData, DTYPE_Interface); /* Ensure that an interface was found, and the end of the descriptor was not reached */ if (!(ConfigDescriptorSize)) return false; while (!(DataINEndpoint) || !(DataOUTEndpoint) || !(EventsEndpoint)) { /* Get the next Bluetooth interface's data endpoint descriptor */ if (USB_GetNextDescriptorComp(&ConfigDescriptorSize, &ConfigDescriptorData, DComp_NextInterfaceBluetoothDataEndpoint) != DESCRIPTOR_SEARCH_COMP_Found) { /* Data endpoints not found within the first bluetooth device interface, error out */ return false; } /* Retrieve the endpoint address from the endpoint descriptor */ USB_Descriptor_Endpoint_t* EndpointData = DESCRIPTOR_PCAST(ConfigDescriptorData, USB_Descriptor_Endpoint_t); uint8_t EndpointType = (EndpointData->Attributes & EP_TYPE_MASK); /* If the endpoint is a IN type endpoint */ if ((EndpointData->EndpointAddress & ENDPOINT_DIR_MASK) == ENDPOINT_DIR_IN) { /* Check if the found endpoint is a interrupt or bulk type descriptor */ if (EndpointType == EP_TYPE_BULK) DataINEndpoint = EndpointData; else if (EndpointType == EP_TYPE_INTERRUPT) EventsEndpoint = EndpointData; } else { if (EndpointType == EP_TYPE_BULK) DataOUTEndpoint = EndpointData; } } /* Configure the Bluetooth data IN pipe */ Pipe_ConfigurePipe(BLUETOOTH_DATA_IN_PIPE, EP_TYPE_BULK, PIPE_TOKEN_IN, DataINEndpoint->EndpointAddress, DataINEndpoint->EndpointSize, PIPE_BANK_SINGLE); /* Configure the Bluetooth data OUT pipe */ Pipe_ConfigurePipe(BLUETOOTH_DATA_OUT_PIPE, EP_TYPE_BULK, PIPE_TOKEN_OUT, DataOUTEndpoint->EndpointAddress, DataOUTEndpoint->EndpointSize, PIPE_BANK_SINGLE); /* Configure the Bluetooth events pipe */ Pipe_ConfigurePipe(BLUETOOTH_EVENTS_PIPE, EP_TYPE_INTERRUPT, PIPE_TOKEN_IN, EventsEndpoint->EndpointAddress, EventsEndpoint->EndpointSize, PIPE_BANK_SINGLE); Pipe_SetInterruptPeriod(EventsEndpoint->PollingIntervalMS); BluetoothAdapter_IsActive = true; return true; }