static uint8_t Bluetooth_SendHCICommand(void* Parameters, uint16_t ParameterLength) { /* Need to reserve the amount of bytes given in the header for the complete payload */ uint8_t CommandBuffer[sizeof(HCICommandHeader) + HCICommandHeader.ParameterLength]; USB_ControlRequest = (USB_Request_Header_t) { .bmRequestType = (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_DEVICE), .bRequest = 0, .wValue = 0, .wIndex = 0, .wLength = sizeof(CommandBuffer) }; /* Copy over the HCI command header to the allocated buffer */ memcpy(CommandBuffer, &HCICommandHeader, sizeof(HCICommandHeader)); /* Zero out the parameter section of the response to ensure that any padding bytes do not expose private RAM contents */ memset(&CommandBuffer[sizeof(HCICommandHeader)], 0x00, HCICommandHeader.ParameterLength); /* Copy over the command parameters (if any) to the command buffer - note, the number of actual source parameter bytes may differ to those in the header; any difference in length is filled with 0x00 padding bytes */ memcpy(&CommandBuffer[sizeof(HCICommandHeader)], Parameters, ParameterLength); Pipe_SelectPipe(PIPE_CONTROLPIPE); return USB_Host_SendControlRequest(CommandBuffer); }
static uint8_t Bluetooth_SendHCICommand(void* Parameters, uint8_t ParamLength) { uint8_t CommandBuffer[sizeof(HCICommandHeader) + HCICommandHeader.ParameterLength]; USB_HostRequest = (USB_Host_Request_Header_t) { bmRequestType: (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_DEVICE), bRequest: 0, wValue: 0, wIndex: 0, wLength: sizeof(CommandBuffer) }; memset(CommandBuffer, 0x00, sizeof(CommandBuffer)); memcpy(CommandBuffer, &HCICommandHeader, sizeof(HCICommandHeader)); if (ParamLength) memcpy(&CommandBuffer[sizeof(HCICommandHeader)], Parameters, ParamLength); return USB_Host_SendControlRequest(CommandBuffer); } static bool Bluetooth_GetNextHCIEventHeader(void) { Pipe_SelectPipe(BLUETOOTH_EVENTS_PIPE); Pipe_Unfreeze(); if (!(Pipe_ReadWriteAllowed())) return false; Pipe_Read_Stream_LE(&HCIEventHeader, sizeof(HCIEventHeader)); return true; }
uint8_t Audio_Host_GetSetEndpointProperty(USB_ClassInfo_Audio_Host_t* const AudioInterfaceInfo, const uint8_t DataPipeIndex, const uint8_t EndpointProperty, const uint8_t EndpointControl, const uint16_t DataLength, void* const Data) { if (!(AudioInterfaceInfo->State.IsActive)) return HOST_SENDCONTROL_DeviceDisconnected; uint8_t RequestType; uint8_t EndpointAddress; if (EndpointProperty & 0x80) RequestType = (REQDIR_DEVICETOHOST | REQTYPE_CLASS | REQREC_ENDPOINT); else RequestType = (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_ENDPOINT); Pipe_SelectPipe(DataPipeIndex); EndpointAddress = Pipe_GetBoundEndpointAddress(); USB_ControlRequest = (USB_Request_Header_t) { .bmRequestType = RequestType, .bRequest = EndpointProperty, .wValue = ((uint16_t)EndpointControl << 8), .wIndex = EndpointAddress, .wLength = DataLength, }; Pipe_SelectPipe(PIPE_CONTROLPIPE); return USB_Host_SendControlRequest(Data); }
/** Writes a report to the attached device. * * \param[in] ReportOUTData Buffer containing the report to send to the device * \param[in] ReportLength Length of the report to send */ void WriteNextReport(uint8_t* const ReportOUTData, const uint16_t ReportLength) { if (USB_HostState != HOST_STATE_Configured) return; /* Select and unfreeze HID data OUT pipe */ Pipe_SelectPipe(HID_DATA_OUT_PIPE); /* Not all HID devices have an OUT endpoint (some require OUT reports to be sent over the * control endpoint instead) - check to see if the OUT endpoint has been initialized */ if (Pipe_IsConfigured()) { Pipe_Unfreeze(); /* Ensure pipe is ready to be written to before continuing */ if (!(Pipe_IsOUTReady())) { /* Refreeze the data OUT pipe */ Pipe_Freeze(); return; } /* Write out HID report data */ Pipe_Write_Stream_LE(ReportOUTData, ReportLength, NULL); /* Clear the OUT endpoint, send last data packet */ Pipe_ClearOUT(); /* Refreeze the data OUT pipe */ Pipe_Freeze(); } else { /* Class specific request to send a HID report to the device */ USB_ControlRequest = (USB_Request_Header_t) { .bmRequestType = (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE), .bRequest = HID_REQ_SetReport, .wValue = 0x02, .wIndex = 0x01, .wLength = ReportLength, }; /* Select the control pipe for the request transfer */ Pipe_SelectPipe(PIPE_CONTROLPIPE); /* Send the request to the device */ USB_Host_SendControlRequest(ReportOUTData); } }
/** Function to read in the HID report descriptor from the attached device, and process it into easy-to-read * structures via the HID parser routines in the LUFA library. * * \return A value from the \ref KeyboardHostWithParser_GetHIDReportDataCodes_t enum */ uint8_t GetHIDReportData(void) { /* Create a buffer big enough to hold the entire returned HID report */ uint8_t HIDReportData[HIDReportSize]; USB_ControlRequest = (USB_Request_Header_t) { .bmRequestType = (REQDIR_DEVICETOHOST | REQTYPE_STANDARD | REQREC_INTERFACE), .bRequest = REQ_GetDescriptor, .wValue = (HID_DTYPE_Report << 8), .wIndex = 0, .wLength = HIDReportSize, }; /* Select the control pipe for the request transfer */ Pipe_SelectPipe(PIPE_CONTROLPIPE); /* Send control request to retrieve the HID report from the attached device */ if (USB_Host_SendControlRequest(HIDReportData) != HOST_SENDCONTROL_Successful) return ParseControlError; /* Send the HID report to the parser for processing */ if (USB_ProcessHIDReport(HIDReportData, HIDReportSize, &HIDReportInfo) != HID_PARSE_Successful) return ParseError; return ParseSuccessful; } /** Callback for the HID Report Parser. This function is called each time the HID report parser is about to store * an IN, OUT or FEATURE item into the HIDReportInfo structure. To save on RAM, we are able to filter out items * we aren't interested in (preventing us from being able to extract them later on, but saving on the RAM they would * have occupied). * * \param[in] CurrentItem Pointer to the item the HID report parser is currently working with * * \return Boolean true if the item should be stored into the HID report structure, false if it should be discarded */ bool CALLBACK_HIDParser_FilterHIDReportItem(HID_ReportItem_t* const CurrentItem) { /* Check the attributes of the current item - see if we are interested in it or not; * only store KEYBOARD usage page items into the Processed HID Report structure to * save RAM and ignore the rest */ return (CurrentItem->Attributes.Usage.Page == USAGE_PAGE_KEYBOARD); }
void CALLBACK_Bluetooth_SendPacket(BT_StackConfig_t* const StackState, const uint8_t Type, const uint16_t Length) { /* Determine the type of packet being sent, use appropriate pipe */ switch (Type) { case BLUETOOTH_PACKET_HCICommand: USB_ControlRequest = (USB_Request_Header_t) { .bmRequestType = (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_DEVICE), .bRequest = 0, .wValue = 0, .wIndex = 0, .wLength = Length }; /* HCI commands must be sent over the Control pipe */ Pipe_SelectPipe(PIPE_CONTROLPIPE); USB_Host_SendControlRequest(StackState->Config.PacketBuffer); break; case BLUETOOTH_PACKET_HCIData: Pipe_SelectPipe(BLUETOOTH_DATA_OUT_PIPE); /* HCI data packets must be sent over the Data OUT pipe */ Pipe_Unfreeze(); Pipe_Write_Stream_LE(StackState->Config.PacketBuffer, Length, NULL); Pipe_ClearOUT(); Pipe_Freeze(); break; } // RGB_SetColour(RGB_ALIAS_Connected); } void EVENT_Bluetooth_InitComplete(BT_StackConfig_t* const StackState) { /* Save the local BDADDR of the connected Bluetooth adapter for later use */ // eeprom_update_block(BluetoothAdapter_Stack.State.HCI.LocalBDADDR, BluetoothAdapter_LastLocalBDADDR, sizeof(BDADDR_t)); }
uint8_t PRNT_Host_SetBidirectionalMode(USB_ClassInfo_PRNT_Host_t* const PRNTInterfaceInfo) { if (PRNTInterfaceInfo->State.AlternateSetting) { uint8_t ErrorCode; USB_ControlRequest = (USB_Request_Header_t) { .bmRequestType = (REQDIR_HOSTTODEVICE | REQTYPE_STANDARD | REQREC_INTERFACE), .bRequest = REQ_SetInterface, .wValue = PRNTInterfaceInfo->State.AlternateSetting, .wIndex = PRNTInterfaceInfo->State.InterfaceNumber, .wLength = 0, }; Pipe_SelectPipe(PIPE_CONTROLPIPE); if ((ErrorCode = USB_Host_SendControlRequest(NULL)) != HOST_SENDCONTROL_Successful) return ErrorCode; } return HOST_SENDCONTROL_Successful; }
/** Function to read in the HID report descriptor from the attached device, and process it into easy-to-read * structures via the HID parser routines in the LUFA library. * * \return A value from the MouseHostWithParser_GetHIDReportDataCodes_t enum */ uint8_t GetHIDReportData(void) { /* Create a buffer big enough to hold the entire returned HID report */ uint8_t HIDReportData[HIDReportSize]; USB_HostRequest = (USB_Host_Request_Header_t) { bmRequestType: (REQDIR_DEVICETOHOST | REQTYPE_STANDARD | REQREC_INTERFACE), bRequest: REQ_GetDescriptor, wValue: (DTYPE_Report << 8), wIndex: 0, wLength: HIDReportSize, }; /* Send control request to retrieve the HID report from the attached device */ if (USB_Host_SendControlRequest(HIDReportData) != HOST_SENDCONTROL_Successful) return ParseControlError; /* Send the HID report to the parser for processing */ if (ProcessHIDReport(HIDReportData, HIDReportSize, &HIDReportInfo) != HID_PARSE_Successful) return ParseError; return ParseSuccessful; }
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); }
/** Task to set the configuration of the attached device after it has been enumerated, and to send some test page * data to the attached printer. */ void USB_Printer_Host(void) { uint8_t ErrorCode; switch (USB_HostState) { case HOST_STATE_Addressed: puts_P(PSTR("Getting Config Data.\r\n")); /* Select the control pipe for the request transfer */ Pipe_SelectPipe(PIPE_CONTROLPIPE); /* Get and process the configuration descriptor data */ if ((ErrorCode = ProcessConfigurationDescriptor()) != SuccessfulConfigRead) { if (ErrorCode == ControlError) puts_P(PSTR(ESC_FG_RED "Control Error (Get Configuration).\r\n")); else puts_P(PSTR(ESC_FG_RED "Invalid Device.\r\n")); printf_P(PSTR(" -- Error Code: %d\r\n"), ErrorCode); /* Indicate error via status LEDs */ LEDs_SetAllLEDs(LEDMASK_USB_ERROR); /* Wait until USB device disconnected */ USB_HostState = HOST_STATE_WaitForDeviceRemoval; break; } /* Set the device configuration to the first configuration (rarely do devices use multiple configurations) */ if ((ErrorCode = USB_Host_SetDeviceConfiguration(1)) != HOST_SENDCONTROL_Successful) { printf_P(PSTR(ESC_FG_RED "Control Error (Set Configuration).\r\n" " -- Error Code: %d\r\n" ESC_FG_WHITE), ErrorCode); /* Indicate error via status LEDs */ LEDs_SetAllLEDs(LEDMASK_USB_ERROR); /* Wait until USB device disconnected */ USB_HostState = HOST_STATE_WaitForDeviceRemoval; break; } /* Some printers use alternate settings to determine the communication protocol used - if so, send a SetInterface * request to switch to the interface alternate setting with the Bidirectional protocol */ if (PrinterAltSetting) { USB_ControlRequest = (USB_Request_Header_t) { .bmRequestType = (REQDIR_HOSTTODEVICE | REQTYPE_STANDARD | REQREC_INTERFACE), .bRequest = REQ_SetInterface, .wValue = PrinterAltSetting, .wIndex = PrinterInterfaceNumber, .wLength = 0, }; if ((ErrorCode = USB_Host_SendControlRequest(NULL)) != HOST_SENDCONTROL_Successful) { printf_P(PSTR(ESC_FG_RED "Control Error (Set Interface).\r\n" " -- Error Code: %d\r\n" ESC_FG_WHITE), ErrorCode); /* Indicate error via status LEDs */ LEDs_SetAllLEDs(LEDMASK_USB_ERROR); /* Wait until USB device disconnected */ USB_HostState = HOST_STATE_WaitForDeviceRemoval; break; } } puts_P(PSTR("Retrieving Device ID...\r\n")); char DeviceIDString[300]; if ((ErrorCode = Printer_GetDeviceID(DeviceIDString, sizeof(DeviceIDString))) != HOST_SENDCONTROL_Successful) { printf_P(PSTR(ESC_FG_RED "Control Error (Get Device ID).\r\n" " -- Error Code: %d\r\n" ESC_FG_WHITE), ErrorCode); /* Indicate error via status LEDs */ LEDs_SetAllLEDs(LEDMASK_USB_ERROR); /* Wait until USB device disconnected */ USB_HostState = HOST_STATE_WaitForDeviceRemoval; break; } printf_P(PSTR("Printer Device ID: %s\r\n"), DeviceIDString); puts_P(PSTR("Printer Enumerated.\r\n")); USB_HostState = HOST_STATE_Configured; break; case HOST_STATE_Configured: /* Indicate device busy via the status LEDs */ LEDs_SetAllLEDs(LEDMASK_USB_BUSY); char TestPageData[] = "\033%-12345X\033E" "LUFA PCL Test Page" "\033E\033%-12345X"; uint16_t TestPageLength = strlen(TestPageData); printf_P(PSTR("Sending Test Page (%d bytes)...\r\n"), TestPageLength); if ((ErrorCode = Printer_SendData(&TestPageData, TestPageLength)) != PIPE_RWSTREAM_NoError) { printf_P(PSTR(ESC_FG_RED "Error Sending Test Page.\r\n" " -- Error Code: %d\r\n" ESC_FG_WHITE), ErrorCode); /* Indicate error via status LEDs */ LEDs_SetAllLEDs(LEDMASK_USB_ERROR); /* Wait until USB device disconnected */ USB_HostState = HOST_STATE_WaitForDeviceRemoval; break; } puts_P(PSTR("Test Page Sent.\r\n")); /* Indicate device no longer busy */ LEDs_SetAllLEDs(LEDMASK_USB_READY); USB_HostState = HOST_STATE_WaitForDeviceRemoval; break; } }
/** Function to read in the HID report descriptor from the attached device, and process it into easy-to-read * structures via the HID parser routines in the LUFA library. * * \return A value from the \ref MouseHostWithParser_GetHIDReportDataCodes_t enum */ uint8_t GetHIDReportData(void) { /* Create a buffer big enough to hold the entire returned HID report */ uint8_t HIDReportData[HIDReportSize]; USB_ControlRequest = (USB_Request_Header_t) { .bmRequestType = (REQDIR_DEVICETOHOST | REQTYPE_STANDARD | REQREC_INTERFACE), .bRequest = REQ_GetDescriptor, .wValue = (HID_DTYPE_Report << 8), .wIndex = 0, .wLength = HIDReportSize, }; /* Select the control pipe for the request transfer */ Pipe_SelectPipe(PIPE_CONTROLPIPE); /* Send control request to retrieve the HID report from the attached device */ if (USB_Host_SendControlRequest(HIDReportData) != HOST_SENDCONTROL_Successful) return ParseControlError; /* Send the HID report to the parser for processing */ if (USB_ProcessHIDReport(HIDReportData, HIDReportSize, &HIDReportInfo) != HID_PARSE_Successful) return ParseError; return ParseSuccessful; } /** Callback for the HID Report Parser. This function is called each time the HID report parser is about to store * an IN, OUT or FEATURE item into the HIDReportInfo structure. To save on RAM, we are able to filter out items * we aren't interested in (preventing us from being able to extract them later on, but saving on the RAM they would * have occupied). * * \param[in] CurrentItem Pointer to the item the HID report parser is currently working with * * \return Boolean true if the item should be stored into the HID report structure, false if it should be discarded */ bool CALLBACK_HIDParser_FilterHIDReportItem(HID_ReportItem_t* const CurrentItem) { bool IsMouse = false; /* Iterate through the item's collection path, until either the root collection node or a collection with the * Mouse Usage is found - this prevents Joysticks, which use identical descriptors except for the Joystick usage * parent node, from being erroneously treated as a mouse */ for (HID_CollectionPath_t* CurrPath = CurrentItem->CollectionPath; CurrPath != NULL; CurrPath = CurrPath->Parent) { if ((CurrPath->Usage.Page == USAGE_PAGE_GENERIC_DCTRL) && (CurrPath->Usage.Usage == USAGE_MOUSE)) { IsMouse = true; break; } } /* If a collection with the mouse usage was not found, indicate that we are not interested in this item */ if (!IsMouse) return false; /* Check the attributes of the current mouse item - see if we are interested in it or not; * only store BUTTON and GENERIC_DESKTOP_CONTROL items into the Processed HID Report * structure to save RAM and ignore the rest */ return ((CurrentItem->Attributes.Usage.Page == USAGE_PAGE_BUTTON) || (CurrentItem->Attributes.Usage.Page == USAGE_PAGE_GENERIC_DCTRL)); }
/** Issues a Printer class Get Device ID command to the attached device, to retrieve the device ID string (which indicates * the accepted printer languages, the printer's model and other pertinent information). * * \param[out] DeviceIDString Pointer to the destination where the returned string should be stored * \param[in] BufferSize Size in bytes of the allocated buffer for the returned Device ID string * * \return A value from the USB_Host_SendControlErrorCodes_t enum */ uint8_t Printer_GetDeviceID(char* DeviceIDString, const uint16_t BufferSize) { uint8_t ErrorCode; uint16_t DeviceIDStringLength = 0; USB_ControlRequest = (USB_Request_Header_t) { .bmRequestType = (REQDIR_DEVICETOHOST | REQTYPE_CLASS | REQREC_INTERFACE), .bRequest = PRNT_REQ_GetDeviceID, .wValue = 0, .wIndex = PrinterInterfaceNumber, .wLength = sizeof(DeviceIDStringLength), }; Pipe_SelectPipe(PIPE_CONTROLPIPE); if ((ErrorCode = USB_Host_SendControlRequest(&DeviceIDStringLength)) != HOST_SENDCONTROL_Successful) return ErrorCode; if (!(DeviceIDStringLength)) { DeviceIDString[0] = 0x00; return HOST_SENDCONTROL_Successful; } DeviceIDStringLength = SwapEndian_16(DeviceIDStringLength); if (DeviceIDStringLength > BufferSize) DeviceIDStringLength = BufferSize; USB_ControlRequest.wLength = DeviceIDStringLength; if ((ErrorCode = USB_Host_SendControlRequest(DeviceIDString)) != HOST_SENDCONTROL_Successful) return ErrorCode; /* Move string back two characters to remove the string length value from the start of the array */ memmove(&DeviceIDString[0], &DeviceIDString[2], DeviceIDStringLength - 2); DeviceIDString[DeviceIDStringLength - 2] = 0x00; return HOST_SENDCONTROL_Successful; } /** Issues a Printer class Get Port Status command to the attached device, to retrieve the current status flags of the * printer. * * \param[out] PortStatus Pointer to the destination where the printer's status flag values should be stored * * \return A value from the USB_Host_SendControlErrorCodes_t enum */ uint8_t Printer_GetPortStatus(uint8_t* const PortStatus) { USB_ControlRequest = (USB_Request_Header_t) { .bmRequestType = (REQDIR_DEVICETOHOST | REQTYPE_CLASS | REQREC_INTERFACE), .bRequest = PRNT_REQ_GetPortStatus, .wValue = 0, .wIndex = PrinterInterfaceNumber, .wLength = sizeof(uint8_t), }; Pipe_SelectPipe(PIPE_CONTROLPIPE); return USB_Host_SendControlRequest(PortStatus); } /** Issues a Printer class Soft Reset command to the attached device, to reset the printer ready for new input without * physically cycling the printer's power. * * \return A value from the USB_Host_SendControlErrorCodes_t enum */ uint8_t Printer_SoftReset(void) { USB_ControlRequest = (USB_Request_Header_t) { .bmRequestType = (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE), .bRequest = PRNT_REQ_SoftReset, .wValue = 0, .wIndex = PrinterInterfaceNumber, .wLength = 0, }; Pipe_SelectPipe(PIPE_CONTROLPIPE); return USB_Host_SendControlRequest(NULL); }
/** Writes a report to the attached device. * * \param[in] ReportOUTData Buffer containing the report to send to the device * \param[in] ReportIndex Index of the report in the device (zero if the device does not use multiple reports) * \param[in] ReportType Type of report to send, either REPORT_TYPE_OUT or REPORT_TYPE_FEATURE * \param[in] ReportLength Length of the report to send */ void WriteNextReport(uint8_t* ReportOUTData, const uint8_t ReportIndex, const uint8_t ReportType, uint16_t ReportLength) { /* Select the HID data OUT pipe */ Pipe_SelectPipe(HID_DATA_OUT_PIPE); /* Not all HID devices have an OUT endpoint (some require OUT reports to be sent over the * control endpoint instead) - check to see if the OUT endpoint has been initialized */ if (Pipe_IsConfigured() && (ReportType == REPORT_TYPE_OUT)) { Pipe_Unfreeze(); /* Ensure pipe is ready to be written to before continuing */ if (!(Pipe_IsOUTReady())) { /* Refreeze the data OUT pipe */ Pipe_Freeze(); return; } /* If the report index is used, send it before the report data */ if (ReportIndex) Pipe_Write_Byte(ReportIndex); /* Write out HID report data */ Pipe_Write_Stream_LE(ReportOUTData, ReportLength); /* Clear the OUT endpoint, send last data packet */ Pipe_ClearOUT(); /* Refreeze the data OUT pipe */ Pipe_Freeze(); } else { /* Class specific request to send a HID report to the device */ USB_ControlRequest = (USB_Request_Header_t) { .bmRequestType = (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE), .bRequest = HID_REQ_SetReport, .wValue = ((ReportType << 8) | ReportIndex), .wIndex = 0, .wLength = ReportLength, }; /* Select the control pipe for the request transfer */ Pipe_SelectPipe(PIPE_CONTROLPIPE); /* Send the request to the device */ USB_Host_SendControlRequest(ReportOUTData); } } /** Task to set the configuration of the attached device after it has been enumerated, and to read and process * HID reports from the device and to send reports if desired. */ void HID_Host_Task(void) { uint8_t ErrorCode; /* Switch to determine what user-application handled host state the host state machine is in */ switch (USB_HostState) { case HOST_STATE_Addressed: puts_P(PSTR("Getting Config Data.\r\n")); /* Get and process the configuration descriptor data */ if ((ErrorCode = ProcessConfigurationDescriptor()) != SuccessfulConfigRead) { if (ErrorCode == ControlError) puts_P(PSTR(ESC_FG_RED "Control Error (Get Configuration).\r\n")); else puts_P(PSTR(ESC_FG_RED "Invalid Device.\r\n")); printf_P(PSTR(" -- Error Code: %d\r\n" ESC_FG_WHITE), ErrorCode); /* Indicate error status */ LEDs_SetAllLEDs(LEDMASK_USB_ERROR); /* Wait until USB device disconnected */ USB_HostState = HOST_STATE_WaitForDeviceRemoval; break; } /* Set the device configuration to the first configuration (rarely do devices use multiple configurations) */ if ((ErrorCode = USB_Host_SetDeviceConfiguration(1)) != HOST_SENDCONTROL_Successful) { printf_P(PSTR(ESC_FG_RED "Control Error (Set Configuration).\r\n" " -- Error Code: %d\r\n" ESC_FG_WHITE), ErrorCode); /* Indicate error status */ LEDs_SetAllLEDs(LEDMASK_USB_ERROR); /* Wait until USB device disconnected */ USB_HostState = HOST_STATE_WaitForDeviceRemoval; break; } puts_P(PSTR("HID Device Enumerated.\r\n")); USB_HostState = HOST_STATE_Configured; break; case HOST_STATE_Configured: ReadNextReport(); break; } }
/** Task to set the configuration of the attached device after it has been enumerated, and to read and process * HID reports from the device and display the results onto the board LEDs. */ void Keyboard_HID_Task(void) { uint8_t ErrorCode; switch (USB_HostState) { case HOST_STATE_Addressed: puts_P(PSTR("Getting Config Data.\r\n")); /* Get and process the configuration descriptor data */ if ((ErrorCode = ProcessConfigurationDescriptor()) != SuccessfulConfigRead) { if (ErrorCode == ControlError) puts_P(PSTR(ESC_FG_RED "Control Error (Get Configuration).\r\n")); else puts_P(PSTR(ESC_FG_RED "Invalid Device.\r\n")); printf_P(PSTR(" -- Error Code: %d\r\n" ESC_FG_WHITE), ErrorCode); /* Indicate error status */ LEDs_SetAllLEDs(LEDMASK_USB_ERROR); /* Wait until USB device disconnected */ USB_HostState = HOST_STATE_WaitForDeviceRemoval; break; } /* Set the device configuration to the first configuration (rarely do devices use multiple configurations) */ if ((ErrorCode = USB_Host_SetDeviceConfiguration(1)) != HOST_SENDCONTROL_Successful) { printf_P(PSTR(ESC_FG_RED "Control Error (Set Configuration).\r\n" " -- Error Code: %d\r\n" ESC_FG_WHITE), ErrorCode); /* Indicate error status */ LEDs_SetAllLEDs(LEDMASK_USB_ERROR); /* Wait until USB device disconnected */ USB_HostState = HOST_STATE_WaitForDeviceRemoval; break; } /* HID class request to set the keyboard protocol to the Boot Protocol */ USB_ControlRequest = (USB_Request_Header_t) { .bmRequestType = (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE), .bRequest = REQ_SetProtocol, .wValue = 0, .wIndex = 0, .wLength = 0, }; /* Select the control pipe for the request transfer */ Pipe_SelectPipe(PIPE_CONTROLPIPE); /* Send the request, display error and wait for device detach if request fails */ if ((ErrorCode = USB_Host_SendControlRequest(NULL)) != HOST_SENDCONTROL_Successful) { printf_P(PSTR(ESC_FG_RED "Control Error (Set Protocol).\r\n" " -- Error Code: %d\r\n" ESC_FG_WHITE), ErrorCode); /* Indicate error status */ LEDs_SetAllLEDs(LEDMASK_USB_ERROR); /* Wait until USB device disconnected */ USB_HostState = HOST_STATE_WaitForDeviceRemoval; break; } puts_P(PSTR("Keyboard Enumerated.\r\n")); USB_HostState = HOST_STATE_Configured; break; case HOST_STATE_Configured: /* If a report has been received, read and process it */ ReadNextReport(); break; } }
uint8_t USB_Host_SetDeviceConfiguration(const uint8_t corenum, const uint8_t ConfigNumber) { uint8_t ErrorCode; USB_ControlRequest = (USB_Request_Header_t) { .bmRequestType = (REQDIR_HOSTTODEVICE | REQTYPE_STANDARD | REQREC_DEVICE), .bRequest = REQ_SetConfiguration, .wValue = ConfigNumber, .wIndex = 0, .wLength = 0, }; Pipe_SelectPipe(corenum, PIPE_CONTROLPIPE); if ((ErrorCode = USB_Host_SendControlRequest(corenum, NULL)) == HOST_SENDCONTROL_Successful) { USB_Host_ConfigurationNumber = ConfigNumber; USB_HostState[corenum] = (ConfigNumber) ? HOST_STATE_Configured : HOST_STATE_Addressed; } return ErrorCode; } uint8_t USB_Host_GetDeviceDescriptor(const uint8_t corenum, void* const DeviceDescriptorPtr) { USB_ControlRequest = (USB_Request_Header_t) { .bmRequestType = (REQDIR_DEVICETOHOST | REQTYPE_STANDARD | REQREC_DEVICE), .bRequest = REQ_GetDescriptor, .wValue = (DTYPE_Device << 8), .wIndex = 0, .wLength = sizeof(USB_Descriptor_Device_t), }; Pipe_SelectPipe(corenum, PIPE_CONTROLPIPE); return USB_Host_SendControlRequest(corenum,DeviceDescriptorPtr); } uint8_t USB_Host_GetDeviceStringDescriptor(const uint8_t corenum, const uint8_t Index, void* const Buffer, const uint8_t BufferLength) { USB_ControlRequest = (USB_Request_Header_t) { .bmRequestType = (REQDIR_DEVICETOHOST | REQTYPE_STANDARD | REQREC_DEVICE), .bRequest = REQ_GetDescriptor, .wValue = (DTYPE_String << 8) | Index, .wIndex = 0, .wLength = BufferLength, }; Pipe_SelectPipe(corenum, PIPE_CONTROLPIPE); return USB_Host_SendControlRequest(corenum,Buffer); } uint8_t USB_Host_GetDeviceStatus(const uint8_t corenum, uint8_t* const FeatureStatus) { USB_ControlRequest = (USB_Request_Header_t) { .bmRequestType = (REQDIR_DEVICETOHOST | REQTYPE_STANDARD | REQREC_DEVICE), .bRequest = REQ_GetStatus, .wValue = 0, .wIndex = 0, .wLength = 0, }; Pipe_SelectPipe(corenum, PIPE_CONTROLPIPE); return USB_Host_SendControlRequest(corenum, FeatureStatus); } uint8_t USB_Host_ClearEndpointStall(const uint8_t corenum, const uint8_t EndpointAddress) { USB_ControlRequest = (USB_Request_Header_t) { .bmRequestType = (REQDIR_HOSTTODEVICE | REQTYPE_STANDARD | REQREC_ENDPOINT), .bRequest = REQ_ClearFeature, .wValue = FEATURE_SEL_EndpointHalt, .wIndex = EndpointAddress, .wLength = 0, }; Pipe_SelectPipe(corenum, PIPE_CONTROLPIPE); return USB_Host_SendControlRequest(corenum,NULL); } uint8_t USB_Host_SetInterfaceAltSetting(const uint8_t corenum, const uint8_t InterfaceIndex, const uint8_t AltSetting) { USB_ControlRequest = (USB_Request_Header_t) { .bmRequestType = (REQDIR_HOSTTODEVICE | REQTYPE_STANDARD | REQREC_INTERFACE), .bRequest = REQ_SetInterface, .wValue = AltSetting, .wIndex = InterfaceIndex, .wLength = 0, }; Pipe_SelectPipe(corenum, PIPE_CONTROLPIPE); return USB_Host_SendControlRequest(corenum,NULL); }
/** Event handler for the USB_DeviceEnumerationComplete event. This indicates that a device has been successfully * enumerated by the host and is now ready to be used by the application. */ void EVENT_USB_Host_DeviceEnumerationComplete(void) { puts_P(PSTR("Getting Config Data.\r\n")); uint8_t ErrorCode; /* Get and process the configuration descriptor data */ if ((ErrorCode = ProcessConfigurationDescriptor()) != SuccessfulConfigRead) { if (ErrorCode == ControlError) puts_P(PSTR(ESC_FG_RED "Control Error (Get Configuration).\r\n")); else puts_P(PSTR(ESC_FG_RED "Invalid Device.\r\n")); printf_P(PSTR(" -- Error Code: %d\r\n" ESC_FG_WHITE), ErrorCode); LEDs_SetAllLEDs(LEDMASK_USB_ERROR); return; } /* Set the device configuration to the first configuration (rarely do devices use multiple configurations) */ if ((ErrorCode = USB_Host_SetDeviceConfiguration(1)) != HOST_SENDCONTROL_Successful) { printf_P(PSTR(ESC_FG_RED "Control Error (Set Configuration).\r\n" " -- Error Code: %d\r\n" ESC_FG_WHITE), ErrorCode); LEDs_SetAllLEDs(LEDMASK_USB_ERROR); return; } /* HID class request to set the mouse protocol to the Boot Protocol */ USB_ControlRequest = (USB_Request_Header_t) { .bmRequestType = (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE), .bRequest = HID_REQ_SetProtocol, .wValue = 0, .wIndex = 0, .wLength = 0, }; /* Select the control pipe for the request transfer */ Pipe_SelectPipe(PIPE_CONTROLPIPE); /* Send the request, display error and wait for device detach if request fails */ if ((ErrorCode = USB_Host_SendControlRequest(NULL)) != HOST_SENDCONTROL_Successful) { printf_P(PSTR(ESC_FG_RED "Control Error (Set Protocol).\r\n" " -- Error Code: %d\r\n" ESC_FG_WHITE), ErrorCode); LEDs_SetAllLEDs(LEDMASK_USB_ERROR); USB_Host_SetDeviceConfiguration(0); return; } puts_P(PSTR("Mouse Enumerated.\r\n")); LEDs_SetAllLEDs(LEDMASK_USB_READY); } /** Event handler for the USB_HostError event. This indicates that a hardware error occurred while in host mode. */ void EVENT_USB_Host_HostError(const uint8_t ErrorCode) { USB_Disable(); printf_P(PSTR(ESC_FG_RED "Host Mode Error\r\n" " -- Error Code %d\r\n" ESC_FG_WHITE), ErrorCode); LEDs_SetAllLEDs(LEDMASK_USB_ERROR); for(;;); }
void USB_Host_ProcessNextHostState(void) { uint8_t ErrorCode = HOST_ENUMERROR_NoError; uint8_t SubErrorCode = HOST_ENUMERROR_NoError; static uint16_t WaitMSRemaining; static uint8_t PostWaitState; switch (USB_HostState) { case HOST_STATE_WaitForDevice: if (WaitMSRemaining) { if ((SubErrorCode = USB_Host_WaitMS(1)) != HOST_WAITERROR_Successful) { USB_HostState = PostWaitState; ErrorCode = HOST_ENUMERROR_WaitStage; break; } if (!(--WaitMSRemaining)) USB_HostState = PostWaitState; } break; case HOST_STATE_Powered: WaitMSRemaining = HOST_DEVICE_SETTLE_DELAY_MS; USB_HostState = HOST_STATE_Powered_WaitForDeviceSettle; break; case HOST_STATE_Powered_WaitForDeviceSettle: if (WaitMSRemaining--) { _delay_ms(1); break; } else { USB_Host_VBUS_Manual_Off(); USB_OTGPAD_On(); USB_Host_VBUS_Auto_Enable(); USB_Host_VBUS_Auto_On(); USB_HostState = HOST_STATE_Powered_WaitForConnect; } break; case HOST_STATE_Powered_WaitForConnect: if (USB_INT_HasOccurred(USB_INT_DCONNI)) { USB_INT_Clear(USB_INT_DCONNI); USB_INT_Clear(USB_INT_DDISCI); USB_INT_Clear(USB_INT_VBERRI); USB_INT_Enable(USB_INT_VBERRI); USB_Host_ResumeBus(); Pipe_ClearPipes(); HOST_TASK_NONBLOCK_WAIT(100, HOST_STATE_Powered_DoReset); } break; case HOST_STATE_Powered_DoReset: USB_Host_ResetDevice(); HOST_TASK_NONBLOCK_WAIT(200, HOST_STATE_Powered_ConfigPipe); break; case HOST_STATE_Powered_ConfigPipe: Pipe_ConfigurePipe(PIPE_CONTROLPIPE, EP_TYPE_CONTROL, PIPE_TOKEN_SETUP, ENDPOINT_CONTROLEP, PIPE_CONTROLPIPE_DEFAULT_SIZE, PIPE_BANK_SINGLE); if (!(Pipe_IsConfigured())) { ErrorCode = HOST_ENUMERROR_PipeConfigError; SubErrorCode = 0; break; } USB_HostState = HOST_STATE_Default; break; case HOST_STATE_Default: USB_ControlRequest = (USB_Request_Header_t) { .bmRequestType = (REQDIR_DEVICETOHOST | REQTYPE_STANDARD | REQREC_DEVICE), .bRequest = REQ_GetDescriptor, .wValue = (DTYPE_Device << 8), .wIndex = 0, .wLength = 8, }; uint8_t DataBuffer[8]; if ((SubErrorCode = USB_Host_SendControlRequest(DataBuffer)) != HOST_SENDCONTROL_Successful) { ErrorCode = HOST_ENUMERROR_ControlError; break; } USB_ControlPipeSize = DataBuffer[offsetof(USB_Descriptor_Device_t, Endpoint0Size)]; USB_Host_ResetDevice(); HOST_TASK_NONBLOCK_WAIT(200, HOST_STATE_Default_PostReset); break; case HOST_STATE_Default_PostReset: Pipe_ConfigurePipe(PIPE_CONTROLPIPE, EP_TYPE_CONTROL, PIPE_TOKEN_SETUP, ENDPOINT_CONTROLEP, USB_ControlPipeSize, PIPE_BANK_SINGLE); if (!(Pipe_IsConfigured())) { ErrorCode = HOST_ENUMERROR_PipeConfigError; SubErrorCode = 0; break; } USB_ControlRequest = (USB_Request_Header_t) { .bmRequestType = (REQDIR_HOSTTODEVICE | REQTYPE_STANDARD | REQREC_DEVICE), .bRequest = REQ_SetAddress, .wValue = USB_HOST_DEVICEADDRESS, .wIndex = 0, .wLength = 0, }; if ((SubErrorCode = USB_Host_SendControlRequest(NULL)) != HOST_SENDCONTROL_Successful) { ErrorCode = HOST_ENUMERROR_ControlError; break; } HOST_TASK_NONBLOCK_WAIT(100, HOST_STATE_Default_PostAddressSet); break; case HOST_STATE_Default_PostAddressSet: USB_Host_SetDeviceAddress(USB_HOST_DEVICEADDRESS); EVENT_USB_Host_DeviceEnumerationComplete(); USB_HostState = HOST_STATE_Addressed; break; } if ((ErrorCode != HOST_ENUMERROR_NoError) && (USB_HostState != HOST_STATE_Unattached)) { EVENT_USB_Host_DeviceEnumerationFailed(ErrorCode, SubErrorCode); USB_Host_VBUS_Auto_Off(); EVENT_USB_Host_DeviceUnattached(); USB_ResetInterface(); } } uint8_t USB_Host_WaitMS(uint8_t MS) { bool BusSuspended = USB_Host_IsBusSuspended(); uint8_t ErrorCode = HOST_WAITERROR_Successful; bool HSOFIEnabled = USB_INT_IsEnabled(USB_INT_HSOFI); USB_INT_Disable(USB_INT_HSOFI); USB_INT_Clear(USB_INT_HSOFI); USB_Host_ResumeBus(); while (MS) { if (USB_INT_HasOccurred(USB_INT_HSOFI)) { USB_INT_Clear(USB_INT_HSOFI); MS--; } if ((USB_HostState == HOST_STATE_Unattached) || (USB_CurrentMode != USB_MODE_Host)) { ErrorCode = HOST_WAITERROR_DeviceDisconnect; break; } if (Pipe_IsError() == true) { Pipe_ClearError(); ErrorCode = HOST_WAITERROR_PipeError; break; } if (Pipe_IsStalled() == true) { Pipe_ClearStall(); ErrorCode = HOST_WAITERROR_SetupStalled; break; } } if (BusSuspended) USB_Host_SuspendBus(); if (HSOFIEnabled) USB_INT_Enable(USB_INT_HSOFI); return ErrorCode; } static void USB_Host_ResetDevice(void) { bool BusSuspended = USB_Host_IsBusSuspended(); USB_INT_Disable(USB_INT_DDISCI); USB_Host_ResetBus(); while (!(USB_Host_IsBusResetComplete())); USB_Host_ResumeBus(); bool HSOFIEnabled = USB_INT_IsEnabled(USB_INT_HSOFI); USB_INT_Disable(USB_INT_HSOFI); USB_INT_Clear(USB_INT_HSOFI); for (uint8_t MSRem = 10; MSRem != 0; MSRem--) { /* Workaround for powerless-pull-up devices. After a USB bus reset, all disconnection interrupts are suppressed while a USB frame is looked for - if it is found within 10ms, the device is still present. */ if (USB_INT_HasOccurred(USB_INT_HSOFI)) { USB_INT_Clear(USB_INT_HSOFI); USB_INT_Clear(USB_INT_DDISCI); break; } _delay_ms(1); } if (HSOFIEnabled) USB_INT_Enable(USB_INT_HSOFI); if (BusSuspended) USB_Host_SuspendBus(); USB_INT_Enable(USB_INT_DDISCI); }
uint8_t USB_Host_GetDeviceConfigDescriptor(uint16_t* const ConfigSizePtr, void* BufferPtr) { uint8_t ErrorCode; USB_HostRequest = (USB_Host_Request_Header_t) { bmRequestType: (REQDIR_DEVICETOHOST | REQTYPE_STANDARD | REQREC_DEVICE), bRequest: REQ_GetDescriptor, wValue: (DTYPE_Configuration << 8), wIndex: 0, wLength: sizeof(USB_Descriptor_Configuration_Header_t), }; if (BufferPtr == NULL) { BufferPtr = alloca(sizeof(USB_Descriptor_Configuration_Header_t)); ErrorCode = USB_Host_SendControlRequest(BufferPtr); #if defined(USE_NONSTANDARD_DESCRIPTOR_NAMES) *ConfigSizePtr = DESCRIPTOR_CAST(BufferPtr, USB_Descriptor_Configuration_Header_t).TotalConfigurationSize; #else *ConfigSizePtr = DESCRIPTOR_CAST(BufferPtr, USB_Descriptor_Configuration_Header_t).wTotalLength; #endif } else { USB_HostRequest.wLength = *ConfigSizePtr; ErrorCode = USB_Host_SendControlRequest(BufferPtr); } return ErrorCode; } void USB_Host_GetNextDescriptorOfType(uint16_t* const BytesRem, uint8_t** const CurrConfigLoc, const uint8_t Type) { while (*BytesRem) { USB_Host_GetNextDescriptor(BytesRem, CurrConfigLoc); if (DESCRIPTOR_TYPE(*CurrConfigLoc) == Type) return; } } void USB_Host_GetNextDescriptorOfTypeBefore(uint16_t* const BytesRem, uint8_t** const CurrConfigLoc, const uint8_t Type, const uint8_t BeforeType) { while (*BytesRem) { USB_Host_GetNextDescriptor(BytesRem, CurrConfigLoc); if (DESCRIPTOR_TYPE(*CurrConfigLoc) == Type) { return; } else if (DESCRIPTOR_TYPE(*CurrConfigLoc) == BeforeType) { *BytesRem = 0; return; } } } void USB_Host_GetNextDescriptorOfTypeAfter(uint16_t* const BytesRem, uint8_t** const CurrConfigLoc, const uint8_t Type, const uint8_t AfterType) { USB_Host_GetNextDescriptorOfType(BytesRem, CurrConfigLoc, AfterType); if (*BytesRem) USB_Host_GetNextDescriptorOfType(BytesRem, CurrConfigLoc, Type); }
/** Event handler for the USB_DeviceEnumerationComplete event. This indicates that a device has been successfully * enumerated by the host and is now ready to be used by the application. */ void EVENT_USB_Host_DeviceEnumerationComplete(void) { puts_P(PSTR("Getting Config Data.\r\n")); uint8_t ErrorCode; /* Get and process the configuration descriptor data */ if ((ErrorCode = ProcessConfigurationDescriptor()) != SuccessfulConfigRead) { if (ErrorCode == ControlError) puts_P(PSTR(ESC_FG_RED "Control Error (Get Configuration).\r\n")); else puts_P(PSTR(ESC_FG_RED "Invalid Device.\r\n")); printf_P(PSTR(" -- Error Code: %d\r\n" ESC_FG_WHITE), ErrorCode); LEDs_SetAllLEDs(LEDMASK_USB_ERROR); return; } /* Set the device configuration to the first configuration (rarely do devices use multiple configurations) */ if ((ErrorCode = USB_Host_SetDeviceConfiguration(1)) != HOST_SENDCONTROL_Successful) { printf_P(PSTR(ESC_FG_RED "Control Error (Set Configuration).\r\n" " -- Error Code: %d\r\n" ESC_FG_WHITE), ErrorCode); LEDs_SetAllLEDs(LEDMASK_USB_ERROR); return; } if ((ErrorCode = USB_Host_SetInterfaceAltSetting(StreamingInterfaceIndex, StreamingInterfaceAltSetting)) != HOST_SENDCONTROL_Successful) { printf_P(PSTR(ESC_FG_RED "Could not set alternative streaming interface setting.\r\n" " -- Error Code: %d\r\n" ESC_FG_WHITE), ErrorCode); LEDs_SetAllLEDs(LEDMASK_USB_ERROR); USB_Host_SetDeviceConfiguration(0); return; } USB_ControlRequest = (USB_Request_Header_t) { .bmRequestType = (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_ENDPOINT), .bRequest = AUDIO_REQ_SetCurrent, .wValue = (AUDIO_EPCONTROL_SamplingFreq << 8), .wIndex = StreamingEndpointAddress, .wLength = sizeof(USB_Audio_SampleFreq_t), }; USB_Audio_SampleFreq_t SampleRate = AUDIO_SAMPLE_FREQ(48000); /* Select the control pipe for the request transfer */ Pipe_SelectPipe(PIPE_CONTROLPIPE); /* Set the sample rate on the streaming interface endpoint */ if ((ErrorCode = USB_Host_SendControlRequest(&SampleRate)) != HOST_SENDCONTROL_Successful) { LEDs_SetAllLEDs(LEDMASK_USB_ERROR); USB_Host_SetDeviceConfiguration(0); return; } /* Sample reload timer initialization */ TIMSK0 = (1 << OCIE0A); OCR0A = ((F_CPU / 8 / 48000) - 1); TCCR0A = (1 << WGM01); // CTC mode TCCR0B = (1 << CS01); // Fcpu/8 speed puts_P(PSTR("Speaker Enumerated.\r\n")); LEDs_SetAllLEDs(LEDMASK_USB_READY); } /** Event handler for the USB_HostError event. This indicates that a hardware error occurred while in host mode. */ void EVENT_USB_Host_HostError(const uint8_t ErrorCode) { USB_Disable(); printf_P(PSTR(ESC_FG_RED "Host Mode Error\r\n" " -- Error Code %d\r\n" ESC_FG_WHITE), ErrorCode); LEDs_SetAllLEDs(LEDMASK_USB_ERROR); for(;;); }
/** Task to set the configuration of the attached device after it has been enumerated. */ void Android_Host_Task(void) { uint8_t ErrorCode; switch (USB_HostState) { case HOST_STATE_Addressed: puts_P(PSTR("Getting Device Data.\r\n")); /* Get and process the configuration descriptor data */ ErrorCode = ProcessDeviceDescriptor(); /* Save whether the Android device needs to be mode-switched later on */ bool RequiresModeSwitch = (ErrorCode == NonAccessoryModeAndroidDevice); /* Error out if the device is not an Android device or an error occurred */ if ((ErrorCode != AccessoryModeAndroidDevice) && !(RequiresModeSwitch)) { if (ErrorCode == DevControlError) puts_P(PSTR(ESC_FG_RED "Control Error (Get Device).\r\n")); else puts_P(PSTR(ESC_FG_RED "Invalid Device.\r\n")); printf_P(PSTR(" -- Error Code: %d\r\n" ESC_FG_WHITE), ErrorCode); /* Indicate error via status LEDs */ LEDs_SetAllLEDs(LEDS_LED1); /* Wait until USB device disconnected */ USB_HostState = HOST_STATE_WaitForDeviceRemoval; break; } printf_P(PSTR("Android Device Detected - %sAccessory mode.\r\n"), (RequiresModeSwitch ? "Non-" : "")); /* Set the device configuration to the first configuration (rarely do devices use multiple configurations) */ if ((ErrorCode = USB_Host_SetDeviceConfiguration(1)) != HOST_SENDCONTROL_Successful) { printf_P(PSTR(ESC_FG_RED "Control Error (Set Configuration).\r\n" " -- Error Code: %d\r\n" ESC_FG_WHITE), ErrorCode); /* Indicate error via status LEDs */ LEDs_SetAllLEDs(LEDS_LED1); /* Wait until USB device disconnected */ USB_HostState = HOST_STATE_WaitForDeviceRemoval; break; } /* Check if a valid Android device was attached, but it is not current in Accessory mode */ if (RequiresModeSwitch) { USB_ControlRequest = (USB_Request_Header_t) { .bmRequestType = (REQDIR_HOSTTODEVICE | REQTYPE_VENDOR | REQREC_DEVICE), .bRequest = ANDROID_Req_StartAccessoryMode, .wValue = 0, .wIndex = 0, .wLength = 0, }; /* Send the control request for the Android device to switch to accessory mode */ Pipe_SelectPipe(PIPE_CONTROLPIPE); USB_Host_SendControlRequest(NULL); /* Wait until USB device disconnected */ USB_HostState = HOST_STATE_WaitForDeviceRemoval; break; } puts_P(PSTR("Getting Config Data.\r\n")); /* Get and process the configuration descriptor data */ if ((ErrorCode = ProcessConfigurationDescriptor()) != SuccessfulConfigRead) { if (ErrorCode == ControlError) puts_P(PSTR(ESC_FG_RED "Control Error (Get Configuration).\r\n")); else puts_P(PSTR(ESC_FG_RED "Invalid Device.\r\n")); printf_P(PSTR(" -- Error Code: %d\r\n" ESC_FG_WHITE), ErrorCode); /* Indicate error via status LEDs */ LEDs_SetAllLEDs(LEDS_LED1); /* Wait until USB device disconnected */ USB_HostState = HOST_STATE_WaitForDeviceRemoval; break; } puts_P(PSTR("Accessory Mode Android Enumerated.\r\n")); USB_HostState = HOST_STATE_Configured; break; case HOST_STATE_Configured: /* Select the data IN pipe */ Pipe_SelectPipe(ANDROID_DATA_IN_PIPE); Pipe_Unfreeze(); /* Check to see if a packet has been received */ if (Pipe_IsINReceived()) { /* Re-freeze IN pipe after the packet has been received */ Pipe_Freeze(); /* Check if data is in the pipe */ if (Pipe_IsReadWriteAllowed()) { uint8_t NextReceivedByte = Pipe_BytesInPipe(); uint8_t LEDMask = LEDS_NO_LEDS; if (NextReceivedByte & 0x01) LEDMask |= LEDS_LED1; if (NextReceivedByte & 0x02) LEDMask |= LEDS_LED2; if (NextReceivedByte & 0x04) LEDMask |= LEDS_LED3; if (NextReceivedByte & 0x08) LEDMask |= LEDS_LED4; LEDs_SetAllLEDs(LEDMask); } else { /* Clear the pipe after all data in the packet has been read, ready for the next packet */ Pipe_ClearIN(); } } /* Re-freeze IN pipe after use */ Pipe_Freeze(); break; } }
/** Event handler for the USB_DeviceEnumerationComplete event. This indicates that a device has been successfully * enumerated by the host and is now ready to be used by the application. */ void EVENT_USB_Host_DeviceEnumerationComplete(void) { puts_P(PSTR("Getting Config Data.\r\n")); uint8_t ErrorCode; /* Get and process the configuration descriptor data */ if ((ErrorCode = ProcessConfigurationDescriptor()) != SuccessfulConfigRead) { if (ErrorCode == ControlError) puts_P(PSTR(ESC_FG_RED "Control Error (Get Configuration).\r\n")); else puts_P(PSTR(ESC_FG_RED "Invalid Device.\r\n")); printf_P(PSTR(" -- Error Code: %d\r\n" ESC_FG_WHITE), ErrorCode); LEDs_SetAllLEDs(LEDMASK_USB_ERROR); return; } /* Set the device configuration to the first configuration (rarely do devices use multiple configurations) */ if ((ErrorCode = USB_Host_SetDeviceConfiguration(1)) != HOST_SENDCONTROL_Successful) { printf_P(PSTR(ESC_FG_RED "Control Error (Set Configuration).\r\n" " -- Error Code: %d\r\n" ESC_FG_WHITE), ErrorCode); LEDs_SetAllLEDs(LEDMASK_USB_ERROR); return; } CDC_LineEncoding_t LineEncoding = { .BaudRateBPS = 9600, .CharFormat = CDC_LINEENCODING_OneStopBit, .ParityType = CDC_PARITY_None, .DataBits = 8 }; USB_ControlRequest = (USB_Request_Header_t) { .bmRequestType = (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE), .bRequest = CDC_REQ_SetLineEncoding, .wValue = 0, .wIndex = 0, .wLength = sizeof(LineEncoding), }; /* Set the Line Encoding of the CDC interface within the device, so that it is ready to accept data */ Pipe_SelectPipe(PIPE_CONTROLPIPE); if (USB_Host_SendControlRequest(&LineEncoding) != HOST_SENDCONTROL_Successful) { printf_P(PSTR(ESC_FG_RED "Control Error (Set Line Encoding).\r\n" " -- Error Code: %d\r\n" ESC_FG_WHITE), ErrorCode); LEDs_SetAllLEDs(LEDMASK_USB_ERROR); return; } puts_P(PSTR("CDC Device Enumerated.\r\n")); LEDs_SetAllLEDs(LEDMASK_USB_READY); } /** Event handler for the USB_HostError event. This indicates that a hardware error occurred while in host mode. */ void EVENT_USB_Host_HostError(const uint8_t ErrorCode) { USB_Disable(); printf_P(PSTR(ESC_FG_RED "Host Mode Error\r\n" " -- Error Code %d\r\n" ESC_FG_WHITE), ErrorCode); LEDs_SetAllLEDs(LEDMASK_USB_ERROR); for(;;); } /** Event handler for the USB_DeviceEnumerationFailed event. This indicates that a problem occurred while * enumerating an attached USB device. */ void EVENT_USB_Host_DeviceEnumerationFailed(const uint8_t ErrorCode, const uint8_t SubErrorCode) { printf_P(PSTR(ESC_FG_RED "Dev Enum Error\r\n" " -- Error Code %d\r\n" " -- Sub Error Code %d\r\n" " -- In State %d\r\n" ESC_FG_WHITE), ErrorCode, SubErrorCode, USB_HostState); LEDs_SetAllLEDs(LEDMASK_USB_ERROR); }
/** Bluetooth HCI processing task. This task should be called repeatedly the main Bluetooth * stack task to manage the HCI processing state. */ void Bluetooth_HCITask(void) { BT_HCICommand_Header_t HCICommandHeader; switch (Bluetooth_State.CurrentHCIState) { case Bluetooth_ProcessEvents: Pipe_SelectPipe(BLUETOOTH_EVENTS_PIPE); Pipe_Unfreeze(); if (Pipe_IsReadWriteAllowed()) { BT_HCIEvent_Header_t HCIEventHeader; /* Read in the event header to fetch the event code and payload length */ Pipe_Read_Stream_LE(&HCIEventHeader, sizeof(HCIEventHeader)); /* Create a temporary buffer for the event parameters */ uint8_t EventParams[HCIEventHeader.ParameterLength]; /* Read in the event parameters into the temporary buffer */ Pipe_Read_Stream_LE(&EventParams, HCIEventHeader.ParameterLength); Pipe_ClearIN(); BT_HCI_DEBUG(1, "Event Received (0x%02X)", HCIEventHeader.EventCode); switch (HCIEventHeader.EventCode) { case EVENT_COMMAND_COMPLETE: BT_HCI_DEBUG(1, "<< Command Complete"); /* Check which operation was completed in case we need to process the even parameters */ switch (((BT_HCIEvent_CommandComplete_t*)&EventParams)->Opcode) { case (OGF_CTRLR_INFORMATIONAL | OCF_CTRLR_INFORMATIONAL_READBDADDR): /* A READ BDADDR command completed, copy over the local device's BDADDR from the response */ memcpy(Bluetooth_State.LocalBDADDR, &((BT_HCIEvent_CommandComplete_t*)&EventParams)->ReturnParams[1], sizeof(Bluetooth_State.LocalBDADDR)); break; } Bluetooth_State.CurrentHCIState = Bluetooth_State.NextHCIState; break; case EVENT_COMMAND_STATUS: BT_HCI_DEBUG(1, "<< Command Status"); BT_HCI_DEBUG(2, "-- Status Code: 0x%02X", (((BT_HCIEvent_CommandStatus_t*)&EventParams)->Status)); /* If the execution of a command failed, reset the stack */ if (((BT_HCIEvent_CommandStatus_t*)&EventParams)->Status) Bluetooth_State.CurrentHCIState = Bluetooth_Init; break; case EVENT_CONNECTION_REQUEST: BT_HCI_DEBUG(1, "<< Connection Request"); BT_HCI_DEBUG(2, "-- Link Type: 0x%02X", (((BT_HCIEvent_ConnectionRequest_t*)&EventParams)->LinkType)); /* Need to store the remote device's BT address in a temporary buffer for later use */ memcpy(Bluetooth_TempDeviceAddress, &((BT_HCIEvent_ConnectionRequest_t*)&EventParams)->RemoteAddress, sizeof(Bluetooth_TempDeviceAddress)); bool IsACLConnection = (((BT_HCIEvent_ConnectionRequest_t*)&EventParams)->LinkType == 0x01); /* Only accept the connection if it is a ACL (data) connection, a device is not already connected and the user application has indicated that the connection should be allowed */ Bluetooth_State.CurrentHCIState = (Bluetooth_Connection.IsConnected || !(IsACLConnection) || !(Bluetooth_ConnectionRequest(Bluetooth_TempDeviceAddress))) ? Bluetooth_Conn_RejectConnection : Bluetooth_Conn_AcceptConnection; BT_HCI_DEBUG(2, "-- Connection %S", (Bluetooth_State.CurrentHCIState == Bluetooth_Conn_RejectConnection) ? PSTR("REJECTED") : PSTR("ACCEPTED")); break; case EVENT_PIN_CODE_REQUEST: BT_HCI_DEBUG(1, "<< Pin Code Request"); /* Need to store the remote device's BT address in a temporary buffer for later use */ memcpy(Bluetooth_TempDeviceAddress, &((BT_HCIEvent_PinCodeReq_t*)&EventParams)->RemoteAddress, sizeof(Bluetooth_TempDeviceAddress)); Bluetooth_State.CurrentHCIState = Bluetooth_Conn_SendPINCode; break; case EVENT_LINK_KEY_REQUEST: BT_HCI_DEBUG(1, "<< Link Key Request"); /* Need to store the remote device's BT address in a temporary buffer for later use */ memcpy(Bluetooth_TempDeviceAddress, &((BT_HCIEvent_LinkKeyReq_t*)&EventParams)->RemoteAddress, sizeof(Bluetooth_TempDeviceAddress)); Bluetooth_State.CurrentHCIState = Bluetooth_Conn_SendLinkKeyNAK; break; case EVENT_CONNECTION_COMPLETE: BT_HCI_DEBUG(1, "<< Connection Complete"); BT_HCI_DEBUG(2, "-- Handle: 0x%04X", ((BT_HCIEvent_ConnectionComplete_t*)&EventParams)->ConnectionHandle); /* Need to store the remote device's BT address in a temporary buffer for later use */ memcpy(Bluetooth_Connection.RemoteAddress, &((BT_HCIEvent_ConnectionComplete_t*)&EventParams)->RemoteAddress, sizeof(Bluetooth_TempDeviceAddress)); /* Store the created connection handle and indicate that the connection has been established */ Bluetooth_Connection.ConnectionHandle = ((BT_HCIEvent_ConnectionComplete_t*)&EventParams)->ConnectionHandle; Bluetooth_Connection.IsConnected = true; Bluetooth_ConnectionComplete(); break; case EVENT_DISCONNECTION_COMPLETE: BT_HCI_DEBUG(1, "<< Disconnection Complete"); /* Device disconnected, indicate connection information no longer valid */ Bluetooth_Connection.IsConnected = false; Bluetooth_DisconnectionComplete(); break; } } Pipe_Freeze(); break; case Bluetooth_Init: BT_HCI_DEBUG(1, "# Init"); Bluetooth_State.IsInitialized = false; /* Reset the connection information structure to destroy any previous connection state */ memset(&Bluetooth_Connection, 0x00, sizeof(Bluetooth_Connection)); Bluetooth_State.CurrentHCIState = Bluetooth_Init_Reset; break; case Bluetooth_Init_Reset: BT_HCI_DEBUG(1, "# Reset"); HCICommandHeader = (BT_HCICommand_Header_t) { OpCode: (OGF_CTRLR_BASEBAND | OCF_CTRLR_BASEBAND_RESET), ParameterLength: 0, }; /* Send the command to reset the Bluetooth dongle controller */ Bluetooth_SendHCICommand(&HCICommandHeader, NULL, 0); Bluetooth_State.NextHCIState = Bluetooth_Init_ReadBufferSize; Bluetooth_State.CurrentHCIState = Bluetooth_ProcessEvents; break; case Bluetooth_Init_ReadBufferSize: BT_HCI_DEBUG(1, "# Read Buffer Size"); HCICommandHeader = (BT_HCICommand_Header_t) { OpCode: (OGF_CTRLR_INFORMATIONAL | OCF_CTRLR_INFORMATIONAL_READBUFFERSIZE), ParameterLength: 0, }; /* Send the command to read the Bluetooth buffer size (mandatory before device sends any data) */ Bluetooth_SendHCICommand(&HCICommandHeader, NULL, 0); Bluetooth_State.NextHCIState = Bluetooth_Init_GetBDADDR; Bluetooth_State.CurrentHCIState = Bluetooth_ProcessEvents; break; case Bluetooth_Init_GetBDADDR: BT_HCI_DEBUG(1, "# Get BDADDR"); HCICommandHeader = (BT_HCICommand_Header_t) { OpCode: (OGF_CTRLR_INFORMATIONAL | OCF_CTRLR_INFORMATIONAL_READBDADDR), ParameterLength: 0, }; /* Send the command to retrieve the BDADDR of the inserted Bluetooth dongle */ Bluetooth_SendHCICommand(&HCICommandHeader, NULL, 0); Bluetooth_State.NextHCIState = Bluetooth_Init_SetLocalName; Bluetooth_State.CurrentHCIState = Bluetooth_ProcessEvents; break; case Bluetooth_Init_SetLocalName: BT_HCI_DEBUG(1, "# Set Local Name"); HCICommandHeader = (BT_HCICommand_Header_t) { OpCode: (OGF_CTRLR_BASEBAND | OCF_CTRLR_BASEBAND_WRITE_LOCAL_NAME), ParameterLength: 248, }; /* Send the command to set the Bluetooth dongle's name for other devices to see */ Bluetooth_SendHCICommand(&HCICommandHeader, Bluetooth_DeviceConfiguration.Name, strlen(Bluetooth_DeviceConfiguration.Name)); Bluetooth_State.NextHCIState = Bluetooth_Init_SetDeviceClass; Bluetooth_State.CurrentHCIState = Bluetooth_ProcessEvents; break; case Bluetooth_Init_SetDeviceClass: BT_HCI_DEBUG(1, "# Set Device Class"); HCICommandHeader = (BT_HCICommand_Header_t) { OpCode: (OGF_CTRLR_BASEBAND | OCF_CTRLR_BASEBAND_WRITE_CLASS_OF_DEVICE), ParameterLength: 3, }; /* Send the command to set the class of the device for other devices to see */ Bluetooth_SendHCICommand(&HCICommandHeader, &Bluetooth_DeviceConfiguration.Class, 3); Bluetooth_State.NextHCIState = Bluetooth_Init_WriteScanEnable; Bluetooth_State.CurrentHCIState = Bluetooth_ProcessEvents; break; case Bluetooth_Init_WriteScanEnable: BT_HCI_DEBUG(1, "# Write Scan Enable"); HCICommandHeader = (BT_HCICommand_Header_t) { OpCode: (OGF_CTRLR_BASEBAND | OCF_CTRLR_BASEBAND_WRITE_SCAN_ENABLE), ParameterLength: 1, }; uint8_t Interval = BT_SCANMODE_InquiryAndPageScans; /* Send the command to set the remote device scanning mode */ Bluetooth_SendHCICommand(&HCICommandHeader, &Interval, 1); Bluetooth_State.NextHCIState = Bluetooth_Init_FinalizeInit; Bluetooth_State.CurrentHCIState = Bluetooth_ProcessEvents; break; case Bluetooth_Init_FinalizeInit: Bluetooth_State.IsInitialized = true; /* Fire the user application callback to indicate that the stack is now fully initialized */ Bluetooth_StackInitialized(); Bluetooth_State.NextHCIState = Bluetooth_ProcessEvents; Bluetooth_State.CurrentHCIState = Bluetooth_ProcessEvents; break; case Bluetooth_Conn_AcceptConnection: BT_HCI_DEBUG(1, "# Accept Connection"); HCICommandHeader = (BT_HCICommand_Header_t) { OpCode: (OGF_LINK_CONTROL | OCF_LINK_CONTROL_ACCEPT_CONNECTION_REQUEST), ParameterLength: sizeof(BT_HCICommand_AcceptConnectionReq_t), }; /* Copy over the temporary BT device address saved from the Connection Request event, indicate slave connection role */ BT_HCICommand_AcceptConnectionReq_t AcceptConnectionParams; memcpy(AcceptConnectionParams.RemoteAddress, Bluetooth_TempDeviceAddress, sizeof(AcceptConnectionParams.RemoteAddress)); AcceptConnectionParams.SlaveRole = true; /* Send the command to accept the remote connection request */ Bluetooth_SendHCICommand(&HCICommandHeader, &AcceptConnectionParams, sizeof(BT_HCICommand_AcceptConnectionReq_t)); Bluetooth_State.CurrentHCIState = Bluetooth_ProcessEvents; break; case Bluetooth_Conn_RejectConnection: BT_HCI_DEBUG(1, "# Reject Connection"); HCICommandHeader = (BT_HCICommand_Header_t) { OpCode: (OGF_LINK_CONTROL | OCF_LINK_CONTROL_REJECT_CONNECTION_REQUEST), ParameterLength: sizeof(BT_HCICommand_RejectConnectionReq_t), }; /* Copy over the temporary BT device address saved from the Connection Request event, indicate failure to accept the connection due to limited device resources or incorrect device address */ BT_HCICommand_RejectConnectionReq_t RejectConnectionParams; memcpy(RejectConnectionParams.RemoteAddress, Bluetooth_TempDeviceAddress, sizeof(RejectConnectionParams.RemoteAddress)); RejectConnectionParams.Reason = Bluetooth_Connection.IsConnected ? ERROR_LIMITED_RESOURCES : ERROR_UNACCEPTABLE_BDADDR; /* Send the command to reject the remote connection request */ Bluetooth_SendHCICommand(&HCICommandHeader, &RejectConnectionParams, sizeof(BT_HCICommand_RejectConnectionReq_t)); Bluetooth_State.CurrentHCIState = Bluetooth_ProcessEvents; break; case Bluetooth_Conn_SendPINCode: BT_HCI_DEBUG(1, "# Send Pin Code"); HCICommandHeader = (BT_HCICommand_Header_t) { OpCode: (OGF_LINK_CONTROL | OCF_LINK_CONTROL_PIN_CODE_REQUEST_REPLY), ParameterLength: sizeof(BT_HCICommand_PinCodeResp_t), }; /* Copy over the temporary BT device address saved from the PIN Code Request event, copy over the local PIN authentication code to the response */ BT_HCICommand_PinCodeResp_t PINCodeRequestParams; memcpy(PINCodeRequestParams.RemoteAddress, Bluetooth_TempDeviceAddress, sizeof(PINCodeRequestParams.RemoteAddress)); PINCodeRequestParams.PINCodeLength = strlen(Bluetooth_DeviceConfiguration.PINCode); memcpy(PINCodeRequestParams.PINCode, Bluetooth_DeviceConfiguration.PINCode, sizeof(PINCodeRequestParams.PINCode)); /* Send the command to transmit the device's local PIN number for authentication */ Bluetooth_SendHCICommand(&HCICommandHeader, &PINCodeRequestParams, sizeof(BT_HCICommand_PinCodeResp_t)); Bluetooth_State.CurrentHCIState = Bluetooth_ProcessEvents; break; case Bluetooth_Conn_SendLinkKeyNAK: BT_HCI_DEBUG(1, "# Send Link Key NAK"); HCICommandHeader = (BT_HCICommand_Header_t) { OpCode: (OGF_LINK_CONTROL | OCF_LINK_CONTROL_LINK_KEY_REQUEST_NEG_REPLY), ParameterLength: sizeof(BT_HCICommand_LinkKeyNAKResp_t), }; /* Copy over the temporary BT device address saved from the Link Key Request event */ BT_HCICommand_LinkKeyNAKResp_t LinkKeyNAKParams; memcpy(LinkKeyNAKParams.RemoteAddress, Bluetooth_TempDeviceAddress, sizeof(LinkKeyNAKParams.RemoteAddress)); /* Send the command to transmit the link key NAK to the receiver */ Bluetooth_SendHCICommand(&HCICommandHeader, &LinkKeyNAKParams, sizeof(BT_HCICommand_LinkKeyNAKResp_t)); Bluetooth_State.CurrentHCIState = Bluetooth_ProcessEvents; break; } } /** Sends a Bluetooth HCI control command to the attached Bluetooth device. * * \param[in] HCICommandHeader HCI command header to send to the attached device * \param[in] Parameters Pointer to the source of the control parameters (if any) * \param[in] ParameterLength Length of the parameters to send in bytes * * \return A value from the USB_Host_SendControlErrorCodes_t enum. */ static uint8_t Bluetooth_SendHCICommand(const BT_HCICommand_Header_t* const HCICommandHeader, const void* Parameters, const uint16_t ParameterLength) { /* Need to reserve the amount of bytes given in the header for the complete payload */ uint8_t CommandBuffer[sizeof(BT_HCICommand_Header_t) + HCICommandHeader->ParameterLength]; USB_ControlRequest = (USB_Request_Header_t) { .bmRequestType = (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_DEVICE), .bRequest = 0, .wValue = 0, .wIndex = 0, .wLength = sizeof(CommandBuffer) }; /* Copy over the HCI command header to the allocated buffer */ memcpy(CommandBuffer, HCICommandHeader, sizeof(BT_HCICommand_Header_t)); /* Zero out the parameter section of the response so that all padding bytes are known to be zero */ memset(&CommandBuffer[sizeof(BT_HCICommand_Header_t)], 0x00, HCICommandHeader->ParameterLength); /* Copy over the command parameters (if any) to the command buffer - note, the number of actual source parameter bytes may differ to those in the header; any difference in length is filled with 0x00 padding bytes */ memcpy(&CommandBuffer[sizeof(BT_HCICommand_Header_t)], Parameters, ParameterLength); Pipe_SelectPipe(PIPE_CONTROLPIPE); return USB_Host_SendControlRequest(CommandBuffer); }
uint8_t AOA_Host_StartAccessoryMode(USB_ClassInfo_AOA_Host_t* const AOAInterfaceInfo) { uint8_t ErrorCode; uint16_t AccessoryProtocol; if ((ErrorCode = AOA_Host_GetAccessoryProtocol(&AccessoryProtocol)) != HOST_WAITERROR_Successful) return ErrorCode; if (AccessoryProtocol != CPU_TO_LE16(AOA_PROTOCOL_AccessoryV1)) return AOA_ERROR_LOGICAL_CMD_FAILED; for (uint8_t PropertyIndex = 0; PropertyIndex < AOA_STRING_TOTAL_STRINGS; PropertyIndex++) { if ((ErrorCode = AOA_Host_SendPropertyString(AOAInterfaceInfo, PropertyIndex)) != HOST_WAITERROR_Successful) return ErrorCode; } USB_ControlRequest = (USB_Request_Header_t) { .bmRequestType = (REQDIR_HOSTTODEVICE | REQTYPE_VENDOR | REQREC_DEVICE), .bRequest = AOA_REQ_StartAccessoryMode, .wValue = 0, .wIndex = 0, .wLength = 0, }; Pipe_SelectPipe(PIPE_CONTROLPIPE); return USB_Host_SendControlRequest(NULL); } static uint8_t AOA_Host_GetAccessoryProtocol(uint16_t* const Protocol) { USB_ControlRequest = (USB_Request_Header_t) { .bmRequestType = (REQDIR_DEVICETOHOST | REQTYPE_VENDOR | REQREC_DEVICE), .bRequest = AOA_REQ_GetAccessoryProtocol, .wValue = 0, .wIndex = 0, .wLength = sizeof(uint16_t), }; Pipe_SelectPipe(PIPE_CONTROLPIPE); return USB_Host_SendControlRequest(Protocol); } static uint8_t AOA_Host_SendPropertyString(USB_ClassInfo_AOA_Host_t* const AOAInterfaceInfo, const uint8_t StringIndex) { const char* String = ((char**)&AOAInterfaceInfo->Config.PropertyStrings)[StringIndex]; if (String == NULL) String = ""; USB_ControlRequest = (USB_Request_Header_t) { .bmRequestType = (REQDIR_HOSTTODEVICE | REQTYPE_VENDOR | REQREC_DEVICE), .bRequest = AOA_REQ_SendString, .wValue = 0, .wIndex = StringIndex, .wLength = (strlen(String) + 1), }; Pipe_SelectPipe(PIPE_CONTROLPIPE); return USB_Host_SendControlRequest((char*)String); } uint8_t AOA_Host_SendData(USB_ClassInfo_AOA_Host_t* const AOAInterfaceInfo, const uint8_t* const Buffer, const uint16_t Length) { if ((USB_HostState != HOST_STATE_Configured) || !(AOAInterfaceInfo->State.IsActive)) return PIPE_READYWAIT_DeviceDisconnected; uint8_t ErrorCode; Pipe_SelectPipe(AOAInterfaceInfo->Config.DataOUTPipeNumber); Pipe_Unfreeze(); ErrorCode = Pipe_Write_Stream_LE(Buffer, Length, NULL); Pipe_Freeze(); return ErrorCode; } uint8_t AOA_Host_SendString(USB_ClassInfo_AOA_Host_t* const AOAInterfaceInfo, const char* const String) { if ((USB_HostState != HOST_STATE_Configured) || !(AOAInterfaceInfo->State.IsActive)) return PIPE_READYWAIT_DeviceDisconnected; uint8_t ErrorCode; Pipe_SelectPipe(AOAInterfaceInfo->Config.DataOUTPipeNumber); Pipe_Unfreeze(); ErrorCode = Pipe_Write_Stream_LE(String, strlen(String), NULL); Pipe_Freeze(); return ErrorCode; } uint8_t AOA_Host_SendByte(USB_ClassInfo_AOA_Host_t* const AOAInterfaceInfo, const uint8_t Data) { if ((USB_HostState != HOST_STATE_Configured) || !(AOAInterfaceInfo->State.IsActive)) return PIPE_READYWAIT_DeviceDisconnected; uint8_t ErrorCode; Pipe_SelectPipe(AOAInterfaceInfo->Config.DataOUTPipeNumber); Pipe_Unfreeze(); if (!(Pipe_IsReadWriteAllowed())) { Pipe_ClearOUT(); if ((ErrorCode = Pipe_WaitUntilReady()) != PIPE_READYWAIT_NoError) return ErrorCode; } Pipe_Write_8(Data); Pipe_Freeze(); return PIPE_READYWAIT_NoError; } uint16_t AOA_Host_BytesReceived(USB_ClassInfo_AOA_Host_t* const AOAInterfaceInfo) { if ((USB_HostState != HOST_STATE_Configured) || !(AOAInterfaceInfo->State.IsActive)) return 0; Pipe_SelectPipe(AOAInterfaceInfo->Config.DataINPipeNumber); Pipe_Unfreeze(); if (Pipe_IsINReceived()) { if (!(Pipe_BytesInPipe())) { Pipe_ClearIN(); Pipe_Freeze(); return 0; } else { Pipe_Freeze(); return Pipe_BytesInPipe(); } } else { Pipe_Freeze(); return 0; } } int16_t AOA_Host_ReceiveByte(USB_ClassInfo_AOA_Host_t* const AOAInterfaceInfo) { if ((USB_HostState != HOST_STATE_Configured) || !(AOAInterfaceInfo->State.IsActive)) return -1; int16_t ReceivedByte = -1; Pipe_SelectPipe(AOAInterfaceInfo->Config.DataINPipeNumber); Pipe_Unfreeze(); if (Pipe_IsINReceived()) { if (Pipe_BytesInPipe()) ReceivedByte = Pipe_Read_8(); if (!(Pipe_BytesInPipe())) Pipe_ClearIN(); } Pipe_Freeze(); return ReceivedByte; } uint8_t AOA_Host_Flush(USB_ClassInfo_AOA_Host_t* const AOAInterfaceInfo) { if ((USB_HostState != HOST_STATE_Configured) || !(AOAInterfaceInfo->State.IsActive)) return PIPE_READYWAIT_DeviceDisconnected; uint8_t ErrorCode; Pipe_SelectPipe(AOAInterfaceInfo->Config.DataOUTPipeNumber); Pipe_Unfreeze(); if (!(Pipe_BytesInPipe())) return PIPE_READYWAIT_NoError; bool BankFull = !(Pipe_IsReadWriteAllowed()); Pipe_ClearOUT(); if (BankFull) { if ((ErrorCode = Pipe_WaitUntilReady()) != PIPE_READYWAIT_NoError) return ErrorCode; Pipe_ClearOUT(); } Pipe_Freeze(); return PIPE_READYWAIT_NoError; } #if defined(FDEV_SETUP_STREAM) void AOA_Host_CreateStream(USB_ClassInfo_AOA_Host_t* const AOAInterfaceInfo, FILE* const Stream) { *Stream = (FILE)FDEV_SETUP_STREAM(AOA_Host_putchar, AOA_Host_getchar, _FDEV_SETUP_RW); fdev_set_udata(Stream, AOAInterfaceInfo); } void AOA_Host_CreateBlockingStream(USB_ClassInfo_AOA_Host_t* const AOAInterfaceInfo, FILE* const Stream) { *Stream = (FILE)FDEV_SETUP_STREAM(AOA_Host_putchar, AOA_Host_getchar_Blocking, _FDEV_SETUP_RW); fdev_set_udata(Stream, AOAInterfaceInfo); }
void USB_Host_ProcessNextHostState(uint8_t corenum) { uint8_t ErrorCode = HOST_ENUMERROR_NoError; uint8_t SubErrorCode = HOST_ENUMERROR_NoError; static uint16_t WaitMSRemaining; static uint8_t PostWaitState; switch (USB_HostState[corenum]) { case HOST_STATE_WaitForDevice: if (WaitMSRemaining) { if ((SubErrorCode = USB_Host_WaitMS(1)) != HOST_WAITERROR_Successful) { USB_HostState[corenum] = PostWaitState; ErrorCode = HOST_ENUMERROR_WaitStage; break; } if (!(--WaitMSRemaining)) USB_HostState[corenum] = PostWaitState; } break; case HOST_STATE_Powered: WaitMSRemaining = HOST_DEVICE_SETTLE_DELAY_MS; USB_HostState[corenum] = HOST_STATE_Powered_WaitForDeviceSettle; break; case HOST_STATE_Powered_WaitForDeviceSettle: if (WaitMSRemaining--) { Delay_MS(1); break; } else { USB_Host_VBUS_Manual_Off(); USB_OTGPAD_On(); USB_Host_VBUS_Auto_Enable(); USB_Host_VBUS_Auto_On(); USB_HostState[corenum] = HOST_STATE_Powered_WaitForConnect; } break; case HOST_STATE_Powered_WaitForConnect: HOST_TASK_NONBLOCK_WAIT(corenum, 100, HOST_STATE_Powered_DoReset); break; case HOST_STATE_Powered_DoReset: { HCD_USB_SPEED DeviceSpeed; HcdRhPortReset(corenum,1); HcdGetDeviceSpeed(corenum, 1, &DeviceSpeed); // skip checking status USB_Host_SetDeviceSpeed(corenum,DeviceSpeed); HOST_TASK_NONBLOCK_WAIT(corenum, 200, HOST_STATE_Powered_ConfigPipe); } break; case HOST_STATE_Powered_ConfigPipe: if (!Pipe_ConfigurePipe(corenum, PIPE_CONTROLPIPE, EP_TYPE_CONTROL, PIPE_TOKEN_SETUP, ENDPOINT_CONTROLEP, PIPE_CONTROLPIPE_DEFAULT_SIZE, PIPE_BANK_SINGLE) ) { ErrorCode = HOST_ENUMERROR_PipeConfigError; SubErrorCode = 0; break; } USB_HostState[corenum] = HOST_STATE_Default; break; case HOST_STATE_Default: { USB_Descriptor_Device_t DevDescriptor; USB_ControlRequest = (USB_Request_Header_t) { .bmRequestType = (REQDIR_DEVICETOHOST | REQTYPE_STANDARD | REQREC_DEVICE), .bRequest = REQ_GetDescriptor, .wValue = (DTYPE_Device << 8), .wIndex = 0, .wLength = 8, }; if ((SubErrorCode = USB_Host_SendControlRequest(corenum, &DevDescriptor)) != HOST_SENDCONTROL_Successful) { ErrorCode = HOST_ENUMERROR_ControlError; break; } USB_Host_ControlPipeSize[corenum] = DevDescriptor.Endpoint0Size; Pipe_ClosePipe(corenum, PIPE_CONTROLPIPE); HcdRhPortReset(corenum,1); HOST_TASK_NONBLOCK_WAIT(corenum, 200, HOST_STATE_Default_PostReset); } break; case HOST_STATE_Default_PostReset: if (!Pipe_ConfigurePipe(corenum, PIPE_CONTROLPIPE, EP_TYPE_CONTROL, PIPE_TOKEN_SETUP, ENDPOINT_CONTROLEP, USB_Host_ControlPipeSize[corenum], PIPE_BANK_SINGLE) ) { ErrorCode = HOST_ENUMERROR_PipeConfigError; SubErrorCode = 0; break; } USB_ControlRequest = (USB_Request_Header_t) { .bmRequestType = (REQDIR_HOSTTODEVICE | REQTYPE_STANDARD | REQREC_DEVICE), .bRequest = REQ_SetAddress, .wValue = USB_HOST_DEVICEADDRESS, .wIndex = 0, .wLength = 0, }; if ((SubErrorCode = USB_Host_SendControlRequest(corenum, NULL)) != HOST_SENDCONTROL_Successful) { ErrorCode = HOST_ENUMERROR_ControlError; break; } Pipe_ClosePipe(corenum, PIPE_CONTROLPIPE); HOST_TASK_NONBLOCK_WAIT(corenum, 100, HOST_STATE_Default_PostAddressSet); break; case HOST_STATE_Default_PostAddressSet: Pipe_ConfigurePipe(corenum, PIPE_CONTROLPIPE, EP_TYPE_CONTROL, PIPE_TOKEN_SETUP, ENDPOINT_CONTROLEP, USB_Host_ControlPipeSize[corenum], PIPE_BANK_SINGLE); USB_Host_SetDeviceAddress(USB_HOST_DEVICEADDRESS); USB_HostState[corenum] = HOST_STATE_Addressed; EVENT_USB_Host_DeviceEnumerationComplete(corenum); break; } if ((ErrorCode != HOST_ENUMERROR_NoError) && (USB_HostState[corenum] != HOST_STATE_Unattached)) { EVENT_USB_Host_DeviceEnumerationFailed(corenum, ErrorCode, SubErrorCode); USB_Host_VBUS_Auto_Off(); EVENT_USB_Host_DeviceUnattached(corenum); USB_ResetInterface(corenum); } } uint8_t USB_Host_WaitMS(uint8_t MS) { return HOST_WAITERROR_Successful; } void USB_Host_Enumerate (uint8_t HostId) /* Part of Interrupt Service Routine */ { // CurrentHostID = HostId; // hostselected = HostId; EVENT_USB_Host_DeviceAttached(HostId); USB_HostState[HostId] = HOST_STATE_Powered; } void USB_Host_DeEnumerate(uint8_t HostId) /* Part of Interrupt Service Routine */ { uint8_t i; Pipe_ClosePipe(HostId, PIPE_CONTROLPIPE); // FIXME close only relevant pipes , take long time in ISR for(i = PIPE_CONTROLPIPE+1; i < PIPE_TOTAL_PIPES; i++) { if(PipeInfo[HostId][i].PipeHandle != 0) { Pipe_ClosePipe(HostId, i); } } EVENT_USB_Host_DeviceUnattached(HostId); USB_HostState[HostId] = HOST_STATE_Unattached; }