315 lines
14 KiB
C
315 lines
14 KiB
C
/*
|
|
* Copyright (c) 2015, Freescale Semiconductor, Inc.
|
|
* Copyright 2016 NXP
|
|
* All rights reserved.
|
|
*
|
|
* SPDX-License-Identifier: BSD-3-Clause
|
|
*/
|
|
|
|
#include <stdbool.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <stdlib.h>
|
|
#include "usb_device_config.h"
|
|
#include "usb.h"
|
|
#include "usb_device.h"
|
|
|
|
#include "usb_device_phdc.h"
|
|
|
|
#include "usb_device_ch9.h"
|
|
#include "usb_device_descriptor.h"
|
|
#include "ieee11073_types.h"
|
|
#include "ieee11073_timer.h"
|
|
#include "ieee11073_agent.h"
|
|
#include "usb_shim_agent.h"
|
|
|
|
/*******************************************************************************
|
|
* Definitions
|
|
******************************************************************************/
|
|
|
|
/*******************************************************************************
|
|
* Prototypes
|
|
******************************************************************************/
|
|
|
|
/*******************************************************************************
|
|
* Variables
|
|
******************************************************************************/
|
|
|
|
#if META_DATA_MESSAGE_PREAMBLE_IMPLEMENTED
|
|
/*! @brief the string used to give preamble verifiability */
|
|
static char metaDataMsgPreambleSignature[16U] = "PhdcQoSSignature";
|
|
#endif
|
|
extern usb_shim_agent_struct_t g_shimAgent;
|
|
|
|
/*******************************************************************************
|
|
* Code
|
|
******************************************************************************/
|
|
|
|
/*!
|
|
* @brief USB shim agent receive data callback function.
|
|
*
|
|
* This function implements a queue to support receiving the PHDC data with length is more than
|
|
* maximum of endpoint packet size. Then notify to upper layer when receiving is all completed.
|
|
*
|
|
* @param handle The device handle.
|
|
* @param param The param of receive callback function.
|
|
*
|
|
* @return A USB error code or kStatus_USB_Success.
|
|
*/
|
|
usb_status_t USB_ShimAgentRecvComplete(void *handle, void *param)
|
|
{
|
|
usb_device_endpoint_callback_message_struct_t *message = (usb_device_endpoint_callback_message_struct_t *)param;
|
|
if ((!message->length) || (USB_CANCELLED_TRANSFER_LENGTH == message->length))
|
|
{
|
|
/* Prepare for the next receiving */
|
|
USB_DeviceRecvRequest((void *)g_shimAgent.deviceHandle, g_shimAgent.bulkOutData.epNumber,
|
|
g_shimAgent.recvDataBuffer, g_shimAgent.bulkOutData.epMaxPacketSize);
|
|
return kStatus_USB_Success;
|
|
}
|
|
#if META_DATA_MESSAGE_PREAMBLE_IMPLEMENTED
|
|
if (1U == g_shimAgent.isMetaDataMessagePreambleEnabled)
|
|
{
|
|
/* The meta-data message preamble feature is enabled, then all data transfers or sets
|
|
of data transfers shall be preceded by a meta-data message preamble transfer. The
|
|
numberTransferBulkOut is initialized as zero for receiving this message preamble data,
|
|
then it is updated to the value of bNumTransfers field of message preamble data */
|
|
if (g_shimAgent.numberTransferBulkOut)
|
|
{
|
|
/* When numberTransferBulkOut reduces to 0, a new meta-data message preamble shall
|
|
be transferred */
|
|
g_shimAgent.numberTransferBulkOut--;
|
|
AGENT_Callback(handle, SHIM_AGENT_EVENT_RECV_OPAQUE_DATA, (uint8_t *)(message->buffer), message->length);
|
|
return kStatus_USB_Success;
|
|
}
|
|
else
|
|
{
|
|
uint8_t preambleSignatureChecking = 1U;
|
|
/* The received packet is meta-data message preamble */
|
|
usb_shim_metadata_preamble_t *metaDataMsgPreamble = (usb_shim_metadata_preamble_t *)message->buffer;
|
|
/* Meta-data message preamble signature checking */
|
|
for (uint8_t i = 0U; i < METADATA_PREAMBLE_SIGNATURE; i++)
|
|
{
|
|
if ((metaDataMsgPreamble->aSignature[i]) != metaDataMsgPreambleSignature[i])
|
|
{
|
|
preambleSignatureChecking = 0U;
|
|
break;
|
|
}
|
|
}
|
|
if (preambleSignatureChecking)
|
|
{
|
|
/* Checks if the meta-data message preamble contains an invalid bmLatencyReliability value
|
|
or bNumTransfers value */
|
|
if ((!(metaDataMsgPreamble->bNumberTransfers)) || /* bNumTransfers shall never equal zero */
|
|
(metaDataMsgPreamble->bQosEncodingVersion != 0x01U) || /* Encoding version should be 0x01 */
|
|
((metaDataMsgPreamble->bmLatencyReliability != 0x02U) && /* Medium.Good latency, reliability bin */
|
|
(metaDataMsgPreamble->bmLatencyReliability !=
|
|
0x04U) && /* Medium.Better latency, reliability bin */
|
|
(metaDataMsgPreamble->bmLatencyReliability != 0x08U) && /* Medium.Best latency, reliability bin */
|
|
(metaDataMsgPreamble->bmLatencyReliability != 0x10U) && /* High.Best latency, reliability bin */
|
|
(metaDataMsgPreamble->bmLatencyReliability != 0x20U) /* VeryHigh.Best latency, reliability bin */))
|
|
{
|
|
/* The device shall stall subsequent transaction to the receiving endpoint */
|
|
return kStatus_USB_InvalidRequest;
|
|
}
|
|
else
|
|
{
|
|
/* The meta-data message preamble data is correct, update the phdc status and numberTransferBulkOut
|
|
* value */
|
|
g_shimAgent.numberTransferBulkOut = metaDataMsgPreamble->bNumberTransfers;
|
|
AGENT_Callback(handle, SHIM_AGENT_EVENT_RECV_MESSAGE_PREAMBLE, (uint8_t *)(message->buffer),
|
|
message->length);
|
|
return kStatus_USB_Success;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* The device shall stall subsequent transaction to the receiving endpoint */
|
|
return kStatus_USB_InvalidRequest;
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
if (NULL == g_shimAgent.bulkOutData.recvData.buffer)
|
|
{
|
|
/* Save the length of the first received data block */
|
|
g_shimAgent.bulkOutData.transferCount = message->length;
|
|
g_shimAgent.bulkOutData.recvData.transferSize =
|
|
(uint32_t)(USB_SHORT_FROM_BIG_ENDIAN(*((uint16_t *)message->buffer + 1U)) + 4U /* APDU header */);
|
|
g_shimAgent.bulkOutData.recvData.buffer = &g_shimAgent.recvDataBuffer[0];
|
|
/* Save the received data */
|
|
memcpy(g_shimAgent.bulkOutData.recvData.buffer, message->buffer, message->length);
|
|
}
|
|
else
|
|
{
|
|
/* update the transferred data length */
|
|
g_shimAgent.bulkOutData.transferCount += message->length;
|
|
}
|
|
if (g_shimAgent.bulkOutData.transferCount == g_shimAgent.bulkOutData.recvData.transferSize)
|
|
{
|
|
/* Receive all the data */
|
|
AGENT_Callback(handle, SHIM_AGENT_EVENT_RECV_COMPLETE, g_shimAgent.bulkOutData.recvData.buffer,
|
|
g_shimAgent.bulkOutData.recvData.transferSize);
|
|
g_shimAgent.bulkOutData.transferCount = 0;
|
|
g_shimAgent.bulkOutData.recvData.transferSize = 0;
|
|
g_shimAgent.bulkOutData.recvData.buffer = NULL;
|
|
/* Prepare for the next receiving */
|
|
USB_DeviceRecvRequest((void *)handle, g_shimAgent.bulkOutData.epNumber, g_shimAgent.recvDataBuffer,
|
|
g_shimAgent.bulkOutData.epMaxPacketSize);
|
|
}
|
|
else
|
|
{
|
|
/* The data is still pending for receiving */
|
|
#if (defined(USB_DEVICE_CONFIG_RETURN_VALUE_CHECK) && (USB_DEVICE_CONFIG_RETURN_VALUE_CHECK > 0U))
|
|
if (kStatus_USB_Success != USB_DeviceRecvRequest((void *)handle, g_shimAgent.bulkOutData.epNumber,
|
|
(uint8_t *)(g_shimAgent.bulkOutData.recvData.buffer +
|
|
g_shimAgent.bulkOutData.transferCount),
|
|
g_shimAgent.bulkOutData.epMaxPacketSize))
|
|
{
|
|
return kStatus_USB_Error;
|
|
}
|
|
#else
|
|
(void)USB_DeviceRecvRequest(
|
|
(void *)handle, g_shimAgent.bulkOutData.epNumber,
|
|
(uint8_t *)(g_shimAgent.bulkOutData.recvData.buffer + g_shimAgent.bulkOutData.transferCount),
|
|
g_shimAgent.bulkOutData.epMaxPacketSize);
|
|
#endif
|
|
}
|
|
return kStatus_USB_Success;
|
|
}
|
|
|
|
/*!
|
|
* @brief USB shim agent send data callback function.
|
|
*
|
|
* This function is the callback function of USB shim agent send function, it is implemented
|
|
* to continue sending the data in sending queue if the queue is not empty.
|
|
*
|
|
* @param handle he device handle.
|
|
* @param param The param of receive callback function.
|
|
*
|
|
* @return A USB error code or kStatus_USB_Success.
|
|
*/
|
|
usb_status_t USB_ShimAgentSendComplete(void *handle, uint32_t event, void *param)
|
|
{
|
|
usb_device_endpoint_callback_message_struct_t *message = (usb_device_endpoint_callback_message_struct_t *)param;
|
|
usb_shim_tx_data_struct_t *sentData = NULL;
|
|
if (USB_PHDC_EVENT_INTERRUPT_IN_SEND_COMPLETE == event)
|
|
{
|
|
sentData = &g_shimAgent.interruptInData;
|
|
}
|
|
else
|
|
{
|
|
sentData = &g_shimAgent.bulkInData;
|
|
}
|
|
g_shimAgent.endpointsHaveData &= (uint16_t)(~(uint16_t)(1U << sentData->epNumber));
|
|
/* notify the application of the send complete */
|
|
AGENT_Callback(handle, SHIM_AGENT_EVENT_SENT_COMPLETE, (uint8_t *)message->buffer, message->length);
|
|
/* de-queue the queue */
|
|
sentData->buyer += 1U;
|
|
if (sentData->buyer != sentData->seller)
|
|
{
|
|
/* Set bit map for the corresponding endpoint*/
|
|
g_shimAgent.endpointsHaveData |= (uint16_t)(1U << sentData->epNumber);
|
|
USB_DeviceSendRequest((void *)handle, sentData->epNumber,
|
|
sentData->sendData[sentData->buyer % SHIM_AGENT_MAX_QUEUE_NUMBER].buffer,
|
|
sentData->sendData[sentData->buyer % SHIM_AGENT_MAX_QUEUE_NUMBER].transferSize);
|
|
}
|
|
return kStatus_USB_Success;
|
|
}
|
|
|
|
/*!
|
|
* @brief USB shim agent send data function.
|
|
*
|
|
* This function implements a queue to support sending multiple transfer request.
|
|
*
|
|
* @param handle The device handle.
|
|
* @param metaData The flag to check the data to send is meta data or not.
|
|
* @param numberTransfer The number of transfer following the meta data message preamble
|
|
* when sending data is meta data.
|
|
* @param qos The current QoS of the transfer.
|
|
* @param appBuffer The data buffer.
|
|
* @param size The length of the transfer.
|
|
*
|
|
* @return A USB error code or kStatus_USB_Success.
|
|
*/
|
|
usb_status_t USB_ShimAgentSendData(void *handle, uint8_t qos, uint8_t *appBuffer, uint32_t size)
|
|
{
|
|
usb_status_t status = kStatus_USB_Success;
|
|
usb_shim_tx_data_struct_t *dataToSend = NULL;
|
|
if (qos != 0x01U /* low latency/good reliability */)
|
|
{
|
|
#if META_DATA_MESSAGE_PREAMBLE_IMPLEMENTED
|
|
if (1U == g_shimAgent.isMetaDataMessagePreambleEnabled)
|
|
{
|
|
/* The meta-data message preamble feature is enabled, then all data transfers or sets
|
|
of data transfers shall be preceded by a meta-data message preamble transfer. The
|
|
numberTransferBulkIn is initialized as zero for sending this message preamble data,
|
|
then it is updated to the value of bNumTransfers field of message preamble data */
|
|
if (g_shimAgent.numberTransferBulkOut)
|
|
{
|
|
/* When numberTransferBulkIn reduces to 0, a new meta-data message preamble shall
|
|
be transferred */
|
|
g_shimAgent.numberTransferBulkIn--;
|
|
}
|
|
{
|
|
uint8_t latencyReliability = ((usb_shim_metadata_preamble_t *)appBuffer)->bmLatencyReliability;
|
|
/* Latency reliability validity checking */
|
|
if ((latencyReliability != 0x02U) && /* Medium.Good latency, reliability bin */
|
|
(latencyReliability != 0x04U) && /* Medium.Better latency, reliability bin */
|
|
(latencyReliability != 0x08U) && /* Medium.Best latency, reliability bin */
|
|
(latencyReliability != 0x10U) && /* High.Best latency, reliability bin */
|
|
(latencyReliability != 0x20U) /* VeryHigh.Best latency, reliability bin */)
|
|
{
|
|
status = kStatus_USB_InvalidRequest;
|
|
usb_echo("USB_ShimAgentSendData: Error invalid LatencyReliability");
|
|
}
|
|
/* LatencyReliablity checking */
|
|
if (0U == (USB_PHDC_WEIGHT_SCALE_BULK_IN_QOS & ~latencyReliability))
|
|
{
|
|
status = kStatus_USB_Error;
|
|
usb_echo(
|
|
"USB_ShimAgentSendData: Error the latency reliability is not supported by Bulk IN endpoint");
|
|
}
|
|
if (0U == ((usb_shim_metadata_preamble_t *)appBuffer)->bNumberTransfers)
|
|
{
|
|
status = kStatus_USB_Error;
|
|
usb_echo("USB_ShimAgentSendData: Error the numTransfer should never zero");
|
|
}
|
|
/* Update the number of bulk in transfer */
|
|
g_shimAgent.numberTransferBulkIn = ((usb_shim_metadata_preamble_t *)appBuffer)->bNumberTransfers;
|
|
}
|
|
}
|
|
#endif
|
|
/* Initialize the data to send */
|
|
dataToSend = &g_shimAgent.bulkInData;
|
|
}
|
|
else
|
|
{
|
|
/* Initialize the data to send */
|
|
dataToSend = &g_shimAgent.interruptInData;
|
|
}
|
|
if (kStatus_USB_Success == status)
|
|
{
|
|
/* Set bit map for the corresponding endpoint*/
|
|
g_shimAgent.endpointsHaveData |= (uint16_t)(1U << dataToSend->epNumber);
|
|
/* Add data to send to sending queue */
|
|
if ((uint8_t)(dataToSend->seller - dataToSend->buyer) < (uint8_t)(SHIM_AGENT_MAX_QUEUE_NUMBER))
|
|
{
|
|
dataToSend->sendData[dataToSend->seller % SHIM_AGENT_MAX_QUEUE_NUMBER].transferSize = size;
|
|
dataToSend->sendData[dataToSend->seller % SHIM_AGENT_MAX_QUEUE_NUMBER].buffer = appBuffer;
|
|
/* increase queue number by 1 */
|
|
dataToSend->seller += 1U;
|
|
/* send the first entry of queue */
|
|
if (1U == (uint32_t)(dataToSend->seller - dataToSend->buyer))
|
|
{
|
|
status = USB_DeviceSendRequest((void *)handle, dataToSend->epNumber, appBuffer, size);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* sending queue is full */
|
|
status = kStatus_USB_Busy;
|
|
}
|
|
}
|
|
return status;
|
|
}
|