shithub: leaf

ref: 21f5ac6f65245a6d5f1b63b0f1a38d4001f1d5dc
dir: /LEAF/Src/usbh_MIDI.c/

View raw version
/**
 ******************************************************************************
 * @file    usbh_MIDI.c
 * @author	Xavier Halgand
 * @version
 * @date
 * @brief   This file is the MIDI Layer Handlers for USB Host MIDI streaming class.
 *
 *
 ******************************************************************************
 */

/*
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 *
 */
 
 /* WE MADE MODIFICATIONS TO PACTIVE CLASS SETTING IN USBH_CORE.C */

/* Includes ------------------------------------------------------------------*/
#include "usbh_MIDI.h"
#include "MIDI_Application.h"
/*------------------------------------------------------------------------------------------------------------------------------*/


/** @defgroup USBH_MIDI_CORE_Private_FunctionPrototypes
 * @{
 */

static USBH_StatusTypeDef USBH_MIDI_InterfaceInit  (USBH_HandleTypeDef *phost);

static USBH_StatusTypeDef USBH_MIDI_InterfaceDeInit  (USBH_HandleTypeDef *phost);

static USBH_StatusTypeDef USBH_MIDI_Process(USBH_HandleTypeDef *phost);

static USBH_StatusTypeDef USBH_MIDI_SOFProcess(USBH_HandleTypeDef *phost);

static USBH_StatusTypeDef USBH_MIDI_ClassRequest (USBH_HandleTypeDef *phost);

static void MIDI_ProcessTransmission(USBH_HandleTypeDef *phost);

static void MIDI_ProcessReception(USBH_HandleTypeDef *phost);

/*-------------------------------------------------------------------------*/

USBH_ClassTypeDef  MIDI_Class =
{
		"MIDI",
		USB_AUDIO_CLASS,
		USBH_MIDI_InterfaceInit,
		USBH_MIDI_InterfaceDeInit,
		USBH_MIDI_ClassRequest,
		USBH_MIDI_Process, // background process called in HOST_CLASS state (core state machine)
		USBH_MIDI_SOFProcess,
		NULL // MIDI handle structure
};

/*------------------------------------------------------------------------------------------------------------------------------*/

/**
 * @brief  USBH_MIDI_InterfaceInit
 *         The function init the MIDI class.
 * @param  phost: Host handle
 * @retval USBH Status
 */
static USBH_StatusTypeDef USBH_MIDI_InterfaceInit (USBH_HandleTypeDef *phost)
{	

	USBH_StatusTypeDef status = USBH_FAIL ;
	uint8_t interface = 0;
	MIDI_HandleTypeDef *MIDI_Handle;

	//USB_MIDI_ChangeConnectionState(0);

	interface = USBH_FindInterface(phost, USB_AUDIO_CLASS, USB_MIDISTREAMING_SubCLASS, 0xFF);

	if(interface == 0xFF) /* No Valid Interface */
	{
		USBH_DbgLog ("Cannot Find the interface for MIDI Interface Class.", phost->pActiveClass->Name);
		status = USBH_FAIL;
	}
	else
	{
		USBH_SelectInterface (phost, interface);

		phost->pActiveClass->pData = (MIDI_HandleTypeDef *)USBH_malloc (sizeof(MIDI_HandleTypeDef));
		MIDI_Handle =  phost->pActiveClass->pData;

		if(phost->device.CfgDesc.Itf_Desc[phost->device.current_interface].Ep_Desc[0].bEndpointAddress & 0x80)
		{
			MIDI_Handle->InEp = (phost->device.CfgDesc.Itf_Desc[phost->device.current_interface].Ep_Desc[0].bEndpointAddress);
			MIDI_Handle->InEpSize  = phost->device.CfgDesc.Itf_Desc[phost->device.current_interface].Ep_Desc[0].wMaxPacketSize;
		}
		else
		{
			MIDI_Handle->OutEp = (phost->device.CfgDesc.Itf_Desc[phost->device.current_interface].Ep_Desc[0].bEndpointAddress);
			MIDI_Handle->OutEpSize  = phost->device.CfgDesc.Itf_Desc[phost->device.current_interface].Ep_Desc[0].wMaxPacketSize;
		}

		if(phost->device.CfgDesc.Itf_Desc[phost->device.current_interface].Ep_Desc[1].bEndpointAddress & 0x80)
		{
			MIDI_Handle->InEp = (phost->device.CfgDesc.Itf_Desc[phost->device.current_interface].Ep_Desc[1].bEndpointAddress);
			MIDI_Handle->InEpSize  = phost->device.CfgDesc.Itf_Desc[phost->device.current_interface].Ep_Desc[1].wMaxPacketSize;
		}
		else
		{
			MIDI_Handle->OutEp = (phost->device.CfgDesc.Itf_Desc[phost->device.current_interface].Ep_Desc[1].bEndpointAddress);
			MIDI_Handle->OutEpSize  = phost->device.CfgDesc.Itf_Desc[phost->device.current_interface].Ep_Desc[1].wMaxPacketSize;
		}

		MIDI_Handle->OutPipe = USBH_AllocPipe(phost, MIDI_Handle->OutEp);
		MIDI_Handle->InPipe = USBH_AllocPipe(phost, MIDI_Handle->InEp);


		/* Open the new channels */
		USBH_OpenPipe  (phost,
				MIDI_Handle->OutPipe,
				MIDI_Handle->OutEp,
				phost->device.address,
				phost->device.speed,
				USB_EP_TYPE_BULK,
				MIDI_Handle->OutEpSize);

		USBH_OpenPipe  (phost,
				MIDI_Handle->InPipe,
				MIDI_Handle->InEp,
				phost->device.address,
				phost->device.speed,
				USB_EP_TYPE_BULK,
				MIDI_Handle->InEpSize);

		//USB_MIDI_ChangeConnectionState(1);
		MIDI_Handle->state = MIDI_IDLE_STATE;


		USBH_LL_SetToggle  (phost, MIDI_Handle->InPipe,0);
		USBH_LL_SetToggle  (phost, MIDI_Handle->OutPipe,0);
		status = USBH_OK;
	}
	return status;
}


/*------------------------------------------------------------------------------------------------------------------------------*/

/**
 * @brief  USBH_MIDI_InterfaceDeInit
 *         The function DeInit the Pipes used for the MIDI class.
 * @param  phost: Host handle
 * @retval USBH Status
 */
USBH_StatusTypeDef USBH_MIDI_InterfaceDeInit (USBH_HandleTypeDef *phost)
{
	MIDI_HandleTypeDef *MIDI_Handle =  phost->pActiveClass->pData;

	if ( MIDI_Handle->OutPipe)
	{
		USBH_ClosePipe(phost, MIDI_Handle->OutPipe);
		USBH_FreePipe  (phost, MIDI_Handle->OutPipe);
		MIDI_Handle->OutPipe = 0;     /* Reset the Channel as Free */
	}

	if ( MIDI_Handle->InPipe)
	{
		USBH_ClosePipe(phost, MIDI_Handle->InPipe);
		USBH_FreePipe  (phost, MIDI_Handle->InPipe);
		MIDI_Handle->InPipe = 0;     /* Reset the Channel as Free */
	}

	if(phost->pActiveClass->pData)
	{
		USBH_free (phost->pActiveClass->pData);
		phost->pActiveClass->pData = 0;
	}

	return USBH_OK;
}

/*------------------------------------------------------------------------------------------------------------------------------*/

/**
 * @brief  USBH_MIDI_ClassRequest
 *         The function is responsible for handling Standard requests
 *         for MIDI class.
 * @param  phost: Host handle
 * @retval USBH Status
 */
static USBH_StatusTypeDef USBH_MIDI_ClassRequest (USBH_HandleTypeDef *phost)
{   

	phost->pUser(phost, HOST_USER_CLASS_ACTIVE);

	return USBH_OK;
}

/*------------------------------------------------------------------------------------------------------------------------------*/

/**
  * @brief  USBH_MIDI_Stop
  *         Stop current MIDI Transmission
  * @param  phost: Host handle
  * @retval USBH Status
  */
USBH_StatusTypeDef  USBH_MIDI_Stop(USBH_HandleTypeDef *phost)
{
  MIDI_HandleTypeDef *MIDI_Handle =  phost->pActiveClass->pData;

  if(phost->gState == HOST_CLASS)
  {
    MIDI_Handle->state = MIDI_IDLE_STATE;

    USBH_ClosePipe(phost, MIDI_Handle->InPipe);
    USBH_ClosePipe(phost, MIDI_Handle->OutPipe);
  }
  return USBH_OK;
}

/*------------------------------------------------------------------------------------------------------------------------------*/

/**
 * @brief  USBH_MIDI_Process
 *         The function is for managing state machine for MIDI data transfers
 *         (background process)
 * @param  phost: Host handle
 * @retval USBH Status
 */
uint32_t transferCounter = 0;
static USBH_StatusTypeDef USBH_MIDI_Process (USBH_HandleTypeDef *phost)
{
	USBH_StatusTypeDef status = USBH_BUSY;
	USBH_StatusTypeDef req_status = USBH_OK;
	MIDI_HandleTypeDef *MIDI_Handle =  phost->pActiveClass->pData;

	switch(MIDI_Handle->state)
	{

	case MIDI_IDLE_STATE:
		status = USBH_OK;
		break;

	case MIDI_TRANSFER_DATA:

		MIDI_ProcessTransmission(phost);

		MIDI_ProcessReception(phost);

		status = USBH_OK;
		break;

	case MIDI_ERROR_STATE:
		req_status = USBH_ClrFeature(phost, 0x00);

		if(req_status == USBH_OK )
		{
			/*Change the state to waiting*/
			MIDI_Handle->state = MIDI_IDLE_STATE ;
		}
		break;

	default:
		break;

	}

	return status;
}
/*------------------------------------------------------------------------------------------------------------------------------*/

/**
  * @brief  USBH_MIDI_SOFProcess 
  *         The function is for managing SOF callback 
  * @param  phost: Host handle
  * @retval USBH Status
  */
static USBH_StatusTypeDef USBH_MIDI_SOFProcess (USBH_HandleTypeDef *phost)
{
	return USBH_OK;
}
  
/*------------------------------------------------------------------------------------------------------------------------------*/

/**
 * @brief  This function return last recieved data size
 * @param  None
 * @retval None
 */
uint32_t USBH_MIDI_GetLastReceivedDataSize(USBH_HandleTypeDef *phost)
{
	MIDI_HandleTypeDef *MIDI_Handle =  phost->pActiveClass->pData;

	if(phost->gState == HOST_CLASS)
	{
		return USBH_LL_GetLastXferSize(phost, MIDI_Handle->InPipe);
	}
	else
	{
		return 0;
	}
}

/*------------------------------------------------------------------------------------------------------------------------------*/

/**
 * @brief  This function prepares the state before issuing the class specific commands
 * @param  None
 * @retval None
 */
USBH_StatusTypeDef  USBH_MIDI_Transmit(USBH_HandleTypeDef *phost, uint8_t *pbuff, uint16_t length)
{
	USBH_StatusTypeDef Status = USBH_BUSY;
	MIDI_HandleTypeDef *MIDI_Handle =  phost->pActiveClass->pData;

	if((MIDI_Handle->state == MIDI_IDLE_STATE) || (MIDI_Handle->state == MIDI_TRANSFER_DATA))
	{
		MIDI_Handle->pTxData = pbuff;
		MIDI_Handle->TxDataLength = length;
		MIDI_Handle->state = MIDI_TRANSFER_DATA;
		MIDI_Handle->data_tx_state = MIDI_SEND_DATA;
		Status = USBH_OK;
#if (USBH_USE_OS == 1)
		osMessagePut ( phost->os_event, USBH_CLASS_EVENT, 0);
#endif
	}
	return Status;
}

/*------------------------------------------------------------------------------------------------------------------------------*/

/**
 * @brief  This function prepares the state before issuing the class specific commands
 * @param  None
 * @retval None
 */
uint8_t tempArray[32];
USBH_StatusTypeDef  USBH_MIDI_Receive(USBH_HandleTypeDef *phost, uint8_t *pbuff, uint16_t length)
{
	USBH_StatusTypeDef Status = USBH_BUSY;
	MIDI_HandleTypeDef *MIDI_Handle =  phost->pActiveClass->pData;

	if((MIDI_Handle->state == MIDI_IDLE_STATE) || (MIDI_Handle->state == MIDI_TRANSFER_DATA))
	{
		MIDI_Handle->pRxData = pbuff;
		MIDI_Handle->RxDataLength = length;
		MIDI_Handle->state = MIDI_TRANSFER_DATA;
		MIDI_Handle->data_rx_state = MIDI_RECEIVE_DATA;
		Status = USBH_OK;
#if (USBH_USE_OS == 1)
		osMessagePut ( phost->os_event, USBH_CLASS_EVENT, 0);
#endif
	}
	return Status;
}

/*------------------------------------------------------------------------------------------------------------------------------*/

/**
 * @brief  The function is responsible for sending data to the device
 *  @param  pdev: Selected device
 * @retval None
 */
static void MIDI_ProcessTransmission(USBH_HandleTypeDef *phost)
{
	MIDI_HandleTypeDef *MIDI_Handle =  phost->pActiveClass->pData;
	USBH_URBStateTypeDef URB_Status = USBH_URB_IDLE;

	switch(MIDI_Handle->data_tx_state)
	{

	case MIDI_SEND_DATA:
		if(MIDI_Handle->TxDataLength > MIDI_Handle->OutEpSize)
		{
			USBH_BulkSendData (phost,
					MIDI_Handle->pTxData,
					MIDI_Handle->OutEpSize,
					MIDI_Handle->OutPipe,
					1);
		}
		else
		{
			USBH_BulkSendData (phost,
					MIDI_Handle->pTxData,
					MIDI_Handle->TxDataLength,
					MIDI_Handle->OutPipe,
					1);
		}

		MIDI_Handle->data_tx_state = MIDI_SEND_DATA_WAIT;

		break;

	case MIDI_SEND_DATA_WAIT:

		URB_Status = USBH_LL_GetURBState(phost, MIDI_Handle->OutPipe);

		/*Check the status done for transmission*/
		if(URB_Status == USBH_URB_DONE )
		{
			if(MIDI_Handle->TxDataLength > MIDI_Handle->OutEpSize)
			{
				MIDI_Handle->TxDataLength -= MIDI_Handle->OutEpSize ;
				MIDI_Handle->pTxData += MIDI_Handle->OutEpSize;
			}
			else
			{
				MIDI_Handle->TxDataLength = 0;
			}

			if( MIDI_Handle->TxDataLength > 0)
			{
				MIDI_Handle->data_tx_state = MIDI_SEND_DATA;
			}
			else
			{
				MIDI_Handle->data_tx_state = MIDI_IDLE;
				USBH_MIDI_TransmitCallback(phost);
			}
#if (USBH_USE_OS == 1)
			osMessagePut ( phost->os_event, USBH_CLASS_EVENT, 0);
#endif
		}
		else if( URB_Status == USBH_URB_NOTREADY )
		{
			MIDI_Handle->data_tx_state = MIDI_SEND_DATA;
#if (USBH_USE_OS == 1)
			osMessagePut ( phost->os_event, USBH_CLASS_EVENT, 0);
#endif
		}
		break;
	default:
		break;
	}
}

/*------------------------------------------------------------------------------------------------------------------------------*/

/**
 * @brief  This function responsible for reception of data from the device
 *  @param  pdev: Selected device
 * @retval None
 */

uint32_t usbFailCounter = 0;
uint8_t fakeThing1 = 0;
uint32_t callbackCounter = 0;
uint32_t callbackFailCounter = 0;
uint8_t prevTestData[8] = {0};
uint8_t doTheThing = 0;
static void MIDI_ProcessReception(USBH_HandleTypeDef *phost)
{
	MIDI_HandleTypeDef *MIDI_Handle =  phost->pActiveClass->pData;
	USBH_URBStateTypeDef URB_Status = USBH_URB_IDLE;
	uint32_t length;

	switch(MIDI_Handle->data_rx_state)
	{

	case MIDI_RECEIVE_DATA:

		//should this happen first? use to be after the receive data command was issued
		MIDI_Handle->data_rx_state = MIDI_RECEIVE_DATA_WAIT;
		//
		USBH_BulkReceiveData (phost,
				MIDI_Handle->pRxData,
				MIDI_Handle->InEpSize,
				MIDI_Handle->InPipe);


		//BSP_LED_On(LED_Red); //ok only here

		break;

	case MIDI_RECEIVE_DATA_WAIT:

		URB_Status = USBH_LL_GetURBState(phost, MIDI_Handle->InPipe);

		/*Check the status done for reception*/
		if((URB_Status == USBH_URB_DONE ) )
		{

			usbFailCounter = 0;
			length = USBH_LL_GetLastXferSize(phost, MIDI_Handle->InPipe);

			if(((MIDI_Handle->RxDataLength - length) > 0) && (length > MIDI_Handle->InEpSize))
			{
				MIDI_Handle->RxDataLength -= length ;
				MIDI_Handle->pRxData += length;
				MIDI_Handle->data_rx_state = MIDI_RECEIVE_DATA;
			}
			else
			{
				MIDI_Handle->data_rx_state = MIDI_IDLE;
				USBH_MIDI_ReceiveCallback(phost, length);
			}

#if (USBH_USE_OS == 1)
			osMessagePut ( phost->os_event, USBH_CLASS_EVENT, 0);
#endif
		}
		break;

	default:
		break;
	}
}


/*------------------------------------------------------------------------------------------------------------------------------*/

/**
 * @brief  The function informs user that data have been transmitted.
 *  @param  pdev: Selected device
 * @retval None
 */
__weak void USBH_MIDI_TransmitCallback(USBH_HandleTypeDef *phost)
{

}

/*------------------------------------------------------------------------------------------------------------------------------*/

/**
 * @brief  The function informs user that data have been received.
 * @retval None
 */
__weak void USBH_MIDI_ReceiveCallback(USBH_HandleTypeDef *phost, uint32_t myLength)
{

}

/**************************END OF FILE*********************************************************/