Ejemplo n.º 1
0
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;
}
Ejemplo n.º 3
0
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);
}
Ejemplo n.º 4
0
/** 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));
}
Ejemplo n.º 7
0
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;
}
Ejemplo n.º 8
0
/** 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;
}
Ejemplo n.º 9
0
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);
}
Ejemplo n.º 10
0
/** 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));
}
Ejemplo n.º 12
0
/** 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);
}
Ejemplo n.º 13
0
/** 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;
	}
}
Ejemplo n.º 14
0
/** 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);
}
Ejemplo n.º 16
0
/** 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(;;);
}
Ejemplo n.º 17
0
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);
}
Ejemplo n.º 18
0
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(;;);
}
Ejemplo n.º 20
0
/** 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);
}
Ejemplo n.º 22
0
/** 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);
}
Ejemplo n.º 24
0
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;
}