/**
******************************************************************************
* @file usbh_mtp_ptp.c
* @author MCD Application Team
* @brief This file includes the PTP operations layer
******************************************************************************
* @attention
*
*
© Copyright (c) 2015 STMicroelectronics.
* All rights reserved.
*
* This software component is licensed by ST under Ultimate Liberty license
* SLA0044, the "License"; You may not use this file except in compliance with
* the License. You may obtain a copy of the License at:
* www.st.com/SLA0044
*
******************************************************************************
*/
/* BSPDependencies
- "stm32xxxxx_{eval}{discovery}.c"
- "stm32xxxxx_{eval}{discovery}_io.c"
- "stm32xxxxx_{eval}{discovery}_audio.c"
- "stm32xxxxx_{eval}{discovery}_sd.c"
- "stm32xxxxx_{eval}{discovery}_lcd.c"
- "stm32xxxxx_{eval}{discovery}_sdram.c"
EndBSPDependencies */
/* Includes ------------------------------------------------------------------*/
#include "usbh_mtp_ptp.h"
#include "usbh_mtp.h"
/** @addtogroup USBH_LIB
* @{
*/
/** @addtogroup USBH_CLASS
* @{
*/
/** @addtogroup USBH_MTP_CLASS
* @{
*/
/** @defgroup USBH_MTP_PTP
* @brief This file includes the mass storage related functions
* @{
*/
/** @defgroup USBH_MTP_PTP_Private_TypesDefinitions
* @{
*/
/**
* @}
*/
/** @defgroup USBH_MTP_PTP_Private_Defines
* @{
*/
/**
* @}
*/
/** @defgroup USBH_MTP_PTP_Private_Macros
* @{
*/
/**
* @}
*/
/** @defgroup USBH_MTP_PTP_Private_Variables
* @{
*/
/**
* @}
*/
/** @defgroup USBH_MTP_PTP_Private_FunctionPrototypes
* @{
*/
static void PTP_DecodeDeviceInfo(USBH_HandleTypeDef *phost, PTP_DeviceInfoTypedef *dev_info);
static void PTP_GetStorageIDs(USBH_HandleTypeDef *phost, PTP_StorageIDsTypedef *stor_ids);
static void PTP_GetStorageInfo(USBH_HandleTypeDef *phost, uint32_t storage_id, PTP_StorageInfoTypedef *stor_info);
static void PTP_GetObjectInfo(USBH_HandleTypeDef *phost, PTP_ObjectInfoTypedef *object_info);
static void PTP_GetObjectPropDesc(USBH_HandleTypeDef *phost, PTP_ObjectPropDescTypeDef *opd, uint32_t opdlen);
static void PTP_DecodeDeviceInfo(USBH_HandleTypeDef *phost, PTP_DeviceInfoTypedef *dev_info);
static void PTP_GetDevicePropValue(USBH_HandleTypeDef *phost, uint32_t *offset,
uint32_t total, PTP_PropertyValueTypedef *value, uint16_t datatype);
static uint32_t PTP_GetObjectPropList(USBH_HandleTypeDef *phost,
MTP_PropertiesTypedef *props,
uint32_t len);
static void PTP_BufferFullCallback(USBH_HandleTypeDef *phost);
static void PTP_GetString(uint8_t *str, uint8_t *data, uint16_t *len);
static uint32_t PTP_GetArray16(uint16_t *array, uint8_t *data, uint32_t offset);
static uint32_t PTP_GetArray32(uint32_t *array, uint8_t *data, uint32_t offset);
/**
* @}
*/
/** @defgroup USBH_MTP_PTP_Exported_Variables
* @{
*/
/**
* @}
*/
/** @defgroup USBH_MTP_PTP_Private_Functions
* @{
*/
/**
* @brief USBH_PTP_Init
* The function Initializes the BOT protocol.
* @param phost: Host handle
* @retval USBH Status
*/
USBH_StatusTypeDef USBH_PTP_Init(USBH_HandleTypeDef *phost)
{
MTP_HandleTypeDef *MTP_Handle = (MTP_HandleTypeDef *)phost->pActiveClass->pData;
/* Set state to idle to be ready for operations */
MTP_Handle->ptp.state = PTP_IDLE;
MTP_Handle->ptp.req_state = PTP_REQ_SEND;
return USBH_OK;
}
/**
* @brief USBH_PTP_Process
* The function handle the BOT protocol.
* @param phost: Host handle
* @param lun: Logical Unit Number
* @retval USBH Status
*/
USBH_StatusTypeDef USBH_PTP_Process(USBH_HandleTypeDef *phost)
{
USBH_StatusTypeDef status = USBH_BUSY;
USBH_URBStateTypeDef URB_Status = USBH_URB_IDLE;
MTP_HandleTypeDef *MTP_Handle = (MTP_HandleTypeDef *)phost->pActiveClass->pData;
PTP_ContainerTypedef ptp_container;
uint32_t len;
switch (MTP_Handle->ptp.state)
{
case PTP_IDLE:
/*Do Nothing */
break;
case PTP_OP_REQUEST_STATE:
USBH_BulkSendData(phost,
(uint8_t *)(void *) & (MTP_Handle->ptp.op_container),
(uint16_t)MTP_Handle->ptp.op_container.length,
MTP_Handle->DataOutPipe,
1U);
MTP_Handle->ptp.state = PTP_OP_REQUEST_WAIT_STATE;
break;
case PTP_OP_REQUEST_WAIT_STATE:
URB_Status = USBH_LL_GetURBState(phost, MTP_Handle->DataOutPipe);
if (URB_Status == USBH_URB_DONE)
{
if (MTP_Handle->ptp.flags == PTP_DP_NODATA)
{
MTP_Handle->ptp.state = PTP_RESPONSE_STATE;
}
else if (MTP_Handle->ptp.flags == PTP_DP_SENDDATA)
{
MTP_Handle->ptp.state = PTP_DATA_OUT_PHASE_STATE;
}
else if (MTP_Handle->ptp.flags == PTP_DP_GETDATA)
{
MTP_Handle->ptp.state = PTP_DATA_IN_PHASE_STATE;
}
else
{
}
#if (USBH_USE_OS == 1U)
phost->os_msg = (uint32_t)USBH_URB_EVENT;
#if (osCMSIS < 0x20000U)
(void)osMessagePut(phost->os_event, phost->os_msg, 0U);
#else
(void)osMessageQueuePut(phost->os_event, &phost->os_msg, 0U, NULL);
#endif
#endif
}
else if (URB_Status == USBH_URB_NOTREADY)
{
/* Resend Request */
MTP_Handle->ptp.state = PTP_OP_REQUEST_STATE;
#if (USBH_USE_OS == 1U)
phost->os_msg = (uint32_t)USBH_URB_EVENT;
#if (osCMSIS < 0x20000U)
(void)osMessagePut(phost->os_event, phost->os_msg, 0U);
#else
(void)osMessageQueuePut(phost->os_event, &phost->os_msg, 0U, NULL);
#endif
#endif
}
else if (URB_Status == USBH_URB_STALL)
{
MTP_Handle->ptp.state = PTP_ERROR;
#if (USBH_USE_OS == 1U)
phost->os_msg = (uint32_t)USBH_URB_EVENT;
#if (osCMSIS < 0x20000U)
(void)osMessagePut(phost->os_event, phost->os_msg, 0U);
#else
(void)osMessageQueuePut(phost->os_event, &phost->os_msg, 0U, NULL);
#endif
#endif
}
else
{
}
break;
case PTP_DATA_OUT_PHASE_STATE:
USBH_BulkSendData(phost,
MTP_Handle->ptp.data_ptr,
MTP_Handle->DataOutEpSize,
MTP_Handle->DataOutPipe,
1U);
MTP_Handle->ptp.state = PTP_DATA_OUT_PHASE_WAIT_STATE;
break;
case PTP_DATA_OUT_PHASE_WAIT_STATE:
URB_Status = USBH_LL_GetURBState(phost, MTP_Handle->DataOutPipe);
if (URB_Status == USBH_URB_DONE)
{
/* Adjust Data pointer and data length */
if (MTP_Handle->ptp.data_length > MTP_Handle->DataOutEpSize)
{
MTP_Handle->ptp.data_ptr += MTP_Handle->DataOutEpSize;
MTP_Handle->ptp.data_length -= MTP_Handle->DataOutEpSize;
MTP_Handle->ptp.data_packet += MTP_Handle->DataOutEpSize;
if (MTP_Handle->ptp.data_packet >= PTP_USB_BULK_PAYLOAD_LEN_READ)
{
PTP_BufferFullCallback(phost);
MTP_Handle->ptp.data_packet = 0U;
MTP_Handle->ptp.iteration++;
}
}
else
{
MTP_Handle->ptp.data_length = 0U;
}
/* More Data To be Sent */
if (MTP_Handle->ptp.data_length > 0U)
{
USBH_BulkSendData(phost,
MTP_Handle->ptp.data_ptr,
MTP_Handle->DataOutEpSize,
MTP_Handle->DataOutPipe,
1U);
}
else
{
/* If value was 0, and successful transfer, then change the state */
MTP_Handle->ptp.state = PTP_RESPONSE_STATE;
}
#if (USBH_USE_OS == 1U)
phost->os_msg = (uint32_t)USBH_URB_EVENT;
#if (osCMSIS < 0x20000U)
(void)osMessagePut(phost->os_event, phost->os_msg, 0U);
#else
(void)osMessageQueuePut(phost->os_event, &phost->os_msg, 0U, NULL);
#endif
#endif
}
else if (URB_Status == USBH_URB_NOTREADY)
{
/* Resend same data */
MTP_Handle->ptp.state = PTP_DATA_OUT_PHASE_STATE;
#if (USBH_USE_OS == 1U)
phost->os_msg = (uint32_t)USBH_URB_EVENT;
#if (osCMSIS < 0x20000U)
(void)osMessagePut(phost->os_event, phost->os_msg, 0U);
#else
(void)osMessageQueuePut(phost->os_event, &phost->os_msg, 0U, NULL);
#endif
#endif
}
else if (URB_Status == USBH_URB_STALL)
{
MTP_Handle->ptp.state = PTP_ERROR;
#if (USBH_USE_OS == 1U)
phost->os_msg = (uint32_t)USBH_URB_EVENT;
#if (osCMSIS < 0x20000U)
(void)osMessagePut(phost->os_event, phost->os_msg, 0U);
#else
(void)osMessageQueuePut(phost->os_event, &phost->os_msg, 0U, NULL);
#endif
#endif
}
else
{
/* .. */
}
break;
case PTP_DATA_IN_PHASE_STATE:
/* Send first packet */
USBH_BulkReceiveData(phost,
MTP_Handle->ptp.data_ptr,
MTP_Handle->DataInEpSize,
MTP_Handle->DataInPipe);
MTP_Handle->ptp.state = PTP_DATA_IN_PHASE_WAIT_STATE;
break;
case PTP_DATA_IN_PHASE_WAIT_STATE:
URB_Status = USBH_LL_GetURBState(phost, MTP_Handle->DataInPipe);
if (URB_Status == USBH_URB_DONE)
{
len = USBH_LL_GetLastXferSize(phost, MTP_Handle->DataInPipe);
if (MTP_Handle->ptp.data_packet_counter++ == 0U)
{
/* This is the first packet; so retrieve exact data length from payload */
MTP_Handle->ptp.data_length = *(uint32_t *)(void *)(MTP_Handle->ptp.data_ptr);
MTP_Handle->ptp.iteration = 0U;
}
if ((len >= MTP_Handle->DataInEpSize) && (MTP_Handle->ptp.data_length > 0U))
{
MTP_Handle->ptp.data_ptr += len;
MTP_Handle->ptp.data_length -= len;
MTP_Handle->ptp.data_packet += len;
if (MTP_Handle->ptp.data_packet >= PTP_USB_BULK_PAYLOAD_LEN_READ)
{
PTP_BufferFullCallback(phost);
MTP_Handle->ptp.data_packet = 0U;
MTP_Handle->ptp.iteration++;
}
/* Continue receiving data*/
USBH_BulkReceiveData(phost,
MTP_Handle->ptp.data_ptr,
MTP_Handle->DataInEpSize,
MTP_Handle->DataInPipe);
}
else
{
MTP_Handle->ptp.data_length -= len;
MTP_Handle->ptp.state = PTP_RESPONSE_STATE;
#if (USBH_USE_OS == 1U)
phost->os_msg = (uint32_t)USBH_URB_EVENT;
#if (osCMSIS < 0x20000U)
(void)osMessagePut(phost->os_event, phost->os_msg, 0U);
#else
(void)osMessageQueuePut(phost->os_event, &phost->os_msg, 0U, NULL);
#endif
#endif
}
}
else if (URB_Status == USBH_URB_STALL)
{
MTP_Handle->ptp.state = PTP_ERROR;
#if (USBH_USE_OS == 1U)
phost->os_msg = (uint32_t)USBH_URB_EVENT;
#if (osCMSIS < 0x20000U)
(void)osMessagePut(phost->os_event, phost->os_msg, 0U);
#else
(void)osMessageQueuePut(phost->os_event, &phost->os_msg, 0U, NULL);
#endif
#endif
}
else
{
/* .. */
}
break;
case PTP_RESPONSE_STATE:
USBH_BulkReceiveData(phost,
(uint8_t *)(void *) & (MTP_Handle->ptp.resp_container),
PTP_USB_BULK_REQ_RESP_MAX_LEN,
MTP_Handle->DataInPipe);
MTP_Handle->ptp.state = PTP_RESPONSE_WAIT_STATE;
break;
case PTP_RESPONSE_WAIT_STATE:
URB_Status = USBH_LL_GetURBState(phost, MTP_Handle->DataInPipe);
if (URB_Status == USBH_URB_DONE)
{
USBH_PTP_GetResponse(phost, &ptp_container);
if (ptp_container.Code == PTP_RC_OK)
{
status = USBH_OK;
}
else
{
status = USBH_FAIL;
}
MTP_Handle->ptp.req_state = PTP_REQ_SEND;
}
else if (URB_Status == USBH_URB_STALL)
{
MTP_Handle->ptp.state = PTP_ERROR;
#if (USBH_USE_OS == 1U)
phost->os_msg = (uint32_t)USBH_URB_EVENT;
#if (osCMSIS < 0x20000U)
(void)osMessagePut(phost->os_event, phost->os_msg, 0U);
#else
(void)osMessageQueuePut(phost->os_event, &phost->os_msg, 0U, NULL);
#endif
#endif
}
else
{
/* .. */
}
break;
case PTP_ERROR:
MTP_Handle->ptp.req_state = PTP_REQ_SEND;
break;
default:
break;
}
return status;
}
/**
* @brief USBH_PTP_OpenSession
* Open a new session
* @param phost: Host handle
* @retval USBH Status
*/
USBH_StatusTypeDef USBH_PTP_SendRequest(USBH_HandleTypeDef *phost, PTP_ContainerTypedef *req)
{
USBH_StatusTypeDef status = USBH_OK;
MTP_HandleTypeDef *MTP_Handle = (MTP_HandleTypeDef *)phost->pActiveClass->pData;
/* Clear PTP Data container*/
USBH_memset(&(MTP_Handle->ptp.op_container), 0, sizeof(PTP_OpContainerTypedef));
/* build appropriate USB container */
MTP_Handle->ptp.op_container.length = PTP_USB_BULK_REQ_LEN - (sizeof(uint32_t) * (5U - req->Nparam));
MTP_Handle->ptp.op_container.type = PTP_USB_CONTAINER_COMMAND;
MTP_Handle->ptp.op_container.code = req->Code;
MTP_Handle->ptp.op_container.trans_id = req->Transaction_ID;
MTP_Handle->ptp.op_container.param1 = req->Param1;
MTP_Handle->ptp.op_container.param2 = req->Param2;
MTP_Handle->ptp.op_container.param3 = req->Param3;
MTP_Handle->ptp.op_container.param4 = req->Param4;
MTP_Handle->ptp.op_container.param5 = req->Param5;
return status;
}
/**
* @brief USBH_PTP_OpenSession
* Open a new session
* @param phost: Host handle
* @retval USBH Status
*/
USBH_StatusTypeDef USBH_PTP_GetResponse(USBH_HandleTypeDef *phost, PTP_ContainerTypedef *resp)
{
USBH_StatusTypeDef status = USBH_OK;
MTP_HandleTypeDef *MTP_Handle = (MTP_HandleTypeDef *)phost->pActiveClass->pData;
/* build an appropriate PTPContainer */
resp->Code = MTP_Handle->ptp.resp_container.code;
resp->SessionID = MTP_Handle->ptp.session_id;
resp->Transaction_ID = MTP_Handle->ptp.resp_container.trans_id;
resp->Param1 = MTP_Handle->ptp.resp_container.param1;
resp->Param2 = MTP_Handle->ptp.resp_container.param2;
resp->Param3 = MTP_Handle->ptp.resp_container.param3;
resp->Param4 = MTP_Handle->ptp.resp_container.param4;
resp->Param5 = MTP_Handle->ptp.resp_container.param5;
return status;
}
/**
* @brief The function informs user that data buffer is full
* @param phost: host handle
* @retval None
*/
static void PTP_BufferFullCallback(USBH_HandleTypeDef *phost)
{
MTP_HandleTypeDef *MTP_Handle = (MTP_HandleTypeDef *)phost->pActiveClass->pData;
switch (MTP_Handle->ptp.data_container.code)
{
case PTP_OC_GetDeviceInfo:
PTP_DecodeDeviceInfo(phost, &(MTP_Handle->info.devinfo));
break;
case PTP_OC_GetPartialObject:
case PTP_OC_GetObject:
/* first packet is in the PTP data payload buffer */
if (MTP_Handle->ptp.iteration == 0U)
{
/* copy it to object */
USBH_memcpy(MTP_Handle->ptp.object_ptr, MTP_Handle->ptp.data_container.payload.data, PTP_USB_BULK_PAYLOAD_LEN_READ);
/* next packet should be directly copied to object */
MTP_Handle->ptp.data_ptr = (MTP_Handle->ptp.object_ptr + PTP_USB_BULK_PAYLOAD_LEN_READ);
}
break;
case PTP_OC_SendObject:
/* first packet is in the PTP data payload buffer */
if (MTP_Handle->ptp.iteration == 0U)
{
/* next packet should be directly copied to object */
MTP_Handle->ptp.data_ptr = (MTP_Handle->ptp.object_ptr + PTP_USB_BULK_PAYLOAD_LEN_READ);
}
break;
default:
break;
}
}
/**
* @brief PTP_GetDeviceInfo
* Gets device info dataset and fills deviceinfo structure.
* @param phost: Host handle
* @param dev_info: Device info structure
* @retval None
*/
static void PTP_DecodeDeviceInfo(USBH_HandleTypeDef *phost, PTP_DeviceInfoTypedef *dev_info)
{
MTP_HandleTypeDef *MTP_Handle = (MTP_HandleTypeDef *)phost->pActiveClass->pData;
uint8_t *data = MTP_Handle->ptp.data_container.payload.data;
uint32_t totallen;
uint16_t len;
/* Max device info is PTP_USB_BULK_HS_MAX_PACKET_LEN_READ */
USBH_DbgLog(" MTP device info size exceeds internal buffer size.\
only available data are decoded.");
if (MTP_Handle->ptp.iteration == 0U)
{
dev_info->StandardVersion = LE16(&data[PTP_di_StandardVersion]);
dev_info->VendorExtensionID = LE32(&data[PTP_di_VendorExtensionID]);
dev_info->VendorExtensionVersion = LE16(&data[PTP_di_VendorExtensionVersion]);
PTP_GetString(dev_info->VendorExtensionDesc, &data[PTP_di_VendorExtensionDesc], &len);
totallen = len * 2U + 1U;
dev_info->FunctionalMode = LE16(&data[PTP_di_FunctionalMode + totallen]);
dev_info->OperationsSupported_len = PTP_GetArray16((uint16_t *)(void *)&dev_info->OperationsSupported,
data, PTP_di_OperationsSupported + totallen);
totallen = totallen + dev_info->OperationsSupported_len * sizeof(uint16_t) + sizeof(uint32_t);
dev_info->EventsSupported_len = PTP_GetArray16((uint16_t *)(void *)&dev_info->EventsSupported,
data, PTP_di_OperationsSupported + totallen);
totallen = totallen + dev_info->EventsSupported_len * sizeof(uint16_t) + sizeof(uint32_t);
dev_info->DevicePropertiesSupported_len = PTP_GetArray16((uint16_t *)(void *)&dev_info->DevicePropertiesSupported,
data, PTP_di_OperationsSupported + totallen);
totallen = totallen + dev_info->DevicePropertiesSupported_len * sizeof(uint16_t) + sizeof(uint32_t);
dev_info->CaptureFormats_len = PTP_GetArray16((uint16_t *)(void *)&dev_info->CaptureFormats,
data, PTP_di_OperationsSupported + totallen);
totallen = totallen + dev_info->CaptureFormats_len * sizeof(uint16_t) + sizeof(uint32_t);
dev_info->ImageFormats_len = PTP_GetArray16((uint16_t *)(void *)&dev_info->ImageFormats,
data, PTP_di_OperationsSupported + totallen);
totallen = totallen + dev_info->ImageFormats_len * sizeof(uint16_t) + sizeof(uint32_t);
PTP_GetString(dev_info->Manufacturer, &data[PTP_di_OperationsSupported + totallen], &len);
totallen += len * 2U + 1U;
PTP_GetString(dev_info->Model, &data[PTP_di_OperationsSupported + totallen], &len);
totallen += len * 2U + 1U;
PTP_GetString(dev_info->DeviceVersion, &data[PTP_di_OperationsSupported + totallen], &len);
totallen += len * 2U + 1U;
PTP_GetString(dev_info->SerialNumber, &data[PTP_di_OperationsSupported + totallen], &len);
}
}
/**
* @brief PTP_GetStorageIDs
* Gets Storage Ids and fills stor_ids structure.
* @param phost: Host handle
* @param stor_ids: Storage IDsstructure
* @retval None
*/
static void PTP_GetStorageIDs(USBH_HandleTypeDef *phost, PTP_StorageIDsTypedef *stor_ids)
{
MTP_HandleTypeDef *MTP_Handle = (MTP_HandleTypeDef *)phost->pActiveClass->pData;
uint8_t *data = MTP_Handle->ptp.data_container.payload.data;
stor_ids->n = PTP_GetArray32(stor_ids->Storage, data, 0U);
}
/**
* @brief PTP_GetStorageInfo
* Gets Storage Info and fills stor_info structure.
* @param phost: Host handle
* @param stor_ids: Storage IDsstructure
* @retval None
*/
static void PTP_GetStorageInfo(USBH_HandleTypeDef *phost, uint32_t storage_id, PTP_StorageInfoTypedef *stor_info)
{
/* Prevent unused argument(s) compilation warning */
UNUSED(storage_id);
MTP_HandleTypeDef *MTP_Handle = (MTP_HandleTypeDef *)phost->pActiveClass->pData;
uint8_t *data = MTP_Handle->ptp.data_container.payload.data;
uint16_t len;
stor_info->StorageType = LE16(&data[PTP_si_StorageType]);
stor_info->FilesystemType = LE16(&data[PTP_si_FilesystemType]);
stor_info->AccessCapability = LE16(&data[PTP_si_AccessCapability]);
stor_info->MaxCapability = LE64(&data[PTP_si_MaxCapability]);
stor_info->FreeSpaceInBytes = LE64(&data[PTP_si_FreeSpaceInBytes]);
stor_info->FreeSpaceInImages = LE32(&data[PTP_si_FreeSpaceInImages]);
PTP_GetString(stor_info->StorageDescription, &data[PTP_si_StorageDescription], &len);
PTP_GetString(stor_info->VolumeLabel, &data[PTP_si_StorageDescription + len * 2U + 1U], &len);
}
/**
* @brief PTP_GetObjectInfo
* Gets objectInfo and fills object_info structure.
* @param phost: Host handle
* @param object_info: object info structure
* @retval None
*/
static void PTP_GetObjectInfo(USBH_HandleTypeDef *phost, PTP_ObjectInfoTypedef *object_info)
{
MTP_HandleTypeDef *MTP_Handle = (MTP_HandleTypeDef *)phost->pActiveClass->pData;
uint8_t *data = MTP_Handle->ptp.data_container.payload.data;
uint16_t filenamelen;
object_info->StorageID = LE32(&data[PTP_oi_StorageID]);
object_info->ObjectFormat = LE16(&data[PTP_oi_ObjectFormat]);
object_info->ProtectionStatus = LE16(&data[PTP_oi_ProtectionStatus]);
object_info->ObjectCompressedSize = LE64(&data[PTP_oi_ObjectCompressedSize]);
/* For Samsung Galaxy */
if ((data[PTP_oi_filenamelen] == 0U) && (data[PTP_oi_filenamelen + 4U] != 0U))
{
data += 4;
}
object_info->ThumbFormat = LE16(&data[PTP_oi_ThumbFormat]);
object_info->ThumbCompressedSize = LE32(&data[PTP_oi_ThumbCompressedSize]);
object_info->ThumbPixWidth = LE32(&data[PTP_oi_ThumbPixWidth]);
object_info->ThumbPixHeight = LE32(&data[PTP_oi_ThumbPixHeight]);
object_info->ImagePixWidth = LE32(&data[PTP_oi_ImagePixWidth]);
object_info->ImagePixHeight = LE32(&data[PTP_oi_ImagePixHeight]);
object_info->ImageBitDepth = LE32(&data[PTP_oi_ImageBitDepth]);
object_info->ParentObject = LE32(&data[PTP_oi_ParentObject]);
object_info->AssociationType = LE16(&data[PTP_oi_AssociationType]);
object_info->AssociationDesc = LE32(&data[PTP_oi_AssociationDesc]);
object_info->SequenceNumber = LE32(&data[PTP_oi_SequenceNumber]);
PTP_GetString(object_info->Filename, &data[PTP_oi_filenamelen], &filenamelen);
}
/**
* @brief PTP_GetObjectPropDesc
* Gets objectInfo and fills object_info structure.
* @param phost: Host handle
* @param opd: object prop descriptor structure
* @retval None
*/
static void PTP_GetObjectPropDesc(USBH_HandleTypeDef *phost, PTP_ObjectPropDescTypeDef *opd, uint32_t opdlen)
{
MTP_HandleTypeDef *MTP_Handle = (MTP_HandleTypeDef *)phost->pActiveClass->pData;
uint8_t *data = MTP_Handle->ptp.data_container.payload.data;
uint32_t offset = 0U, i;
opd->ObjectPropertyCode = LE16(&data[PTP_opd_ObjectPropertyCode]);
opd->DataType = LE16(&data[PTP_opd_DataType]);
opd->GetSet = *(uint8_t *)(&data[PTP_opd_GetSet]);
offset = PTP_opd_FactoryDefaultValue;
PTP_GetDevicePropValue(phost, &offset, opdlen, &opd->FactoryDefaultValue, opd->DataType);
opd->GroupCode = LE32(&data[offset]);
offset += sizeof(uint32_t);
opd->FormFlag = *(uint8_t *)(&data[offset]);
offset += sizeof(uint8_t);
switch (opd->FormFlag)
{
case PTP_OPFF_Range:
PTP_GetDevicePropValue(phost, &offset, opdlen, &opd->FORM.Range.MinimumValue, opd->DataType);
PTP_GetDevicePropValue(phost, &offset, opdlen, &opd->FORM.Range.MaximumValue, opd->DataType);
PTP_GetDevicePropValue(phost, &offset, opdlen, &opd->FORM.Range.StepSize, opd->DataType);
break;
case PTP_OPFF_Enumeration:
opd->FORM.Enum.NumberOfValues = LE16(&data[offset]);
offset += sizeof(uint16_t);
for (i = 0U; i < opd->FORM.Enum.NumberOfValues ; i++)
{
PTP_GetDevicePropValue(phost, &offset, opdlen, &opd->FORM.Enum.SupportedValue[i], opd->DataType);
}
break;
default:
break;
}
}
/**
* @brief PTP_GetDevicePropValue
* Gets objectInfo and fills object_info structure.
* @param phost: Host handle
* @param opd: object prop descriptor structure
* @retval None
*/
static void PTP_GetDevicePropValue(USBH_HandleTypeDef *phost,
uint32_t *offset,
uint32_t total,
PTP_PropertyValueTypedef *value,
uint16_t datatype)
{
/* Prevent unused argument(s) compilation warning */
UNUSED(total);
MTP_HandleTypeDef *MTP_Handle = (MTP_HandleTypeDef *)phost->pActiveClass->pData;
uint8_t *data = MTP_Handle->ptp.data_container.payload.data;
uint16_t len;
switch (datatype)
{
case PTP_DTC_INT8:
value->i8 = *(int8_t *)(void *) &(data[*offset]);
*offset += 1U;
break;
case PTP_DTC_UINT8:
value->u8 = *(uint8_t *) &(data[*offset]);
*offset += 1U;
break;
case PTP_DTC_INT16:
value->i16 = *(int16_t *)(void *) &(data[*offset]);
*offset += 2U;
break;
case PTP_DTC_UINT16:
value->u16 = LE16(&(data[*offset]));
*offset += 2U;
break;
case PTP_DTC_INT32:
value->i32 = *(int32_t *)(void *)(&(data[*offset]));
*offset += 4U;
break;
case PTP_DTC_UINT32:
value->u32 = LE32(&(data[*offset]));
*offset += 4U;
break;
case PTP_DTC_INT64:
value->i64 = *(int64_t *)(void *)(&(data[*offset]));
*offset += 8U;
break;
case PTP_DTC_UINT64:
value->u64 = LE64(&(data[*offset]));
*offset += 8U;
break;
case PTP_DTC_UINT128:
*offset += 16U;
break;
case PTP_DTC_INT128:
*offset += 16U;
break;
case PTP_DTC_STR:
PTP_GetString((uint8_t *)(void *)value->str, (uint8_t *) & (data[*offset]), &len);
*offset += len * 2U + 1U;
break;
default:
break;
}
}
/**
* @brief PTP_GetDevicePropValue
* Gets objectInfo and fills object_info structure.
* @param phost: Host handle
* @param opd: object prop descriptor structure
* @retval None
*/
static uint32_t PTP_GetObjectPropList(USBH_HandleTypeDef *phost,
MTP_PropertiesTypedef *props,
uint32_t len)
{
MTP_HandleTypeDef *MTP_Handle = (MTP_HandleTypeDef *)phost->pActiveClass->pData;
uint8_t *data = MTP_Handle->ptp.data_container.payload.data;
uint32_t prop_count;
uint32_t offset = 0U, i;
prop_count = LE32(data);
if (prop_count == 0U)
{
return 0U;
}
data += sizeof(uint32_t);
len -= sizeof(uint32_t);
for (i = 0U; i < prop_count; i++)
{
if (len <= 0U)
{
return 0U;
}
props[i].ObjectHandle = LE32(data);
data += sizeof(uint32_t);
len -= sizeof(uint32_t);
props[i].property = LE16(data);
data += sizeof(uint16_t);
len -= sizeof(uint16_t);
props[i].datatype = LE16(data);
data += sizeof(uint16_t);
len -= sizeof(uint16_t);
offset = 0U;
PTP_GetDevicePropValue(phost, &offset, len, &props[i].propval, props[i].datatype);
data += offset;
len -= offset;
}
return prop_count;
}
/**
* @brief PTP_GetString
* Gets SCII String from.
* @param str: ascii string
* @param data: Device info structure
* @retval None
*/
static void PTP_GetString(uint8_t *str, uint8_t *data, uint16_t *len)
{
uint16_t strlength;
uint16_t idx;
*len = data[0];
strlength = (uint16_t)(2U * (uint32_t)data[0]);
data ++; /* Adjust the offset ignoring the String Len */
for (idx = 0U; idx < strlength; idx += 2U)
{
/* Copy Only the string and ignore the UNICODE ID, hence add the src */
*str = data[idx];
str++;
}
*str = 0U; /* mark end of string */
}
/**
* @brief PTP_GetString
* Gets SCII String from.
* @param str: ascii string
* @param data: Device info structure
* @retval None
*/
static uint32_t PTP_GetArray16(uint16_t *array, uint8_t *data, uint32_t offset)
{
uint32_t size, idx = 0U;
size = LE32(&data[offset]);
while (size > idx)
{
array[idx] = (uint16_t)data[offset + (sizeof(uint16_t) * (idx + 2U))];
idx++;
}
return size;
}
/**
* @brief PTP_GetString
* Gets SCII String from.
* @param str: ascii string
* @param data: Device info structure
* @retval None
*/
static uint32_t PTP_GetArray32(uint32_t *array, uint8_t *data, uint32_t offset)
{
uint32_t size, idx = 0U;
size = LE32(&data[offset]);
while (size > idx)
{
array[idx] = LE32(&data[offset + (sizeof(uint32_t) * (idx + 1U))]);
idx++;
}
return size;
}
/*******************************************************************************
PTP Requests
*******************************************************************************/
/**
* @brief USBH_PTP_OpenSession
* Open a new session
* @param phost: Host handle
* @param session: Session ID (MUST BE > 0U)
* @retval USBH Status
*/
USBH_StatusTypeDef USBH_PTP_OpenSession(USBH_HandleTypeDef *phost, uint32_t session)
{
USBH_StatusTypeDef status = USBH_BUSY;
MTP_HandleTypeDef *MTP_Handle = (MTP_HandleTypeDef *)phost->pActiveClass->pData;
PTP_ContainerTypedef ptp_container;
switch (MTP_Handle->ptp.req_state)
{
case PTP_REQ_SEND:
/* Init session params */
MTP_Handle->ptp.transaction_id = 0x00000000U;
MTP_Handle->ptp.session_id = session;
MTP_Handle->ptp.flags = PTP_DP_NODATA;
/* Fill operation request params */
ptp_container.Code = PTP_OC_OpenSession;
ptp_container.SessionID = session;
ptp_container.Transaction_ID = MTP_Handle->ptp.transaction_id ++;
ptp_container.Param1 = session;
ptp_container.Nparam = 1U;
/* convert request packet inti USB raw packet*/
USBH_PTP_SendRequest(phost, &ptp_container);
/* Setup State machine and start transfer */
MTP_Handle->ptp.state = PTP_OP_REQUEST_STATE;
MTP_Handle->ptp.req_state = PTP_REQ_WAIT;
status = USBH_BUSY;
#if (USBH_USE_OS == 1U)
phost->os_msg = (uint32_t)USBH_STATE_CHANGED_EVENT;
#if (osCMSIS < 0x20000U)
(void)osMessagePut(phost->os_event, phost->os_msg, 0U);
#else
(void)osMessageQueuePut(phost->os_event, &phost->os_msg, 0U, NULL);
#endif
#endif
break;
case PTP_REQ_WAIT:
status = USBH_PTP_Process(phost);
break;
default:
break;
}
return status;
}
/**
* @brief USBH_PTP_GetDevicePropDesc
* Gets object partially
* @param phost: Host handle
* @param dev_info: Device info structure
* @retval USBH Status
*/
USBH_StatusTypeDef USBH_PTP_GetDevicePropDesc(USBH_HandleTypeDef *phost,
uint16_t propcode,
PTP_DevicePropDescTypdef *devicepropertydesc)
{
USBH_StatusTypeDef status = USBH_BUSY;
MTP_HandleTypeDef *MTP_Handle = (MTP_HandleTypeDef *)phost->pActiveClass->pData;
PTP_ContainerTypedef ptp_container;
uint8_t *data = MTP_Handle->ptp.data_container.payload.data;
switch (MTP_Handle->ptp.req_state)
{
case PTP_REQ_SEND:
/* Set operation request type */
MTP_Handle->ptp.flags = PTP_DP_GETDATA;
MTP_Handle->ptp.data_ptr = (uint8_t *)(void *) & (MTP_Handle->ptp.data_container);
MTP_Handle->ptp.data_length = 0U;
MTP_Handle->ptp.data_packet_counter = 0U;
MTP_Handle->ptp.data_packet = 0U;
/* Fill operation request params */
ptp_container.Code = PTP_OC_GetDevicePropDesc;
ptp_container.SessionID = MTP_Handle->ptp.session_id;
ptp_container.Transaction_ID = MTP_Handle->ptp.transaction_id ++;
ptp_container.Param1 = propcode;
ptp_container.Nparam = 1U;
/* convert request packet into USB raw packet*/
USBH_PTP_SendRequest(phost, &ptp_container);
/* Setup State machine and start transfer */
MTP_Handle->ptp.state = PTP_OP_REQUEST_STATE;
MTP_Handle->ptp.req_state = PTP_REQ_WAIT;
status = USBH_BUSY;
#if (USBH_USE_OS == 1U)
phost->os_msg = (uint32_t)USBH_STATE_CHANGED_EVENT;
#if (osCMSIS < 0x20000U)
(void)osMessagePut(phost->os_event, phost->os_msg, 0U);
#else
(void)osMessageQueuePut(phost->os_event, &phost->os_msg, 0U, NULL);
#endif
#endif
break;
case PTP_REQ_WAIT:
status = USBH_PTP_Process(phost);
if (status == USBH_OK)
{
devicepropertydesc->DevicePropertyCode = LE16(&data[PTP_dpd_DevicePropertyCode]);
devicepropertydesc->DataType = LE16(&data[PTP_dpd_DataType]);
devicepropertydesc->GetSet = *(uint8_t *)(&data[PTP_dpd_GetSet]);
devicepropertydesc->FormFlag = PTP_DPFF_None;
}
break;
default:
break;
}
return status;
}
/**
* @brief USBH_PTP_GetDeviceInfo
* Gets device info dataset and fills deviceinfo structure.
* @param phost: Host handle
* @param dev_info: Device info structure
* @retval USBH Status
*/
USBH_StatusTypeDef USBH_PTP_GetDeviceInfo(USBH_HandleTypeDef *phost, PTP_DeviceInfoTypedef *dev_info)
{
USBH_StatusTypeDef status = USBH_BUSY;
MTP_HandleTypeDef *MTP_Handle = (MTP_HandleTypeDef *)phost->pActiveClass->pData;
PTP_ContainerTypedef ptp_container;
switch (MTP_Handle->ptp.req_state)
{
case PTP_REQ_SEND:
/* Set operation request type */
MTP_Handle->ptp.flags = PTP_DP_GETDATA;
MTP_Handle->ptp.data_ptr = (uint8_t *)(void *) &(MTP_Handle->ptp.data_container);
MTP_Handle->ptp.data_length = 0U;
MTP_Handle->ptp.data_packet_counter = 0U;
MTP_Handle->ptp.data_packet = 0U;
/* Fill operation request params */
ptp_container.Code = PTP_OC_GetDeviceInfo;
ptp_container.SessionID = MTP_Handle->ptp.session_id;
ptp_container.Transaction_ID = MTP_Handle->ptp.transaction_id++;
ptp_container.Nparam = 0U;
/* convert request packet inti USB raw packet*/
USBH_PTP_SendRequest(phost, &ptp_container);
/* Setup State machine and start transfer */
MTP_Handle->ptp.state = PTP_OP_REQUEST_STATE;
MTP_Handle->ptp.req_state = PTP_REQ_WAIT;
status = USBH_BUSY;
#if (USBH_USE_OS == 1U)
phost->os_msg = (uint32_t)USBH_STATE_CHANGED_EVENT;
#if (osCMSIS < 0x20000U)
(void)osMessagePut(phost->os_event, phost->os_msg, 0U);
#else
(void)osMessageQueuePut(phost->os_event, &phost->os_msg, 0U, NULL);
#endif
#endif
break;
case PTP_REQ_WAIT:
status = USBH_PTP_Process(phost);
if (status == USBH_OK)
{
PTP_DecodeDeviceInfo(phost, dev_info);
}
break;
default:
break;
}
return status;
}
/**
* @brief USBH_PTP_GetStorageIds
* Gets device info dataset and fills deviceinfo structure.
* @param phost: Host handle
* @param dev_info: Device info structure
* @retval USBH Status
*/
USBH_StatusTypeDef USBH_PTP_GetStorageIds(USBH_HandleTypeDef *phost, PTP_StorageIDsTypedef *storage_ids)
{
USBH_StatusTypeDef status = USBH_BUSY;
MTP_HandleTypeDef *MTP_Handle = (MTP_HandleTypeDef *)phost->pActiveClass->pData;
PTP_ContainerTypedef ptp_container;
switch (MTP_Handle->ptp.req_state)
{
case PTP_REQ_SEND:
/* Set operation request type */
MTP_Handle->ptp.flags = PTP_DP_GETDATA;
MTP_Handle->ptp.data_ptr = (uint8_t *)(void *) &(MTP_Handle->ptp.data_container);
MTP_Handle->ptp.data_length = 0U;
MTP_Handle->ptp.data_packet_counter = 0U;
MTP_Handle->ptp.data_packet = 0U;
/* Fill operation request params */
ptp_container.Code = PTP_OC_GetStorageIDs;
ptp_container.SessionID = MTP_Handle->ptp.session_id;
ptp_container.Transaction_ID = MTP_Handle->ptp.transaction_id++;
ptp_container.Nparam = 0U;
/* convert request packet inti USB raw packet*/
USBH_PTP_SendRequest(phost, &ptp_container);
/* Setup State machine and start transfer */
MTP_Handle->ptp.state = PTP_OP_REQUEST_STATE;
MTP_Handle->ptp.req_state = PTP_REQ_WAIT;
status = USBH_BUSY;
#if (USBH_USE_OS == 1U)
phost->os_msg = (uint32_t)USBH_STATE_CHANGED_EVENT;
#if (osCMSIS < 0x20000U)
(void)osMessagePut(phost->os_event, phost->os_msg, 0U);
#else
(void)osMessageQueuePut(phost->os_event, &phost->os_msg, 0U, NULL);
#endif
#endif
break;
case PTP_REQ_WAIT:
status = USBH_PTP_Process(phost);
if (status == USBH_OK)
{
PTP_GetStorageIDs(phost, storage_ids);
}
break;
default:
break;
}
return status;
}
/**
* @brief USBH_PTP_GetDeviceInfo
* Gets device info dataset and fills deviceinfo structure.
* @param phost: Host handle
* @param dev_info: Device info structure
* @retval USBH Status
*/
USBH_StatusTypeDef USBH_PTP_GetStorageInfo(USBH_HandleTypeDef *phost,
uint32_t storage_id,
PTP_StorageInfoTypedef *storage_info)
{
USBH_StatusTypeDef status = USBH_BUSY;
MTP_HandleTypeDef *MTP_Handle = (MTP_HandleTypeDef *)phost->pActiveClass->pData;
PTP_ContainerTypedef ptp_container;
switch (MTP_Handle->ptp.req_state)
{
case PTP_REQ_SEND:
/* Set operation request type */
MTP_Handle->ptp.flags = PTP_DP_GETDATA;
MTP_Handle->ptp.data_ptr = (uint8_t *)(void *) &(MTP_Handle->ptp.data_container);
MTP_Handle->ptp.data_length = 0U;
MTP_Handle->ptp.data_packet_counter = 0U;
MTP_Handle->ptp.data_packet = 0U;
/* Fill operation request params */
ptp_container.Code = PTP_OC_GetStorageInfo;
ptp_container.SessionID = MTP_Handle->ptp.session_id;
ptp_container.Transaction_ID = MTP_Handle->ptp.transaction_id++;
ptp_container.Param1 = storage_id;
ptp_container.Nparam = 1U;
/* convert request packet inti USB raw packet*/
USBH_PTP_SendRequest(phost, &ptp_container);
/* Setup State machine and start transfer */
MTP_Handle->ptp.state = PTP_OP_REQUEST_STATE;
MTP_Handle->ptp.req_state = PTP_REQ_WAIT;
status = USBH_BUSY;
#if (USBH_USE_OS == 1U)
phost->os_msg = (uint32_t)USBH_STATE_CHANGED_EVENT;
#if (osCMSIS < 0x20000U)
(void)osMessagePut(phost->os_event, phost->os_msg, 0U);
#else
(void)osMessageQueuePut(phost->os_event, &phost->os_msg, 0U, NULL);
#endif
#endif
break;
case PTP_REQ_WAIT:
status = USBH_PTP_Process(phost);
if (status == USBH_OK)
{
PTP_GetStorageInfo(phost, storage_id, storage_info);
}
break;
default:
break;
}
return status;
}
/**
* @brief USBH_PTP_GetNumObjects
* Gets device info dataset and fills deviceinfo structure.
* @param phost: Host handle
* @param dev_info: Device info structure
* @retval USBH Status
*/
USBH_StatusTypeDef USBH_PTP_GetNumObjects(USBH_HandleTypeDef *phost,
uint32_t storage_id,
uint32_t objectformatcode,
uint32_t associationOH,
uint32_t *numobs)
{
USBH_StatusTypeDef status = USBH_BUSY;
MTP_HandleTypeDef *MTP_Handle = (MTP_HandleTypeDef *)phost->pActiveClass->pData;
PTP_ContainerTypedef ptp_container;
switch (MTP_Handle->ptp.req_state)
{
case PTP_REQ_SEND:
/* Set operation request type */
MTP_Handle->ptp.flags = PTP_DP_NODATA;
/* Fill operation request params */
ptp_container.Code = PTP_OC_GetNumObjects;
ptp_container.SessionID = MTP_Handle->ptp.session_id;
ptp_container.Transaction_ID = MTP_Handle->ptp.transaction_id++;
ptp_container.Param1 = storage_id;
ptp_container.Param2 = objectformatcode;
ptp_container.Param3 = associationOH;
ptp_container.Nparam = 3U;
/* convert request packet into USB raw packet*/
USBH_PTP_SendRequest(phost, &ptp_container);
/* Setup State machine and start transfer */
MTP_Handle->ptp.state = PTP_OP_REQUEST_STATE;
MTP_Handle->ptp.req_state = PTP_REQ_WAIT;
status = USBH_BUSY;
#if (USBH_USE_OS == 1U)
phost->os_msg = (uint32_t)USBH_STATE_CHANGED_EVENT;
#if (osCMSIS < 0x20000U)
(void)osMessagePut(phost->os_event, phost->os_msg, 0U);
#else
(void)osMessageQueuePut(phost->os_event, &phost->os_msg, 0U, NULL);
#endif
#endif
break;
case PTP_REQ_WAIT:
status = USBH_PTP_Process(phost);
if (status == USBH_OK)
{
*numobs = MTP_Handle->ptp.resp_container.param1;
}
break;
default:
break;
}
return status;
}
/**
* @brief USBH_PTP_GetObjectHandles
* Gets device info dataset and fills deviceinfo structure.
* @param phost: Host handle
* @param dev_info: Device info structure
* @retval USBH Status
*/
USBH_StatusTypeDef USBH_PTP_GetObjectHandles(USBH_HandleTypeDef *phost,
uint32_t storage_id,
uint32_t objectformatcode,
uint32_t associationOH,
PTP_ObjectHandlesTypedef *objecthandles)
{
USBH_StatusTypeDef status = USBH_BUSY;
MTP_HandleTypeDef *MTP_Handle = (MTP_HandleTypeDef *)phost->pActiveClass->pData;
PTP_ContainerTypedef ptp_container;
switch (MTP_Handle->ptp.req_state)
{
case PTP_REQ_SEND:
/* Set operation request type */
MTP_Handle->ptp.flags = PTP_DP_GETDATA;
MTP_Handle->ptp.data_ptr = (uint8_t *)(void *) &(MTP_Handle->ptp.data_container);
MTP_Handle->ptp.data_length = 0U;
MTP_Handle->ptp.data_packet_counter = 0U;
MTP_Handle->ptp.data_packet = 0U;
/* Fill operation request params */
ptp_container.Code = PTP_OC_GetObjectHandles;
ptp_container.SessionID = MTP_Handle->ptp.session_id;
ptp_container.Transaction_ID = MTP_Handle->ptp.transaction_id++;
ptp_container.Param1 = storage_id;
ptp_container.Param2 = objectformatcode;
ptp_container.Param3 = associationOH;
ptp_container.Nparam = 3U;
/* convert request packet into USB raw packet*/
USBH_PTP_SendRequest(phost, &ptp_container);
/* Setup State machine and start transfer */
MTP_Handle->ptp.state = PTP_OP_REQUEST_STATE;
MTP_Handle->ptp.req_state = PTP_REQ_WAIT;
status = USBH_BUSY;
#if (USBH_USE_OS == 1U)
phost->os_msg = (uint32_t)USBH_STATE_CHANGED_EVENT;
#if (osCMSIS < 0x20000U)
(void)osMessagePut(phost->os_event, phost->os_msg, 0U);
#else
(void)osMessageQueuePut(phost->os_event, &phost->os_msg, 0U, NULL);
#endif
#endif
break;
case PTP_REQ_WAIT:
status = USBH_PTP_Process(phost);
if (status == USBH_OK)
{
objecthandles->n = PTP_GetArray32(objecthandles->Handler,
MTP_Handle->ptp.data_container.payload.data,
0U);
}
break;
default:
break;
}
return status;
}
/**
* @brief USBH_PTP_GetObjectInfo
* Gets objert info
* @param phost: Host handle
* @param dev_info: Device info structure
* @retval USBH Status
*/
USBH_StatusTypeDef USBH_PTP_GetObjectInfo(USBH_HandleTypeDef *phost,
uint32_t handle,
PTP_ObjectInfoTypedef *object_info)
{
USBH_StatusTypeDef status = USBH_BUSY;
MTP_HandleTypeDef *MTP_Handle = (MTP_HandleTypeDef *)phost->pActiveClass->pData;
PTP_ContainerTypedef ptp_container;
switch (MTP_Handle->ptp.req_state)
{
case PTP_REQ_SEND:
/* Set operation request type */
MTP_Handle->ptp.flags = PTP_DP_GETDATA;
MTP_Handle->ptp.data_ptr = (uint8_t *)(void *) &(MTP_Handle->ptp.data_container);
MTP_Handle->ptp.data_length = 0U;
MTP_Handle->ptp.data_packet_counter = 0U;
MTP_Handle->ptp.data_packet = 0U;
/* Fill operation request params */
ptp_container.Code = PTP_OC_GetObjectInfo;
ptp_container.SessionID = MTP_Handle->ptp.session_id;
ptp_container.Transaction_ID = MTP_Handle->ptp.transaction_id++;
ptp_container.Param1 = handle;
ptp_container.Nparam = 1U;
/* convert request packet into USB raw packet*/
USBH_PTP_SendRequest(phost, &ptp_container);
/* Setup State machine and start transfer */
MTP_Handle->ptp.state = PTP_OP_REQUEST_STATE;
MTP_Handle->ptp.req_state = PTP_REQ_WAIT;
status = USBH_BUSY;
#if (USBH_USE_OS == 1U)
phost->os_msg = (uint32_t)USBH_STATE_CHANGED_EVENT;
#if (osCMSIS < 0x20000U)
(void)osMessagePut(phost->os_event, phost->os_msg, 0U);
#else
(void)osMessageQueuePut(phost->os_event, &phost->os_msg, 0U, NULL);
#endif
#endif
break;
case PTP_REQ_WAIT:
status = USBH_PTP_Process(phost);
if (status == USBH_OK)
{
PTP_GetObjectInfo(phost, object_info);
}
break;
default:
break;
}
return status;
}
/**
* @brief USBH_PTP_DeleteObject
* Delete an object.
* @param phost: Host handle
* @param handle : Object Handle
* @retval USBH Status
*/
USBH_StatusTypeDef USBH_PTP_DeleteObject(USBH_HandleTypeDef *phost,
uint32_t handle,
uint32_t objectformatcode)
{
USBH_StatusTypeDef status = USBH_BUSY;
MTP_HandleTypeDef *MTP_Handle = (MTP_HandleTypeDef *)phost->pActiveClass->pData;
PTP_ContainerTypedef ptp_container;
switch (MTP_Handle->ptp.req_state)
{
case PTP_REQ_SEND:
/* Set operation request type */
MTP_Handle->ptp.flags = PTP_DP_NODATA;
/* Fill operation request params */
ptp_container.Code = PTP_OC_DeleteObject;
ptp_container.SessionID = MTP_Handle->ptp.session_id;
ptp_container.Transaction_ID = MTP_Handle->ptp.transaction_id++;
ptp_container.Param1 = handle;
ptp_container.Param2 = objectformatcode;
ptp_container.Nparam = 2U;
/* convert request packet into USB raw packet*/
USBH_PTP_SendRequest(phost, &ptp_container);
/* Setup State machine and start transfer */
MTP_Handle->ptp.state = PTP_OP_REQUEST_STATE;
MTP_Handle->ptp.req_state = PTP_REQ_WAIT;
status = USBH_BUSY;
#if (USBH_USE_OS == 1U)
phost->os_msg = (uint32_t)USBH_STATE_CHANGED_EVENT;
#if (osCMSIS < 0x20000U)
(void)osMessagePut(phost->os_event, phost->os_msg, 0U);
#else
(void)osMessageQueuePut(phost->os_event, &phost->os_msg, 0U, NULL);
#endif
#endif
break;
case PTP_REQ_WAIT:
status = USBH_PTP_Process(phost);
break;
default:
break;
}
return status;
}
/**
* @brief USBH_PTP_GetObject
* Gets object
* @param phost: Host handle
* @param dev_info: Device info structure
* @retval USBH Status
*/
USBH_StatusTypeDef USBH_PTP_GetObject(USBH_HandleTypeDef *phost,
uint32_t handle,
uint8_t *object)
{
USBH_StatusTypeDef status = USBH_BUSY;
MTP_HandleTypeDef *MTP_Handle = (MTP_HandleTypeDef *)phost->pActiveClass->pData;
PTP_ContainerTypedef ptp_container;
switch (MTP_Handle->ptp.req_state)
{
case PTP_REQ_SEND:
/* Set operation request type */
MTP_Handle->ptp.flags = PTP_DP_GETDATA;
MTP_Handle->ptp.data_ptr = (uint8_t *)(void *) &(MTP_Handle->ptp.data_container);
MTP_Handle->ptp.data_length = 0U;
MTP_Handle->ptp.data_packet_counter = 0U;
MTP_Handle->ptp.data_packet = 0U;
/* set object control params */
MTP_Handle->ptp.object_ptr = object;
/* Fill operation request params */
ptp_container.Code = PTP_OC_GetObject;
ptp_container.SessionID = MTP_Handle->ptp.session_id;
ptp_container.Transaction_ID = MTP_Handle->ptp.transaction_id++;
ptp_container.Param1 = handle;
ptp_container.Nparam = 1U;
/* convert request packet into USB raw packet*/
USBH_PTP_SendRequest(phost, &ptp_container);
/* Setup State machine and start transfer */
MTP_Handle->ptp.state = PTP_OP_REQUEST_STATE;
MTP_Handle->ptp.req_state = PTP_REQ_WAIT;
status = USBH_BUSY;
#if (USBH_USE_OS == 1U)
phost->os_msg = (uint32_t)USBH_STATE_CHANGED_EVENT;
#if (osCMSIS < 0x20000U)
(void)osMessagePut(phost->os_event, phost->os_msg, 0U);
#else
(void)osMessageQueuePut(phost->os_event, &phost->os_msg, 0U, NULL);
#endif
#endif
break;
case PTP_REQ_WAIT:
status = USBH_PTP_Process(phost);
if (status == USBH_OK)
{
/* first packet is in the PTP data payload buffer */
if (MTP_Handle->ptp.iteration == 0U)
{
/* copy it to object */
USBH_memcpy(MTP_Handle->ptp.object_ptr,
MTP_Handle->ptp.data_container.payload.data,
PTP_USB_BULK_PAYLOAD_LEN_READ);
}
}
break;
default:
break;
}
return status;
}
/**
* @brief USBH_PTP_GetPartialObject
* Gets object partially
* @param phost: Host handle
* @param dev_info: Device info structure
* @retval USBH Status
*/
USBH_StatusTypeDef USBH_PTP_GetPartialObject(USBH_HandleTypeDef *phost,
uint32_t handle,
uint32_t offset,
uint32_t maxbytes,
uint8_t *object,
uint32_t *len)
{
USBH_StatusTypeDef status = USBH_BUSY;
MTP_HandleTypeDef *MTP_Handle = (MTP_HandleTypeDef *)phost->pActiveClass->pData;
PTP_ContainerTypedef ptp_container;
switch (MTP_Handle->ptp.req_state)
{
case PTP_REQ_SEND:
/* Set operation request type */
MTP_Handle->ptp.flags = PTP_DP_GETDATA;
MTP_Handle->ptp.data_ptr = (uint8_t *)(void *) &(MTP_Handle->ptp.data_container);
MTP_Handle->ptp.data_length = 0U;
MTP_Handle->ptp.data_packet_counter = 0U;
MTP_Handle->ptp.data_packet = 0U;
/* set object control params */
MTP_Handle->ptp.object_ptr = object;
/* Fill operation request params */
ptp_container.Code = PTP_OC_GetPartialObject;
ptp_container.SessionID = MTP_Handle->ptp.session_id;
ptp_container.Transaction_ID = MTP_Handle->ptp.transaction_id++;
ptp_container.Param1 = handle;
ptp_container.Param2 = offset;
ptp_container.Param3 = maxbytes;
ptp_container.Nparam = 3U;
/* convert request packet into USB raw packet*/
USBH_PTP_SendRequest(phost, &ptp_container);
/* Setup State machine and start transfer */
MTP_Handle->ptp.state = PTP_OP_REQUEST_STATE;
MTP_Handle->ptp.req_state = PTP_REQ_WAIT;
status = USBH_BUSY;
#if (USBH_USE_OS == 1U)
phost->os_msg = (uint32_t)USBH_STATE_CHANGED_EVENT;
#if (osCMSIS < 0x20000U)
(void)osMessagePut(phost->os_event, phost->os_msg, 0U);
#else
(void)osMessageQueuePut(phost->os_event, &phost->os_msg, 0U, NULL);
#endif
#endif
break;
case PTP_REQ_WAIT:
status = USBH_PTP_Process(phost);
if (status == USBH_OK)
{
*len = MTP_Handle->ptp.resp_container.param1;
/* first packet is in the PTP data payload buffer */
if (MTP_Handle->ptp.iteration == 0U)
{
/* copy it to object */
USBH_memcpy(MTP_Handle->ptp.object_ptr,
MTP_Handle->ptp.data_container.payload.data, *len);
}
}
break;
default:
break;
}
return status;
}
/**
* @brief USBH_PTP_GetObjectPropsSupported
* Gets object partially
* @param phost: Host handle
* @param dev_info: Device info structure
* @retval USBH Status
*/
USBH_StatusTypeDef USBH_PTP_GetObjectPropsSupported(USBH_HandleTypeDef *phost,
uint16_t ofc,
uint32_t *propnum,
uint16_t *props)
{
USBH_StatusTypeDef status = USBH_BUSY;
MTP_HandleTypeDef *MTP_Handle = (MTP_HandleTypeDef *)phost->pActiveClass->pData;
PTP_ContainerTypedef ptp_container;
switch (MTP_Handle->ptp.req_state)
{
case PTP_REQ_SEND:
/* Set operation request type */
MTP_Handle->ptp.flags = PTP_DP_GETDATA;
MTP_Handle->ptp.data_ptr = (uint8_t *)(void *) &(MTP_Handle->ptp.data_container);
MTP_Handle->ptp.data_length = 0U;
MTP_Handle->ptp.data_packet_counter = 0U;
MTP_Handle->ptp.data_packet = 0U;
/* Fill operation request params */
ptp_container.Code = PTP_OC_GetObjectPropsSupported;
ptp_container.SessionID = MTP_Handle->ptp.session_id;
ptp_container.Transaction_ID = MTP_Handle->ptp.transaction_id++;
ptp_container.Param1 = ofc;
ptp_container.Nparam = 1U;
/* convert request packet into USB raw packet*/
USBH_PTP_SendRequest(phost, &ptp_container);
/* Setup State machine and start transfer */
MTP_Handle->ptp.state = PTP_OP_REQUEST_STATE;
MTP_Handle->ptp.req_state = PTP_REQ_WAIT;
status = USBH_BUSY;
#if (USBH_USE_OS == 1U)
phost->os_msg = (uint32_t)USBH_STATE_CHANGED_EVENT;
#if (osCMSIS < 0x20000U)
(void)osMessagePut(phost->os_event, phost->os_msg, 0U);
#else
(void)osMessageQueuePut(phost->os_event, &phost->os_msg, 0U, NULL);
#endif
#endif
break;
case PTP_REQ_WAIT:
status = USBH_PTP_Process(phost);
if (status == USBH_OK)
{
*propnum = PTP_GetArray16(props, MTP_Handle->ptp.data_container.payload.data, 0U);
}
break;
default:
break;
}
return status;
}
/**
* @brief USBH_PTP_GetObjectPropDesc
* Gets object partially
* @param phost: Host handle
* @param dev_info: Device info structure
* @retval USBH Status
*/
USBH_StatusTypeDef USBH_PTP_GetObjectPropDesc(USBH_HandleTypeDef *phost,
uint16_t opc,
uint16_t ofc,
PTP_ObjectPropDescTypeDef *opd)
{
USBH_StatusTypeDef status = USBH_BUSY;
MTP_HandleTypeDef *MTP_Handle = (MTP_HandleTypeDef *)phost->pActiveClass->pData;
PTP_ContainerTypedef ptp_container;
switch (MTP_Handle->ptp.req_state)
{
case PTP_REQ_SEND:
/* Set operation request type */
MTP_Handle->ptp.flags = PTP_DP_GETDATA;
MTP_Handle->ptp.data_ptr = (uint8_t *)(void *) &(MTP_Handle->ptp.data_container);
MTP_Handle->ptp.data_length = 0U;
MTP_Handle->ptp.data_packet_counter = 0U;
MTP_Handle->ptp.data_packet = 0U;
/* Fill operation request params */
ptp_container.Code = PTP_OC_GetObjectPropDesc;
ptp_container.SessionID = MTP_Handle->ptp.session_id;
ptp_container.Transaction_ID = MTP_Handle->ptp.transaction_id++;
ptp_container.Param1 = opc;
ptp_container.Param2 = ofc;
ptp_container.Nparam = 2U;
/* convert request packet into USB raw packet*/
USBH_PTP_SendRequest(phost, &ptp_container);
/* Setup State machine and start transfer */
MTP_Handle->ptp.state = PTP_OP_REQUEST_STATE;
MTP_Handle->ptp.req_state = PTP_REQ_WAIT;
status = USBH_BUSY;
#if (USBH_USE_OS == 1U)
phost->os_msg = (uint32_t)USBH_STATE_CHANGED_EVENT;
#if (osCMSIS < 0x20000U)
(void)osMessagePut(phost->os_event, phost->os_msg, 0U);
#else
(void)osMessageQueuePut(phost->os_event, &phost->os_msg, 0U, NULL);
#endif
#endif
break;
case PTP_REQ_WAIT:
status = USBH_PTP_Process(phost);
if (status == USBH_OK)
{
PTP_GetObjectPropDesc(phost, opd, MTP_Handle->ptp.data_length);
}
break;
default:
break;
}
return status;
}
/**
* @brief USBH_PTP_GetObjectPropList
* Gets object partially
* @param phost: Host handle
* @param dev_info: Device info structure
* @retval USBH Status
*/
USBH_StatusTypeDef USBH_PTP_GetObjectPropList(USBH_HandleTypeDef *phost,
uint32_t handle,
MTP_PropertiesTypedef *pprops,
uint32_t *nrofprops)
{
/* Prevent unused argument(s) compilation warning */
UNUSED(nrofprops);
USBH_StatusTypeDef status = USBH_BUSY;
MTP_HandleTypeDef *MTP_Handle = (MTP_HandleTypeDef *)phost->pActiveClass->pData;
PTP_ContainerTypedef ptp_container;
switch (MTP_Handle->ptp.req_state)
{
case PTP_REQ_SEND:
/* Set operation request type */
MTP_Handle->ptp.flags = PTP_DP_GETDATA;
MTP_Handle->ptp.data_ptr = (uint8_t *)(void *) &(MTP_Handle->ptp.data_container);
MTP_Handle->ptp.data_length = 0U;
MTP_Handle->ptp.data_packet_counter = 0U;
MTP_Handle->ptp.data_packet = 0U;
/* copy first packet of the object into data container */
USBH_memcpy(MTP_Handle->ptp.data_container.payload.data,
MTP_Handle->ptp.object_ptr, PTP_USB_BULK_PAYLOAD_LEN_READ);
/* Fill operation request params */
ptp_container.Code = PTP_OC_GetObjPropList;
ptp_container.SessionID = MTP_Handle->ptp.session_id;
ptp_container.Transaction_ID = MTP_Handle->ptp.transaction_id++;
ptp_container.Param1 = handle;
ptp_container.Param2 = 0x00000000U; /* 0x00000000U should be "all formats" */
ptp_container.Param3 = 0xFFFFFFFFU; /* 0xFFFFFFFFU should be "all properties" */
ptp_container.Param4 = 0x00000000U;
ptp_container.Param5 = 0xFFFFFFFFU; /* Return full tree below the Param1 handle */
ptp_container.Nparam = 5U;
/* convert request packet into USB raw packet*/
USBH_PTP_SendRequest(phost, &ptp_container);
/* Setup State machine and start transfer */
MTP_Handle->ptp.state = PTP_OP_REQUEST_STATE;
MTP_Handle->ptp.req_state = PTP_REQ_WAIT;
status = USBH_BUSY;
#if (USBH_USE_OS == 1U)
phost->os_msg = (uint32_t)USBH_STATE_CHANGED_EVENT;
#if (osCMSIS < 0x20000U)
(void)osMessagePut(phost->os_event, phost->os_msg, 0U);
#else
(void)osMessageQueuePut(phost->os_event, &phost->os_msg, 0U, NULL);
#endif
#endif
break;
case PTP_REQ_WAIT:
status = USBH_PTP_Process(phost);
if (status == USBH_OK)
{
PTP_GetObjectPropList(phost, pprops, MTP_Handle->ptp.data_length);
}
break;
default:
break;
}
return status;
}
/**
* @brief USBH_PTP_SendObject
* Send an object
* @param phost: Host handle
* @param dev_info: Device info structure
* @retval USBH Status
*/
USBH_StatusTypeDef USBH_PTP_SendObject(USBH_HandleTypeDef *phost,
uint32_t handle,
uint8_t *object,
uint32_t size)
{
/* Prevent unused argument(s) compilation warning */
UNUSED(handle);
USBH_StatusTypeDef status = USBH_BUSY;
MTP_HandleTypeDef *MTP_Handle = (MTP_HandleTypeDef *)phost->pActiveClass->pData;
PTP_ContainerTypedef ptp_container;
switch (MTP_Handle->ptp.req_state)
{
case PTP_REQ_SEND:
/* Set operation request type */
MTP_Handle->ptp.flags = PTP_DP_SENDDATA;
MTP_Handle->ptp.data_ptr = (uint8_t *)(void *) &(MTP_Handle->ptp.data_container);
MTP_Handle->ptp.data_packet_counter = 0U;
MTP_Handle->ptp.data_packet = 0U;
MTP_Handle->ptp.iteration = 0U;
/* set object control params */
MTP_Handle->ptp.object_ptr = object;
MTP_Handle->ptp.data_length = size;
/* Fill operation request params */
ptp_container.Code = PTP_OC_SendObject;
ptp_container.SessionID = MTP_Handle->ptp.session_id;
ptp_container.Transaction_ID = MTP_Handle->ptp.transaction_id ++;
ptp_container.Nparam = 0U;
/* convert request packet into USB raw packet*/
USBH_PTP_SendRequest(phost, &ptp_container);
/* Setup State machine and start transfer */
MTP_Handle->ptp.state = PTP_OP_REQUEST_STATE;
MTP_Handle->ptp.req_state = PTP_REQ_WAIT;
status = USBH_BUSY;
#if (USBH_USE_OS == 1U)
phost->os_msg = (uint32_t)USBH_STATE_CHANGED_EVENT;
#if (osCMSIS < 0x20000U)
(void)osMessagePut(phost->os_event, phost->os_msg, 0U);
#else
(void)osMessageQueuePut(phost->os_event, &phost->os_msg, 0U, NULL);
#endif
#endif
break;
case PTP_REQ_WAIT:
status = USBH_PTP_Process(phost);
break;
default:
break;
}
return status;
}
/**
* @}
*/
/**
* @}
*/
/**
* @}
*/
/**
* @}
*/
/**
* @}
*/
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/