/** 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(); }
/** Internal Bluetooth stack Signal Command processing routine for a Connection Request command. * * \param[in] SignalCommandHeader Pointer to the start of the received packet's Signal Command header */ static inline void Bluetooth_Signal_ConnectionReq(const BT_Signal_Header_t* const SignalCommandHeader) { BT_Signal_ConnectionReq_t ConnectionRequest; Pipe_Read_Stream_LE(&ConnectionRequest, sizeof(ConnectionRequest), NULL); Pipe_ClearIN(); Pipe_Freeze(); BT_ACL_DEBUG(1, "<< L2CAP Connection Request"); BT_ACL_DEBUG(2, "-- PSM: 0x%04X", ConnectionRequest.PSM); BT_ACL_DEBUG(2, "-- Source Channel: 0x%04X", ConnectionRequest.SourceChannel); /* Try to retrieve the existing channel's information structure if it exists */ Bluetooth_Channel_t* ChannelData = Bluetooth_GetChannelData(ConnectionRequest.SourceChannel, CHANNEL_SEARCH_REMOTENUMBER); /* If an existing channel item with the correct remote channel number was not found, find a free channel entry */ if (ChannelData == NULL) { /* Look through the channel information list for a free entry */ for (uint8_t i = 0; i < BLUETOOTH_MAX_OPEN_CHANNELS; i++) { if (Bluetooth_Connection.Channels[i].State == BT_Channel_Closed) { ChannelData = &Bluetooth_Connection.Channels[i]; /* Set the new channel structure's local channel number to a unique value within the connection orientated channel address space */ ChannelData->LocalNumber = (BT_CHANNELNUMBER_BASEOFFSET + i); break; } } } uint8_t ChannelStatus = BT_CONNECTION_REFUSED_RESOURCES; /* Reset the channel item contents only if a channel entry was found for it */ if (ChannelData != NULL) { /* Check if the user application will allow the connection based on its PSM */ if (Bluetooth_ChannelConnectionRequest(ConnectionRequest.PSM)) { ChannelData->RemoteNumber = ConnectionRequest.SourceChannel; ChannelData->PSM = ConnectionRequest.PSM; ChannelData->LocalMTU = MAXIMUM_CHANNEL_MTU; ChannelData->State = BT_Channel_Config_WaitConfig; ChannelStatus = BT_CONNECTION_SUCCESSFUL; } else { ChannelStatus = BT_CONNECTION_REFUSED_PSM; } } struct { BT_Signal_Header_t SignalCommandHeader; BT_Signal_ConnectionResp_t ConnectionResponse; } ResponsePacket; /* Fill out the Signal Command header in the response packet */ ResponsePacket.SignalCommandHeader.Code = BT_SIGNAL_CONNECTION_RESPONSE; ResponsePacket.SignalCommandHeader.Identifier = SignalCommandHeader->Identifier; ResponsePacket.SignalCommandHeader.Length = sizeof(ResponsePacket.ConnectionResponse); /* Fill out the Connection Response in the response packet */ ResponsePacket.ConnectionResponse.DestinationChannel = ChannelData->LocalNumber; ResponsePacket.ConnectionResponse.SourceChannel = ChannelData->RemoteNumber; ResponsePacket.ConnectionResponse.Result = ChannelStatus; ResponsePacket.ConnectionResponse.Status = 0x00; Bluetooth_SendPacket(&ResponsePacket, sizeof(ResponsePacket), NULL); BT_ACL_DEBUG(1, ">> L2CAP Connection Response"); BT_ACL_DEBUG(2, "-- Result: 0x%02X", ResponsePacket.ConnectionResponse.Result); BT_ACL_DEBUG(2, "-- Destination Channel: 0x%04X", ResponsePacket.ConnectionResponse.DestinationChannel); BT_ACL_DEBUG(2, "-- Source Channel: 0x%04X", ResponsePacket.ConnectionResponse.SourceChannel); }
/** Internal Bluetooth stack Signal Command processing routine for a Configuration Request command. * * \param[in] SignalCommandHeader Pointer to the start of the received packet's Signal Command header */ static inline void Bluetooth_Signal_ConfigurationReq(const BT_Signal_Header_t* const SignalCommandHeader) { BT_Signal_ConfigurationReq_t ConfigurationRequest; /* Allocate a buffer large enough to hold the variable number of configuration options in the request */ uint8_t OptionsLen = (SignalCommandHeader->Length - sizeof(ConfigurationRequest)); uint8_t Options[OptionsLen]; Pipe_Read_Stream_LE(&ConfigurationRequest, sizeof(ConfigurationRequest), NULL); Pipe_Read_Stream_LE(&Options, sizeof(Options), NULL); Pipe_ClearIN(); Pipe_Freeze(); /* Search for the referenced channel in the channel information list */ Bluetooth_Channel_t* ChannelData = Bluetooth_GetChannelData(ConfigurationRequest.DestinationChannel, CHANNEL_SEARCH_LOCALNUMBER); BT_ACL_DEBUG(1, "<< L2CAP Configuration Request"); BT_ACL_DEBUG(2, "-- Destination Channel: 0x%04X", ConfigurationRequest.DestinationChannel); BT_ACL_DEBUG(2, "-- Options Len: 0x%04X", OptionsLen); /* Only look at the channel configuration options if a valid channel entry for the local channel number was found */ if (ChannelData != NULL) { /* Iterate through each option in the configuration request to look for ones which can be processed */ uint8_t OptionPos = 0; while (OptionPos < OptionsLen) { BT_Config_Option_Header_t* OptionHeader = (BT_Config_Option_Header_t*)&Options[OptionPos]; void* OptionData = &Options[OptionPos + sizeof(BT_Config_Option_Header_t)]; BT_ACL_DEBUG(2, "-- Option Type: 0x%04X", OptionHeader->Type); BT_ACL_DEBUG(2, "-- Option Length: 0x%04X", (sizeof(BT_Config_Option_Header_t) + OptionHeader->Length)); /* Store the remote MTU option's value if present */ if (OptionHeader->Type == BT_CONFIG_OPTION_MTU) ChannelData->RemoteMTU = *((uint16_t*)OptionData); /* Progress to the next option in the packet */ OptionPos += (sizeof(BT_Config_Option_Header_t) + OptionHeader->Length); } } struct { BT_Signal_Header_t SignalCommandHeader; BT_Signal_ConfigurationResp_t ConfigurationResponse; } ResponsePacket; /* Fill out the Signal Command header in the response packet */ ResponsePacket.SignalCommandHeader.Code = BT_SIGNAL_CONFIGURATION_RESPONSE; ResponsePacket.SignalCommandHeader.Identifier = SignalCommandHeader->Identifier; ResponsePacket.SignalCommandHeader.Length = sizeof(ResponsePacket.ConfigurationResponse); /* Fill out the Configuration Response in the response packet */ ResponsePacket.ConfigurationResponse.SourceChannel = ChannelData->RemoteNumber; ResponsePacket.ConfigurationResponse.Flags = 0x00; ResponsePacket.ConfigurationResponse.Result = (ChannelData != NULL) ? BT_CONFIGURATION_SUCCESSFUL : BT_CONFIGURATION_REJECTED; Bluetooth_SendPacket(&ResponsePacket, sizeof(ResponsePacket), NULL); if (ChannelData != NULL) { switch (ChannelData->State) { case BT_Channel_Config_WaitConfig: ChannelData->State = BT_Channel_Config_WaitSendConfig; break; case BT_Channel_Config_WaitReqResp: ChannelData->State = BT_Channel_Config_WaitResp; break; case BT_Channel_Config_WaitReq: ChannelData->State = BT_Channel_Open; Bluetooth_ChannelOpened(ChannelData); break; } } BT_ACL_DEBUG(1, ">> L2CAP Configuration Response"); BT_ACL_DEBUG(2, "-- Source Channel: 0x%04X", ResponsePacket.ConfigurationResponse.SourceChannel); BT_ACL_DEBUG(2, "-- Result: 0x%02X", ResponsePacket.ConfigurationResponse.Result); }
uint8_t USB_Host_SendControlRequest(void* const BufferPtr) { uint8_t* DataStream = (uint8_t*)BufferPtr; bool BusSuspended = USB_Host_IsBusSuspended(); uint8_t ReturnStatus = HOST_SENDCONTROL_Successful; uint16_t DataLen = USB_ControlRequest.wLength; USB_Host_ResumeBus(); if ((ReturnStatus = USB_Host_WaitMS(1)) != HOST_WAITERROR_Successful) goto End_Of_Control_Send; Pipe_SetPipeToken(PIPE_TOKEN_SETUP); Pipe_ClearError(); Pipe_Unfreeze(); Pipe_Write_8(USB_ControlRequest.bmRequestType); Pipe_Write_8(USB_ControlRequest.bRequest); Pipe_Write_16_LE(USB_ControlRequest.wValue); Pipe_Write_16_LE(USB_ControlRequest.wIndex); Pipe_Write_16_LE(USB_ControlRequest.wLength); Pipe_ClearSETUP(); if ((ReturnStatus = USB_Host_WaitForIOS(USB_HOST_WAITFOR_SetupSent)) != HOST_SENDCONTROL_Successful) goto End_Of_Control_Send; Pipe_Freeze(); if ((ReturnStatus = USB_Host_WaitMS(1)) != HOST_WAITERROR_Successful) goto End_Of_Control_Send; if ((USB_ControlRequest.bmRequestType & CONTROL_REQTYPE_DIRECTION) == REQDIR_DEVICETOHOST) { Pipe_SetPipeToken(PIPE_TOKEN_IN); if (DataStream != NULL) { while (DataLen) { Pipe_Unfreeze(); if ((ReturnStatus = USB_Host_WaitForIOS(USB_HOST_WAITFOR_InReceived)) != HOST_SENDCONTROL_Successful) goto End_Of_Control_Send; if (!(Pipe_BytesInPipe())) DataLen = 0; while (Pipe_BytesInPipe() && DataLen) { *(DataStream++) = Pipe_Read_8(); DataLen--; } Pipe_Freeze(); Pipe_ClearIN(); } } Pipe_SetPipeToken(PIPE_TOKEN_OUT); Pipe_Unfreeze(); if ((ReturnStatus = USB_Host_WaitForIOS(USB_HOST_WAITFOR_OutReady)) != HOST_SENDCONTROL_Successful) goto End_Of_Control_Send; Pipe_ClearOUT(); if ((ReturnStatus = USB_Host_WaitForIOS(USB_HOST_WAITFOR_OutReady)) != HOST_SENDCONTROL_Successful) goto End_Of_Control_Send; } else { if (DataStream != NULL) { Pipe_SetPipeToken(PIPE_TOKEN_OUT); Pipe_Unfreeze(); while (DataLen) { if ((ReturnStatus = USB_Host_WaitForIOS(USB_HOST_WAITFOR_OutReady)) != HOST_SENDCONTROL_Successful) goto End_Of_Control_Send; while (DataLen && (Pipe_BytesInPipe() < USB_ControlPipeSize)) { Pipe_Write_8(*(DataStream++)); DataLen--; } Pipe_ClearOUT(); } if ((ReturnStatus = USB_Host_WaitForIOS(USB_HOST_WAITFOR_OutReady)) != HOST_SENDCONTROL_Successful) goto End_Of_Control_Send; Pipe_Freeze(); } Pipe_SetPipeToken(PIPE_TOKEN_IN); Pipe_Unfreeze(); if ((ReturnStatus = USB_Host_WaitForIOS(USB_HOST_WAITFOR_InReceived)) != HOST_SENDCONTROL_Successful) goto End_Of_Control_Send; Pipe_ClearIN(); } End_Of_Control_Send: Pipe_Freeze(); if (BusSuspended) USB_Host_SuspendBus(); Pipe_ResetPipe(PIPE_CONTROLPIPE); return ReturnStatus; }
/** 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), NULL); Pipe_Read_Stream_LE(&DataHeader, sizeof(DataHeader), NULL); 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), NULL); /* 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), NULL); Pipe_Discard_Stream(ACLPacketHeader.DataLength - sizeof(RejectReason), NULL); 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, NULL); 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, NULL); Pipe_ClearIN(); Pipe_Freeze(); Bluetooth_PacketReceived(PacketData, DataHeader.PayloadLength, Bluetooth_GetChannelData(DataHeader.DestinationChannel, CHANNEL_SEARCH_LOCALNUMBER)); } }
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; }
/** 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; uint16_t PreviousFrameNumber = USB_Host_GetFrameNumber(); /* Unfreeze the data IN pipe */ Pipe_SelectPipe(SIMAGE_DATA_IN_PIPE); Pipe_Unfreeze(); /* Wait until data received on the IN pipe */ while (!(Pipe_IsINReceived())) { uint16_t CurrentFrameNumber = USB_Host_GetFrameNumber(); /* Check to see if a new frame has been issued (1ms elapsed) */ if (CurrentFrameNumber != PreviousFrameNumber) { /* Save the new frame number and decrement the timeout period */ PreviousFrameNumber = CurrentFrameNumber; TimeoutMSRem--; /* Check to see if the timeout period for the command has elapsed */ if (!(TimeoutMSRem)) 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_ClearEndpointStall(Pipe_GetBoundEndpointAddress()); /* 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_ClearEndpointStall(Pipe_GetBoundEndpointAddress()); /* 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), NULL); /* Check if the returned block type is a response block */ if (PIMA_ReceivedBlock.Type == PIMA_CONTAINER_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, NULL); } /* Clear pipe bank after use */ Pipe_ClearIN(); } /* Freeze the IN pipe after use */ Pipe_Freeze(); return PIPE_RWSTREAM_NoError; }
/** 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; } }
/** Task to print device information through the serial port, and open/close a test PIMA session with the * attached Still Image device. */ void StillImageHost_Task(void) { if (USB_HostState != HOST_STATE_Configured) return; uint8_t ErrorCode; /* Indicate device busy via the status LEDs */ LEDs_SetAllLEDs(LEDMASK_USB_BUSY); puts_P(PSTR("Retrieving Device Info...\r\n")); PIMA_SendBlock = (PIMA_Container_t) { .DataLength = PIMA_COMMAND_SIZE(0), .Type = PIMA_CONTAINER_CommandBlock, .Code = PIMA_OPERATION_GETDEVICEINFO, .TransactionID = 0x00000000, .Params = {}, }; /* Send the GETDEVICEINFO block */ SImage_SendBlockHeader(); /* Receive the response data block */ if ((ErrorCode = SImage_ReceiveBlockHeader()) != PIPE_RWSTREAM_NoError) { ShowCommandError(ErrorCode, false); USB_Host_SetDeviceConfiguration(0); return; } /* Calculate the size of the returned device info data structure */ uint16_t DeviceInfoSize = (PIMA_ReceivedBlock.DataLength - PIMA_COMMAND_SIZE(0)); /* Create a buffer large enough to hold the entire device info */ uint8_t DeviceInfo[DeviceInfoSize]; /* Read in the data block data (containing device info) */ SImage_ReadData(DeviceInfo, DeviceInfoSize); /* Once all the data has been read, the pipe must be cleared before the response can be sent */ Pipe_ClearIN(); /* Create a pointer for walking through the info dataset */ uint8_t* DeviceInfoPos = DeviceInfo; /* Skip over the data before the unicode device information strings */ DeviceInfoPos += 8; // Skip to VendorExtensionDesc String DeviceInfoPos += (1 + UNICODE_STRING_LENGTH(*DeviceInfoPos)); // Skip over VendorExtensionDesc String DeviceInfoPos += 2; // Skip over FunctionalMode DeviceInfoPos += (4 + (*(uint32_t*)DeviceInfoPos << 1)); // Skip over Supported Operations Array DeviceInfoPos += (4 + (*(uint32_t*)DeviceInfoPos << 1)); // Skip over Supported Events Array DeviceInfoPos += (4 + (*(uint32_t*)DeviceInfoPos << 1)); // Skip over Supported Device Properties Array DeviceInfoPos += (4 + (*(uint32_t*)DeviceInfoPos << 1)); // Skip over Capture Formats Array DeviceInfoPos += (4 + (*(uint32_t*)DeviceInfoPos << 1)); // Skip over Image Formats Array /* Extract and convert the Manufacturer Unicode string to ASCII and print it through the USART */ char Manufacturer[*DeviceInfoPos]; UnicodeToASCII(DeviceInfoPos, Manufacturer); printf_P(PSTR(" Manufacturer: %s\r\n"), Manufacturer); DeviceInfoPos += 1 + UNICODE_STRING_LENGTH(*DeviceInfoPos); // Skip over Manufacturer String /* Extract and convert the Model Unicode string to ASCII and print it through the USART */ char Model[*DeviceInfoPos]; UnicodeToASCII(DeviceInfoPos, Model); printf_P(PSTR(" Model: %s\r\n"), Model); DeviceInfoPos += 1 + UNICODE_STRING_LENGTH(*DeviceInfoPos); // Skip over Model String /* Extract and convert the Device Version Unicode string to ASCII and print it through the USART */ char DeviceVersion[*DeviceInfoPos]; UnicodeToASCII(DeviceInfoPos, DeviceVersion); printf_P(PSTR(" Device Version: %s\r\n"), DeviceVersion); /* Receive the final response block from the device */ if ((ErrorCode = SImage_ReceiveBlockHeader()) != PIPE_RWSTREAM_NoError) { ShowCommandError(ErrorCode, false); USB_Host_SetDeviceConfiguration(0); return; } /* Verify that the command completed successfully */ if ((PIMA_ReceivedBlock.Type != PIMA_CONTAINER_ResponseBlock) || (PIMA_ReceivedBlock.Code != PIMA_RESPONSE_OK)) { ShowCommandError(PIMA_ReceivedBlock.Code, true); USB_Host_SetDeviceConfiguration(0); return; } puts_P(PSTR("Opening Session...\r\n")); PIMA_SendBlock = (PIMA_Container_t) { .DataLength = PIMA_COMMAND_SIZE(1), .Type = PIMA_CONTAINER_CommandBlock, .Code = PIMA_OPERATION_OPENSESSION, .TransactionID = 0x00000000, .Params = {0x00000001}, }; /* Send the OPENSESSION block, open a session with an ID of 0x0001 */ SImage_SendBlockHeader(); /* Receive the response block from the device */ if ((ErrorCode = SImage_ReceiveBlockHeader()) != PIPE_RWSTREAM_NoError) { ShowCommandError(ErrorCode, false); USB_Host_SetDeviceConfiguration(0); return; } /* Verify that the command completed successfully */ if ((PIMA_ReceivedBlock.Type != PIMA_CONTAINER_ResponseBlock) || (PIMA_ReceivedBlock.Code != PIMA_RESPONSE_OK)) { ShowCommandError(PIMA_ReceivedBlock.Code, true); USB_Host_SetDeviceConfiguration(0); return; } puts_P(PSTR("Closing Session...\r\n")); PIMA_SendBlock = (PIMA_Container_t) { .DataLength = PIMA_COMMAND_SIZE(1), .Type = PIMA_CONTAINER_CommandBlock, .Code = PIMA_OPERATION_CLOSESESSION, .TransactionID = 0x00000001, .Params = {0x00000001}, }; /* Send the CLOSESESSION block, close the session with an ID of 0x0001 */ SImage_SendBlockHeader(); /* Receive the response block from the device */ if ((ErrorCode = SImage_ReceiveBlockHeader()) != PIPE_RWSTREAM_NoError) { ShowCommandError(ErrorCode, false); USB_Host_SetDeviceConfiguration(0); return; } /* Verify that the command completed successfully */ if ((PIMA_ReceivedBlock.Type != PIMA_CONTAINER_ResponseBlock) || (PIMA_ReceivedBlock.Code != PIMA_RESPONSE_OK)) { ShowCommandError(PIMA_ReceivedBlock.Code, true); USB_Host_SetDeviceConfiguration(0); return; } puts_P(PSTR("Done.\r\n")); /* Indicate device no longer busy */ LEDs_SetAllLEDs(LEDMASK_USB_READY); USB_Host_SetDeviceConfiguration(0); } /** Function to convert a given Unicode encoded string to ASCII. This function will only work correctly on Unicode * strings which contain ASCII printable characters only. * * \param[in] UnicodeString Pointer to a Unicode encoded input string * \param[out] Buffer Pointer to a buffer where the converted ASCII string should be stored */ void UnicodeToASCII(uint8_t* UnicodeString, char* Buffer) { /* Get the number of characters in the string, skip to the start of the string data */ uint8_t CharactersRemaining = *(UnicodeString++); /* Loop through the entire unicode string */ while (CharactersRemaining--) { /* Load in the next unicode character (only the lower byte, as only Unicode coded ASCII is supported) */ *(Buffer++) = *UnicodeString; /* Jump to the next unicode character */ UnicodeString += 2; } /* Null terminate the string */ *Buffer = 0; } /** Displays a PIMA command error via the device's serial port. * * \param[in] ErrorCode Error code of the function which failed to complete successfully * \param[in] ResponseCodeError Indicates if the error is due to a command failed indication from the device, or a communication failure */ void ShowCommandError(uint8_t ErrorCode, bool ResponseCodeError) { const char* FailureType = ((ResponseCodeError) ? PSTR("Response Code != OK") : PSTR("Transaction Fail")); printf_P(PSTR(ESC_FG_RED "Command Error (%S).\r\n" " -- Error Code %d\r\n" ESC_FG_WHITE), FailureType, ErrorCode); /* Indicate error via status LEDs */ LEDs_SetAllLEDs(LEDMASK_USB_ERROR); }
uint8_t SI_Host_ReceiveBlockHeader(USB_ClassInfo_SI_Host_t* const SIInterfaceInfo, PIMA_Container_t* const PIMAHeader) { uint16_t TimeoutMSRem = SI_COMMAND_DATA_TIMEOUT_MS; uint16_t PreviousFrameNumber = USB_Host_GetFrameNumber(); if ((USB_HostState != HOST_STATE_Configured) || !(SIInterfaceInfo->State.IsActive)) return PIPE_RWSTREAM_DeviceDisconnected; Pipe_SelectPipe(SIInterfaceInfo->Config.DataINPipe.Address); Pipe_Unfreeze(); while (!(Pipe_IsINReceived())) { uint16_t CurrentFrameNumber = USB_Host_GetFrameNumber(); if (CurrentFrameNumber != PreviousFrameNumber) { PreviousFrameNumber = CurrentFrameNumber; if (!(TimeoutMSRem--)) return PIPE_RWSTREAM_Timeout; } Pipe_Freeze(); Pipe_SelectPipe(SIInterfaceInfo->Config.DataOUTPipe.Address); Pipe_Unfreeze(); if (Pipe_IsStalled()) { USB_Host_ClearEndpointStall(Pipe_GetBoundEndpointAddress()); return PIPE_RWSTREAM_PipeStalled; } Pipe_Freeze(); Pipe_SelectPipe(SIInterfaceInfo->Config.DataINPipe.Address); Pipe_Unfreeze(); if (Pipe_IsStalled()) { USB_Host_ClearEndpointStall(Pipe_GetBoundEndpointAddress()); return PIPE_RWSTREAM_PipeStalled; } if (USB_HostState == HOST_STATE_Unattached) return PIPE_RWSTREAM_DeviceDisconnected; } Pipe_Read_Stream_LE(PIMAHeader, PIMA_COMMAND_SIZE(0), NULL); if (PIMAHeader->Type == CPU_TO_LE16(PIMA_CONTAINER_ResponseBlock)) { uint8_t ParamBytes = (PIMAHeader->DataLength - PIMA_COMMAND_SIZE(0)); if (ParamBytes) Pipe_Read_Stream_LE(&PIMAHeader->Params, ParamBytes, NULL); Pipe_ClearIN(); } Pipe_Freeze(); return PIPE_RWSTREAM_NoError; }
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; }
/** 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; } }
static uint8_t USB_Host_SendControlRequest_PRV(void* const BufferPtr) { uint8_t* DataStream = (uint8_t*)BufferPtr; uint8_t ReturnStatus = HOST_SENDCONTROL_Successful; uint16_t DataLen = USB_ControlRequest.wLength; USB_Host_ResumeBus(); if ((ReturnStatus = USB_Host_WaitMS(1)) != HOST_WAITERROR_Successful) return ReturnStatus; Pipe_SetPipeToken(PIPE_TOKEN_SETUP); Pipe_ClearError(); Pipe_Unfreeze(); #if defined(ARCH_BIG_ENDIAN) Pipe_Write_8(USB_ControlRequest.bmRequestType); Pipe_Write_8(USB_ControlRequest.bRequest); Pipe_Write_16_LE(USB_ControlRequest.wValue); Pipe_Write_16_LE(USB_ControlRequest.wIndex); Pipe_Write_16_LE(USB_ControlRequest.wLength); #else uint8_t* HeaderStream = (uint8_t*)&USB_ControlRequest; for (uint8_t HeaderByte = 0; HeaderByte < sizeof(USB_Request_Header_t); HeaderByte++) Pipe_Write_8(*(HeaderStream++)); #endif Pipe_ClearSETUP(); if ((ReturnStatus = USB_Host_WaitForIOS(USB_HOST_WAITFOR_SetupSent)) != HOST_SENDCONTROL_Successful) return ReturnStatus; Pipe_Freeze(); if ((ReturnStatus = USB_Host_WaitMS(1)) != HOST_WAITERROR_Successful) return ReturnStatus; if ((USB_ControlRequest.bmRequestType & CONTROL_REQTYPE_DIRECTION) == REQDIR_DEVICETOHOST) { Pipe_SetPipeToken(PIPE_TOKEN_IN); if (DataStream != NULL) { while (DataLen) { Pipe_Unfreeze(); if ((ReturnStatus = USB_Host_WaitForIOS(USB_HOST_WAITFOR_InReceived)) != HOST_SENDCONTROL_Successful) return ReturnStatus; if (!(Pipe_BytesInPipe())) DataLen = 0; while (Pipe_BytesInPipe() && DataLen) { *(DataStream++) = Pipe_Read_8(); DataLen--; } Pipe_Freeze(); Pipe_ClearIN(); } } Pipe_SetPipeToken(PIPE_TOKEN_OUT); Pipe_Unfreeze(); if ((ReturnStatus = USB_Host_WaitForIOS(USB_HOST_WAITFOR_OutReady)) != HOST_SENDCONTROL_Successful) return ReturnStatus; Pipe_ClearOUT(); if ((ReturnStatus = USB_Host_WaitForIOS(USB_HOST_WAITFOR_OutReady)) != HOST_SENDCONTROL_Successful) return ReturnStatus; } else { if (DataStream != NULL) { Pipe_SetPipeToken(PIPE_TOKEN_OUT); Pipe_Unfreeze(); while (DataLen) { if ((ReturnStatus = USB_Host_WaitForIOS(USB_HOST_WAITFOR_OutReady)) != HOST_SENDCONTROL_Successful) return ReturnStatus; while (DataLen && (Pipe_BytesInPipe() < USB_Host_ControlPipeSize)) { Pipe_Write_8(*(DataStream++)); DataLen--; } Pipe_ClearOUT(); } if ((ReturnStatus = USB_Host_WaitForIOS(USB_HOST_WAITFOR_OutReady)) != HOST_SENDCONTROL_Successful) return ReturnStatus; Pipe_Freeze(); } Pipe_SetPipeToken(PIPE_TOKEN_IN); Pipe_Unfreeze(); if ((ReturnStatus = USB_Host_WaitForIOS(USB_HOST_WAITFOR_InReceived)) != HOST_SENDCONTROL_Successful) return ReturnStatus; Pipe_ClearIN(); } return ReturnStatus; }
/** 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 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 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) { puts_P(PSTR(ESC_FG_RED "Control Error (Set Configuration).\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; } 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 Keyboard." 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("Keyboard Enumerated.\r\n")); USB_HostState = HOST_STATE_Configured; break; case HOST_STATE_Configured: /* Select and unfreeze keyboard data pipe */ Pipe_SelectPipe(KEYBOARD_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 keyboard */ if (Pipe_IsReadWriteAllowed()) { /* Create buffer big enough for the report */ uint8_t KeyboardReport[Pipe_BytesInPipe()]; /* Load in the keyboard report */ Pipe_Read_Stream_LE(KeyboardReport, Pipe_BytesInPipe(), NULL); /* Process the read in keyboard report from the device */ ProcessKeyboardReport(KeyboardReport); } /* Clear the IN endpoint, ready for next data packet */ Pipe_ClearIN(); } /* Freeze keyboard data pipe */ Pipe_Freeze(); break; } }
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); }
/** 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); }
/** 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 MouseHost_Task(void) { if (USB_HostState != HOST_STATE_Configured) return; USB_MouseReport_Data_t MouseReport; uint8_t LEDMask = LEDS_NO_LEDS; /* Select mouse data pipe */ Pipe_SelectPipe(MOUSE_DATA_IN_PIPE); /* Unfreeze mouse 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), NULL); /* 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(); }
/** Task to read in note on/off messages from the attached MIDI device and print it to the serial port. * When the board joystick or buttons are pressed, note on/off messages are sent to the attached device. */ void MIDIHost_Task(void) { if (USB_HostState != HOST_STATE_Configured) return; Pipe_SelectPipe(MIDI_DATA_IN_PIPE); Pipe_Unfreeze(); if (Pipe_IsINReceived()) { MIDI_EventPacket_t MIDIEvent; Pipe_Read_Stream_LE(&MIDIEvent, sizeof(MIDIEvent), NULL); if (!(Pipe_BytesInPipe())) Pipe_ClearIN(); bool NoteOnEvent = (MIDIEvent.Event == MIDI_EVENT(0, MIDI_COMMAND_NOTE_ON)); bool NoteOffEvent = (MIDIEvent.Event == MIDI_EVENT(0, MIDI_COMMAND_NOTE_OFF)); if (NoteOnEvent || NoteOffEvent) { printf_P(PSTR("MIDI Note %s - Channel %d, Pitch %d, Velocity %d\r\n"), NoteOnEvent ? "On" : "Off", ((MIDIEvent.Data1 & 0x0F) + 1), MIDIEvent.Data2, MIDIEvent.Data3); } } Pipe_Freeze(); Pipe_SelectPipe(MIDI_DATA_OUT_PIPE); Pipe_Unfreeze(); if (Pipe_IsOUTReady()) { uint8_t MIDICommand = 0; uint8_t MIDIPitch; static uint8_t PrevJoystickStatus; uint8_t JoystickStatus = Joystick_GetStatus(); uint8_t JoystickChanges = (JoystickStatus ^ PrevJoystickStatus); /* Get board button status - if pressed use channel 10 (percussion), otherwise use channel 1 */ uint8_t Channel = ((Buttons_GetStatus() & BUTTONS_BUTTON1) ? MIDI_CHANNEL(10) : MIDI_CHANNEL(1)); if (JoystickChanges & JOY_LEFT) { MIDICommand = ((JoystickStatus & JOY_LEFT)? MIDI_COMMAND_NOTE_ON : MIDI_COMMAND_NOTE_OFF); MIDIPitch = 0x3C; } if (JoystickChanges & JOY_UP) { MIDICommand = ((JoystickStatus & JOY_UP)? MIDI_COMMAND_NOTE_ON : MIDI_COMMAND_NOTE_OFF); MIDIPitch = 0x3D; } if (JoystickChanges & JOY_RIGHT) { MIDICommand = ((JoystickStatus & JOY_RIGHT)? MIDI_COMMAND_NOTE_ON : MIDI_COMMAND_NOTE_OFF); MIDIPitch = 0x3E; } if (JoystickChanges & JOY_DOWN) { MIDICommand = ((JoystickStatus & JOY_DOWN)? MIDI_COMMAND_NOTE_ON : MIDI_COMMAND_NOTE_OFF); MIDIPitch = 0x3F; } if (JoystickChanges & JOY_PRESS) { MIDICommand = ((JoystickStatus & JOY_PRESS)? MIDI_COMMAND_NOTE_ON : MIDI_COMMAND_NOTE_OFF); MIDIPitch = 0x3B; } /* Check if a MIDI command is to be sent */ if (MIDICommand) { MIDI_EventPacket_t MIDIEvent = (MIDI_EventPacket_t) { .Event = MIDI_EVENT(0, MIDICommand), .Data1 = MIDICommand | Channel, .Data2 = MIDIPitch, .Data3 = MIDI_STANDARD_VELOCITY, }; /* Write the MIDI event packet to the pipe */ Pipe_Write_Stream_LE(&MIDIEvent, sizeof(MIDIEvent), NULL); /* Send the data in the pipe to the device */ Pipe_ClearOUT(); } Pipe_Freeze(); /* Save previous joystick value for next joystick change detection */ PrevJoystickStatus = JoystickStatus; } }