Ejemplo n.º 1
0
bool SideShow_AddSimpleContent(SideShow_PacketHeader_t* const PacketHeader,
                               SideShow_Application_t* const Application)
{
    uint32_t ContentSize;
    uint32_t ContentID;

    Endpoint_Read_Stream_LE(&ContentID, sizeof(uint32_t));

    PacketHeader->Length -= sizeof(uint32_t);

    if (Application->CurrentContentID != ContentID)
    {
        Endpoint_Discard_Stream(PacketHeader->Length);

        return false;
    }

    Endpoint_Read_Stream_LE(&ContentSize, sizeof(uint32_t));
    Endpoint_Read_Stream_LE(&Application->CurrentContent, sizeof(XML_START_TAG) - 1);

    PacketHeader->Length -= sizeof(uint32_t) + (sizeof(XML_START_TAG) - 1);

    if (!(memcmp(&Application->CurrentContent, XML_START_TAG, (sizeof(XML_START_TAG) - 1))))
    {
        SideShow_ProcessXMLContent(&Application->CurrentContent, (ContentSize - (sizeof(XML_END_TAG) - 1)));

        Endpoint_Discard_Stream(sizeof(XML_END_TAG) - 1);

        Application->HaveContent = true;
    }
    else
    {
        printf(" BINARY");
        Endpoint_Discard_Stream(ContentSize);
    }

    return true;
}
Ejemplo n.º 2
0
/* This function receives number of bytes from the USB host.*/
status_t USBVC001_ReceiveData(int8_t* DataBuffer, int16_t DataByte)
{
  status_t Status = (uint32_t)DAVEApp_SUCCESS;
  uint16_t BytesProcessed = 0;
  uint8_t ret = 0;

  /* Fix for new read/write */
  Endpoint_SelectEndpoint(CDC_RX_EPNUM, ENDPOINT_DIR_OUT);
  while ((ret=Endpoint_Read_Stream_LE(DataBuffer, DataByte, &BytesProcessed))==ENDPOINT_RWSTREAM_IncompleteTransfer);
  if (ret!=ENDPOINT_RWSTREAM_NoError)
	return -1;

  return Status;
}
Ejemplo n.º 3
0
/*
 * Read a block from the host's OUT endpoint, handling aborts.
 */
bool
USB_ReadBlock(uint8_t *buf, uint8_t len)
{
    // Get the requested data from the host
    Endpoint_SelectEndpoint(XUM_BULK_OUT_ENDPOINT);
    Endpoint_Read_Stream_LE(buf, len, AbortOnReset);

    // Check if the current command is being aborted by the host
    if (doDeviceReset)
        return false;

    Endpoint_ClearOUT();
    return true;
}
Ejemplo n.º 4
0
static bool MS_Device_ReadInCommandBlock(USB_ClassInfo_MS_Device_t* const MSInterfaceInfo)
{
	Endpoint_SelectEndpoint(MSInterfaceInfo->Config.DataOUTEndpointNumber);

	CallbackIsResetSource = &MSInterfaceInfo->State.IsMassStoreReset;
	if (Endpoint_Read_Stream_LE(&MSInterfaceInfo->State.CommandBlock,
	                            (sizeof(MS_CommandBlockWrapper_t) - 16),
	                            StreamCallback_MS_Device_AbortOnMassStoreReset))
	{
		return false;
	}
	
	if ((MSInterfaceInfo->State.CommandBlock.Signature         != MS_CBW_SIGNATURE)                  ||
	    (MSInterfaceInfo->State.CommandBlock.LUN               >= MSInterfaceInfo->Config.TotalLUNs) ||
		(MSInterfaceInfo->State.CommandBlock.Flags              & 0x1F)                              ||
		(MSInterfaceInfo->State.CommandBlock.SCSICommandLength == 0)                                 ||
		(MSInterfaceInfo->State.CommandBlock.SCSICommandLength >  16))
	{
		Endpoint_StallTransaction();
		Endpoint_SelectEndpoint(MSInterfaceInfo->Config.DataINEndpointNumber);
		Endpoint_StallTransaction();
		
		return false;
	}

	CallbackIsResetSource = &MSInterfaceInfo->State.IsMassStoreReset;
	if (Endpoint_Read_Stream_LE(&MSInterfaceInfo->State.CommandBlock.SCSICommandData,
	                            MSInterfaceInfo->State.CommandBlock.SCSICommandLength,
	                            StreamCallback_MS_Device_AbortOnMassStoreReset))
	{
		return false;
	}

	Endpoint_ClearOUT();
	
	return true;
}
Ejemplo n.º 5
0
void usb::poll() {
	USB_USBTask();

	Endpoint_SelectEndpoint(VENDOR_OUT_EPADDR);
	if (Endpoint_IsOUTReceived()) {
		led::setState(led::YELLOW, true);

		timerReset();

		usb::InputBuff.length = USB_SETTINGS_HOST_TO_DEVICE_DATAPACKET_SIZE;

		Endpoint_Read_Stream_LE(usb::InputBuff.data, VENDOR_OUT_EPSIZE, NULL);
		Endpoint_Read_Stream_LE(usb::InputBuff.data + VENDOR_OUT_EPSIZE, VENDOR_OUT_EPSIZE, NULL);
		Endpoint_ClearOUT();

		usb::executeCommandsFromUSB();

		Endpoint_SelectEndpoint(VENDOR_IN_EPADDR);
		Endpoint_Write_Stream_LE(usb::OutputBuff.data, VENDOR_IN_EPSIZE, NULL);
		Endpoint_ClearIN();

		led::setState(led::YELLOW, false);
	}
}
Ejemplo n.º 6
0
void HID_Task(void)
{
	/* Device must be connected and configured for the task to run */
	if (USB_DeviceState != DEVICE_STATE_Configured)
	  return;

	Endpoint_SelectEndpoint(GENERIC_OUT_EPADDR);

	/* Check to see if a packet has been sent from the host */
	if (Endpoint_IsOUTReceived())
	{
		/* Check to see if the packet contains data */
		if (Endpoint_IsReadWriteAllowed())
		{
			/* Create a temporary buffer to hold the read in report from the host */
			uint8_t GenericData[GENERIC_REPORT_SIZE];

			/* Read Generic Report Data */
			Endpoint_Read_Stream_LE(&GenericData, sizeof(GenericData), NULL);

			/* Process Generic Report Data */
			ProcessGenericHIDReport(GenericData);
		}

		/* Finalize the stream transfer to send the last packet */
		Endpoint_ClearOUT();
	}

	Endpoint_SelectEndpoint(GENERIC_IN_EPADDR);

	/* Check to see if the host is ready to accept another packet */
	if (Endpoint_IsINReady())
	{
		/* Create a temporary buffer to hold the report to send to the host */
		uint8_t GenericData[GENERIC_REPORT_SIZE];

		/* Create Generic Report Data */
		CreateGenericHIDReport(GenericData);

		/* Write Generic Report Data */
		Endpoint_Write_Stream_LE(&GenericData, sizeof(GenericData), NULL);

		/* Finalize the stream transfer to send the last packet */
		Endpoint_ClearIN();
	}
}
Ejemplo n.º 7
0
bool MIDI_Device_ReceiveEventPacket(USB_ClassInfo_MIDI_Device_t* const MIDIInterfaceInfo,
                                    MIDI_EventPacket_t* const Event)
{
	if (USB_DeviceState != DEVICE_STATE_Configured)
	  return false;

	Endpoint_SelectEndpoint(MIDIInterfaceInfo->Config.DataOUTEndpoint.Address);

	if (!(Endpoint_IsReadWriteAllowed()))
	  return false;

	Endpoint_Read_Stream_LE(Event, sizeof(MIDI_EventPacket_t), NULL);

	if (!(Endpoint_IsReadWriteAllowed()))
	  Endpoint_ClearOUT();

	return true;
}
Ejemplo n.º 8
0
/** Attempts to read in the TMC message header from the TMC interface.
 *
 *  \param[out] MessageHeader  Pointer to a location where the read header (if any) should be stored
 *
 *  \return Boolean true if a header was read, false otherwise
 */
bool ReadTMCHeader(TMC_MessageHeader_t* const MessageHeader)
{
    /* Select the Data Out endpoint */
    Endpoint_SelectEndpoint(TMC_OUT_EPNUM);

    /* Abort if no command has been sent from the host */
    if (!(Endpoint_IsOUTReceived()))
        return false;

    /* Read in the header of the command from the host */
    Endpoint_Read_Stream_LE(MessageHeader, sizeof(TMC_MessageHeader_t), StreamCallback_AbortOUTOnRequest);

    /* Store the new command tag value for later use */
    CurrentTransferTag = MessageHeader->Tag;

    /* Indicate if the command has been aborted or not */
    return !(IsTMCBulkOUTReset);
}
Ejemplo n.º 9
0
/** Handler for the XPROG READ_MEMORY command to read data from a specific address space within the
 *  attached device.
 */
static void XPROGProtocol_ReadMemory(void)
{
	uint8_t ReturnStatus = XPROG_ERR_OK;

	struct
	{
		uint8_t  MemoryType;
		uint32_t Address;
		uint16_t Length;
	} ReadMemory_XPROG_Params;

	Endpoint_Read_Stream_LE(&ReadMemory_XPROG_Params, sizeof(ReadMemory_XPROG_Params), NULL);
	ReadMemory_XPROG_Params.Address = SwapEndian_32(ReadMemory_XPROG_Params.Address);
	ReadMemory_XPROG_Params.Length  = SwapEndian_16(ReadMemory_XPROG_Params.Length);

	Endpoint_ClearOUT();
	Endpoint_SelectEndpoint(AVRISP_DATA_IN_EPADDR);
	Endpoint_SetEndpointDirection(ENDPOINT_DIR_IN);

	uint8_t ReadBuffer[256];

	if (XPROG_SelectedProtocol == XPROG_PROTOCOL_PDI)
	{
		/* Read the PDI target's memory, indicate timeout if occurred */
		if (!(XMEGANVM_ReadMemory(ReadMemory_XPROG_Params.Address, ReadBuffer, ReadMemory_XPROG_Params.Length)))
		  ReturnStatus = XPROG_ERR_TIMEOUT;
	}
	else
	{
		/* Read the TPI target's memory, indicate timeout if occurred */
		if (!(TINYNVM_ReadMemory(ReadMemory_XPROG_Params.Address, ReadBuffer, ReadMemory_XPROG_Params.Length)))
		  ReturnStatus = XPROG_ERR_TIMEOUT;
	}

	Endpoint_Write_8(CMD_XPROG);
	Endpoint_Write_8(XPROG_CMD_READ_MEM);
	Endpoint_Write_8(ReturnStatus);

	if (ReturnStatus == XPROG_ERR_OK)
	  Endpoint_Write_Stream_LE(ReadBuffer, ReadMemory_XPROG_Params.Length, NULL);

	Endpoint_ClearIN();
}
Ejemplo n.º 10
0
/** Handler for the CMD_XPROG_SETMODE command, which sets the programmer-to-target protocol used for PDI/TPI
 *  programming.
 */
void XPROGProtocol_SetMode(void)
{
	struct
	{
		uint8_t Protocol;
	} SetMode_XPROG_Params;

	Endpoint_Read_Stream_LE(&SetMode_XPROG_Params, sizeof(SetMode_XPROG_Params), NULL);

	Endpoint_ClearOUT();
	Endpoint_SelectEndpoint(AVRISP_DATA_IN_EPADDR);
	Endpoint_SetEndpointDirection(ENDPOINT_DIR_IN);

	XPROG_SelectedProtocol = SetMode_XPROG_Params.Protocol;

	Endpoint_Write_8(CMD_XPROG_SETMODE);
	Endpoint_Write_8((SetMode_XPROG_Params.Protocol != XPROG_PROTOCOL_JTAG) ? STATUS_CMD_OK : STATUS_CMD_FAILED);
	Endpoint_ClearIN();
}
Ejemplo n.º 11
0
/** Reads data from the host */
void ReceiveDataFromHost(void)
{
	/* Select the OUT Endpoint */
	Endpoint_SelectEndpoint(OUT_EP);

	/* Check if the OUT EP contains a packet */
	if (Endpoint_IsOUTReceived())
	{
		/* Check to see if the packet contains data */
		if (Endpoint_IsReadWriteAllowed())
		{
			/* Read in data from the host */
			Endpoint_Read_Stream_LE(&dataReceived, sizeof(dataReceived));
		}

		/* Handshake the OUT Endpoint - clear endpoint and get ready for next transfer */
		Endpoint_ClearOUT();
	}
}
Ejemplo n.º 12
0
/** Function to manage CDC data transmission and reception to and from the host for the second CDC interface, which echoes back
 *  all data sent to it from the host.
 */
void CDC2_Task(void)
{
	/* Device must be connected and configured for the task to run */
	if (USB_DeviceState != DEVICE_STATE_Configured)
	  return;

	/* Select the Serial Rx Endpoint */
	Endpoint_SelectEndpoint(CDC2_RX_EPNUM);

	/* Check to see if any data has been received */
	if (Endpoint_IsOUTReceived())
	{
		/* Create a temp buffer big enough to hold the incoming endpoint packet */
		uint8_t  Buffer[Endpoint_BytesInEndpoint()];

		/* Remember how large the incoming packet is */
		uint16_t DataLength = Endpoint_BytesInEndpoint();

		/* Read in the incoming packet into the buffer */
		Endpoint_Read_Stream_LE(&Buffer, DataLength);

		/* Finalize the stream transfer to send the last packet */
		Endpoint_ClearOUT();

		/* Select the Serial Tx Endpoint */
		Endpoint_SelectEndpoint(CDC2_TX_EPNUM);

		/* Write the received data to the endpoint */
		Endpoint_Write_Stream_LE(&Buffer, DataLength);

		/* Finalize the stream transfer to send the last packet */
		Endpoint_ClearIN();

		/* Wait until the endpoint is ready for the next packet */
		Endpoint_WaitUntilReady();

		/* Send an empty packet to prevent host buffering */
		Endpoint_ClearIN();
	}
}
void Endpoint_Streaming(uint8_t corenum, uint8_t *buffer, uint16_t packetsize,
						uint16_t totalpackets, uint16_t dummypackets)
{
	uint8_t PhyEP = endpointhandle(corenum)[endpointselected[corenum]];
	uint16_t i;
	dummypackets = dummypackets;
	if (PhyEP & 1) {
		for (i = 0; i < totalpackets; i++) {
				while (!Endpoint_IsReadWriteAllowed(corenum)) ;
				Endpoint_Write_Stream_LE(corenum, (void *) (buffer + i * packetsize), packetsize, NULL);
				Endpoint_ClearIN(corenum);
			}
		}
	else {
		for (i = 0; i < totalpackets; i++) {
			DcdDataTransfer(PhyEP, usb_data_buffer_OUT[corenum], packetsize);
			Endpoint_ClearOUT(corenum);
			while (!Endpoint_IsReadWriteAllowed(corenum)) ;
			Endpoint_Read_Stream_LE(corenum, (void *) (buffer + i * packetsize), packetsize, NULL);
		}
	}
}
Ejemplo n.º 14
0
	void 				JIG_Task								(void)					{
	 static int bytes_out = 0, bytes_in = 0;
     Endpoint_SelectEndpoint(2);
     if (Endpoint_IsReadWriteAllowed()) {
		Endpoint_Read_Stream_LE  (&jig_challenge_res[bytes_out], 8, NO_STREAM_CALLBACK) ;		
        Endpoint_ClearOUT();
		bytes_out += 8;
		if (bytes_out >= 64) {			
			//prepare the response (by guess?)
			jig_challenge_res[1]--;
			jig_challenge_res[3]++;
			jig_challenge_res[6]++;
			HMACBlock(&jig_challenge_res[CHALLENGE_INDEX],20);
			
			USB_USBTask(); //just in case
			HMACDone();
			jig_challenge_res[7] = jig_id[0];
			jig_challenge_res[8] = jig_id[1];
			int i;
			for( i = 0; i < 20; i++)
				jig_challenge_res[9+i] = hmacdigest[i];
			state = p5_challenged;
			expire = 50; // was 90
		}
	 }
     Endpoint_SelectEndpoint(1);
     if (Endpoint_IsReadWriteAllowed() && state == p5_challenged && expire == 0) {
		if ( bytes_in < 64) {
			Endpoint_Write_PStream_LE(&jig_challenge_res[bytes_in], 8, NO_STREAM_CALLBACK);
			Endpoint_ClearIN();
			bytes_in += 8;
			if ( bytes_in >= 64) {
				state = p5_responded;
				expire = 50;
			}
		}
	 }
	}
/** Handler for the CMD_LEAVE_ISP command, which releases the target from programming mode. */
void ISPProtocol_LeaveISPMode(void)
{
	struct
	{
		uint8_t PreDelayMS;
		uint8_t PostDelayMS;
	} Leave_ISP_Params;

	Endpoint_Read_Stream_LE(&Leave_ISP_Params, sizeof(Leave_ISP_Params), NULL);

	Endpoint_ClearOUT();
	Endpoint_SelectEndpoint(AVRISP_DATA_IN_EPADDR);
	Endpoint_SetEndpointDirection(ENDPOINT_DIR_IN);

	/* Perform pre-exit delay, release the target /RESET, disable the SPI bus and perform the post-exit delay */
	ISPProtocol_DelayMS(Leave_ISP_Params.PreDelayMS);
	ISPTarget_ChangeTargetResetLine(false);
	ISPTarget_DisableTargetISP();
	ISPProtocol_DelayMS(Leave_ISP_Params.PostDelayMS);

	Endpoint_Write_8(CMD_LEAVE_PROGMODE_ISP);
	Endpoint_Write_8(STATUS_CMD_OK);
	Endpoint_ClearIN();
}
Ejemplo n.º 16
0
/** Handler for the CMD_PROGRAM_FLASH_ISP and CMD_PROGRAM_EEPROM_ISP commands, writing out bytes,
 *  words or pages of data to the attached device.
 *
 *  \param[in] V2Command  Issued V2 Protocol command byte from the host
 */
void ISPProtocol_ProgramMemory(uint8_t V2Command)
{
	struct
	{
		uint16_t BytesToWrite;
		uint8_t  ProgrammingMode;
		uint8_t  DelayMS;
		uint8_t  ProgrammingCommands[3];
		uint8_t  PollValue1;
		uint8_t  PollValue2;
		uint8_t  ProgData[256]; // Note, the Jungo driver has a very short ACK timeout period, need to buffer the
	} Write_Memory_Params;      // whole page and ACK the packet as fast as possible to prevent it from aborting
	
	Endpoint_Read_Stream_LE(&Write_Memory_Params, (sizeof(Write_Memory_Params) -
	                                               sizeof(Write_Memory_Params.ProgData)), NO_STREAM_CALLBACK);


	Write_Memory_Params.BytesToWrite = SwapEndian_16(Write_Memory_Params.BytesToWrite);
	
	if (Write_Memory_Params.BytesToWrite > sizeof(Write_Memory_Params.ProgData))
	{
		Endpoint_ClearOUT();
		Endpoint_SelectEndpoint(AVRISP_DATA_IN_EPNUM);
		Endpoint_SetEndpointDirection(ENDPOINT_DIR_IN);

		Endpoint_Write_Byte(V2Command);
		Endpoint_Write_Byte(STATUS_CMD_FAILED);
		Endpoint_ClearIN();
		return;
	}
	
	Endpoint_Read_Stream_LE(&Write_Memory_Params.ProgData, Write_Memory_Params.BytesToWrite, NO_STREAM_CALLBACK);

	Endpoint_ClearOUT();
	Endpoint_SelectEndpoint(AVRISP_DATA_IN_EPNUM);
	Endpoint_SetEndpointDirection(ENDPOINT_DIR_IN);

	uint8_t  ProgrammingStatus = STATUS_CMD_OK;	
	uint16_t PollAddress       = 0;
	uint8_t  PollValue         = (V2Command == CMD_PROGRAM_FLASH_ISP) ? Write_Memory_Params.PollValue1 :
	                                                                    Write_Memory_Params.PollValue2;
	uint8_t* NextWriteByte     = Write_Memory_Params.ProgData;

	/* Check the programming mode desired by the host, either Paged or Word memory writes */
	if (Write_Memory_Params.ProgrammingMode & PROG_MODE_PAGED_WRITES_MASK)
	{
		uint16_t StartAddress = (CurrentAddress & 0xFFFF);
	
		/* Check to see if we need to send a LOAD EXTENDED ADDRESS command to the target */
		if (MustLoadExtendedAddress)
		{
			ISPTarget_LoadExtendedAddress();
			MustLoadExtendedAddress = false;
		}

		/* Paged mode memory programming */
		for (uint16_t CurrentByte = 0; CurrentByte < Write_Memory_Params.BytesToWrite; CurrentByte++)
		{
			bool    IsOddByte   = (CurrentByte & 0x01);
			uint8_t ByteToWrite = *(NextWriteByte++);
		
			ISPTarget_SendByte(Write_Memory_Params.ProgrammingCommands[0]);
			ISPTarget_SendByte(CurrentAddress >> 8);
			ISPTarget_SendByte(CurrentAddress & 0xFF);
			ISPTarget_SendByte(ByteToWrite);
			
			/* AVR FLASH addressing requires us to modify the write command based on if we are writing a high
			 * or low byte at the current word address */
			if (V2Command == CMD_PROGRAM_FLASH_ISP)
			  Write_Memory_Params.ProgrammingCommands[0] ^= READ_WRITE_HIGH_BYTE_MASK;

			/* Check to see the write completion method, to see if we have a valid polling address */
			if (!(PollAddress) && (ByteToWrite != PollValue))
			{
				if (IsOddByte && (V2Command == CMD_PROGRAM_FLASH_ISP))
				  Write_Memory_Params.ProgrammingCommands[2] |= READ_WRITE_HIGH_BYTE_MASK;

				PollAddress = (CurrentAddress & 0xFFFF);				
			}		

			/* EEPROM increments the address on each byte, flash needs to increment on each word */
			if (IsOddByte || (V2Command == CMD_PROGRAM_EEPROM_ISP))
			  CurrentAddress++;
		}
		
		/* If the current page must be committed, send the PROGRAM PAGE command to the target */
		if (Write_Memory_Params.ProgrammingMode & PROG_MODE_COMMIT_PAGE_MASK)
		{
			ISPTarget_SendByte(Write_Memory_Params.ProgrammingCommands[1]);
			ISPTarget_SendByte(StartAddress >> 8);
			ISPTarget_SendByte(StartAddress & 0xFF);
			ISPTarget_SendByte(0x00);
			
			/* Check if polling is possible and enabled, if not switch to timed delay mode */
			if (!(PollAddress) && (Write_Memory_Params.ProgrammingMode & PROG_MODE_PAGED_VALUE_MASK))
			{
				Write_Memory_Params.ProgrammingMode &= ~PROG_MODE_PAGED_VALUE_MASK;
				Write_Memory_Params.ProgrammingMode |=  PROG_MODE_PAGED_TIMEDELAY_MASK;				
			}

			ProgrammingStatus = ISPTarget_WaitForProgComplete(Write_Memory_Params.ProgrammingMode, PollAddress, PollValue,
			                                                  Write_Memory_Params.DelayMS, Write_Memory_Params.ProgrammingCommands[2]);

			/* Check to see if the FLASH address has crossed the extended address boundary */
			if ((V2Command == CMD_PROGRAM_FLASH_ISP) && !(CurrentAddress & 0xFFFF))
			  MustLoadExtendedAddress = true;			
		}
Ejemplo n.º 17
0
/** Handler for the XPROG WRITE_MEMORY command to write to a specific memory space within the attached device. */
static void XPROGProtocol_WriteMemory(void)
{
	uint8_t ReturnStatus = XPROG_ERR_OK;

	struct
	{
		uint8_t  MemoryType;
		uint8_t  PageMode;
		uint32_t Address;
		uint16_t Length;
		uint8_t  ProgData[256];
	} WriteMemory_XPROG_Params;

	Endpoint_Read_Stream_LE(&WriteMemory_XPROG_Params, (sizeof(WriteMemory_XPROG_Params) -
	                                                    sizeof(WriteMemory_XPROG_Params).ProgData), NULL);
	WriteMemory_XPROG_Params.Address = SwapEndian_32(WriteMemory_XPROG_Params.Address);
	WriteMemory_XPROG_Params.Length  = SwapEndian_16(WriteMemory_XPROG_Params.Length);
	Endpoint_Read_Stream_LE(&WriteMemory_XPROG_Params.ProgData, WriteMemory_XPROG_Params.Length, NULL);

	// The driver will terminate transfers that are a round multiple of the endpoint bank in size with a ZLP, need
	// to catch this and discard it before continuing on with packet processing to prevent communication issues
	if (((sizeof(uint8_t) + sizeof(WriteMemory_XPROG_Params) - sizeof(WriteMemory_XPROG_Params.ProgData)) +
	    WriteMemory_XPROG_Params.Length) % AVRISP_DATA_EPSIZE == 0)
	{
		Endpoint_ClearOUT();
		Endpoint_WaitUntilReady();
	}

	Endpoint_ClearOUT();
	Endpoint_SelectEndpoint(AVRISP_DATA_IN_EPADDR);
	Endpoint_SetEndpointDirection(ENDPOINT_DIR_IN);

	if (XPROG_SelectedProtocol == XPROG_PROTOCOL_PDI)
	{
		/* Assume FLASH page programming by default, as it is the common case */
		uint8_t WriteCommand     = XMEGA_NVM_CMD_WRITEFLASHPAGE;
		uint8_t WriteBuffCommand = XMEGA_NVM_CMD_LOADFLASHPAGEBUFF;
		uint8_t EraseBuffCommand = XMEGA_NVM_CMD_ERASEFLASHPAGEBUFF;
		bool    PagedMemory      = true;

		switch (WriteMemory_XPROG_Params.MemoryType)
		{
			case XPROG_MEM_TYPE_APPL:
				WriteCommand     = XMEGA_NVM_CMD_WRITEAPPSECPAGE;
				break;
			case XPROG_MEM_TYPE_BOOT:
				WriteCommand     = XMEGA_NVM_CMD_WRITEBOOTSECPAGE;
				break;
			case XPROG_MEM_TYPE_EEPROM:
				WriteCommand     = XMEGA_NVM_CMD_ERASEWRITEEEPROMPAGE;
				WriteBuffCommand = XMEGA_NVM_CMD_LOADEEPROMPAGEBUFF;
				EraseBuffCommand = XMEGA_NVM_CMD_ERASEEEPROMPAGEBUFF;
				break;
			case XPROG_MEM_TYPE_USERSIG:
				WriteCommand     = XMEGA_NVM_CMD_WRITEUSERSIG;
				break;
			case XPROG_MEM_TYPE_FUSE:
				WriteCommand     = XMEGA_NVM_CMD_WRITEFUSE;
				PagedMemory      = false;
				break;
			case XPROG_MEM_TYPE_LOCKBITS:
				WriteCommand     = XMEGA_NVM_CMD_WRITELOCK;
				PagedMemory      = false;
				break;
		}

		/* Send the appropriate memory write commands to the device, indicate timeout if occurred */
		if ((PagedMemory && !(XMEGANVM_WritePageMemory(WriteBuffCommand, EraseBuffCommand, WriteCommand,
													   WriteMemory_XPROG_Params.PageMode, WriteMemory_XPROG_Params.Address,
													   WriteMemory_XPROG_Params.ProgData, WriteMemory_XPROG_Params.Length))) ||
		   (!PagedMemory && !(XMEGANVM_WriteByteMemory(WriteCommand, WriteMemory_XPROG_Params.Address,
													   WriteMemory_XPROG_Params.ProgData[0]))))
		{
			ReturnStatus = XPROG_ERR_TIMEOUT;
		}
	}
	else
	{
		/* Send write command to the TPI device, indicate timeout if occurred */
		if (!(TINYNVM_WriteMemory(WriteMemory_XPROG_Params.Address, WriteMemory_XPROG_Params.ProgData,
		      WriteMemory_XPROG_Params.Length)))
		{
			ReturnStatus = XPROG_ERR_TIMEOUT;
		}
	}

	Endpoint_Write_8(CMD_XPROG);
	Endpoint_Write_8(XPROG_CMD_WRITE_MEM);
	Endpoint_Write_8(ReturnStatus);
	Endpoint_ClearIN();
}
Ejemplo n.º 18
0
/** Handler for the XPRG ERASE command to erase a specific memory address space in the attached device. */
static void XPROGProtocol_Erase(void)
{
	uint8_t ReturnStatus = XPROG_ERR_OK;

	struct
	{
		uint8_t  MemoryType;
		uint32_t Address;
	} Erase_XPROG_Params;

	Endpoint_Read_Stream_LE(&Erase_XPROG_Params, sizeof(Erase_XPROG_Params), NULL);
	Erase_XPROG_Params.Address = SwapEndian_32(Erase_XPROG_Params.Address);

	Endpoint_ClearOUT();
	Endpoint_SelectEndpoint(AVRISP_DATA_IN_EPADDR);
	Endpoint_SetEndpointDirection(ENDPOINT_DIR_IN);

	uint8_t EraseCommand;

	if (XPROG_SelectedProtocol == XPROG_PROTOCOL_PDI)
	{
		/* Determine which NVM command to send to the device depending on the memory to erase */
		switch (Erase_XPROG_Params.MemoryType)
		{
			case XPROG_ERASE_CHIP:
				EraseCommand = XMEGA_NVM_CMD_CHIPERASE;
				break;
			case XPROG_ERASE_APP:
				EraseCommand = XMEGA_NVM_CMD_ERASEAPPSEC;
				break;
			case XPROG_ERASE_BOOT:
				EraseCommand = XMEGA_NVM_CMD_ERASEBOOTSEC;
				break;
			case XPROG_ERASE_EEPROM:
				EraseCommand = XMEGA_NVM_CMD_ERASEEEPROM;
				break;
			case XPROG_ERASE_APP_PAGE:
				EraseCommand = XMEGA_NVM_CMD_ERASEAPPSECPAGE;
				break;
			case XPROG_ERASE_BOOT_PAGE:
				EraseCommand = XMEGA_NVM_CMD_ERASEBOOTSECPAGE;
				break;
			case XPROG_ERASE_EEPROM_PAGE:
				EraseCommand = XMEGA_NVM_CMD_ERASEEEPROMPAGE;
				break;
			case XPROG_ERASE_USERSIG:
				EraseCommand = XMEGA_NVM_CMD_ERASEUSERSIG;
				break;
			default:
				EraseCommand = XMEGA_NVM_CMD_NOOP;
				break;
		}

		/* Erase the target memory, indicate timeout if occurred */
		if (!(XMEGANVM_EraseMemory(EraseCommand, Erase_XPROG_Params.Address)))
		  ReturnStatus = XPROG_ERR_TIMEOUT;
	}
	else
	{
		if (Erase_XPROG_Params.MemoryType == XPROG_ERASE_CHIP)
		  EraseCommand = TINY_NVM_CMD_CHIPERASE;
		else
		  EraseCommand = TINY_NVM_CMD_SECTIONERASE;

		/* Erase the target memory, indicate timeout if occurred */
		if (!(TINYNVM_EraseMemory(EraseCommand, Erase_XPROG_Params.Address)))
		  ReturnStatus = XPROG_ERR_TIMEOUT;
	}

	Endpoint_Write_8(CMD_XPROG);
	Endpoint_Write_8(XPROG_CMD_ERASE);
	Endpoint_Write_8(ReturnStatus);
	Endpoint_ClearIN();
}
Ejemplo n.º 19
0
/** Handler for the CMD_ENTER_PROGMODE_ISP command, which attempts to enter programming mode on
 *  the attached device, returning success or failure back to the host.
 */
void ISPProtocol_EnterISPMode(void)
{
	struct
	{
		uint8_t TimeoutMS;
		uint8_t PinStabDelayMS;
		uint8_t ExecutionDelayMS;
		uint8_t SynchLoops;
		uint8_t ByteDelay;
		uint8_t PollValue;
		uint8_t PollIndex;
		uint8_t EnterProgBytes[4];
	} Enter_ISP_Params;
	
	Endpoint_Read_Stream_LE(&Enter_ISP_Params, sizeof(Enter_ISP_Params), NO_STREAM_CALLBACK);

	Endpoint_ClearOUT();
	Endpoint_SelectEndpoint(AVRISP_DATA_IN_EPNUM);
	Endpoint_SetEndpointDirection(ENDPOINT_DIR_IN);

	uint8_t ResponseStatus = STATUS_CMD_FAILED;
	
	CurrentAddress = 0;
	
	/* Set up the synchronous USART to generate the .5MHz recovery clock on XCK pin */
	UBRR1  = (F_CPU / 500000UL);
	UCSR1B = (1 << TXEN1);
	UCSR1C = (1 << UMSEL10) | (1 << UPM11) | (1 << USBS1) | (1 << UCSZ11) | (1 << UCSZ10) | (1 << UCPOL1);
	DDRD  |= (1 << 5);

	/* Perform execution delay, initialize SPI bus */
	ISPProtocol_DelayMS(Enter_ISP_Params.ExecutionDelayMS); 
	ISPTarget_Init();

	/* Continuously attempt to synchronize with the target until either the number of attempts specified
	 * by the host has exceeded, or the the device sends back the expected response values */
	while (Enter_ISP_Params.SynchLoops-- && (ResponseStatus == STATUS_CMD_FAILED) && TimeoutTicksRemaining)
	{
		uint8_t ResponseBytes[4];

		ISPTarget_ChangeTargetResetLine(true);
		ISPProtocol_DelayMS(Enter_ISP_Params.PinStabDelayMS);

		for (uint8_t RByte = 0; RByte < sizeof(ResponseBytes); RByte++)
		{
			ISPProtocol_DelayMS(Enter_ISP_Params.ByteDelay);
			ResponseBytes[RByte] = ISPTarget_TransferByte(Enter_ISP_Params.EnterProgBytes[RByte]);
		}
		
		/* Check if polling disabled, or if the polled value matches the expected value */
		if (!(Enter_ISP_Params.PollIndex) || (ResponseBytes[Enter_ISP_Params.PollIndex - 1] == Enter_ISP_Params.PollValue))
		{
			ResponseStatus = STATUS_CMD_OK;
		}
		else
		{
			ISPTarget_ChangeTargetResetLine(false);
			ISPProtocol_DelayMS(Enter_ISP_Params.PinStabDelayMS);
		}
	}

	Endpoint_Write_Byte(CMD_ENTER_PROGMODE_ISP);
	Endpoint_Write_Byte(ResponseStatus);
	Endpoint_ClearIN();
}
void hidTask(void)
{
    // Only process HID tasks if the device is configured and ready
    if (USB_DeviceState != DEVICE_STATE_Configured)
        return;

    // GenericHID -------------------------------------------------------------

    // Select the OUT end-point
    Endpoint_SelectEndpoint(GENERIC_OUT_EPADDR);

    // Check to see if a packet has been sent from the host and we have nothing waiting to send
    if (Endpoint_IsOUTReceived() && waitingToSend == 0)
    {
#ifdef USART_DEBUG
        printf("Packet received on OUT End-point\r\n");
#endif

        // Check to see if the end-point is ready for reading
        if (Endpoint_IsReadWriteAllowed())
        {
            // Read the report data from the control end-point
            Endpoint_Read_Stream_LE(&hidReceiveBuffer, sizeof(hidReceiveBuffer), NULL);

#ifdef USART_DEBUG
            uint8_t counter;
            printf("Dumping hex from OUT End-point (from host)\r\n");

            for (counter = 0; counter < GENERIC_EPSIZE; counter++)
            {
                printf("%02x ", hidReceiveBuffer[counter]);
                if (!((counter+1) % 8)) printf("\r\n");
            }
            printf("\r\n");
#endif

            // Process GenericHID packet header
            switch(hidReceiveBuffer[0])
            {
            // Command group 0x01: System command group
            case RPF_COMMANDGROUP_SYSTEM:
#ifdef USART_DEBUG
                printf("Command group 0x01: System command group\r\n");
#endif
                waitingToSend = systemCommandGroup(hidReceiveBuffer, hidSendBuffer);
                break;

            // Command group 0x02: Input/output command group
            case RPF_COMMANDGROUP_IO:
#ifdef USART_DEBUG
                printf("Command group 0x02: Input/output command group\r\n");
#endif
                break;

            // Command group 0x03: ADC command group
            case RPF_COMMANDGROUP_ADC:
#ifdef USART_DEBUG
                printf("Command group 0x03: ADC command group\r\n");
#endif
                break;

            // Command group 0x04: User defined command group
            case RPF_COMMANDGROUP_USER:
#ifdef USART_DEBUG
                printf("Command group 0x04: User defined command group\r\n");
#endif
                break;

            // Command group 0x05: PWM command group
            case RPF_COMMANDGROUP_PWM:
#ifdef USART_DEBUG
                printf("Command group 0x05: PWM command group\r\n");
#endif
                break;

            // Command group 0x06: SPI command group
            case RPF_COMMANDGROUP_SPI:
#ifdef USART_DEBUG
                printf("Command group 0x06: SPI command group\r\n");
#endif
                break;

            // Command group 0x07: I2C command group
            case RPF_COMMANDGROUP_I2C:
#ifdef USART_DEBUG
                printf("Command group 0x07: I2C command group\r\n");
#endif
                break;

            // Command group 0x08: USART command group
            case RPF_COMMANDGROUP_USART:
#ifdef USART_DEBUG
                printf("Command group 0x08: USART command group\r\n");
#endif
                break;

            default:
#ifdef USART_DEBUG
                printf("Host requested non-existent command group %d\r\n", hidReceiveBuffer[0]);
#endif
                break;
            }
        }

        // Finalize the stream transfer to send the last packet
        Endpoint_ClearOUT();
    }

    // Select the IN end-point
    Endpoint_SelectEndpoint(GENERIC_IN_EPADDR);

    // Check to see if the host is ready to accept another packet and that we have one to send
    if (Endpoint_IsINReady() && waitingToSend == 1)
    {
#ifdef USART_DEBUG
        printf("Sending packet on IN End-point\r\n");
#endif

        // Write Generic Report Data
        Endpoint_Write_Stream_LE(&hidSendBuffer, sizeof(hidSendBuffer), NULL);

        // Finalize the stream transfer to send the last packet
        Endpoint_ClearIN();

        // Clear the waiting to send flag
        waitingToSend = 0;

        // Turn on the Tx activity indicator
        activityIndicatorTx = 1;

#ifdef USART_DEBUG
        uint8_t counter;
        printf("Dumping hex from IN End-point (to host)\r\n");

        for (counter = 0; counter < GENERIC_EPSIZE; counter++)
        {
            printf("%02x ", hidSendBuffer[counter]);
            if (!((counter+1) % 8)) printf("\r\n");
        }
        printf("\r\n");
#endif
    }

    // Joystick ---------------------------------------------------------------

    // Select the Joystick Report End-point
    Endpoint_SelectEndpoint(JOYSTICK_EPADDR);

    // Check to see if the host is ready for another joystick packet
    if (Endpoint_IsINReady())
    {
        USB_JoystickReport_Data_t joystickReportData;

        // Create the next HID report to send to the host
        generateJoystickReport(&joystickReportData);

        // Write Joystick Report Data
        Endpoint_Write_Stream_LE(&joystickReportData, sizeof(joystickReportData), NULL);

        // Finalize the stream transfer to send the last packet
        Endpoint_ClearIN();

        // Clear the report data afterwards */
        memset(&joystickReportData, 0, sizeof(joystickReportData));
    }
}
/** Handler for the CMD_PROGRAM_FLASH_ISP and CMD_PROGRAM_EEPROM_ISP commands, writing out bytes,
 *  words or pages of data to the attached device.
 *
 *  \param[in] V2Command  Issued V2 Protocol command byte from the host
 */
void ISPProtocol_ProgramMemory(uint8_t V2Command)
{
	struct
	{
		uint16_t BytesToWrite;
		uint8_t  ProgrammingMode;
		uint8_t  DelayMS;
		uint8_t  ProgrammingCommands[3];
		uint8_t  PollValue1;
		uint8_t  PollValue2;
		uint8_t  ProgData[256]; // Note, the Jungo driver has a very short ACK timeout period, need to buffer the
	} Write_Memory_Params;      // whole page and ACK the packet as fast as possible to prevent it from aborting

	Endpoint_Read_Stream_LE(&Write_Memory_Params, (sizeof(Write_Memory_Params) -
	                                               sizeof(Write_Memory_Params.ProgData)), NULL);
	Write_Memory_Params.BytesToWrite = SwapEndian_16(Write_Memory_Params.BytesToWrite);

	if (Write_Memory_Params.BytesToWrite > sizeof(Write_Memory_Params.ProgData))
	{
		Endpoint_ClearOUT();
		Endpoint_SelectEndpoint(AVRISP_DATA_IN_EPADDR);
		Endpoint_SetEndpointDirection(ENDPOINT_DIR_IN);

		Endpoint_Write_8(V2Command);
		Endpoint_Write_8(STATUS_CMD_FAILED);
		Endpoint_ClearIN();
		return;
	}

	Endpoint_Read_Stream_LE(&Write_Memory_Params.ProgData, Write_Memory_Params.BytesToWrite, NULL);

	// The driver will terminate transfers that are a round multiple of the endpoint bank in size with a ZLP, need
	// to catch this and discard it before continuing on with packet processing to prevent communication issues
	if (((sizeof(uint8_t) + sizeof(Write_Memory_Params) - sizeof(Write_Memory_Params.ProgData)) +
	    Write_Memory_Params.BytesToWrite) % AVRISP_DATA_EPSIZE == 0)
	{
		Endpoint_ClearOUT();
		Endpoint_WaitUntilReady();
	}

	Endpoint_ClearOUT();
	Endpoint_SelectEndpoint(AVRISP_DATA_IN_EPADDR);
	Endpoint_SetEndpointDirection(ENDPOINT_DIR_IN);

	uint8_t  ProgrammingStatus = STATUS_CMD_OK;
	uint8_t  PollValue         = (V2Command == CMD_PROGRAM_FLASH_ISP) ? Write_Memory_Params.PollValue1 :
	                                                                    Write_Memory_Params.PollValue2;
	uint16_t PollAddress       = 0;
	uint8_t* NextWriteByte     = Write_Memory_Params.ProgData;
	uint16_t PageStartAddress  = (CurrentAddress & 0xFFFF);

	for (uint16_t CurrentByte = 0; CurrentByte < Write_Memory_Params.BytesToWrite; CurrentByte++)
	{
		uint8_t ByteToWrite     = *(NextWriteByte++);
		uint8_t ProgrammingMode = Write_Memory_Params.ProgrammingMode;

		/* Check to see if we need to send a LOAD EXTENDED ADDRESS command to the target */
		if (MustLoadExtendedAddress)
		{
			ISPTarget_LoadExtendedAddress();
			MustLoadExtendedAddress = false;
		}

		ISPTarget_SendByte(Write_Memory_Params.ProgrammingCommands[0]);
		ISPTarget_SendByte(CurrentAddress >> 8);
		ISPTarget_SendByte(CurrentAddress & 0xFF);
		ISPTarget_SendByte(ByteToWrite);

		/* AVR FLASH addressing requires us to modify the write command based on if we are writing a high
		 * or low byte at the current word address */
		if (V2Command == CMD_PROGRAM_FLASH_ISP)
		  Write_Memory_Params.ProgrammingCommands[0] ^= READ_WRITE_HIGH_BYTE_MASK;

		/* Check to see if we have a valid polling address */
		if (!(PollAddress) && (ByteToWrite != PollValue))
		{
			if ((CurrentByte & 0x01) && (V2Command == CMD_PROGRAM_FLASH_ISP))
			  Write_Memory_Params.ProgrammingCommands[2] |=  READ_WRITE_HIGH_BYTE_MASK;
			else
			  Write_Memory_Params.ProgrammingCommands[2] &= ~READ_WRITE_HIGH_BYTE_MASK;

			PollAddress = (CurrentAddress & 0xFFFF);
		}

		/* If in word programming mode, commit the byte to the target's memory */
		if (!(ProgrammingMode & PROG_MODE_PAGED_WRITES_MASK))
		{
			/* If the current polling address is invalid, switch to timed delay write completion mode */
			if (!(PollAddress) && !(ProgrammingMode & PROG_MODE_WORD_READYBUSY_MASK))
			  ProgrammingMode = (ProgrammingMode & ~PROG_MODE_WORD_VALUE_MASK) | PROG_MODE_WORD_TIMEDELAY_MASK;

			ProgrammingStatus = ISPTarget_WaitForProgComplete(ProgrammingMode, PollAddress, PollValue,
			                                                  Write_Memory_Params.DelayMS,
			                                                  Write_Memory_Params.ProgrammingCommands[2]);

			/* Abort the programming loop early if the byte/word programming failed */
			if (ProgrammingStatus != STATUS_CMD_OK)
			  break;

			/* Must reset the polling address afterwards, so it is not erroneously used for the next byte */
			PollAddress = 0;
		}

		/* EEPROM just increments the address each byte, flash needs to increment on each word and
		 * also check to ensure that a LOAD EXTENDED ADDRESS command is issued each time the extended
		 * address boundary has been crossed during FLASH memory programming */
		if ((CurrentByte & 0x01) || (V2Command == CMD_PROGRAM_EEPROM_ISP))
		{
			CurrentAddress++;

			if ((V2Command == CMD_PROGRAM_FLASH_ISP) && !(CurrentAddress & 0xFFFF))
			  MustLoadExtendedAddress = true;
		}
	}

	/* If the current page must be committed, send the PROGRAM PAGE command to the target */
	if (Write_Memory_Params.ProgrammingMode & PROG_MODE_COMMIT_PAGE_MASK)
	{
		ISPTarget_SendByte(Write_Memory_Params.ProgrammingCommands[1]);
		ISPTarget_SendByte(PageStartAddress >> 8);
		ISPTarget_SendByte(PageStartAddress & 0xFF);
		ISPTarget_SendByte(0x00);

		/* Check if polling is enabled and possible, if not switch to timed delay mode */
		if ((Write_Memory_Params.ProgrammingMode & PROG_MODE_PAGED_VALUE_MASK) && !(PollAddress))
		{
			Write_Memory_Params.ProgrammingMode = (Write_Memory_Params.ProgrammingMode & ~PROG_MODE_PAGED_VALUE_MASK) |
												   PROG_MODE_PAGED_TIMEDELAY_MASK;
		}

		ProgrammingStatus = ISPTarget_WaitForProgComplete(Write_Memory_Params.ProgrammingMode, PollAddress, PollValue,
		                                                  Write_Memory_Params.DelayMS,
		                                                  Write_Memory_Params.ProgrammingCommands[2]);

		/* Check to see if the FLASH address has crossed the extended address boundary */
		if ((V2Command == CMD_PROGRAM_FLASH_ISP) && !(CurrentAddress & 0xFFFF))
		  MustLoadExtendedAddress = true;
	}
Ejemplo n.º 22
0
static void SideShow_GetCapabilities(SideShow_PacketHeader_t* PacketHeader)
{
	SideShow_PropertyKey_t  Property;
	SideShow_PropertyData_t PropertyData;

	Endpoint_Read_Stream_LE(&Property, sizeof(SideShow_PropertyKey_t));
	Endpoint_ClearOUT();
	
	printf(" ID: %lu", Property.PropertyID);

	PacketHeader->Length = sizeof(SideShow_PacketHeader_t);

	if (GUID_COMPARE(&Property.PropertyGUID, (uint32_t[])SIDESHOW_PROPERTY_GUID))
	{
		switch (Property.PropertyID)
		{
			case PROPERTY_SIDESHOW_SCREENTYPE:
				PropertyData.DataType    = VT_I4;
				PropertyData.Data.Data32 = ScreenText;
				PacketHeader->Length += sizeof(uint32_t);
				
				break;
			case PROPERTY_SIDESHOW_SCREENWIDTH:
			case PROPERTY_SIDESHOW_CLIENTWIDTH:
				PropertyData.DataType    = VT_UI2;
				PropertyData.Data.Data16 = 16;
				PacketHeader->Length += sizeof(uint16_t);
			
				break;
			case PROPERTY_SIDESHOW_SCREENHEIGHT:
			case PROPERTY_SIDESHOW_CLIENTHEIGHT:
				PropertyData.DataType    = VT_UI2;
				PropertyData.Data.Data16 = 2;
				PacketHeader->Length += sizeof(uint16_t);
			
				break;
			case PROPERTY_SIDESHOW_COLORDEPTH:
				PropertyData.DataType    = VT_UI2;
				PropertyData.Data.Data16 = 1;
				PacketHeader->Length += sizeof(uint16_t);
			
				break;
			case PROPERTY_SIDESHOW_COLORTYPE:
				PropertyData.DataType    = VT_UI2;
				PropertyData.Data.Data16 = BlackAndWhiteDisplay;
				PacketHeader->Length += sizeof(uint16_t);
			
				break;
			case PROPERTY_SIDESHOW_DATACACHE:
				PropertyData.DataType    = VT_BOOL;
				PropertyData.Data.Data16 = false;
				PacketHeader->Length += sizeof(uint16_t);
			
				break;
			case PROPERTY_SIDESHOW_SUPPORTEDLANGS:
			case PROPERTY_SIDESHOW_CURRENTLANG:
				PropertyData.DataType    = VT_LPWSTR;
				PropertyData.Data.DataPointer = &SupportedLanguage;
				PacketHeader->Length += SupportedLanguage.LengthInBytes;
			
				break;
			default:
				PropertyData.DataType    = VT_EMPTY;
				break;
		}
	}
	else if (GUID_COMPARE(&Property.PropertyGUID, (uint32_t[])DEVICE_PROPERTY_GUID))
	{
		switch (Property.PropertyID)
		{
			case PROPERTY_DEVICE_DEVICETYPE:
				PropertyData.DataType    = VT_UI4;
				PropertyData.Data.Data32 = GenericDevice;
				PacketHeader->Length += sizeof(uint32_t);
				
				break;
		}
	}	
	else
	{
		PacketHeader->Type.NAK = true;		
		
		printf(" WRONG GUID");
		printf(" %lX %lX %lX %lX", Property.PropertyGUID.Chunks[0], Property.PropertyGUID.Chunks[1],
		                           Property.PropertyGUID.Chunks[2],  Property.PropertyGUID.Chunks[3]);		
	}

	Endpoint_SelectEndpoint(SIDESHOW_IN_EPNUM);
	Endpoint_Write_Stream_LE(PacketHeader, sizeof(SideShow_PacketHeader_t));
	
	if (!(PacketHeader->Type.NAK))
	{
		switch (PropertyData.DataType)
		{
			case VT_UI4:
			case VT_I4:
				Endpoint_Write_Stream_LE(&PropertyData.Data.Data32, sizeof(uint32_t));
				break;
			case VT_UI2:
			case VT_I2:
			case VT_BOOL:
				Endpoint_Write_Stream_LE(&PropertyData.Data.Data16, sizeof(uint16_t));
				break;
			case VT_LPWSTR:
				SideShow_Write_Unicode_String((Unicode_String_t*)PropertyData.Data.Data16);
				break;
		}
	}
	
	Endpoint_ClearIN();
	return;
}
Ejemplo n.º 23
0
void RNDIS_Device_USBTask(USB_ClassInfo_RNDIS_Device_t* const RNDISInterfaceInfo)
{
	if (USB_DeviceState != DEVICE_STATE_Configured)
	  return;

	RNDIS_Message_Header_t* MessageHeader = (RNDIS_Message_Header_t*)&RNDISInterfaceInfo->State.RNDISMessageBuffer;

	Endpoint_SelectEndpoint(RNDISInterfaceInfo->Config.NotificationEndpointNumber);

	if (Endpoint_IsINReady() && RNDISInterfaceInfo->State.ResponseReady)
	{
		USB_Request_Header_t Notification = (USB_Request_Header_t)
			{
				.bmRequestType = (REQDIR_DEVICETOHOST | REQTYPE_CLASS | REQREC_INTERFACE),
				.bRequest      = NOTIF_ResponseAvailable,
				.wValue        = 0,
				.wIndex        = 0,
				.wLength       = 0,
			};
		
		Endpoint_Write_Stream_LE(&Notification, sizeof(Notification), NO_STREAM_CALLBACK);

		Endpoint_ClearIN();

		RNDISInterfaceInfo->State.ResponseReady = false;
	}
	
	if ((RNDISInterfaceInfo->State.CurrRNDISState == RNDIS_Data_Initialized) && !(MessageHeader->MessageLength))
	{
		RNDIS_Packet_Message_t RNDISPacketHeader;

		Endpoint_SelectEndpoint(RNDISInterfaceInfo->Config.DataOUTEndpointNumber);

		if (Endpoint_IsOUTReceived() && !(RNDISInterfaceInfo->State.FrameIN.FrameInBuffer))
		{
			Endpoint_Read_Stream_LE(&RNDISPacketHeader, sizeof(RNDIS_Packet_Message_t), NO_STREAM_CALLBACK);

			if (RNDISPacketHeader.DataLength > ETHERNET_FRAME_SIZE_MAX)
			{
				Endpoint_StallTransaction();
				return;
			}
			
			Endpoint_Read_Stream_LE(RNDISInterfaceInfo->State.FrameIN.FrameData, RNDISPacketHeader.DataLength, NO_STREAM_CALLBACK);

			Endpoint_ClearOUT();
			
			RNDISInterfaceInfo->State.FrameIN.FrameLength = RNDISPacketHeader.DataLength;

			RNDISInterfaceInfo->State.FrameIN.FrameInBuffer = true;
		}
		
		Endpoint_SelectEndpoint(RNDISInterfaceInfo->Config.DataINEndpointNumber);
		
		if (Endpoint_IsINReady() && RNDISInterfaceInfo->State.FrameOUT.FrameInBuffer)
		{
			memset(&RNDISPacketHeader, 0, sizeof(RNDIS_Packet_Message_t));

			RNDISPacketHeader.MessageType   = REMOTE_NDIS_PACKET_MSG;
			RNDISPacketHeader.MessageLength = (sizeof(RNDIS_Packet_Message_t) + RNDISInterfaceInfo->State.FrameOUT.FrameLength);
			RNDISPacketHeader.DataOffset    = (sizeof(RNDIS_Packet_Message_t) - sizeof(RNDIS_Message_Header_t));
			RNDISPacketHeader.DataLength    = RNDISInterfaceInfo->State.FrameOUT.FrameLength;

			Endpoint_Write_Stream_LE(&RNDISPacketHeader, sizeof(RNDIS_Packet_Message_t), NO_STREAM_CALLBACK);
			Endpoint_Write_Stream_LE(RNDISInterfaceInfo->State.FrameOUT.FrameData, RNDISPacketHeader.DataLength, NO_STREAM_CALLBACK);
			Endpoint_ClearIN();
			
			RNDISInterfaceInfo->State.FrameOUT.FrameInBuffer = false;
		}
	}
}							
Ejemplo n.º 24
0
/** Task to handle the generation of MIDI note change events in response to presses of the board joystick, and send them
 *  to the host.
 */
void MIDI_Task(void)
{
	static uint8_t PrevJoystickStatus;

	/* Device must be connected and configured for the task to run */
	if (USB_DeviceState != DEVICE_STATE_Configured)
	  return;

	Endpoint_SelectEndpoint(MIDI_STREAM_IN_EPADDR);

	if (Endpoint_IsINReady())
	{
		uint8_t MIDICommand = 0;
		uint8_t MIDIPitch;

		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 endpoint */
			Endpoint_Write_Stream_LE(&MIDIEvent, sizeof(MIDIEvent), NULL);

			/* Send the data in the endpoint to the host */
			Endpoint_ClearIN();
		}

		/* Save previous joystick value for next joystick change detection */
		PrevJoystickStatus = JoystickStatus;
	}

	/* Select the MIDI OUT stream */
	Endpoint_SelectEndpoint(MIDI_STREAM_OUT_EPADDR);

	/* Check if a MIDI command has been received */
	if (Endpoint_IsOUTReceived())
	{
		MIDI_EventPacket_t MIDIEvent;

		/* Read the MIDI event packet from the endpoint */
		Endpoint_Read_Stream_LE(&MIDIEvent, sizeof(MIDIEvent), NULL);

		/* Check to see if the sent command is a note on message with a non-zero velocity */
		if ((MIDIEvent.Event == MIDI_EVENT(0, MIDI_COMMAND_NOTE_ON)) && (MIDIEvent.Data3 > 0))
		{
			/* Change LEDs depending on the pitch of the sent note */
			LEDs_SetAllLEDs(MIDIEvent.Data2 > 64 ? LEDS_LED1 : LEDS_LED2);
		}
		else
		{
			/* Turn off all LEDs in response to non Note On messages */
			LEDs_SetAllLEDs(LEDS_NO_LEDS);
		}

		/* If the endpoint is now empty, clear the bank */
		if (!(Endpoint_BytesInEndpoint()))
		{
			/* Clear the endpoint ready for new packet */
			Endpoint_ClearOUT();
		}
	}
}
Ejemplo n.º 25
0
/** Task to manage the sending and receiving of encapsulated RNDIS data and notifications. This removes the RNDIS
 *  wrapper from received Ethernet frames and places them in the FrameIN global buffer, or adds the RNDIS wrapper
 *  to a frame in the FrameOUT global before sending the buffer contents to the host.
 */
void RNDIS_Task(void)
{
	/* Select the notification endpoint */
	Endpoint_SelectEndpoint(CDC_NOTIFICATION_EPADDR);

	/* Check if a message response is ready for the host */
	if (Endpoint_IsINReady() && ResponseReady)
	{
		USB_Request_Header_t Notification = (USB_Request_Header_t)
			{
				.bmRequestType = (REQDIR_DEVICETOHOST | REQTYPE_CLASS | REQREC_INTERFACE),
				.bRequest      = RNDIS_NOTIF_ResponseAvailable,
				.wValue        = 0,
				.wIndex        = 0,
				.wLength       = 0,
			};

		/* Indicate that a message response is ready for the host */
		Endpoint_Write_Stream_LE(&Notification, sizeof(Notification), NULL);

		/* Finalize the stream transfer to send the last packet */
		Endpoint_ClearIN();

		/* Indicate a response is no longer ready */
		ResponseReady = false;
	}

	/* Don't process the data endpoints until the system is in the data initialized state, and the buffer is free */
	if ((CurrRNDISState == RNDIS_Data_Initialized) && !(MessageHeader->MessageLength))
	{
		/* Create a new packet header for reading/writing */
		RNDIS_Packet_Message_t RNDISPacketHeader;

		/* Select the data OUT endpoint */
		Endpoint_SelectEndpoint(CDC_RX_EPADDR);

		/* Check if the data OUT endpoint contains data, and that the IN buffer is empty */
		if (Endpoint_IsOUTReceived() && !(FrameIN.FrameLength))
		{
			/* Read in the packet message header */
			Endpoint_Read_Stream_LE(&RNDISPacketHeader, sizeof(RNDIS_Packet_Message_t), NULL);

			/* Stall the request if the data is too large */
			if (RNDISPacketHeader.DataLength > ETHERNET_FRAME_SIZE_MAX)
			{
				Endpoint_StallTransaction();
				return;
			}

			/* Read in the Ethernet frame into the buffer */
			Endpoint_Read_Stream_LE(FrameIN.FrameData, RNDISPacketHeader.DataLength, NULL);

			/* Finalize the stream transfer to send the last packet */
			Endpoint_ClearOUT();

			/* Store the size of the Ethernet frame */
			FrameIN.FrameLength = RNDISPacketHeader.DataLength;
		}

		/* Select the data IN endpoint */
		Endpoint_SelectEndpoint(CDC_TX_EPADDR);

		/* Check if the data IN endpoint is ready for more data, and that the IN buffer is full */
		if (Endpoint_IsINReady() && FrameOUT.FrameLength)
		{
			/* Clear the packet header with all 0s so that the relevant fields can be filled */
			memset(&RNDISPacketHeader, 0, sizeof(RNDIS_Packet_Message_t));

			/* Construct the required packet header fields in the buffer */
			RNDISPacketHeader.MessageType   = REMOTE_NDIS_PACKET_MSG;
			RNDISPacketHeader.MessageLength = (sizeof(RNDIS_Packet_Message_t) + FrameOUT.FrameLength);
			RNDISPacketHeader.DataOffset    = (sizeof(RNDIS_Packet_Message_t) - sizeof(RNDIS_Message_Header_t));
			RNDISPacketHeader.DataLength    = FrameOUT.FrameLength;

			/* Send the packet header to the host */
			Endpoint_Write_Stream_LE(&RNDISPacketHeader, sizeof(RNDIS_Packet_Message_t), NULL);

			/* Send the Ethernet frame data to the host */
			Endpoint_Write_Stream_LE(FrameOUT.FrameData, RNDISPacketHeader.DataLength, NULL);

			/* Finalize the stream transfer to send the last packet */
			Endpoint_ClearIN();

			/* Indicate Ethernet OUT buffer no longer full */
			FrameOUT.FrameLength = 0;
		}
	}
}
Ejemplo n.º 26
0
/** ISR for the general Pipe/Endpoint interrupt vector. This ISR fires when an endpoint's status changes (such as
 *  a packet has been received) on an endpoint with its corresponding ISR enabling bits set. This is used to send
 *  HID packets to the host each time the HID interrupt endpoints polling period elapses, as managed by the USB
 *  controller.
 */
ISR(ENDPOINT_PIPE_vect, ISR_BLOCK)
{
	/* Save previously selected endpoint before selecting a new endpoint */
	uint8_t PrevSelectedEndpoint = Endpoint_GetCurrentEndpoint();

	#if defined(INTERRUPT_CONTROL_ENDPOINT)
	/* Check if the control endpoint has received a request */
	if (Endpoint_HasEndpointInterrupted(ENDPOINT_CONTROLEP))
	{
		/* Clear the endpoint interrupt */
		Endpoint_ClearEndpointInterrupt(ENDPOINT_CONTROLEP);

		/* Process the control request */
		USB_USBTask();

		/* Handshake the endpoint setup interrupt - must be after the call to USB_USBTask() */
		USB_INT_Clear(ENDPOINT_INT_SETUP);
	}
	#endif

	#if defined(INTERRUPT_DATA_ENDPOINT)
	/* Check if Generic IN endpoint has interrupted */
	if (Endpoint_HasEndpointInterrupted(GENERIC_IN_EPNUM))
	{
		/* Select the Generic IN Report Endpoint */
		Endpoint_SelectEndpoint(GENERIC_IN_EPNUM);

		/* Clear the endpoint IN interrupt flag */
		USB_INT_Clear(ENDPOINT_INT_IN);

		/* Clear the Generic IN Report endpoint interrupt and select the endpoint */
		Endpoint_ClearEndpointInterrupt(GENERIC_IN_EPNUM);

		/* Create a temporary buffer to hold the report to send to the host */
		uint8_t GenericData[GENERIC_REPORT_SIZE];
		
		/* Create Generic Report Data */
		CreateGenericHIDReport(GenericData);

		/* Write Generic Report Data */
		Endpoint_Write_Stream_LE(&GenericData, sizeof(GenericData));

		/* Finalize the stream transfer to send the last packet */
		Endpoint_ClearIN();
	}

	/* Check if Generic OUT endpoint has interrupted */
	if (Endpoint_HasEndpointInterrupted(GENERIC_OUT_EPNUM))
	{
		/* Select the Generic OUT Report Endpoint */
		Endpoint_SelectEndpoint(GENERIC_OUT_EPNUM);

		/* Clear the endpoint OUT Interrupt flag */
		USB_INT_Clear(ENDPOINT_INT_OUT);

		/* Clear the Generic OUT Report endpoint interrupt and select the endpoint */
		Endpoint_ClearEndpointInterrupt(GENERIC_OUT_EPNUM);

		/* Create a temporary buffer to hold the read in report from the host */
		uint8_t GenericData[GENERIC_REPORT_SIZE];
		
		/* Read Generic Report Data */
		Endpoint_Read_Stream_LE(&GenericData, sizeof(GenericData));
		
		/* Process Generic Report Data */
		ProcessGenericHIDReport(GenericData);

		/* Finalize the stream transfer to send the last packet */
		Endpoint_ClearOUT();
	}
	#endif

	/* Restore previously selected endpoint */
	Endpoint_SelectEndpoint(PrevSelectedEndpoint);
}
Ejemplo n.º 27
0
/** Command processing for an issued SCSI READ (10) or WRITE (10) command. This command reads in the block start address
 *  and total number of blocks to process, then calls the appropriate low-level Dataflash routine to handle the actual
 *  reading and writing of the data.
 *
 *  \param[in] MSInterfaceInfo  Pointer to the Mass Storage class interface structure that the command is associated with
 *  \param[in] IsDataRead  Indicates if the command is a READ (10) command or WRITE (10) command (DATA_READ or DATA_WRITE)
 *
 *  \return Boolean true if the command completed successfully, false otherwise.
 */
static bool SCSI_Command_ReadWrite_10 (USB_ClassInfo_MS_Device_t* const MSInterfaceInfo, const bool IsDataRead)
{
	uint32_t BlockAddress;
	uint16_t TotalBlocks;
	//uint8_t buffer[VIRTUAL_MEMORY_BLOCK_SIZE];

	/* Check if the disk is write protected or not */
	if ((IsDataRead == DATA_WRITE) && DISK_READ_ONLY)
	{
		/* Block address is invalid, update SENSE key and return command fail */
		SCSI_SET_SENSE(SCSI_SENSE_KEY_DATA_PROTECT, SCSI_ASENSE_WRITE_PROTECTED, SCSI_ASENSEQ_NO_QUALIFIER);

		return false;
	}

	/* Load in the 32-bit block address (SCSI uses big-endian, so have to reverse the byte order) */
	//BlockAddress = SwapEndian_32(*(uint32_t*)&MSInterfaceInfo->State.CommandBlock.SCSICommandData[2]);
	BlockAddress = (MSInterfaceInfo->State.CommandBlock.SCSICommandData[2] << 24) + (MSInterfaceInfo->State.CommandBlock.SCSICommandData[3] << 16) + (MSInterfaceInfo->State.CommandBlock.SCSICommandData[4] << 8) + MSInterfaceInfo->State.CommandBlock.SCSICommandData[5];

	/* Load in the 16-bit total blocks (SCSI uses big-endian, so have to reverse the byte order) */
	//TotalBlocks  = SwapEndian_16(*(uint16_t*)&MSInterfaceInfo->State.CommandBlock.SCSICommandData[7]);
	TotalBlocks = (MSInterfaceInfo->State.CommandBlock.SCSICommandData[7] << 8) + MSInterfaceInfo->State.CommandBlock.SCSICommandData[8];

	/* Check if the block address is outside the maximum allowable value for the LUN */
	if (BlockAddress >= LUN_MEDIA_BLOCKS)
	{
		/* Block address is invalid, update SENSE key and return command fail */
		SCSI_SET_SENSE(SCSI_SENSE_KEY_ILLEGAL_REQUEST, SCSI_ASENSE_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE, SCSI_ASENSEQ_NO_QUALIFIER);

		return false;
	}

#if (TOTAL_LUNS > 1)
	/* Adjust the given block address to the real media address based on the selected LUN */
	BlockAddress += ((uint32_t)MSInterfaceInfo->State.CommandBlock.LUN * LUN_MEDIA_BLOCKS);
#endif
	
	/* Determine if the packet is a READ (10) or WRITE (10) command, call appropriate function */
#if 0
	if (IsDataRead == DATA_READ)
	{
		int i;
		for(i=0;i<TotalBlocks;i++)
		{
			while(!Endpoint_IsReadWriteAllowed());
			MassStorage_Read(((BlockAddress+i)*VIRTUAL_MEMORY_BLOCK_SIZE), buffer, VIRTUAL_MEMORY_BLOCK_SIZE);
			Endpoint_Write_Stream_LE(buffer, VIRTUAL_MEMORY_BLOCK_SIZE,NULL);
			Endpoint_ClearIN();
		}
	}
	else
	{
		int i;
		for(i=0;i<TotalBlocks;i++)
		{
			while(!Endpoint_IsReadWriteAllowed());
			Endpoint_Read_Stream_LE(buffer,VIRTUAL_MEMORY_BLOCK_SIZE,NULL);
			Endpoint_ClearOUT();
			MassStorage_Write((BlockAddress+i)*VIRTUAL_MEMORY_BLOCK_SIZE,buffer, VIRTUAL_MEMORY_BLOCK_SIZE);
		}
	}
#else
	uint32_t startaddr;
	uint16_t blocks, dummyblocks;

	startaddr = MassStorage_GetAddressInImage(BlockAddress, TotalBlocks, &blocks);
	if (blocks == 0)
		dummyblocks = TotalBlocks;
	else if (blocks < TotalBlocks)
		dummyblocks = TotalBlocks - blocks;
	else
		dummyblocks = 0;
	Endpoint_Streaming((uint8_t*) startaddr, VIRTUAL_MEMORY_BLOCK_SIZE, blocks, dummyblocks);
#endif
	/* Update the bytes transferred counter and succeed the command */
	MSInterfaceInfo->State.CommandBlock.DataTransferLength -= ((uint32_t) TotalBlocks * VIRTUAL_MEMORY_BLOCK_SIZE);

	return true;
}
/** Handler for the CMD_ENTER_PROGMODE_ISP command, which attempts to enter programming mode on
 *  the attached device, returning success or failure back to the host.
 */
void ISPProtocol_EnterISPMode(void)
{
	struct
	{
		uint8_t TimeoutMS;
		uint8_t PinStabDelayMS;
		uint8_t ExecutionDelayMS;
		uint8_t SynchLoops;
		uint8_t ByteDelay;
		uint8_t PollValue;
		uint8_t PollIndex;
		uint8_t EnterProgBytes[4];
	} Enter_ISP_Params;

	Endpoint_Read_Stream_LE(&Enter_ISP_Params, sizeof(Enter_ISP_Params), NULL);

	Endpoint_ClearOUT();
	Endpoint_SelectEndpoint(AVRISP_DATA_IN_EPADDR);
	Endpoint_SetEndpointDirection(ENDPOINT_DIR_IN);

	uint8_t ResponseStatus = STATUS_CMD_FAILED;

	CurrentAddress = 0;

	/* Perform execution delay, initialize SPI bus */
	ISPProtocol_DelayMS(Enter_ISP_Params.ExecutionDelayMS);
	ISPTarget_EnableTargetISP();

	ISPTarget_ChangeTargetResetLine(true);
	ISPProtocol_DelayMS(Enter_ISP_Params.PinStabDelayMS);

	/* Continuously attempt to synchronize with the target until either the number of attempts specified
	 * by the host has exceeded, or the the device sends back the expected response values */
	while (Enter_ISP_Params.SynchLoops-- && TimeoutTicksRemaining)
	{
		uint8_t ResponseBytes[4];

		for (uint8_t RByte = 0; RByte < sizeof(ResponseBytes); RByte++)
		{
			ISPProtocol_DelayMS(Enter_ISP_Params.ByteDelay);
			ResponseBytes[RByte] = ISPTarget_TransferByte(Enter_ISP_Params.EnterProgBytes[RByte]);
		}

		/* Check if polling disabled, or if the polled value matches the expected value */
		if (!(Enter_ISP_Params.PollIndex) || (ResponseBytes[Enter_ISP_Params.PollIndex - 1] == Enter_ISP_Params.PollValue))
		{
			ResponseStatus = STATUS_CMD_OK;
			break;
		}
		else
		{
			ISPTarget_ChangeTargetResetLine(false);
			ISPProtocol_DelayMS(Enter_ISP_Params.PinStabDelayMS);
			ISPTarget_ChangeTargetResetLine(true);
			ISPProtocol_DelayMS(Enter_ISP_Params.PinStabDelayMS);
		}
	}

	Endpoint_Write_8(CMD_ENTER_PROGMODE_ISP);
	Endpoint_Write_8(ResponseStatus);
	Endpoint_ClearIN();
}
Ejemplo n.º 29
0
/** Handler for the XPROG WRITE_MEMORY command to write to a specific memory space within the attached device. */
static void XPROGProtocol_WriteMemory(void)
{
    uint8_t ReturnStatus = XPRG_ERR_OK;

    struct
    {
        uint8_t  MemoryType;
        uint8_t  PageMode;
        uint32_t Address;
        uint16_t Length;
        uint8_t  ProgData[256];
    } WriteMemory_XPROG_Params;

    Endpoint_Read_Stream_LE(&WriteMemory_XPROG_Params, (sizeof(WriteMemory_XPROG_Params) -
                            sizeof(WriteMemory_XPROG_Params).ProgData), NO_STREAM_CALLBACK);
    WriteMemory_XPROG_Params.Address = SwapEndian_32(WriteMemory_XPROG_Params.Address);
    WriteMemory_XPROG_Params.Length  = SwapEndian_16(WriteMemory_XPROG_Params.Length);
    Endpoint_Read_Stream_LE(&WriteMemory_XPROG_Params.ProgData, WriteMemory_XPROG_Params.Length, NO_STREAM_CALLBACK);

    Endpoint_ClearOUT();
    Endpoint_SelectEndpoint(AVRISP_DATA_IN_EPNUM);
    Endpoint_SetEndpointDirection(ENDPOINT_DIR_IN);

    if (XPROG_SelectedProtocol == XPRG_PROTOCOL_PDI)
    {
        /* Assume FLASH page programming by default, as it is the common case */
        uint8_t WriteCommand     = XMEGA_NVM_CMD_WRITEFLASHPAGE;
        uint8_t WriteBuffCommand = XMEGA_NVM_CMD_LOADFLASHPAGEBUFF;
        uint8_t EraseBuffCommand = XMEGA_NVM_CMD_ERASEFLASHPAGEBUFF;
        bool    PagedMemory      = true;

        switch (WriteMemory_XPROG_Params.MemoryType)
        {
        case XPRG_MEM_TYPE_APPL:
            WriteCommand     = XMEGA_NVM_CMD_WRITEAPPSECPAGE;
            break;
        case XPRG_MEM_TYPE_BOOT:
            WriteCommand     = XMEGA_NVM_CMD_WRITEBOOTSECPAGE;
            break;
        case XPRG_MEM_TYPE_EEPROM:
            WriteCommand     = XMEGA_NVM_CMD_ERASEWRITEEEPROMPAGE;
            WriteBuffCommand = XMEGA_NVM_CMD_LOADEEPROMPAGEBUFF;
            EraseBuffCommand = XMEGA_NVM_CMD_ERASEEEPROMPAGEBUFF;
            break;
        case XPRG_MEM_TYPE_USERSIG:
            /* User signature is paged, but needs us to manually indicate the mode bits since the host doesn't set them */
            WriteMemory_XPROG_Params.PageMode = (XPRG_PAGEMODE_ERASE | XPRG_PAGEMODE_WRITE);
            WriteCommand     = XMEGA_NVM_CMD_WRITEUSERSIG;
            break;
        case XPRG_MEM_TYPE_FUSE:
            WriteCommand     = XMEGA_NVM_CMD_WRITEFUSE;
            PagedMemory      = false;
            break;
        case XPRG_MEM_TYPE_LOCKBITS:
            WriteCommand     = XMEGA_NVM_CMD_WRITELOCK;
            PagedMemory      = false;
            break;
        }

        /* Send the appropriate memory write commands to the device, indicate timeout if occurred */
        if ((PagedMemory && !(XMEGANVM_WritePageMemory(WriteBuffCommand, EraseBuffCommand, WriteCommand,
                              WriteMemory_XPROG_Params.PageMode, WriteMemory_XPROG_Params.Address,
                              WriteMemory_XPROG_Params.ProgData, WriteMemory_XPROG_Params.Length))) ||
                (!PagedMemory && !(XMEGANVM_WriteByteMemory(WriteCommand, WriteMemory_XPROG_Params.Address,
                                   WriteMemory_XPROG_Params.ProgData[0]))))
        {
            ReturnStatus = XPRG_ERR_TIMEOUT;
        }
    }
    else
    {
        /* Send write command to the TPI device, indicate timeout if occurred */
        if (!(TINYNVM_WriteMemory(WriteMemory_XPROG_Params.Address, WriteMemory_XPROG_Params.ProgData,
                                  WriteMemory_XPROG_Params.Length)))
        {
            ReturnStatus = XPRG_ERR_TIMEOUT;
        }
    }

    Endpoint_Write_Byte(CMD_XPROG);
    Endpoint_Write_Byte(XPRG_CMD_WRITE_MEM);
    Endpoint_Write_Byte(ReturnStatus);
    Endpoint_ClearIN();
}