MCUXpresso_LPC55S69/boards/lpcxpresso55s69/usb_examples/usb_device_composite_cdc_vcom_cdc_vcom/freertos/cm33_core0/virtual_com.c
Yilin Sun 3969019d6a
Updated SDK v2.13.0
Signed-off-by: Yilin Sun <imi415@imi.moe>
2023-01-26 10:53:53 +08:00

440 lines
18 KiB
C

/*
* Copyright 2017 NXP
* All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <stdio.h>
#include <stdlib.h>
/*${standard_header_anchor}*/
#include "fsl_device_registers.h"
#include "clock_config.h"
#include "board.h"
#include "usb_device_config.h"
#include "usb.h"
#include "usb_device.h"
#include "usb_device_class.h"
#include "usb_device_cdc_acm.h"
#include "usb_device_ch9.h"
#include "fsl_debug_console.h"
#include "usb_device_descriptor.h"
#include "composite.h"
/*******************************************************************************
* Definitions
******************************************************************************/
/*******************************************************************************
* Variables
******************************************************************************/
extern usb_device_endpoint_struct_t g_cdcVcomDicEndpoints[];
extern usb_device_endpoint_struct_t g_cdcVcomDicEndpoints_2[];
extern usb_device_endpoint_struct_t g_cdcVcomCicEndpoints[];
extern usb_device_endpoint_struct_t g_cdcVcomCicEndpoints_2[];
extern usb_device_class_struct_t g_UsbDeviceCdcVcomConfig[2];
/* Line coding of cdc device */
USB_DMA_INIT_DATA_ALIGN(USB_DATA_ALIGN_SIZE)
static uint8_t s_lineCoding[USB_DEVICE_CONFIG_CDC_ACM][LINE_CODING_SIZE] = {
{/* E.g. 0x00,0xC2,0x01,0x00 : 0x0001C200 is 115200 bits per second */
(LINE_CODING_DTERATE >> 0U) & 0x000000FFU, (LINE_CODING_DTERATE >> 8U) & 0x000000FFU,
(LINE_CODING_DTERATE >> 16U) & 0x000000FFU, (LINE_CODING_DTERATE >> 24U) & 0x000000FFU, LINE_CODING_CHARFORMAT,
LINE_CODING_PARITYTYPE, LINE_CODING_DATABITS},
{/* E.g. 0x00,0xC2,0x01,0x00 : 0x0001C200 is 115200 bits per second */
(LINE_CODING_DTERATE >> 0U) & 0x000000FFU, (LINE_CODING_DTERATE >> 8U) & 0x000000FFU,
(LINE_CODING_DTERATE >> 16U) & 0x000000FFU, (LINE_CODING_DTERATE >> 24U) & 0x000000FFU, LINE_CODING_CHARFORMAT,
LINE_CODING_PARITYTYPE, LINE_CODING_DATABITS},
};
/* Abstract state of cdc device */
USB_DMA_INIT_DATA_ALIGN(USB_DATA_ALIGN_SIZE)
static uint8_t s_abstractState[USB_DEVICE_CONFIG_CDC_ACM][COMM_FEATURE_DATA_SIZE] = {
{(STATUS_ABSTRACT_STATE >> 0U) & 0x00FFU, (STATUS_ABSTRACT_STATE >> 8U) & 0x00FFU},
{(STATUS_ABSTRACT_STATE >> 0U) & 0x00FFU, (STATUS_ABSTRACT_STATE >> 8U) & 0x00FFU},
};
/* Country code of cdc device */
USB_DMA_INIT_DATA_ALIGN(USB_DATA_ALIGN_SIZE)
static uint8_t s_countryCode[USB_DEVICE_CONFIG_CDC_ACM][COMM_FEATURE_DATA_SIZE] = {
{(COUNTRY_SETTING >> 0U) & 0x00FFU, (COUNTRY_SETTING >> 8U) & 0x00FFU},
{(COUNTRY_SETTING >> 0U) & 0x00FFU, (COUNTRY_SETTING >> 8U) & 0x00FFU},
};
/* CDC ACM information */
USB_DMA_INIT_DATA_ALIGN(USB_DATA_ALIGN_SIZE)
static usb_cdc_acm_info_t s_usbCdcAcmInfo[USB_DEVICE_CONFIG_CDC_ACM] = {
{{0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 0, 0, 0, 0, 0},
{{0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 0, 0, 0, 0, 0},
};
/* Data buffer for receiving and sending*/
USB_DMA_NONINIT_DATA_ALIGN(USB_DATA_ALIGN_SIZE) static uint8_t s_currRecvBuf[USB_DEVICE_CONFIG_CDC_ACM][DATA_BUFF_SIZE];
USB_DMA_NONINIT_DATA_ALIGN(USB_DATA_ALIGN_SIZE) static uint8_t s_currSendBuf[USB_DEVICE_CONFIG_CDC_ACM][DATA_BUFF_SIZE];
volatile static uint32_t s_recvSize[USB_DEVICE_CONFIG_CDC_ACM] = {0};
volatile static uint32_t s_sendSize[USB_DEVICE_CONFIG_CDC_ACM] = {0};
volatile static usb_device_composite_struct_t *g_deviceComposite;
/*******************************************************************************
* Code
******************************************************************************/
/*!
* @brief CDC class specific callback function.
*
* This function handles the CDC class specific requests.
*
* @param handle The CDC ACM class handle.
* @param event The CDC ACM class event type.
* @param param The parameter of the class specific request.
*
* @return A USB error code or kStatus_USB_Success.
*/
usb_status_t USB_DeviceCdcVcomCallback(class_handle_t handle, uint32_t event, void *param)
{
uint32_t len;
uint8_t *uartBitmap;
usb_cdc_acm_info_t *acmInfo;
usb_device_cdc_acm_request_param_struct_t *acmReqParam;
usb_device_endpoint_callback_message_struct_t *epCbParam;
volatile usb_cdc_vcom_struct_t *vcomInstance;
usb_status_t error = kStatus_USB_InvalidRequest;
uint8_t i;
acmReqParam = (usb_device_cdc_acm_request_param_struct_t *)param;
epCbParam = (usb_device_endpoint_callback_message_struct_t *)param;
for (i = 0; i < USB_DEVICE_CONFIG_CDC_ACM; i++)
{
if (handle == g_deviceComposite->cdcVcom[i].cdcAcmHandle)
{
break;
}
}
if (i >= USB_DEVICE_CONFIG_CDC_ACM)
{
return error;
}
vcomInstance = &g_deviceComposite->cdcVcom[i];
acmInfo = vcomInstance->usbCdcAcmInfo;
switch (event)
{
case kUSB_DeviceCdcEventSendResponse:
{
if ((epCbParam->length != 0) && (!(epCbParam->length % vcomInstance->bulkInEndpointMaxPacketSize)))
{
/* If the last packet is the size of endpoint, then send also zero-ended packet,
** meaning that we want to inform the host that we do not have any additional
** data, so it can flush the output.
*/
error = USB_DeviceCdcAcmSend(handle, vcomInstance->bulkInEndpoint, NULL, 0);
}
else if ((1 == vcomInstance->attach) && (1 == vcomInstance->startTransactions))
{
if ((epCbParam->buffer != NULL) || ((epCbParam->buffer == NULL) && (epCbParam->length == 0)))
{
/* User: add your own code for send complete event */
/* Schedule buffer for next receive event */
error = USB_DeviceCdcAcmRecv(handle, vcomInstance->bulkOutEndpoint, vcomInstance->currRecvBuf,
vcomInstance->bulkOutEndpointMaxPacketSize);
}
}
else
{
}
}
break;
case kUSB_DeviceCdcEventRecvResponse:
{
if ((1 == vcomInstance->attach) && (1 == vcomInstance->startTransactions))
{
vcomInstance->recvSize = epCbParam->length;
if (!vcomInstance->recvSize)
{
/* Schedule buffer for next receive event */
error = USB_DeviceCdcAcmRecv(handle, vcomInstance->bulkOutEndpoint, vcomInstance->currRecvBuf,
vcomInstance->bulkOutEndpointMaxPacketSize);
}
}
}
break;
case kUSB_DeviceCdcEventSerialStateNotif:
((usb_device_cdc_acm_struct_t *)handle)->hasSentState = 0;
error = kStatus_USB_Success;
break;
case kUSB_DeviceCdcEventSendEncapsulatedCommand:
break;
case kUSB_DeviceCdcEventGetEncapsulatedResponse:
break;
case kUSB_DeviceCdcEventSetCommFeature:
if (USB_DEVICE_CDC_FEATURE_ABSTRACT_STATE == acmReqParam->setupValue)
{
if (1 == acmReqParam->isSetup)
{
*(acmReqParam->buffer) = vcomInstance->abstractState;
*(acmReqParam->length) = COMM_FEATURE_DATA_SIZE;
}
else
{
/* no action, data phase, s_abstractState has been assigned */
}
error = kStatus_USB_Success;
}
else if (USB_DEVICE_CDC_FEATURE_COUNTRY_SETTING == acmReqParam->setupValue)
{
if (1 == acmReqParam->isSetup)
{
*(acmReqParam->buffer) = vcomInstance->countryCode;
*(acmReqParam->length) = COMM_FEATURE_DATA_SIZE;
}
else
{
/* no action, data phase, s_countryCode has been assigned */
}
error = kStatus_USB_Success;
}
else
{
/* no action, return kStatus_USB_InvalidRequest */
}
break;
case kUSB_DeviceCdcEventGetCommFeature:
if (USB_DEVICE_CDC_FEATURE_ABSTRACT_STATE == acmReqParam->setupValue)
{
*(acmReqParam->buffer) = vcomInstance->abstractState;
*(acmReqParam->length) = COMM_FEATURE_DATA_SIZE;
error = kStatus_USB_Success;
}
else if (USB_DEVICE_CDC_FEATURE_COUNTRY_SETTING == acmReqParam->setupValue)
{
*(acmReqParam->buffer) = vcomInstance->countryCode;
*(acmReqParam->length) = COMM_FEATURE_DATA_SIZE;
error = kStatus_USB_Success;
}
else
{
/* no action, return kStatus_USB_InvalidRequest */
}
break;
case kUSB_DeviceCdcEventClearCommFeature:
break;
case kUSB_DeviceCdcEventGetLineCoding:
*(acmReqParam->buffer) = vcomInstance->lineCoding;
*(acmReqParam->length) = LINE_CODING_SIZE;
error = kStatus_USB_Success;
break;
case kUSB_DeviceCdcEventSetLineCoding:
{
if (1 == acmReqParam->isSetup)
{
*(acmReqParam->buffer) = vcomInstance->lineCoding;
*(acmReqParam->length) = LINE_CODING_SIZE;
}
else
{
/* no action, data phase, s_lineCoding has been assigned */
}
error = kStatus_USB_Success;
}
break;
case kUSB_DeviceCdcEventSetControlLineState:
{
error = kStatus_USB_Success;
vcomInstance->usbCdcAcmInfo->dteStatus = acmReqParam->setupValue;
/* activate/deactivate Tx carrier */
if (acmInfo->dteStatus & USB_DEVICE_CDC_CONTROL_SIG_BITMAP_CARRIER_ACTIVATION)
{
acmInfo->uartState |= USB_DEVICE_CDC_UART_STATE_TX_CARRIER;
}
else
{
acmInfo->uartState &= (uint16_t)~USB_DEVICE_CDC_UART_STATE_TX_CARRIER;
}
/* activate carrier and DTE. Com port of terminal tool running on PC is open now */
if (acmInfo->dteStatus & USB_DEVICE_CDC_CONTROL_SIG_BITMAP_DTE_PRESENCE)
{
acmInfo->uartState |= USB_DEVICE_CDC_UART_STATE_RX_CARRIER;
}
/* Com port of terminal tool running on PC is closed now */
else
{
acmInfo->uartState &= (uint16_t)~USB_DEVICE_CDC_UART_STATE_RX_CARRIER;
}
/* Indicates to DCE if DTE is present or not */
acmInfo->dtePresent = (acmInfo->dteStatus & USB_DEVICE_CDC_CONTROL_SIG_BITMAP_DTE_PRESENCE) ? true : false;
/* Initialize the serial state buffer */
acmInfo->serialStateBuf[0] = NOTIF_REQUEST_TYPE; /* bmRequestType */
acmInfo->serialStateBuf[1] = USB_DEVICE_CDC_NOTIF_SERIAL_STATE; /* bNotification */
acmInfo->serialStateBuf[2] = 0x00; /* wValue */
acmInfo->serialStateBuf[3] = 0x00;
acmInfo->serialStateBuf[4] = 0x00; /* wIndex */
acmInfo->serialStateBuf[5] = 0x00;
acmInfo->serialStateBuf[6] = UART_BITMAP_SIZE; /* wLength */
acmInfo->serialStateBuf[7] = 0x00;
/* Notify to host the line state */
acmInfo->serialStateBuf[4] = acmReqParam->interfaceIndex;
/* Lower byte of UART BITMAP */
uartBitmap = (uint8_t *)&acmInfo->serialStateBuf[NOTIF_PACKET_SIZE + UART_BITMAP_SIZE - 2];
uartBitmap[0] = acmInfo->uartState & 0xFFu;
uartBitmap[1] = (acmInfo->uartState >> 8) & 0xFFu;
len = (uint32_t)(NOTIF_PACKET_SIZE + UART_BITMAP_SIZE);
if (0 == ((usb_device_cdc_acm_struct_t *)handle)->hasSentState)
{
error = USB_DeviceCdcAcmSend(handle, vcomInstance->interruptEndpoint, acmInfo->serialStateBuf, len);
if (kStatus_USB_Success != error)
{
usb_echo("kUSB_DeviceCdcEventSetControlLineState error!");
}
((usb_device_cdc_acm_struct_t *)handle)->hasSentState = 1;
}
/* Update status */
if (acmInfo->dteStatus & USB_DEVICE_CDC_CONTROL_SIG_BITMAP_CARRIER_ACTIVATION)
{
/* To do: CARRIER_ACTIVATED */
}
else
{
/* To do: CARRIER_DEACTIVATED */
}
if (1U == vcomInstance->attach)
{
vcomInstance->startTransactions = 1;
}
error = kStatus_USB_Success;
}
break;
case kUSB_DeviceCdcEventSendBreak:
break;
default:
break;
}
return error;
}
/*!
* @brief Application task function.
*
* This function runs the task for application.
*
* @return None.
*/
void USB_DeviceCdcVcomTask(void)
{
usb_status_t error = kStatus_USB_Error;
volatile usb_cdc_vcom_struct_t *vcomInstance;
for (uint8_t i = 0; i < USB_DEVICE_CONFIG_CDC_ACM; i++)
{
vcomInstance = &g_deviceComposite->cdcVcom[i];
if ((1 == vcomInstance->attach) && (1 == vcomInstance->startTransactions))
{
/* User Code */
/* endpoint callback length is USB_CANCELLED_TRANSFER_LENGTH (0xFFFFFFFFU) when transfer is canceled */
if ((0 != vcomInstance->recvSize) && (USB_CANCELLED_TRANSFER_LENGTH != vcomInstance->recvSize))
{
int32_t i;
/* Copy Buffer to Send Buff */
for (i = 0; i < vcomInstance->recvSize; i++)
{
vcomInstance->currSendBuf[vcomInstance->sendSize++] = vcomInstance->currRecvBuf[i];
}
vcomInstance->recvSize = 0;
}
if (vcomInstance->sendSize)
{
uint32_t size = vcomInstance->sendSize;
vcomInstance->sendSize = 0;
error = USB_DeviceCdcAcmSend(vcomInstance->cdcAcmHandle, vcomInstance->bulkInEndpoint,
vcomInstance->currSendBuf, size);
if (error != kStatus_USB_Success)
{
/* Failure to send Data Handling code here */
}
}
}
}
}
/*!
* @brief Virtual COM device set configuration function.
*
* This function sets configuration for CDC class.
*
* @param handle The CDC ACM class handle.
* @param configure The CDC ACM class configure index.
*
* @return A USB error code or kStatus_USB_Success.
*/
usb_status_t USB_DeviceCdcVcomSetConfigure(class_handle_t handle, uint8_t configure)
{
if (USB_COMPOSITE_CONFIGURE_INDEX == configure)
{
/*endpoint information for cdc 1*/
g_deviceComposite->cdcVcom[0].attach = 1;
g_deviceComposite->cdcVcom[0].interruptEndpoint = USB_CDC_VCOM_CIC_INTERRUPT_IN_ENDPOINT;
g_deviceComposite->cdcVcom[0].interruptEndpointMaxPacketSize = g_cdcVcomCicEndpoints[0].maxPacketSize;
g_deviceComposite->cdcVcom[0].bulkInEndpoint = USB_CDC_VCOM_DIC_BULK_IN_ENDPOINT;
g_deviceComposite->cdcVcom[0].bulkInEndpointMaxPacketSize = g_cdcVcomDicEndpoints[0].maxPacketSize;
g_deviceComposite->cdcVcom[0].bulkOutEndpoint = USB_CDC_VCOM_DIC_BULK_OUT_ENDPOINT;
g_deviceComposite->cdcVcom[0].bulkOutEndpointMaxPacketSize = g_cdcVcomDicEndpoints[1].maxPacketSize;
/* Schedule buffer for receive */
USB_DeviceCdcAcmRecv(g_deviceComposite->cdcVcom[0].cdcAcmHandle, g_deviceComposite->cdcVcom[0].bulkOutEndpoint,
s_currRecvBuf[0], g_deviceComposite->cdcVcom[0].bulkOutEndpointMaxPacketSize);
/*endpoint information for cdc 2*/
g_deviceComposite->cdcVcom[1].attach = 1;
g_deviceComposite->cdcVcom[1].interruptEndpoint = USB_CDC_VCOM_CIC_INTERRUPT_IN_ENDPOINT_2;
g_deviceComposite->cdcVcom[1].interruptEndpointMaxPacketSize = g_cdcVcomCicEndpoints_2[0].maxPacketSize;
g_deviceComposite->cdcVcom[1].bulkInEndpoint = USB_CDC_VCOM_DIC_BULK_IN_ENDPOINT_2;
g_deviceComposite->cdcVcom[1].bulkInEndpointMaxPacketSize = g_cdcVcomDicEndpoints_2[0].maxPacketSize;
g_deviceComposite->cdcVcom[1].bulkOutEndpoint = USB_CDC_VCOM_DIC_BULK_OUT_ENDPOINT_2;
g_deviceComposite->cdcVcom[1].bulkOutEndpointMaxPacketSize = g_cdcVcomDicEndpoints_2[1].maxPacketSize;
/* Schedule buffer for receive */
USB_DeviceCdcAcmRecv(g_deviceComposite->cdcVcom[1].cdcAcmHandle, g_deviceComposite->cdcVcom[1].bulkOutEndpoint,
s_currRecvBuf[1], g_deviceComposite->cdcVcom[1].bulkOutEndpointMaxPacketSize);
}
return kStatus_USB_Success;
}
/*!
* @brief Virtual COM device initialization function.
*
* This function initializes the device with the composite device class information.
*
* @param deviceComposite The pointer to the composite device structure.
*
* @return A USB error code or kStatus_USB_Success.
*/
usb_status_t USB_DeviceCdcVcomInit(usb_device_composite_struct_t *deviceComposite)
{
g_deviceComposite = deviceComposite;
for (uint8_t i = 0; i < USB_DEVICE_CONFIG_CDC_ACM; i++)
{
g_deviceComposite->cdcVcom[i].lineCoding = (uint8_t *)&s_lineCoding[i];
g_deviceComposite->cdcVcom[i].abstractState = (uint8_t *)&s_abstractState[i];
g_deviceComposite->cdcVcom[i].countryCode = (uint8_t *)&s_countryCode[i];
g_deviceComposite->cdcVcom[i].usbCdcAcmInfo = &s_usbCdcAcmInfo[i];
g_deviceComposite->cdcVcom[i].currRecvBuf = (uint8_t *)&s_currRecvBuf[i][0];
;
g_deviceComposite->cdcVcom[i].currSendBuf = (uint8_t *)&s_currSendBuf[i][0];
}
return kStatus_USB_Success;
}