/** Task to read and process the HID report descriptor and HID reports from the device and display the
 *  results onto the board LEDs.
 */
void MouseHost_Task(void)
{
	if (USB_HostState != HOST_STATE_Configured)
	  return;

	/* Select and unfreeze mouse data pipe */
	Pipe_SelectPipe(MOUSE_DATA_IN_PIPE);
	Pipe_Unfreeze();

	/* Check to see if a packet has been received */
	if (Pipe_IsINReceived())
	{
		/* Check if data has been received from the attached mouse */
		if (Pipe_IsReadWriteAllowed())
		{
			/* Create buffer big enough for the report */
			uint8_t MouseReport[Pipe_BytesInPipe()];

			/* Load in the mouse report */
			Pipe_Read_Stream_LE(MouseReport, Pipe_BytesInPipe(), NULL);

			/* Process the read in mouse report from the device */
			ProcessMouseReport(MouseReport);
		}

		/* Clear the IN endpoint, ready for next data packet */
		Pipe_ClearIN();
	}

	/* Freeze mouse data pipe */
	Pipe_Freeze();
}
Beispiel #2
0
uint8_t Pipe_WaitUntilReady(const uint8_t corenum)
{
	/*	#if (USB_STREAM_TIMEOUT_MS < 0xFF)
	    uint8_t  TimeoutMSRem = USB_STREAM_TIMEOUT_MS;
	   #else
	    uint16_t TimeoutMSRem = USB_STREAM_TIMEOUT_MS;
	   #endif

	    uint16_t PreviousFrameNumber = USB_Host_GetFrameNumber();*/

	for (;; ) {
		if (Pipe_IsReadWriteAllowed(corenum)) {
			return PIPE_READYWAIT_NoError;
		}

		if (Pipe_IsStalled(corenum)) {
			return PIPE_READYWAIT_PipeStalled;
		}
		else if (USB_HostState[corenum] == HOST_STATE_Unattached) {
			return PIPE_READYWAIT_DeviceDisconnected;
		}

		/*TODO no timeout yet */
		/* uint16_t CurrentFrameNumber = USB_Host_GetFrameNumber();

		   if (CurrentFrameNumber != PreviousFrameNumber)
		   {
		    PreviousFrameNumber = CurrentFrameNumber;

		    if (!(TimeoutMSRem--))
		      return PIPE_READYWAIT_Timeout;
		   }*/
	}
}
Beispiel #3
0
/** Reads in and processes the next report from the attached device, displaying the report
 *  contents on the board LEDs and via the serial port.
 */
void ReadNextReport(void)
{
	USB_MouseReport_Data_t MouseReport;
	uint8_t                LEDMask = LEDS_NO_LEDS;

	/* Select mouse data pipe */
	Pipe_SelectPipe(MOUSE_DATA_IN_PIPE);

	/* Unfreeze keyboard data pipe */
	Pipe_Unfreeze();

	/* Check to see if a packet has been received */
	if (!(Pipe_IsINReceived()))
	{
		/* No packet received (no movement), turn off LEDs */
		LEDs_SetAllLEDs(LEDS_NO_LEDS);

		/* Refreeze HID data IN pipe */
		Pipe_Freeze();

		return;
	}

	/* Ensure pipe contains data before trying to read from it */
	if (Pipe_IsReadWriteAllowed())
	{
		/* Read in mouse report data */
		Pipe_Read_Stream_LE(&MouseReport, sizeof(MouseReport));

		/* Alter status LEDs according to mouse X movement */
		if (MouseReport.X > 0)
		  LEDMask |= LEDS_LED1;
		else if (MouseReport.X < 0)
		  LEDMask |= LEDS_LED2;

		/* Alter status LEDs according to mouse Y movement */
		if (MouseReport.Y > 0)
		  LEDMask |= LEDS_LED3;
		else if (MouseReport.Y < 0)
		  LEDMask |= LEDS_LED4;

		/* Alter status LEDs according to mouse button position */
		if (MouseReport.Button)
		  LEDMask  = LEDS_ALL_LEDS;

		LEDs_SetAllLEDs(LEDMask);

		/* Print mouse report data through the serial port */
		printf_P(PSTR("dX:%2d dY:%2d Button:%d\r\n"), MouseReport.X,
													  MouseReport.Y,
													  MouseReport.Button);
	}

	/* Clear the IN endpoint, ready for next data packet */
	Pipe_ClearIN();

	/* Refreeze mouse data pipe */
	Pipe_Freeze();
}
Beispiel #4
0
bool MIDI_Host_ReceiveEventPacket(USB_ClassInfo_MIDI_Host_t* const MIDIInterfaceInfo, MIDI_EventPacket_t* const Event)
{
	if ((USB_HostState != HOST_STATE_Configured) || !(MIDIInterfaceInfo->State.IsActive))
	  return HOST_SENDCONTROL_DeviceDisconnected;
	
	Pipe_SelectPipe(MIDIInterfaceInfo->Config.DataINPipeNumber);

	if (!(Pipe_IsReadWriteAllowed()))
	  return false;

	Pipe_Read_Stream_LE(Event, sizeof(MIDI_EventPacket_t), NO_STREAM_CALLBACK);

	if (!(Pipe_IsReadWriteAllowed()))
	  Pipe_ClearIN();
	
	return true;
}
Beispiel #5
0
/** Reads in and processes the next report from the attached device, displaying the report
 *  contents on the board LEDs and via the serial port.
 */
void ReadNextReport(void)
{
	USB_KeyboardReport_Data_t KeyboardReport;
		
	/* Select keyboard data pipe */
	Pipe_SelectPipe(KEYBOARD_DATAPIPE);	

	/* Unfreeze keyboard data pipe */
	Pipe_Unfreeze();

	/* Check to see if a packet has been received */
	if (!(Pipe_IsINReceived()))
	{
		/* Refreeze HID data IN pipe */
		Pipe_Freeze();
			
		return;
	}
	
	/* Ensure pipe contains data before trying to read from it */
	if (Pipe_IsReadWriteAllowed())
	{
		/* Read in keyboard report data */
		Pipe_Read_Stream_LE(&KeyboardReport, sizeof(KeyboardReport));

		/* Indicate if the modifier byte is non-zero (special key such as shift is being pressed) */
		LEDs_ChangeLEDs(LEDS_LED1, (KeyboardReport.Modifier) ? LEDS_LED1 : 0);
		
		/* Check if a key has been pressed */
		if (KeyboardReport.KeyCode)
		{
			/* Toggle status LED to indicate keypress */
			LEDs_ToggleLEDs(LEDS_LED2);
				  
			char PressedKey = 0;

			/* Retrieve pressed key character if alphanumeric */
			if ((KeyboardReport.KeyCode[0] >= 0x04) && (KeyboardReport.KeyCode[0] <= 0x1D))
			  PressedKey = (KeyboardReport.KeyCode[0] - 0x04) + 'A';
			else if ((KeyboardReport.KeyCode[0] >= 0x1E) && (KeyboardReport.KeyCode[0] <= 0x27))
			  PressedKey = (KeyboardReport.KeyCode[0] - 0x1E) + '0';
			else if (KeyboardReport.KeyCode[0] == 0x2C)
			  PressedKey = ' ';						
			else if (KeyboardReport.KeyCode[0] == 0x28)
			  PressedKey = '\n';
				 
			/* Print the pressed key character out through the serial port if valid */
			if (PressedKey)
			  putchar(PressedKey);
		}
	}
		
	/* Clear the IN endpoint, ready for next data packet */
	Pipe_ClearIN();

	/* Refreeze keyboard data pipe */
	Pipe_Freeze();
}
bool MIDI_Host_ReceiveEventPacket(USB_ClassInfo_MIDI_Host_t* const MIDIInterfaceInfo,
                                  MIDI_EventPacket_t* const Event)
{
	uint8_t portnum = MIDIInterfaceInfo->Config.PortNumber;

	if ((USB_HostState[portnum] != HOST_STATE_Configured) || !(MIDIInterfaceInfo->State.IsActive))
	  return HOST_SENDCONTROL_DeviceDisconnected;

	Pipe_SelectPipe(portnum,MIDIInterfaceInfo->Config.DataINPipeNumber);

	if (!(Pipe_IsReadWriteAllowed(portnum)))
	  return false;

	Pipe_Read_Stream_LE(portnum,Event, sizeof(MIDI_EventPacket_t), NULL);

	if (!(Pipe_IsReadWriteAllowed(portnum)))
	  Pipe_ClearIN(portnum);

	return true;
}
Beispiel #7
0
uint8_t MIDI_Host_SendEventPacket(USB_ClassInfo_MIDI_Host_t* const MIDIInterfaceInfo, MIDI_EventPacket_t* const Event)
{
	if ((USB_HostState != HOST_STATE_Configured) || !(MIDIInterfaceInfo->State.IsActive))
	  return HOST_SENDCONTROL_DeviceDisconnected;
	
	Pipe_SelectPipe(MIDIInterfaceInfo->Config.DataOUTPipeNumber);

	if (Pipe_IsReadWriteAllowed())
	{
		uint8_t ErrorCode;

		if ((ErrorCode = Pipe_Write_Stream_LE(Event, sizeof(MIDI_EventPacket_t), NO_STREAM_CALLBACK)) != PIPE_RWSTREAM_NoError)
		  return ErrorCode;

		if (!(Pipe_IsReadWriteAllowed()))
		  Pipe_ClearOUT();
	}
	
	return PIPE_RWSTREAM_NoError;
}
/** Task to read in data received from the attached CDC device and print it to the serial port.
 */
void CDCHost_Task(void)
{
	if (USB_HostState != HOST_STATE_Configured)
	  return;

	/* Select the data IN pipe */
	Pipe_SelectPipe(CDC_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())
		{
			/* Get the length of the pipe data, and create a new buffer to hold it */
			uint16_t BufferLength = Pipe_BytesInPipe();
			uint8_t  Buffer[BufferLength];

			/* Read in the pipe data to the temporary buffer */
			Pipe_Read_Stream_LE(Buffer, BufferLength, NULL);

			/* Print out the buffer contents to the USART */
			for (uint16_t BufferByte = 0; BufferByte < BufferLength; BufferByte++)
			  putchar(Buffer[BufferByte]);
		}

		/* Clear the pipe after it is read, ready for the next packet */
		Pipe_ClearIN();
	}

	/* Re-freeze IN pipe after use */
	Pipe_Freeze();

	/* Select and unfreeze the notification pipe */
	Pipe_SelectPipe(CDC_NOTIFICATION_PIPE);
	Pipe_Unfreeze();

	/* Check if a packet has been received */
	if (Pipe_IsINReceived())
	{
		/* Discard the unused event notification */
		Pipe_ClearIN();
	}

	/* Freeze notification IN pipe after use */
	Pipe_Freeze();
}
Beispiel #9
0
uint8_t TEMPLATE_FUNC_NAME (TEMPLATE_BUFFER_TYPE const Buffer,
                            uint16_t Length,
                            uint16_t* const BytesProcessed)
{
	uint8_t* DataStream      = ((uint8_t*)Buffer + TEMPLATE_BUFFER_OFFSET(Length));
	uint16_t BytesInTransfer = 0;
	uint8_t  ErrorCode;

	Pipe_SetPipeToken(TEMPLATE_TOKEN);

	if ((ErrorCode = Pipe_WaitUntilReady()))
	  return ErrorCode;

	if (BytesProcessed != NULL)
	{
		Length -= *BytesProcessed;
		TEMPLATE_BUFFER_MOVE(DataStream, *BytesProcessed);
	}

	while (Length)
	{
		if (!(Pipe_IsReadWriteAllowed()))
		{
			TEMPLATE_CLEAR_PIPE();

			if (BytesProcessed != NULL)
			{
				*BytesProcessed += BytesInTransfer;
				return PIPE_RWSTREAM_IncompleteTransfer;
			}

			if ((ErrorCode = Pipe_WaitUntilReady()))
			  return ErrorCode;
		}
		else
		{
			TEMPLATE_TRANSFER_BYTE(DataStream);
			TEMPLATE_BUFFER_MOVE(DataStream, 1);
			Length--;
			BytesInTransfer++;
		}
	}

	return PIPE_RWSTREAM_NoError;
}
/** Task to set the configuration of the attached device after it has been enumerated. */
void AndroidHost_Task(void)
{
    if (USB_HostState != HOST_STATE_Configured)
        return;

    /* 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_Read_8();
            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();
}
Beispiel #11
0
uint8_t Pipe_Null_Stream(uint16_t Length,
                         uint16_t* const BytesProcessed)
{
	uint8_t  ErrorCode;
	uint16_t BytesInTransfer = 0;
	
	Pipe_SetPipeToken(PIPE_TOKEN_OUT);

	if ((ErrorCode = Pipe_WaitUntilReady()))
	  return ErrorCode;

	if (BytesProcessed != NULL)
	  Length -= *BytesProcessed;

	while (Length)
	{
		if (!(Pipe_IsReadWriteAllowed()))
		{
			Pipe_ClearOUT();
				
			if (BytesProcessed != NULL)
			{
				*BytesProcessed += BytesInTransfer;
				return PIPE_RWSTREAM_IncompleteTransfer;
			}
			
			USB_USBTask();

			if ((ErrorCode = Pipe_WaitUntilReady()))
			  return ErrorCode;
		}
		else
		{
			Pipe_Write_8(0);
			
			Length--;
			BytesInTransfer++;
		}
	}

	return PIPE_RWSTREAM_NoError;
}
/** ISR to handle the reloading of the endpoint with the next sample. */
ISR(TIMER0_COMPA_vect, ISR_BLOCK)
{
	uint8_t PrevPipe = Pipe_GetCurrentPipe();

	Pipe_SelectPipe(AUDIO_DATA_OUT_PIPE);
	Pipe_Unfreeze();

	/* Check if the current pipe can be written to (device ready for more data) */
	if (Pipe_IsOUTReady())
	{
		int16_t AudioSample;

		#if defined(USE_TEST_TONE)
			static uint8_t SquareWaveSampleCount;
			static int16_t CurrentWaveValue;

			/* In test tone mode, generate a square wave at 1/256 of the sample rate */
			if (SquareWaveSampleCount++ == 0xFF)
			  CurrentWaveValue ^= 0x8000;

			/* Only generate audio if the board button is being pressed */
			AudioSample = (Buttons_GetStatus() & BUTTONS_BUTTON1) ? CurrentWaveValue : 0;
		#else
			/* Audio sample is ADC value scaled to fit the entire range */
			AudioSample = ((SAMPLE_MAX_RANGE / ADC_MAX_RANGE) * ADC_GetResult());

			#if defined(MICROPHONE_BIASED_TO_HALF_RAIL)
			/* Microphone is biased to half rail voltage, subtract the bias from the sample value */
			AudioSample -= (SAMPLE_MAX_RANGE / 2);
			#endif
		#endif

		Pipe_Write_16_LE(AudioSample);
		Pipe_Write_16_LE(AudioSample);

		if (!(Pipe_IsReadWriteAllowed()))
		  Pipe_ClearOUT();
	}

	Pipe_Freeze();
	Pipe_SelectPipe(PrevPipe);
}
Beispiel #13
0
/** Reads in and processes the next report from the attached device, displaying the report
 *  contents on the board LEDs and via the serial port.
 */
void ReadNextReport(void)
{
	/* Select and unfreeze HID data IN pipe */
	Pipe_SelectPipe(HID_DATA_IN_PIPE);
	Pipe_Unfreeze();

	/* Check to see if a packet has been received */
	if (!(Pipe_IsINReceived()))
	{
		/* Refreeze HID data IN pipe */
		Pipe_Freeze();

		return;
	}

	/* Ensure pipe contains data before trying to read from it */
	if (Pipe_IsReadWriteAllowed())
	{
		uint8_t ReportINData[Pipe_BytesInPipe()];

		/* Read in HID report data */
		Pipe_Read_Stream_LE(&ReportINData, sizeof(ReportINData));

		/* Print report data through the serial port */
		for (uint16_t CurrByte = 0; CurrByte < sizeof(ReportINData); CurrByte++)
		  printf_P(PSTR("0x%02X "), ReportINData[CurrByte]);

		puts_P(PSTR("\r\n"));
	}

	/* Clear the IN endpoint, ready for next data packet */
	Pipe_ClearIN();

	/* Refreeze HID data IN pipe */
	Pipe_Freeze();
}
Beispiel #14
0
/** Task to set the configuration of the attached device after it has been enumerated, and to read in
 *  data received from the attached CDC device and print it to the serial port.
 */
void CDC_Host_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 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;
			}

			puts_P(PSTR("CDC Device Enumerated.\r\n"));

			USB_HostState = HOST_STATE_Configured;
			break;
		case HOST_STATE_Configured:
			/* Select and the data IN pipe */
			Pipe_SelectPipe(CDC_DATAPIPE_IN);
			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())
				{
					/* Get the length of the pipe data, and create a new buffer to hold it */
					uint16_t BufferLength = Pipe_BytesInPipe();
					uint8_t  Buffer[BufferLength];
					
					/* Read in the pipe data to the temporary buffer */
					Pipe_Read_Stream_LE(Buffer, BufferLength);
									
					/* Print out the buffer contents to the USART */
					for (uint16_t BufferByte = 0; BufferByte < BufferLength; BufferByte++)
					  putchar(Buffer[BufferByte]);
				}

				/* Clear the pipe after it is read, ready for the next packet */
				Pipe_ClearIN();
			}

			/* Re-freeze IN pipe after use */
			Pipe_Freeze();

			/* Select and unfreeze the notification pipe */
			Pipe_SelectPipe(CDC_NOTIFICATIONPIPE);
			Pipe_Unfreeze();
			
			/* Check if a packet has been received */
			if (Pipe_IsINReceived())
			{
				/* Discard the unused event notification */
				Pipe_ClearIN();
			}
			
			/* Freeze notification IN pipe after use */
			Pipe_Freeze();
						
			break;
	}
}
Beispiel #15
0
/** Task to read in and processes the next report from the attached device, displaying the report
 *  contents on the board LEDs and via the serial port.
 */
void KeyboardHost_Task(void)
{
	if (USB_HostState != HOST_STATE_Configured)
	  return;

	/* Select keyboard data pipe */
	Pipe_SelectPipe(KEYBOARD_DATA_IN_PIPE);

	/* Unfreeze keyboard data pipe */
	Pipe_Unfreeze();

	/* Check to see if a packet has been received */
	if (!(Pipe_IsINReceived()))
	{
		/* Refreeze HID data IN pipe */
		Pipe_Freeze();

		return;
	}

	/* Ensure pipe contains data before trying to read from it */
	if (Pipe_IsReadWriteAllowed())
	{
		USB_KeyboardReport_Data_t KeyboardReport;

		/* Read in keyboard report data */
		Pipe_Read_Stream_LE(&KeyboardReport, sizeof(KeyboardReport), NULL);

		/* Indicate if the modifier byte is non-zero (special key such as shift is being pressed) */
		LEDs_ChangeLEDs(LEDS_LED1, (KeyboardReport.Modifier) ? LEDS_LED1 : 0);

		uint8_t KeyCode = KeyboardReport.KeyCode[0];

		/* Check if a key has been pressed */
		if (KeyCode)
		{
			/* Toggle status LED to indicate keypress */
			LEDs_ToggleLEDs(LEDS_LED2);

			char PressedKey = 0;

			/* Retrieve pressed key character if alphanumeric */
			if ((KeyCode >= HID_KEYBOARD_SC_A) && (KeyCode <= HID_KEYBOARD_SC_Z))
			{
				PressedKey = (KeyCode - HID_KEYBOARD_SC_A) + 'A';
			}
			else if ((KeyCode >= HID_KEYBOARD_SC_1_AND_EXCLAMATION) &
					 (KeyCode  < HID_KEYBOARD_SC_0_AND_CLOSING_PARENTHESIS))
			{
				PressedKey = (KeyCode - HID_KEYBOARD_SC_1_AND_EXCLAMATION) + '1';
			}
			else if (KeyCode == HID_KEYBOARD_SC_0_AND_CLOSING_PARENTHESIS)
			{
				PressedKey = '0';
			}
			else if (KeyCode == HID_KEYBOARD_SC_SPACE)
			{
				PressedKey = ' ';
			}
			else if (KeyCode == HID_KEYBOARD_SC_ENTER)
			{
				PressedKey = '\n';
			}

			/* Print the pressed key character out through the serial port if valid */
			if (PressedKey)
			  putchar(PressedKey);
		}
	}

	/* Clear the IN endpoint, ready for next data packet */
	Pipe_ClearIN();

	/* Refreeze keyboard data pipe */
	Pipe_Freeze();
}
Beispiel #16
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;
	}
}
Beispiel #17
0
void Bluetooth_HCITask(void)
{
	switch (Bluetooth_HCIProcessingState)
	{
		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();

				switch (HCIEventHeader.EventCode)
				{
					case EVENT_COMMAND_COMPLETE:
						Bluetooth_HCIProcessingState = Bluetooth_HCINextState;
						break;
					case EVENT_COMMAND_STATUS:
						/* If the execution of a command failed, reset the stack */
						if (((BT_HCIEvent_CommandStatus_t*)&EventParams)->Status)
						  Bluetooth_HCIProcessingState = Bluetooth_Init;
						break;
					case EVENT_CONNECTION_REQUEST:
						/* 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_HCIProcessingState = (Bluetooth_Connection.IsConnected || !(IsACLConnection) ||
													    !(Bluetooth_ConnectionRequest(Bluetooth_TempDeviceAddress))) ?
													   Bluetooth_Conn_RejectConnection : Bluetooth_Conn_AcceptConnection;
						break;
					case EVENT_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_HCIProcessingState = Bluetooth_Conn_SendPINCode;
						break;
					case EVENT_CONNECTION_COMPLETE:
						/* 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:
						/* Device disconnected, indicate connection information no longer valid */
						Bluetooth_Connection.IsConnected = false;
						
						Bluetooth_DisconnectionComplete();
						
						Bluetooth_HCIProcessingState = Bluetooth_Init;
						break;					
				}
			}
			
			Pipe_Freeze();
			
			break;
		case Bluetooth_Init:
			/* Reset the connection information structure to destroy any previous connection state */
			memset(&Bluetooth_Connection, 0x00, sizeof(Bluetooth_Connection));

			Bluetooth_HCIProcessingState = Bluetooth_Init_Reset; 
			break;
		case Bluetooth_Init_Reset:
			HCICommandHeader = (BT_HCICommand_Header_t)
			{
				OpCode: {OGF: OGF_CTRLR_BASEBAND, OCF: OCF_CTRLR_BASEBAND_RESET},
				ParameterLength: 0,
			};

			/* Send the command to reset the bluetooth dongle controller */
			Bluetooth_SendHCICommand(NULL, 0);
			
			Bluetooth_HCINextState       = Bluetooth_Init_SetLocalName;
			Bluetooth_HCIProcessingState = Bluetooth_ProcessEvents;
			break;
		case Bluetooth_Init_SetLocalName:
			HCICommandHeader = (BT_HCICommand_Header_t)
				{
					OpCode: {OGF: OGF_CTRLR_BASEBAND, OCF: 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(Bluetooth_DeviceConfiguration.Name, strlen(Bluetooth_DeviceConfiguration.Name));

			Bluetooth_HCINextState       = Bluetooth_Init_SetDeviceClass;
			Bluetooth_HCIProcessingState = Bluetooth_ProcessEvents;
			break;
		case Bluetooth_Init_SetDeviceClass:
			HCICommandHeader = (BT_HCICommand_Header_t)
				{
					OpCode: {OGF: OGF_CTRLR_BASEBAND, OCF: 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(&Bluetooth_DeviceConfiguration.Class, 3);

			Bluetooth_HCINextState       = Bluetooth_Init_WriteScanEnable;
			Bluetooth_HCIProcessingState = Bluetooth_ProcessEvents;
			break;
		case Bluetooth_Init_WriteScanEnable:
			HCICommandHeader = (BT_HCICommand_Header_t)
			{
				OpCode: {OGF: OGF_CTRLR_BASEBAND, OCF: 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(&Interval, 1);
			
			Bluetooth_HCINextState       = Bluetooth_ProcessEvents;
			Bluetooth_HCIProcessingState = Bluetooth_ProcessEvents;
			break;
		case Bluetooth_Conn_AcceptConnection:
			HCICommandHeader = (BT_HCICommand_Header_t)
				{
					OpCode: {OGF: OGF_LINK_CONTROL, OCF: 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(&AcceptConnectionParams, sizeof(BT_HCICommand_AcceptConnectionReq_t));
			
			Bluetooth_HCIProcessingState = Bluetooth_ProcessEvents;
			break;
		case Bluetooth_Conn_RejectConnection:
			HCICommandHeader = (BT_HCICommand_Header_t)
				{
					OpCode: {OGF: OGF_LINK_CONTROL, OCF: 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(&RejectConnectionParams, sizeof(BT_HCICommand_RejectConnectionReq_t));
		
			Bluetooth_HCIProcessingState = Bluetooth_ProcessEvents;
			break;
		case Bluetooth_Conn_SendPINCode:
			HCICommandHeader = (BT_HCICommand_Header_t)
				{
					OpCode: {OGF: OGF_LINK_CONTROL, OCF: 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(&PINCodeRequestParams, sizeof(BT_HCICommand_PinCodeResp_t));

			Bluetooth_HCIProcessingState = Bluetooth_ProcessEvents;
			break;
	}
}
Beispiel #18
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);
}
static uint8_t SImage_Host_ReceiveBlockHeader(USB_ClassInfo_SI_Host_t* const SIInterfaceInfo, SI_PIMA_Container_t* const PIMAHeader)
{
	uint16_t TimeoutMSRem = COMMAND_DATA_TIMEOUT_MS;

	Pipe_SelectPipe(SIInterfaceInfo->Config.DataINPipeNumber);
	Pipe_Unfreeze();
	
	while (!(Pipe_IsReadWriteAllowed()))
	{
		if (USB_INT_HasOccurred(USB_INT_HSOFI))
		{
			USB_INT_Clear(USB_INT_HSOFI);
			TimeoutMSRem--;

			if (!(TimeoutMSRem))
			{
				return PIPE_RWSTREAM_Timeout;
			}
		}
		
		Pipe_Freeze();
		Pipe_SelectPipe(SIInterfaceInfo->Config.DataOUTPipeNumber);
		Pipe_Unfreeze();

		if (Pipe_IsStalled())
		{
			USB_Host_ClearPipeStall(SIInterfaceInfo->Config.DataOUTPipeNumber);
			return PIPE_RWSTREAM_PipeStalled;
		}

		Pipe_Freeze();
		Pipe_SelectPipe(SIInterfaceInfo->Config.DataINPipeNumber);
		Pipe_Unfreeze();

		if (Pipe_IsStalled())
		{
			USB_Host_ClearPipeStall(SIInterfaceInfo->Config.DataINPipeNumber);
			return PIPE_RWSTREAM_PipeStalled;
		}
		  
		if (USB_HostState == HOST_STATE_Unattached)
		  return PIPE_RWSTREAM_DeviceDisconnected;
	}
	
	Pipe_Read_Stream_LE(PIMAHeader, PIMA_COMMAND_SIZE(0), NO_STREAM_CALLBACK);
	
	if (PIMAHeader->Type == CType_ResponseBlock)
	{
		uint8_t ParamBytes = (PIMAHeader->DataLength - PIMA_COMMAND_SIZE(0));

		if (ParamBytes)
		  Pipe_Read_Stream_LE(&PIMAHeader->Params, ParamBytes, NO_STREAM_CALLBACK);
		
		Pipe_ClearIN();
		
		PIMAHeader->Code &= 0x0000000F;
	}
	
	Pipe_Freeze();
	
	return PIPE_RWSTREAM_NoError;
}
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);
}
Beispiel #21
0
/** Incoming ACL packet processing task. This task is called by the main ACL processing task to read in and process
 *  any incoming ACL packets to the device, handling signal requests as they are received or passing along channel
 *  data to the user application.
 */
static void Bluetooth_ProcessIncomingACLPackets(void)
{
	BT_ACL_Header_t        ACLPacketHeader;
	BT_DataPacket_Header_t DataHeader;

	Pipe_SelectPipe(BLUETOOTH_DATA_IN_PIPE);
	Pipe_Unfreeze();

	if (!(Pipe_IsReadWriteAllowed()))
	{
		Pipe_Freeze();
		return;
	}

	/* Read in the received ACL packet headers when it has been discovered that a packet has been received */
	Pipe_Read_Stream_LE(&ACLPacketHeader, sizeof(ACLPacketHeader));
	Pipe_Read_Stream_LE(&DataHeader, sizeof(DataHeader));

	BT_ACL_DEBUG(2, "");
	BT_ACL_DEBUG(2, "Packet Received");
	BT_ACL_DEBUG(2, "-- Connection Handle: 0x%04X", (ACLPacketHeader.ConnectionHandle & 0x0FFF));
	BT_ACL_DEBUG(2, "-- Data Length: 0x%04X", ACLPacketHeader.DataLength);
	BT_ACL_DEBUG(2, "-- Destination Channel: 0x%04X", DataHeader.DestinationChannel);
	BT_ACL_DEBUG(2, "-- Payload Length: 0x%04X", DataHeader.PayloadLength);

	/* Check the packet's destination channel - signaling channel should be processed by the stack internally */
	if (DataHeader.DestinationChannel == BT_CHANNEL_SIGNALING)
	{
		/* Read in the Signal Command header of the incoming packet */
		BT_Signal_Header_t SignalCommandHeader;
		Pipe_Read_Stream_LE(&SignalCommandHeader, sizeof(SignalCommandHeader));

		/* Dispatch to the appropriate handler function based on the Signal message code */
		switch (SignalCommandHeader.Code)
		{
			case BT_SIGNAL_CONNECTION_REQUEST:
				Bluetooth_Signal_ConnectionReq(&SignalCommandHeader);
				break;
			case BT_SIGNAL_CONNECTION_RESPONSE:
				Bluetooth_Signal_ConnectionResp(&SignalCommandHeader);
				break;
			case BT_SIGNAL_CONFIGURATION_REQUEST:
				Bluetooth_Signal_ConfigurationReq(&SignalCommandHeader);
				break;
			case BT_SIGNAL_CONFIGURATION_RESPONSE:
				Bluetooth_Signal_ConfigurationResp(&SignalCommandHeader);
				break;
			case BT_SIGNAL_DISCONNECTION_REQUEST:
				Bluetooth_Signal_DisconnectionReq(&SignalCommandHeader);
				break;
			case BT_SIGNAL_DISCONNECTION_RESPONSE:
				Bluetooth_Signal_DisconnectionResp(&SignalCommandHeader);
				break;
			case BT_SIGNAL_ECHO_REQUEST:
				Bluetooth_Signal_EchoReq(&SignalCommandHeader);
				break;
			case BT_SIGNAL_INFORMATION_REQUEST:
				Bluetooth_Signal_InformationReq(&SignalCommandHeader);
				break;
			case BT_SIGNAL_COMMAND_REJECT:
				BT_ACL_DEBUG(1, "<< Command Reject");

				uint16_t RejectReason;
				Pipe_Read_Stream_LE(&RejectReason, sizeof(RejectReason));
				Pipe_Discard_Stream(ACLPacketHeader.DataLength - sizeof(RejectReason));
				Pipe_ClearIN();
				Pipe_Freeze();

				BT_ACL_DEBUG(2, "-- Reason: %d", RejectReason);
				break;
			default:
				BT_ACL_DEBUG(1, "<< Unknown Signaling Command 0x%02X", SignalCommandHeader.Code);

				Pipe_Discard_Stream(ACLPacketHeader.DataLength);
				Pipe_ClearIN();
				Pipe_Freeze();
				break;
		}
	}
	else
	{
		/* Non-signaling packet received, read in the packet contents and pass to the user application */
		uint8_t PacketData[DataHeader.PayloadLength];
		Pipe_Read_Stream_LE(PacketData, DataHeader.PayloadLength);
		Pipe_ClearIN();
		Pipe_Freeze();

		Bluetooth_PacketReceived(PacketData, DataHeader.PayloadLength,
		                         Bluetooth_GetChannelData(DataHeader.DestinationChannel, CHANNEL_SEARCH_LOCALNUMBER));
	}
}
Beispiel #22
0
uint8_t Pipe_Discard_Stream(uint16_t Length
#if !defined(NO_STREAM_CALLBACKS)
                            , StreamCallbackPtr_t Callback
#endif
                            )
{
	uint8_t  ErrorCode;
	
	Pipe_SetPipeToken(PIPE_TOKEN_IN);

	if ((ErrorCode = Pipe_WaitUntilReady()))
	  return ErrorCode;

	#if defined(FAST_STREAM_TRANSFERS)
	uint8_t BytesRemToAlignment = (Pipe_BytesInPipe() & 0x07);

	if (Length >= 8)
	{
		Length -= BytesRemToAlignment;

		switch (BytesRemToAlignment)
		{
			default:
				do
				{
					if (!(Pipe_IsReadWriteAllowed()))
					{
						Pipe_ClearIN();
							
						#if !defined(NO_STREAM_CALLBACKS)
						if ((Callback != NULL) && (Callback() == STREAMCALLBACK_Abort))
						  return PIPE_RWSTREAM_CallbackAborted;
						#endif

						if ((ErrorCode = Pipe_WaitUntilReady()))
						  return ErrorCode;
					}

					Length -= 8;
					
					Pipe_Discard_Byte();
			case 7: Pipe_Discard_Byte();
			case 6: Pipe_Discard_Byte();
			case 5: Pipe_Discard_Byte();
			case 4: Pipe_Discard_Byte();
			case 3: Pipe_Discard_Byte();
			case 2: Pipe_Discard_Byte();
			case 1:	Pipe_Discard_Byte();
				} while (Length >= 8);	
		}
	}
	#endif

	while (Length)
	{
		if (!(Pipe_IsReadWriteAllowed()))
		{
			Pipe_ClearIN();
				
			#if !defined(NO_STREAM_CALLBACKS)
			if ((Callback != NULL) && (Callback() == STREAMCALLBACK_Abort))
			  return PIPE_RWSTREAM_CallbackAborted;
			#endif

			if ((ErrorCode = Pipe_WaitUntilReady()))
			  return ErrorCode;
		}
		else
		{
			Pipe_Discard_Byte();
			Length--;
		}
	}

	return PIPE_RWSTREAM_NoError;
}
Beispiel #23
0
/** Task to set the configuration of the attached device after it has been enumerated, and to read and process
 *  the HID report descriptor and HID reports from the device and display the results onto the board LEDs.
 */
void Joystick_HID_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 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;
			}

			printf_P(PSTR("Processing HID Report (Size %d Bytes).\r\n"), HIDReportSize);

			/* Get and process the device's first HID report descriptor */
			if ((ErrorCode = GetHIDReportData()) != ParseSuccessful)
			{
				puts_P(PSTR(ESC_FG_RED "Report Parse Error.\r\n"));

				if (!(HIDReportInfo.TotalReportItems))
					puts_P(PSTR("Not a valid Joystick." ESC_FG_WHITE));
				else
					printf_P(PSTR(" -- 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("Joystick Enumerated.\r\n"));

			USB_HostState = HOST_STATE_Configured;
			break;
		case HOST_STATE_Configured:
			/* Select and unfreeze joystick data pipe */
			Pipe_SelectPipe(JOYSTICK_DATA_IN_PIPE);
			Pipe_Unfreeze();

			/* Check to see if a packet has been received */
			if (Pipe_IsINReceived())
			{
				/* Check if data has been received from the attached joystick */
				if (Pipe_IsReadWriteAllowed())
				{
					/* Create buffer big enough for the report */
					uint8_t JoystickReport[Pipe_BytesInPipe()];

					/* Load in the joystick report */
					Pipe_Read_Stream_LE(JoystickReport, Pipe_BytesInPipe(), NULL);

					/* Process the read in joystick report from the device */
					ProcessJoystickReport(JoystickReport);
				}

				/* Clear the IN endpoint, ready for next data packet */
				Pipe_ClearIN();
			}

			/* Freeze joystick data pipe */
			Pipe_Freeze();
			break;
	}
}
Beispiel #24
0
/** Function to receive a PIMA response container from the attached still image device.
 *
 *  \return A value from the Pipe_Stream_RW_ErrorCodes_t enum
 */
uint8_t SImage_ReceiveBlockHeader(void)
{
    uint16_t TimeoutMSRem = COMMAND_DATA_TIMEOUT_MS;

    /* Unfreeze the data IN pipe */
    Pipe_SelectPipe(SIMAGE_DATA_IN_PIPE);
    Pipe_Unfreeze();

    /* Wait until data received on the IN pipe */
    while (!(Pipe_IsReadWriteAllowed()))
    {
        /* Check to see if a new frame has been issued (1ms elapsed) */
        if (USB_INT_HasOccurred(USB_INT_HSOFI))
        {
            /* Clear the flag and decrement the timeout period counter */
            USB_INT_Clear(USB_INT_HSOFI);
            TimeoutMSRem--;

            /* Check to see if the timeout period for the command has elapsed */
            if (!(TimeoutMSRem))
            {
                /* Return error code */
                return PIPE_RWSTREAM_Timeout;
            }
        }

        Pipe_Freeze();
        Pipe_SelectPipe(SIMAGE_DATA_OUT_PIPE);
        Pipe_Unfreeze();

        /* Check if pipe stalled (command failed by device) */
        if (Pipe_IsStalled())
        {
            /* Clear the stall condition on the OUT pipe */
            USB_Host_ClearPipeStall(SIMAGE_DATA_OUT_PIPE);

            /* Return error code and break out of the loop */
            return PIPE_RWSTREAM_PipeStalled;
        }

        Pipe_Freeze();
        Pipe_SelectPipe(SIMAGE_DATA_IN_PIPE);
        Pipe_Unfreeze();

        /* Check if pipe stalled (command failed by device) */
        if (Pipe_IsStalled())
        {
            /* Clear the stall condition on the IN pipe */
            USB_Host_ClearPipeStall(SIMAGE_DATA_IN_PIPE);

            /* Return error code */
            return PIPE_RWSTREAM_PipeStalled;
        }

        /* Check to see if the device was disconnected, if so exit function */
        if (USB_HostState == HOST_STATE_Unattached)
            return PIPE_RWSTREAM_DeviceDisconnected;
    }

    /* Load in the response from the attached device */
    Pipe_Read_Stream_LE(&PIMA_ReceivedBlock, PIMA_COMMAND_SIZE(0));

    /* Check if the returned block type is a response block */
    if (PIMA_ReceivedBlock.Type == CType_ResponseBlock)
    {
        /* Determine the size of the parameters in the block via the data length attribute */
        uint8_t ParamBytes = (PIMA_ReceivedBlock.DataLength - PIMA_COMMAND_SIZE(0));

        /* Check if the device has returned any parameters */
        if (ParamBytes)
        {
            /* Read the PIMA parameters from the data IN pipe */
            Pipe_Read_Stream_LE(&PIMA_ReceivedBlock.Params, ParamBytes);
        }

        /* Clear pipe bank after use */
        Pipe_ClearIN();
    }

    /* Freeze the IN pipe after use */
    Pipe_Freeze();

    return PIPE_RWSTREAM_NoError;
}