Files
test/middleware/usb/uC-USBD/Class/CDC/ACM/usbd_acm_serial.c
2025-11-07 20:19:23 +08:00

1947 lines
87 KiB
C

/*
*********************************************************************************************************
* uC/USB-Device
* The Embedded USB Device Stack
*
* Copyright 2004-2021 Silicon Laboratories Inc. www.silabs.com
*
* SPDX-License-Identifier: APACHE-2.0
*
* This software is subject to an open source license and is distributed by
* Silicon Laboratories Inc. pursuant to the terms of the Apache License,
* Version 2.0 available at www.apache.org/licenses/LICENSE-2.0.
*
*********************************************************************************************************
*/
/*
*********************************************************************************************************
* NOTICE
*
* Semidrive modified this file to adapt it for ssdk platform.
* The modifications are only intended for use with Semidrive chips.
* Copyright of all the modifications belongs to Semidrive Semiconductor.
*
*********************************************************************************************************
*/
/*
*********************************************************************************************************
*
* USB COMMUNICATIONS DEVICE CLASS (CDC)
* ABSTRACT CONTROL MODEL (ACM)
* SERIAL EMULATION
*
* Filename : usbd_acm_serial.c
* Version : V4.06.01
*********************************************************************************************************
* Note(s) : (1) This implementation is compliant with the PSTN subclass specification revision 1.2
* February 9, 2007.
*********************************************************************************************************
*/
/*
*********************************************************************************************************
* INCLUDE FILES
*********************************************************************************************************
*/
#define MICRIUM_SOURCE
#include "usbd_acm_serial.h"
/*
*********************************************************************************************************
* MODULE
*********************************************************************************************************
*/
/*
*********************************************************************************************************
* LOCAL DEFINES
*********************************************************************************************************
*/
#define USBD_ACM_CTRL_REQ_TIMEOUT_mS 5000u
/*
*********************************************************************************************************
* ACM FUNCTIONAL DESCRIPTORS SIZES DEFINES
*
* Note(s) : (1) Table 3 and 4 from the PSTN specification version 1.2 defines the Call management
* and ACM management functional descriptors.
*********************************************************************************************************
*/
#define USBD_ACM_DESC_CALL_MGMT_SIZE 5u
#define USBD_ACM_DESC_SIZE 4u
#define USBD_ACM_DESC_TOT_SIZE (USBD_ACM_DESC_CALL_MGMT_SIZE + \
USBD_ACM_DESC_SIZE)
/*
*********************************************************************************************************
* ACM SERIAL NOTIFICATIONS DEFINES
*********************************************************************************************************
*/
#define USBD_ACM_SERIAL_REQ_STATE USBD_CDC_NTF_SERIAL_STATE /* Serial state notification code. */
#define USBD_ACM_SERIAL_REQ_STATE_SIZE 2u /* Serial state notification data size. */
#define USBD_ACM_SERIAL_STATE_BUF_SIZE (USBD_CDC_NOTIFICATION_HEADER + \
USBD_ACM_SERIAL_REQ_STATE_SIZE)
/*
*********************************************************************************************************
* ABSTRACT STATE FEATURE DEFINES
*********************************************************************************************************
*/
#define USBD_ACM_SERIAL_ABSTRACT_DATA_MUX DEF_BIT_01
#define USBD_ACM_SERIAL_ABSTRACT_IDLE DEF_BIT_00
/*
*********************************************************************************************************
* LINE STATE SIGNAL DEFINES
*********************************************************************************************************
*/
/* Consistent signals. */
#define USBD_ACM_SERIAL_EVENTS_CONS (USBD_ACM_SERIAL_STATE_DCD | \
USBD_ACM_SERIAL_STATE_DSR)
/* Irregular signals. */
#define USBD_ACM_SERIAL_EVENTS_IRRE (USBD_ACM_SERIAL_STATE_BREAK | \
USBD_ACM_SERIAL_STATE_RING | \
USBD_ACM_SERIAL_STATE_PARITY | \
USBD_ACM_SERIAL_STATE_FRAMING | \
USBD_ACM_SERIAL_STATE_OVERUN)
/*
*********************************************************************************************************
* SET CONTROL LINE STATE DEFINES
*
* Note(s): (1) The PSTN specification version 1.2 defines the 'SetControlLineState' request as:
*
* +---------------+-------------------+------------------+-----------+---------+------+
* | bmRequestType | bRequestCode | wValue | wIndex | wLength | Data |
* +---------------+-------------------+------------------+-----------+---------+------+
* | 00100001B | SET_CONTROL_LINE_ | Control Signal | Interface | Zero | None |
* | | STATE | Bitmap | | | |
* +---------------+-------------------+------------------+-----------+---------+------+
*
*
* (a) Table 18 from the PSTN specification defines the control signal bitmap values for
* the SET_CONTROL_LINE_STATE
*
* Bit Position
* -------------
* D1 Carrier control for half duplex modems. This signal correspond to
* V.24 signal 105 and RS-232 signal RTS.
*
* D0 Indicates to DCE if DTE is present or not. This signal corresponds to
* V.24 signal 108/2 and RS-232 signal DTR.
*********************************************************************************************************
*/
#define USBD_ACM_SERIAL_REQ_DTR DEF_BIT_00
#define USBD_ACM_SERIAL_REQ_RTS DEF_BIT_01
/*
*********************************************************************************************************
* COMMUNICATION FEATURE SELECTOR DEFINES
*
** Note(s): (1) The PSTN specification version 1.2 defines the 'GetCommFeature' request as:
*
* +---------------+-------------------+------------------+-----------+-------------+--------+
* | bmRequestType | bRequestCode | wValue | wIndex | wLength | Data |
* +---------------+-------------------+------------------+-----------+-------------+--------+
* | 00100001B | GET_COMM_FEATURE | Feature Selector | Interface | Length of | Status |
* | | | Bitmap | | Status Data | |
* +---------------+-------------------+------------------+-----------+-------------+--------+
*
*
* (a) Table 14 from the PSTN specification defines the communication feature selector codes:
*
* Feature Code Description
* Selector
* ---------------- -------- ----------------------------------------------------
* ABSTRACT_STATE 01h Two bytes of data describing multiplexed state and idle
* state for this Abstract Model communications device.
*
* COUNTRY_SETTING 02h Country code in hexadecimal format as defined in
* [ISO3166], release date as specified in offset 3 of
* the Country Selection Functional Descriptor. This
* selector is only valid for devices that provide a
* Country Selection Functional Descriptor, and the value
* supplied shall appear as supported country in the
* Country Selection Functional Descriptor.
*********************************************************************************************************
*/
#define USBD_ACM_SERIAL_ABSTRACT_STATE 0x01u
#define USBD_ACM_SERIAL_COUNTRY_SETTING 0x02u
/*
*********************************************************************************************************
* LOCAL CONSTANTS
*********************************************************************************************************
*/
/*
*********************************************************************************************************
* LOCAL DATA TYPES
*********************************************************************************************************
*/
/*
*********************************************************************************************************
* FORWARD DECLARATIONS
*********************************************************************************************************
*/
/*
*********************************************************************************************************
* CDC ACM SERIAL CTRL DATA TYPE
*********************************************************************************************************
*/
typedef struct usbd_acm_serial_ctrl { /* --------- ACM SUBCLASS CONTROL INFORMATION --------- */
CPU_INT08U Nbr; /* CDC dev nbr. */
CPU_BOOLEAN Idle;
USBD_ACM_SERIAL_LINE_CODING_CHNGD LineCodingChngdFnct;
void *LineCodingChngdArgPtr;
USBD_ACM_SERIAL_LINE_CODING LineCoding;
USBD_ACM_SERIAL_LINE_CTRL_CHNGD LineCtrlChngdFnct;
void *LineCtrlChngdArgPtr;
CPU_INT08U LineCtrl;
CPU_INT08U LineState;
CPU_INT16U LineStateInterval;
CPU_INT08U *LineStateBufPtr;
CPU_BOOLEAN LineStateSent;
CPU_INT08U CallMgmtCapabilities;
CPU_INT08U *ReqBufPtr;
} USBD_ACM_SERIAL_CTRL;
/*
*********************************************************************************************************
* LOCAL TABLES
*********************************************************************************************************
*/
/*
*********************************************************************************************************
* LOCAL GLOBAL VARIABLES
*********************************************************************************************************
*/
static USBD_ACM_SERIAL_CTRL USBD_ACM_SerialCtrlTbl[USBD_ACM_SERIAL_CFG_MAX_NBR_DEV];
static CPU_INT08U USBD_ACM_SerialCtrlNbrNext;
/*
*********************************************************************************************************
* LOCAL FUNCTION PROTOTYPES
*********************************************************************************************************
*/
static CPU_BOOLEAN USBD_ACM_SerialMgmtReq ( CPU_INT08U dev_nbr,
const USBD_SETUP_REQ *p_setup_req,
void *p_subclass_arg);
static void USBD_ACM_SerialNotifyCmpl ( CPU_INT08U dev_nbr,
void *p_subclass_arg);
static void USBD_ACM_SerialFnctDesc ( CPU_INT08U dev_nbr,
void *p_subclass_arg,
CPU_INT08U first_dci_if_nbr);
static CPU_INT16U USBD_ACM_SerialFnctDescSizeGet( CPU_INT08U dev_nbr,
void *p_subclass_arg);
/*
*********************************************************************************************************
* CDC ACM CLASS DRIVER
*********************************************************************************************************
*/
static USBD_CDC_SUBCLASS_DRV USBD_ACM_SerialDrv = {
USBD_ACM_SerialMgmtReq,
USBD_ACM_SerialNotifyCmpl,
USBD_ACM_SerialFnctDesc,
USBD_ACM_SerialFnctDescSizeGet,
DEF_NULL,
#if (USBD_CFG_MS_OS_DESC_EN == DEF_ENABLED)
NULL,
#endif
};
/*
*********************************************************************************************************
* LOCAL CONFIGURATION ERRORS
*********************************************************************************************************
*/
/*
*********************************************************************************************************
* INTERFACE DRIVER
*********************************************************************************************************
*/
/*
*********************************************************************************************************
*********************************************************************************************************
* APPLICATION FUNCTIONS
*********************************************************************************************************
*********************************************************************************************************
*/
/*
*********************************************************************************************************
* USBD_ACM_SerialInit()
*
* Description : Initialize CDC ACM serial emulation subclass.
*
* Argument(s) : p_err Pointer to variable that will receive the return error code from this function :
*
* USBD_ERR_NONE CDC ACM serial emulation subclass initialized successfully.
*
* Return(s) : none.
*
* Note(s) : none.
*********************************************************************************************************
*/
void USBD_ACM_SerialInit (USBD_ERR *p_err)
{
CPU_INT08U ix;
USBD_ACM_SERIAL_CTRL *p_ctrl;
LIB_ERR err_lib;
#if (USBD_CFG_ERR_ARG_CHK_EXT_EN == DEF_ENABLED) /* ---------------- VALIDATE ARGUMENTS ---------------- */
if (p_err == (USBD_ERR *)0) { /* Validate error ptr. */
CPU_SW_EXCEPTION(;);
}
#endif
/* Init ACM serial ctrl. */
for (ix = 0u; ix < USBD_ACM_SERIAL_CFG_MAX_NBR_DEV; ix++) {
p_ctrl = &USBD_ACM_SerialCtrlTbl[ix];
p_ctrl->Nbr = USBD_CDC_NBR_NONE;
p_ctrl->Idle = DEF_NO;
p_ctrl->LineCodingChngdFnct = (USBD_ACM_SERIAL_LINE_CODING_CHNGD)0;
p_ctrl->LineCodingChngdArgPtr = (void *)0;
p_ctrl->LineCoding.BaudRate = 9600u;
p_ctrl->LineCoding.Parity = USBD_ACM_SERIAL_PARITY_NONE;
p_ctrl->LineCoding.StopBits = USBD_ACM_SERIAL_STOP_BIT_1;
p_ctrl->LineCoding.DataBits = 8u;
p_ctrl->LineCtrlChngdFnct = (USBD_ACM_SERIAL_LINE_CTRL_CHNGD)0;
p_ctrl->LineCtrlChngdArgPtr = (void *)0;
p_ctrl->LineCtrl = DEF_BIT_NONE;
p_ctrl->LineStateSent = DEF_NO;
p_ctrl->LineStateInterval = 0u;
p_ctrl->LineState = 0u;
p_ctrl->CallMgmtCapabilities = 0u;
p_ctrl->ReqBufPtr = (CPU_INT08U *)Mem_HeapAlloc( 7u,
USBD_CFG_BUF_ALIGN_OCTETS,
(CPU_SIZE_T *)DEF_NULL,
&err_lib);
if (err_lib != LIB_MEM_ERR_NONE) {
*p_err = USBD_ERR_ALLOC;
return;
}
p_ctrl->LineStateBufPtr = (CPU_INT08U *)Mem_HeapAlloc( USBD_ACM_SERIAL_STATE_BUF_SIZE,
USBD_CFG_BUF_ALIGN_OCTETS,
(CPU_SIZE_T *)DEF_NULL,
&err_lib);
if (err_lib != LIB_MEM_ERR_NONE) {
*p_err = USBD_ERR_ALLOC;
return;
}
Mem_Clr((void *)&p_ctrl->LineStateBufPtr[0],
USBD_ACM_SERIAL_STATE_BUF_SIZE);
}
USBD_ACM_SerialCtrlNbrNext = 0u;
*p_err = USBD_ERR_NONE;
}
/*
*********************************************************************************************************
* USBD_ACM_SerialAdd()
*
* Description : Add a new instance of the CDC ACM serial emulation subclass.
*
* Argument(s) : line_state_interval Line state notification interval in milliseconds. The value must
* be a power of 2.
*
* call_mgmt_capabilities Call Management Capabilities bitmap. OR'ed of the following
* flags (see Note #1):
*
* USBD_ACM_SERIAL_CALL_MGMT_DEV Device handles call management itself.
* USBD_ACM_SERIAL_CALL_MGMT_DATA_CCI_DCI Device can send/receive call management
* information over a Data Class interface.
*
* p_err Pointer to variable that will receive the return error code from this function :
*
* USBD_ERR_NONE CDC ACM serial emulation subclass instance
* successfully added.
* USBD_ERR_ALLOC CDC ACM serial emulation subclass instance NOT available.
*
* ---------- RETURNED BY USBD_CDC_Add() : ----------
* USBD_ERR_ALLOC CDC class instance NOT available.
*
* ------ RETURNED BY USBD_CDC_DataIF_Add() : -------
* USBD_ERR_ALLOC Data interface instance NOT available.
* USBD_ERR_INVALID_ARG Invalid argument(s) passed to 'class_nbr/'isoc_en'.
*
* Return(s) : CDC ACM serial emulation subclass instance number.
*
* Note(s) : (1) See Note #2 of the function USBD_ACM_SerialFnctDesc() for more details about the
* Call Management capabilities.
*
* (2) Depending on the operating system (Windows, Linux or Mac OS X), not all the possible
* flags combinations are supported. Windows and Linux supports all combinations whereas
* Mac OS X supports all except the combination (USBD_ACM_SERIAL_CALL_MGMT_DEV).
*********************************************************************************************************
*/
CPU_INT08U USBD_ACM_SerialAdd (CPU_INT16U line_state_interval,
CPU_INT16U call_mgmt_capabilities,
USBD_ERR *p_err)
{
USBD_ACM_SERIAL_CTRL *p_ctrl;
CPU_INT08U subclass_nbr;
CPU_INT08U class_nbr;
CPU_SR_ALLOC();
#if (USBD_CFG_ERR_ARG_CHK_EXT_EN == DEF_ENABLED) /* ---------------- VALIDATE ARGUMENTS ---------------- */
if (p_err == (USBD_ERR *)0) { /* Validate error ptr. */
CPU_SW_EXCEPTION(0);
}
#endif
CPU_CRITICAL_ENTER();
subclass_nbr = USBD_ACM_SerialCtrlNbrNext; /* Alloc new CDC ACM serial emulation subclass. */
if (subclass_nbr >= USBD_ACM_SERIAL_CFG_MAX_NBR_DEV) {
CPU_CRITICAL_EXIT();
*p_err = USBD_ERR_CDC_SUBCLASS_INSTANCE_ALLOC;
return (USBD_ACM_SERIAL_NBR_NONE);
}
USBD_ACM_SerialCtrlNbrNext++;
CPU_CRITICAL_EXIT();
/* Init control struct. */
p_ctrl = &USBD_ACM_SerialCtrlTbl[subclass_nbr];
/* Create new CDC device. */
class_nbr = USBD_CDC_Add( USBD_CDC_SUBCLASS_ACM,
&USBD_ACM_SerialDrv,
(void *)p_ctrl,
USBD_CDC_COMM_PROTOCOL_AT_V250,
DEF_ENABLED,
line_state_interval,
p_err);
if (*p_err != USBD_ERR_NONE) {
return (USBD_ACM_SERIAL_NBR_NONE);
}
/* Add data IF class to CDC device. */
(void)USBD_CDC_DataIF_Add(class_nbr,
DEF_DISABLED,
USBD_CDC_DATA_PROTOCOL_NONE,
p_err);
if (*p_err != USBD_ERR_NONE) {
return (USBD_ACM_SERIAL_NBR_NONE);
}
p_ctrl->LineStateInterval = line_state_interval;
p_ctrl->CallMgmtCapabilities = call_mgmt_capabilities; /* See Note #2. */
p_ctrl->Nbr = class_nbr;
*p_err = USBD_ERR_NONE;
return (subclass_nbr);
}
/*
*********************************************************************************************************
* USBD_ACM_SerialCfgAdd()
*
* Description : Add CDC ACM subclass class instance into USB device configuration.
*
* Argument(s) : subclass_nbr CDC ACM serial emulation subclass instance number.
*
* dev_nbr Device number.
*
* cfg_nbr Configuration index to add new test class interface to.
*
* p_err Pointer to variable that will receive the return error code from this function :
*
* USBD_ERR_NONE CDC ACM serial subclass configuration
* successfully added.
* USBD_ERR_INVALID_ARG Invalid argument(s) passed to 'subclass_nbr'.
*
* -------- RETURNED BY USBD_CDC_CfgAdd() : --------
* USBD_ERR_ALLOC CDC class communication instances NOT available.
* USBD_ERR_INVALID_ARG Invalid argument(s) passed to 'interval'.
*
* USBD_ERR_DEV_INVALID_NBR Invalid device number.
* USBD_ERR_INVALID_CLASS_STATE Invalid class state.
* USBD_ERR_CFG_INVALID_NBR Invalid configuration number.
* USBD_ERR_IF_ALLOC Interfaces NOT available.
* USBD_ERR_IF_ALT_ALLOC Interface alternate settings NOT available.
* USBD_ERR_EP_NONE_AVAIL Physical endpoint NOT available.
* USBD_ERR_EP_ALLOC Endpoints NOT available.
*
* Return(s) : DEF_YES, if CDC ACM serial subclass instance added to USB device configuration
* successfully.
*
* DEF_NO, otherwise.
*
* Note(s) : none.
*********************************************************************************************************
*/
CPU_BOOLEAN USBD_ACM_SerialCfgAdd (CPU_INT08U subclass_nbr,
CPU_INT08U dev_nbr,
CPU_INT08U cfg_nbr,
USBD_ERR *p_err)
{
USBD_ACM_SERIAL_CTRL *p_ctrl;
#if (USBD_CFG_ERR_ARG_CHK_EXT_EN == DEF_ENABLED) /* ---------------- VALIDATE ARGUMENTS ---------------- */
if (p_err == (USBD_ERR *)0) { /* Validate error ptr. */
CPU_SW_EXCEPTION(DEF_NO);
}
#endif
if (subclass_nbr >= USBD_ACM_SerialCtrlNbrNext) {
*p_err = USBD_ERR_CLASS_INVALID_NBR;
return (DEF_NO);
}
p_ctrl = &USBD_ACM_SerialCtrlTbl[subclass_nbr];
(void)USBD_CDC_CfgAdd(p_ctrl->Nbr,
dev_nbr,
cfg_nbr,
"CDC ACM Comm",
"CDC ACM Data",
"CDC ACM",
p_err);
if (*p_err != USBD_ERR_NONE) {
return (DEF_NO);
}
return (DEF_YES);
}
/*
*********************************************************************************************************
* USBD_ACM_SerialIsConn()
*
* Description : Get CDC ACM serial emulation subclass connection state.
*
* Argument(s) : subclass_nbr CDC ACM serial emulation subclass instance number.
*
* Return(s) : DEF_YES, CDC ACM serial emulation is connected.
*
* DEF_NO, otherwise.
*
* Note(s) : none.
*********************************************************************************************************
*/
CPU_BOOLEAN USBD_ACM_SerialIsConn (CPU_INT08U subclass_nbr)
{
USBD_ACM_SERIAL_CTRL *p_ctrl;
CPU_BOOLEAN conn;
#if (USBD_CFG_ERR_ARG_CHK_EXT_EN == DEF_ENABLED)
if (subclass_nbr >= USBD_ACM_SerialCtrlNbrNext) {
return (DEF_NO);
}
#endif
p_ctrl = &USBD_ACM_SerialCtrlTbl[subclass_nbr];
conn = USBD_CDC_IsConn(p_ctrl->Nbr);
return (conn);
}
/*
*********************************************************************************************************
* USBD_ACM_SerialRx()
*
* Description : Receive data on CDC ACM serial emulation subclass.
*
* Argument(s) : subclass_nbr CDC ACM serial emulation subclass instance number.
*
* p_buf Pointer to destination buffer to receive data.
*
* buf_len Number of octets to receive.
*
* timeout_ms Timeout in milliseconds.
*
* p_err Pointer to variable that will receive return error code from this function :
*
* USBD_ERR_NONE Data successfully received.
* USBD_ERR_INVALID_ARG Invalid argument(s) passed to 'subclass_nbr'.
* USBD_ERR_INVALID_CLASS_STATE Invalid subclass state or subclass is in
* idle mode.
*
* ------- RETURNED BY USBD_CDC_DataRx() : -------
* USBD_ERR_INVALID_ARG Invalid argument(s) passed to 'class_nbr'/
* 'data_if_nbr'.
* USBD_ERR_INVALID_CLASS_STATE Invalid subclass state.
* USBD_ERR_EP_INVALID_ADDR Invalid endpoint address.
* USBD_ERR_EP_INVALID_STATE Invalid endpoint state.
* USBD_ERR_EP_INVALID_TYPE Invalid endpoint type.
*
* USBD_ERR_OS_TIMEOUT OS signal NOT successfully acquired in the time
* specified by 'timeout_ms'.
* USBD_ERR_OS_ABORT OS signal aborted.
* USBD_ERR_OS_FAIL OS signal not acquired because another error.
*
* See specific device driver(s) 'EP_RxStart()' for
* additional return error codes.
*
* See specific device driver(s) 'EP_Rx()' for
* additional return error codes.
*
* Return(s) : Number of octets received, if NO error(s).
*
* 0, otherwise.
*
* Note(s) : none.
*********************************************************************************************************
*/
CPU_INT32U USBD_ACM_SerialRx (CPU_INT08U subclass_nbr,
CPU_INT08U *p_buf,
CPU_INT32U buf_len,
CPU_INT16U timeout,
USBD_ERR *p_err)
{
USBD_ACM_SERIAL_CTRL *p_ctrl;
CPU_BOOLEAN conn;
CPU_INT32U xfer_len;
#if (USBD_CFG_ERR_ARG_CHK_EXT_EN == DEF_ENABLED) /* ---------------- VALIDATE ARGUMENTS ---------------- */
if (p_err == (USBD_ERR *)0) { /* Validate error ptr. */
CPU_SW_EXCEPTION(0);
}
#endif
if (subclass_nbr >= USBD_ACM_SerialCtrlNbrNext) {
*p_err = USBD_ERR_CLASS_INVALID_NBR;
return (0u);
}
p_ctrl = &USBD_ACM_SerialCtrlTbl[subclass_nbr];
conn = USBD_CDC_IsConn(p_ctrl->Nbr);
if ((conn == DEF_NO ) ||
(p_ctrl->Idle == DEF_TRUE)) {
*p_err = USBD_ERR_INVALID_CLASS_STATE;
return (0u);
}
xfer_len = USBD_CDC_DataRx(p_ctrl->Nbr,
0u,
p_buf,
buf_len,
timeout,
p_err);
return (xfer_len);
}
/*
*********************************************************************************************************
* USBD_ACM_SerialRxAsync()
*
* Description : Receive data on CDC ACM serial emulation subclass.
*
* Argument(s) : subclass_nbr CDC ACM serial emulation subclass instance number.
*
* p_buf Pointer to destination buffer to receive data.
*
* buf_len Number of octets to receive.
*
* async_fnct Function that will be invoked upon completion of receive operation.
*
* p_async_arg Pointer to argument that will be passed as parameter of 'async_fnct'.
*
* p_err Pointer to variable that will receive return error code from this function :
*
* USBD_ERR_NONE Data successfully received.
* USBD_ERR_INVALID_ARG Invalid argument(s) passed to 'subclass_nbr'.
* USBD_ERR_INVALID_CLASS_STATE Invalid subclass state or subclass is in
* idle mode.
*
* ------- RETURNED BY USBD_CDC_DataRx() : -------
* USBD_ERR_INVALID_ARG Invalid argument(s) passed to 'class_nbr'/
* 'data_if_nbr'.
* USBD_ERR_INVALID_CLASS_STATE Invalid subclass state.
* USBD_ERR_EP_INVALID_ADDR Invalid endpoint address.
* USBD_ERR_EP_INVALID_STATE Invalid endpoint state.
* USBD_ERR_EP_INVALID_TYPE Invalid endpoint type.
*
* USBD_ERR_OS_TIMEOUT OS signal NOT successfully acquired in the time
* specified by 'timeout_ms'.
* USBD_ERR_OS_ABORT OS signal aborted.
* USBD_ERR_OS_FAIL OS signal not acquired because another error.
*
* See specific device driver(s) 'EP_RxStart()' for
* additional return error codes.
*
* See specific device driver(s) 'EP_Rx()' for
* additional return error codes.
*
* Return(s) : none.
*
* Note(s) : none.
*********************************************************************************************************
*/
void USBD_ACM_SerialRxAsync (CPU_INT08U subclass_nbr,
CPU_INT08U *p_buf,
CPU_INT32U buf_len,
USBD_ASYNC_FNCT async_fnct,
void *p_async_arg,
USBD_ERR *p_err)
{
USBD_ACM_SERIAL_CTRL *p_ctrl;
CPU_BOOLEAN conn;
#if (USBD_CFG_ERR_ARG_CHK_EXT_EN == DEF_ENABLED) /* ---------------- VALIDATE ARGUMENTS ---------------- */
if (p_err == (USBD_ERR *)0) { /* Validate error ptr. */
CPU_SW_EXCEPTION(0);
}
#endif
if (subclass_nbr >= USBD_ACM_SerialCtrlNbrNext) {
*p_err = USBD_ERR_CLASS_INVALID_NBR;
return ;
}
p_ctrl = &USBD_ACM_SerialCtrlTbl[subclass_nbr];
conn = USBD_CDC_IsConn(p_ctrl->Nbr);
if ((conn == DEF_NO ) ||
(p_ctrl->Idle == DEF_TRUE)) {
*p_err = USBD_ERR_INVALID_CLASS_STATE;
return ;
}
USBD_CDC_DataRxAsync(p_ctrl->Nbr,
0u,
p_buf,
buf_len,
async_fnct,
p_async_arg,
p_err);
return ;
}
/*
*********************************************************************************************************
* USBD_ACM_SerialTx()
*
* Description : Send data on CDC ACM serial emulation subclass.
*
* Argument(s) : subclass_nbr CDC ACM serial emulation subclass instance number.
*
* p_buf Pointer to buffer of data that will be transmitted.
*
* buf_len Number of octets to transmit.
*
* timeout_ms Timeout in milliseconds.
*
* p_err Pointer to variable that will receive return error code from this function :
*
* USBD_ERR_NONE Data successfully received.
* USBD_ERR_INVALID_ARG Invalid argument(s) passed to 'subclass_nbr'.
* USBD_ERR_INVALID_CLASS_STATE Invalid subclass state or subclass is in
* idle mode.
*
* ------- RETURNED BY USBD_CDC_DataTx() : -------
* USBD_ERR_INVALID_ARG Invalid argument(s) passed to 'class_nbr'/
* 'data_if_nbr'.
* USBD_ERR_DEV_INVALID_STATE Transfer type only available if CDC device is in
* configured state.
* USBD_ERR_EP_INVALID_ADDR Invalid endpoint address.
* USBD_ERR_EP_INVALID_STATE Invalid endpoint state.
* USBD_ERR_EP_INVALID_TYPE Invalid endpoint type.
*
* USBD_ERR_OS_TIMEOUT OS signal NOT successfully acquired in the time
* specified by 'timeout_ms'.
* USBD_ERR_OS_ABORT OS signal aborted.
* USBD_ERR_OS_FAIL OS signal not acquired because another error.
*
* See specific device driver(s) 'EP_Tx()' for
* additional return error codes.
*
* See specific device driver(s) 'EP_TxStart()' for
* additional return error codes.
*
* See specific device driver(s) 'EP_TxZLP()' for
* additional return error codes.
* Return(s) : Number of octets transmitted, if NO error(s).
*
* 0, otherwise.
*
* Note(s) : none.
*********************************************************************************************************
*/
CPU_INT32U USBD_ACM_SerialTx (CPU_INT08U subclass_nbr,
CPU_INT08U *p_buf,
CPU_INT32U buf_len,
CPU_INT16U timeout,
USBD_ERR *p_err)
{
USBD_ACM_SERIAL_CTRL *p_ctrl;
CPU_BOOLEAN conn;
CPU_INT32U xfer_len;
#if (USBD_CFG_ERR_ARG_CHK_EXT_EN == DEF_ENABLED) /* ---------------- VALIDATE ARGUMENTS ---------------- */
if (p_err == (USBD_ERR *)0) { /* Validate error ptr. */
CPU_SW_EXCEPTION(0);
}
#endif
if (subclass_nbr >= USBD_ACM_SerialCtrlNbrNext) {
*p_err = USBD_ERR_CLASS_INVALID_NBR;
return (0u);
}
p_ctrl = &USBD_ACM_SerialCtrlTbl[subclass_nbr];
conn = USBD_CDC_IsConn(p_ctrl->Nbr);
if ((conn == DEF_NO ) ||
(p_ctrl->Idle == DEF_TRUE)) {
*p_err = USBD_ERR_INVALID_CLASS_STATE;
return (0u);
}
xfer_len = USBD_CDC_DataTx(p_ctrl->Nbr,
0u,
p_buf,
buf_len,
timeout,
p_err);
return (xfer_len);
}
/*
*********************************************************************************************************
* USBD_ACM_SerialTxAsync()
*
* Description : Send data on CDC ACM serial emulation subclass.
*
* Argument(s) : subclass_nbr CDC ACM serial emulation subclass instance number.
*
* p_buf Pointer to buffer of data that will be transmitted.
*
* buf_len Number of octets to transmit.
*
* async_fnct Function that will be invoked upon completion of transmit operation.
*
* p_async_arg Pointer to argument that will be passed as parameter of 'async_fnct'.
*
* p_err Pointer to variable that will receive return error code from this function :
*
* USBD_ERR_NONE Data successfully received.
* USBD_ERR_INVALID_ARG Invalid argument(s) passed to 'subclass_nbr'.
* USBD_ERR_INVALID_CLASS_STATE Invalid subclass state or subclass is in
* idle mode.
*
* ------- RETURNED BY USBD_CDC_DataTx() : -------
* USBD_ERR_INVALID_ARG Invalid argument(s) passed to 'class_nbr'/
* 'data_if_nbr'.
* USBD_ERR_DEV_INVALID_STATE Transfer type only available if CDC device is in
* configured state.
* USBD_ERR_EP_INVALID_ADDR Invalid endpoint address.
* USBD_ERR_EP_INVALID_STATE Invalid endpoint state.
* USBD_ERR_EP_INVALID_TYPE Invalid endpoint type.
*
* USBD_ERR_OS_TIMEOUT OS signal NOT successfully acquired in the time
* specified by 'timeout_ms'.
* USBD_ERR_OS_ABORT OS signal aborted.
* USBD_ERR_OS_FAIL OS signal not acquired because another error.
*
* See specific device driver(s) 'EP_Tx()' for
* additional return error codes.
*
* See specific device driver(s) 'EP_TxStart()' for
* additional return error codes.
*
* See specific device driver(s) 'EP_TxZLP()' for
* additional return error codes.
* Return(s) : none.
*
* Note(s) : none.
*********************************************************************************************************
*/
void USBD_ACM_SerialTxAsync (CPU_INT08U subclass_nbr,
CPU_INT08U *p_buf,
CPU_INT32U buf_len,
USBD_ASYNC_FNCT async_fnct,
void *p_async_arg,
USBD_ERR *p_err)
{
USBD_ACM_SERIAL_CTRL *p_ctrl;
CPU_BOOLEAN conn;
#if (USBD_CFG_ERR_ARG_CHK_EXT_EN == DEF_ENABLED) /* ---------------- VALIDATE ARGUMENTS ---------------- */
if (p_err == (USBD_ERR *)0) { /* Validate error ptr. */
CPU_SW_EXCEPTION(0);
}
#endif
if (subclass_nbr >= USBD_ACM_SerialCtrlNbrNext) {
*p_err = USBD_ERR_CLASS_INVALID_NBR;
return ;
}
p_ctrl = &USBD_ACM_SerialCtrlTbl[subclass_nbr];
conn = USBD_CDC_IsConn(p_ctrl->Nbr);
if ((conn == DEF_NO ) ||
(p_ctrl->Idle == DEF_TRUE)) {
*p_err = USBD_ERR_INVALID_CLASS_STATE;
return ;
}
USBD_CDC_DataTxAsync(p_ctrl->Nbr,
0u,
p_buf,
buf_len,
async_fnct,
p_async_arg,
p_err);
return ;
}
/*
*********************************************************************************************************
* USBD_ACM_SerialLineCtrlGet()
*
* Description : Return the state of control lines.
*
* Argument(s) : subclass_nbr CDC ACM serial emulation subclass instance number.
*
* p_err Pointer to variable that will receive return error code from this function :
*
* USBD_ERR_NONE Data successfully received.
* USBD_ERR_INVALID_ARG Invalid argument(s) passed to 'subclass_nbr'.
*
* Return(s) : Bit-field with the state of the control line.
*
* USBD_ACM_SERIAL_CTRL_BREAK
* USBD_ACM_SERIAL_CTRL_RTS
* USBD_ACM_SERIAL_CTRL_DTR
*
* Note(s) : none.
*********************************************************************************************************
*/
CPU_INT08U USBD_ACM_SerialLineCtrlGet (CPU_INT08U subclass_nbr,
USBD_ERR *p_err)
{
USBD_ACM_SERIAL_CTRL *p_ctrl;
CPU_INT08U line_ctrl;
#if (USBD_CFG_ERR_ARG_CHK_EXT_EN == DEF_ENABLED) /* ---------------- VALIDATE ARGUMENTS ---------------- */
if (p_err == (USBD_ERR *)0) { /* Validate error ptr. */
CPU_SW_EXCEPTION(0);
}
#endif
if (subclass_nbr >= USBD_ACM_SerialCtrlNbrNext) {
*p_err = USBD_ERR_CLASS_INVALID_NBR;
return (DEF_BIT_NONE);
}
p_ctrl = &USBD_ACM_SerialCtrlTbl[subclass_nbr];
line_ctrl = p_ctrl->LineCtrl;
*p_err = USBD_ERR_NONE;
return (line_ctrl);
}
/*
*********************************************************************************************************
* USBD_ACM_SerialLineCtrlReg()
*
* Description : Set line control change notification callback.
*
* Argument(s) : subclass_nbr CDC ACM serial emulation subclass instance number.
*
* line_ctrl_chngd Line control change notification callback (see Note #1).
*
* p_arg Pointer to callback argument.
*
* p_err Pointer to variable that will receive the return error code from this function :
*
* USBD_ERR_NONE Line control change notification callback successfully
* registered.
*
* USBD_ERR_INVALID_ARG Invalid argument(s) passed to 'subclass_nbr'.
*
* Return(s) : ACM serial emulation subclass device number.
*
* Note(s) : (1) The callback specified by 'line_ctrl_chngd' argument is used to notify changes in the
* control signals to the application.
*
* The line control notification function has the following prototype:
*
* void AppLineCtrlChngd (CPU_INT08U subclass_nbr,
* CPU_INT08U events,
* CPU_INT08U events_chngd,
* void *p_arg);
*
* Argument(s) : subclass_nbr CDC ACM serial emulation subclass instance number.
*
* events Current line state. The line state is a OR'ed of
* the following flags:
*
* USBD_ACM_SERIAL_CTRL_BREAK
* USBD_ACM_SERIAL_CTRL_RTS
* USBD_ACM_SERIAL_CTRL_DTR
*
* events_chngd Line state flags that have changed.
*
* p_arg Pointer to callback argument.
*
*********************************************************************************************************
*/
void USBD_ACM_SerialLineCtrlReg (CPU_INT08U subclass_nbr,
USBD_ACM_SERIAL_LINE_CTRL_CHNGD line_ctrl_chngd,
void *p_arg,
USBD_ERR *p_err)
{
USBD_ACM_SERIAL_CTRL *p_ctrl;
CPU_SR_ALLOC();
#if (USBD_CFG_ERR_ARG_CHK_EXT_EN == DEF_ENABLED) /* ---------------- VALIDATE ARGUMENTS ---------------- */
if (p_err == (USBD_ERR *)0) { /* Validate error ptr. */
CPU_SW_EXCEPTION(;);
}
#endif
if (subclass_nbr >= USBD_ACM_SerialCtrlNbrNext) {
*p_err = USBD_ERR_CLASS_INVALID_NBR;
return;
}
p_ctrl = &USBD_ACM_SerialCtrlTbl[subclass_nbr];
CPU_CRITICAL_ENTER();
p_ctrl->LineCtrlChngdFnct = line_ctrl_chngd;
p_ctrl->LineCtrlChngdArgPtr = p_arg;
CPU_CRITICAL_EXIT();
*p_err = USBD_ERR_NONE;
}
/*
*********************************************************************************************************
* USBD_ACM_SerialLineCodingGet()
*
* Description : Get the current state of the line coding.
*
* Argument(s) : subclass_nbr CDC ACM serial emulation subclass instance number.
*
* p_line_coding Pointer to the structure where the current line coding will be stored.
*
* p_err Pointer to variable that will receive the return error code from this function :
*
* USBD_ERR_NONE Line coding successfully retrieved.
* USBD_ERR_INVALID_ARG Invalid argument(s) to 'subclass_nbr'.
* USBD_ERR_NULL_PTR Argument 'p_line_coding' passed a NULL pointer.
*
* Return(s) : none.
*
* Note(s) : none.
*********************************************************************************************************
*/
void USBD_ACM_SerialLineCodingGet (CPU_INT08U subclass_nbr,
USBD_ACM_SERIAL_LINE_CODING *p_line_coding,
USBD_ERR *p_err)
{
USBD_ACM_SERIAL_CTRL *p_ctrl;
CPU_SR_ALLOC();
#if (USBD_CFG_ERR_ARG_CHK_EXT_EN == DEF_ENABLED) /* ---------------- VALIDATE ARGUMENTS ---------------- */
if (p_err == (USBD_ERR *)0) { /* Validate error ptr. */
CPU_SW_EXCEPTION(;);
}
if (p_line_coding == (USBD_ACM_SERIAL_LINE_CODING *)0) {
*p_err = USBD_ERR_NULL_PTR;
return;
}
#endif
if (subclass_nbr >= USBD_ACM_SerialCtrlNbrNext) {
*p_err = USBD_ERR_CLASS_INVALID_NBR;
return;
}
p_ctrl = &USBD_ACM_SerialCtrlTbl[subclass_nbr];
CPU_CRITICAL_ENTER();
p_line_coding->BaudRate = p_ctrl->LineCoding.BaudRate;
p_line_coding->DataBits = p_ctrl->LineCoding.DataBits;
p_line_coding->StopBits = p_ctrl->LineCoding.StopBits;
p_line_coding->Parity = p_ctrl->LineCoding.Parity;
CPU_CRITICAL_EXIT();
*p_err = USBD_ERR_NONE;
}
/*
*********************************************************************************************************
* USBD_ACM_SerialLineCodingSet()
*
* Description : Set a new line coding.
*
* Argument(s) : subclass_nbr CDC ACM serial emulation subclass instance number.
*
* p_line_coding Pointer to the structure that contains the new line coding.
*
* p_err Pointer to variable that will receive the return error code from this function :
*
* USBD_ERR_NONE Line coding successfully set.
* USBD_ERR_INVALID_ARG Invalid argument(s) to 'subclass_nbr'.
* USBD_ERR_NULL_PTR Argument 'p_line_coding' passed a NULL pointer.
*
* Return(s) : none.
*
* Note(s) : none.
*********************************************************************************************************
*/
void USBD_ACM_SerialLineCodingSet (CPU_INT08U subclass_nbr,
USBD_ACM_SERIAL_LINE_CODING *p_line_coding,
USBD_ERR *p_err)
{
USBD_ACM_SERIAL_CTRL *p_ctrl;
CPU_SR_ALLOC();
#if (USBD_CFG_ERR_ARG_CHK_EXT_EN == DEF_ENABLED) /* ---------------- VALIDATE ARGUMENTS ---------------- */
if (p_err == (USBD_ERR *)0) { /* Validate error ptr. */
CPU_SW_EXCEPTION(;);
}
if (p_line_coding == (USBD_ACM_SERIAL_LINE_CODING *)0) {
*p_err = USBD_ERR_NULL_PTR;
return;
}
#endif
if (subclass_nbr >= USBD_ACM_SerialCtrlNbrNext) {
*p_err = USBD_ERR_CLASS_INVALID_NBR;
return;
}
if ((p_line_coding->DataBits != 5u) &&
(p_line_coding->DataBits != 6u) &&
(p_line_coding->DataBits != 7u) &&
(p_line_coding->DataBits != 8u) &&
(p_line_coding->DataBits != 16u)) {
*p_err = USBD_ERR_INVALID_ARG;
return;
}
if ((p_line_coding->StopBits != USBD_ACM_SERIAL_STOP_BIT_1 ) &&
(p_line_coding->StopBits != USBD_ACM_SERIAL_STOP_BIT_1_5) &&
(p_line_coding->StopBits != USBD_ACM_SERIAL_STOP_BIT_2 )) {
*p_err = USBD_ERR_INVALID_ARG;
return;
}
if ((p_line_coding->Parity != USBD_ACM_SERIAL_PARITY_NONE ) &&
(p_line_coding->Parity != USBD_ACM_SERIAL_PARITY_ODD ) &&
(p_line_coding->Parity != USBD_ACM_SERIAL_PARITY_EVEN ) &&
(p_line_coding->Parity != USBD_ACM_SERIAL_PARITY_MARK ) &&
(p_line_coding->Parity != USBD_ACM_SERIAL_PARITY_SPACE)) {
*p_err = USBD_ERR_INVALID_ARG;
return;
}
p_ctrl = &USBD_ACM_SerialCtrlTbl[subclass_nbr];
CPU_CRITICAL_ENTER();
p_ctrl->LineCoding.BaudRate = p_line_coding->BaudRate;
p_ctrl->LineCoding.DataBits = p_line_coding->DataBits;
p_ctrl->LineCoding.StopBits = p_line_coding->StopBits;
p_ctrl->LineCoding.Parity = p_line_coding->Parity;
CPU_CRITICAL_EXIT();
*p_err = USBD_ERR_NONE;
}
/*
*********************************************************************************************************
* USBD_ACM_SerialLineCodingReg()
*
* Description : Set line coding change notification callback.
*
* Argument(s) : subclass_nbr CDC ACM serial emulation subclass instance number.
*
* line_coding_chngd Line coding change notification callback (see Note #1).
*
* p_arg Pointer to callback argument.
*
* p_err Pointer to variable that will receive the return error code from this function :
*
* USBD_ERR_NONE Line control change notification callback successfully
* registered.
* USBD_ERR_INVALID_ARG Invalid argument(s) passed to 'subclass_nbr'.
*
* Return(s) : None.
*
* Note(s) : (1) This callback is used to notify changes in the line coding to the application.
*
* The line coding change notification function has the following prototype:
*
* CPU_BOOLEAN AppLineCodingChngd (CPU_INT08U subclass_nbr,
* USBD_ACM_SERIAL_LINE_CODING *p_line_coding,
* void *p_arg);
*
* Argument(s) : subclass_nbr CDC ACM serial emulation subclass instance number.
*
* p_line_coding Pointer to line coding structure.
*
* p_arg Pointer to callback argument.
*
* Return(s) : DEF_OK, if line coding is supported by the app.
*
* DEF_FAIL, otherwise.
*********************************************************************************************************
*/
void USBD_ACM_SerialLineCodingReg(CPU_INT08U subclass_nbr,
USBD_ACM_SERIAL_LINE_CODING_CHNGD line_coding_chngd,
void *p_arg,
USBD_ERR *p_err)
{
USBD_ACM_SERIAL_CTRL *p_ctrl;
CPU_SR_ALLOC();
#if (USBD_CFG_ERR_ARG_CHK_EXT_EN == DEF_ENABLED) /* ---------------- VALIDATE ARGUMENTS ---------------- */
if (p_err == (USBD_ERR *)0) { /* Validate error ptr. */
CPU_SW_EXCEPTION(;);
}
#endif
if (subclass_nbr >= USBD_ACM_SerialCtrlNbrNext) {
*p_err = USBD_ERR_CLASS_INVALID_NBR;
return;
}
p_ctrl = &USBD_ACM_SerialCtrlTbl[subclass_nbr];
CPU_CRITICAL_ENTER();
p_ctrl->LineCodingChngdFnct = line_coding_chngd;
p_ctrl->LineCodingChngdArgPtr = p_arg;
CPU_CRITICAL_EXIT();
*p_err = USBD_ERR_NONE;
}
/*
*********************************************************************************************************
* USBD_ACM_SerialLineStateSet()
*
* Description : Set a line state event(s).
*
* Argument(s) : subclass_nbr CDC ACM serial emulation subclass instance number.
*
* events Line state event(s) to set. OR'ed of the following flags:
*
* USBD_ACM_SERIAL_STATE_DCD Set DCD signal (Rx carrier).
* USBD_ACM_SERIAL_STATE_DSR Set DSR signal (Tx carrier).
* USBD_ACM_SERIAL_STATE_BREAK Set break.
* USBD_ACM_SERIAL_STATE_RING Set ring.
* USBD_ACM_SERIAL_STATE_FRAMING Set framing error.
* USBD_ACM_SERIAL_STATE_PARITY Set parity error.
* USBD_ACM_SERIAL_STATE_OVERUN Set overrun.
*
* p_err Pointer to variable that will receive return error code from this function :
*
* USBD_ERR_NONE State events successfully set.
* USBD_ERR_CLASS_INVALID_NBR Invalid number passed to 'subclass_nbr'.
* USBD_ERR_INVALID_CLASS_STATE Invalid subclass state or subclass is in
* idle mode.
*
* See 'USBD_CDC_Notify()' for additional return
* error codes.
*
* Return(s) : none.
*
* Note(s) : none.
*********************************************************************************************************
*/
void USBD_ACM_SerialLineStateSet (CPU_INT08U subclass_nbr,
CPU_INT08U events,
USBD_ERR *p_err)
{
USBD_ACM_SERIAL_CTRL *p_ctrl;
CPU_INT08U line_state_chngd;
CPU_BOOLEAN conn;
CPU_SR_ALLOC();
#if (USBD_CFG_ERR_ARG_CHK_EXT_EN == DEF_ENABLED) /* ---------------- VALIDATE ARGUMENTS ---------------- */
if (p_err == (USBD_ERR *)0) { /* Validate error ptr. */
CPU_SW_EXCEPTION(;);
}
#endif
if (subclass_nbr >= USBD_ACM_SerialCtrlNbrNext) {
*p_err = USBD_ERR_CLASS_INVALID_NBR;
return;
}
p_ctrl = &USBD_ACM_SerialCtrlTbl[subclass_nbr];
conn = USBD_CDC_IsConn(p_ctrl->Nbr);
if (conn == DEF_NO) {
*p_err = USBD_ERR_INVALID_CLASS_STATE;
return;
}
events &= (USBD_ACM_SERIAL_EVENTS_CONS | USBD_ACM_SERIAL_EVENTS_IRRE);
CPU_CRITICAL_ENTER();
line_state_chngd = events ^ p_ctrl->LineState;
if (line_state_chngd != DEF_BIT_NONE) {
DEF_BIT_SET(p_ctrl->LineState, events & USBD_ACM_SERIAL_EVENTS_CONS);
if (p_ctrl->LineStateSent == DEF_NO) {
p_ctrl->LineStateSent = DEF_YES;
p_ctrl->LineStateBufPtr[USBD_CDC_NOTIFICATION_HEADER] = p_ctrl->LineState
| (events & USBD_ACM_SERIAL_EVENTS_IRRE);
CPU_CRITICAL_EXIT();
(void)USBD_CDC_Notify( p_ctrl->Nbr,
USBD_ACM_SERIAL_REQ_STATE,
0u,
&p_ctrl->LineStateBufPtr[0],
USBD_ACM_SERIAL_REQ_STATE_SIZE,
p_err);
if (*p_err != USBD_ERR_NONE) {
return;
}
} else {
DEF_BIT_SET(p_ctrl->LineState, events & USBD_ACM_SERIAL_EVENTS_IRRE);
CPU_CRITICAL_EXIT();
}
} else {
CPU_CRITICAL_EXIT();
}
*p_err = USBD_ERR_NONE;
}
/*
*********************************************************************************************************
* USBD_ACM_SerialLineStateClr()
*
* Description : Clear a line state event(s).
*
* Argument(s) : subclass_nbr CDC ACM serial emulation subclass instance number.
*
* events Line state event(s) set to be cleared. OR'ed of the following
flags (see Note #1) :
*
* USBD_ACM_SERIAL_STATE_DCD Set DCD signal (Rx carrier).
* USBD_ACM_SERIAL_STATE_DSR Set DSR signal (Tx carrier).
*
* p_err Pointer to variable that will receive return error code from this function :
*
* USBD_ERR_NONE State events successfully cleared.
* USBD_ERR_CLASS_INVALID_NBR Invalid number passed to 'subclass_nbr'.
* USBD_ERR_INVALID_CLASS_STATE Invalid subclass state or subclass is in
* idle mode.
*
* See 'USBD_CDC_Notify()' for additional return
* error codes.
*
* Return(s) : none.
*
* Note(s) : (1) USB PSTN spec ver 1.20 states: "For the irregular signals like break, the
* incoming ring signal, or the overrun error state, this will reset their values
* to zero and again will not send another notification until their state changes"
*
* The irregular events are self-clear by the ACM serial emulation subclass.
*********************************************************************************************************
*/
void USBD_ACM_SerialLineStateClr (CPU_INT08U subclass_nbr,
CPU_INT08U events,
USBD_ERR *p_err)
{
USBD_ACM_SERIAL_CTRL *p_ctrl;
CPU_INT08U line_state_clr;
CPU_BOOLEAN conn;
CPU_SR_ALLOC();
#if (USBD_CFG_ERR_ARG_CHK_EXT_EN == DEF_ENABLED) /* ---------------- VALIDATE ARGUMENTS ---------------- */
if (p_err == (USBD_ERR *)0) { /* Validate error ptr. */
CPU_SW_EXCEPTION(;);
}
#endif
if (subclass_nbr >= USBD_ACM_SerialCtrlNbrNext) {
*p_err = USBD_ERR_CLASS_INVALID_NBR;
return;
}
p_ctrl = &USBD_ACM_SerialCtrlTbl[subclass_nbr];
conn = USBD_CDC_IsConn(p_ctrl->Nbr);
if (conn == DEF_NO) {
*p_err = USBD_ERR_INVALID_CLASS_STATE;
return;
}
events &= USBD_ACM_SERIAL_EVENTS_CONS;
CPU_CRITICAL_ENTER();
line_state_clr = events & p_ctrl->LineState;
if (line_state_clr != DEF_BIT_NONE) {
DEF_BIT_CLR(p_ctrl->LineState, (CPU_INT32U)events);
if (p_ctrl->LineStateSent == DEF_NO) {
p_ctrl->LineStateSent = DEF_YES;
p_ctrl->LineStateBufPtr[USBD_CDC_NOTIFICATION_HEADER] = p_ctrl->LineState;
CPU_CRITICAL_EXIT();
(void)USBD_CDC_Notify( p_ctrl->Nbr,
USBD_ACM_SERIAL_REQ_STATE,
0u,
&p_ctrl->LineStateBufPtr[0],
USBD_ACM_SERIAL_REQ_STATE_SIZE,
p_err);
if (*p_err != USBD_ERR_NONE) {
return;
}
} else {
CPU_CRITICAL_EXIT();
}
} else {
CPU_CRITICAL_EXIT();
}
*p_err = USBD_ERR_NONE;
}
/*
*********************************************************************************************************
* USBD_ACM_SerialMgmtReq()
*
* Description : CDC ACM serial emulation class management request.
*
* Argument(s) : dev_nbr Device number.
*
* p_setup_req Pointer to setup request structure.
*
* p_subclass_arg Pointer to subclass argument.
*
* Return(s) : DEF_OK, if NO error(s) occurred and request is supported.
*
* DEF_FAIL, otherwise.
*
* Note(s) : (1) CDC ACM defines the following requests :
*
* (a) SET_COMM_FEATURE This request controls the settings for a particular communications
* feature of a particular target.
*
* (b) GET_COMM_FEATURE This request returns the current settings for the communications
* feature as selected
*
* (c) CLEAR_COMM_FEATURE This request controls the settings for a particular communications
* feature of a particular target, setting the selected feature
* to its default state.
*
* (d) SET_LINE_CODING This request allows the host to specify typical asynchronous
* line-character formatting properties, which may be required by
* some applications.
*
* (e) GET_LINE_CODING This request allows the host to find out the currently configured
* line coding.
*
* (f) SET_CONTROL_LINE_STATE This request generates RS-232/V.24 style control signals.
*
* (g) SEND_BREAK This request sends special carrier modulation that generates an
* RS-232 style break.
*
* See 'Universal Serial Bus Communications Class Subclass Specification for PSTN Devices
* 02/09/2007, Version 1.2', section 6.2.2 for more details about ACM requests.
*
* (2) $$$$ 'SEND_BREAK' with variable length is not implemented in most USB host stacks.
* This feature may be implemented in the feature.
*********************************************************************************************************
*/
static CPU_BOOLEAN USBD_ACM_SerialMgmtReq ( CPU_INT08U dev_nbr,
const USBD_SETUP_REQ *p_setup_req,
void *p_subclass_arg)
{
USBD_ACM_SERIAL_CTRL *p_ctrl;
CPU_INT08U request_code;
USBD_ACM_SERIAL_LINE_CODING line_coding;
CPU_INT08U event_chngd;
CPU_INT08U event_state;
CPU_BOOLEAN valid;
USBD_ERR err;
CPU_SR_ALLOC();
p_ctrl = (USBD_ACM_SERIAL_CTRL *)p_subclass_arg;
request_code = p_setup_req->bRequest;
valid = DEF_FAIL;
switch (request_code) {
case USBD_CDC_REQ_SET_COMM_FEATURE: /* ---------- SET_COMM_FEATURE (see Note #1a) --------- */
/* Only 'ABSTRACT_STATE' feature is supported. */
if (p_setup_req->wValue == USBD_ACM_SERIAL_ABSTRACT_STATE) {
(void)USBD_CtrlRx( dev_nbr,
(void *)&p_ctrl->ReqBufPtr[0],
2u,
USBD_ACM_CTRL_REQ_TIMEOUT_mS,
&err);
/* Multiplexing call management command on data is ... */
/* ... not supported */
if ((err == USBD_ERR_NONE) &&
(DEF_BIT_IS_CLR(p_ctrl->ReqBufPtr[0], USBD_ACM_SERIAL_ABSTRACT_DATA_MUX))) {
CPU_CRITICAL_ENTER();
p_ctrl->Idle = DEF_BIT_IS_SET(p_ctrl->ReqBufPtr[0], USBD_ACM_SERIAL_ABSTRACT_IDLE);
CPU_CRITICAL_EXIT();
valid = DEF_OK;
}
}
break;
case USBD_CDC_REQ_GET_COMM_FEATURE: /* ---------- GET_COMM_FEATURE (see Note #1b) --------- */
if (p_setup_req->wValue == USBD_ACM_SERIAL_ABSTRACT_STATE) {
p_ctrl->ReqBufPtr[0] = (p_ctrl->Idle == DEF_NO) ? USBD_ACM_SERIAL_ABSTRACT_IDLE : DEF_BIT_NONE;
p_ctrl->ReqBufPtr[1] = DEF_BIT_NONE;
(void)USBD_CtrlTx( dev_nbr,
(void *)&p_ctrl->ReqBufPtr[0],
2u,
USBD_ACM_CTRL_REQ_TIMEOUT_mS,
DEF_NO,
&err);
if (err == USBD_ERR_NONE) {
valid = DEF_OK;
}
}
break;
case USBD_CDC_REQ_CLR_COMM_FEATURE: /* --------- CLEAR_COMM_FEATURE (see Note #1c) -------- */
if (p_setup_req->wValue == USBD_ACM_SERIAL_ABSTRACT_STATE) {
CPU_CRITICAL_ENTER();
p_ctrl->Idle = DEF_NO;
CPU_CRITICAL_EXIT();
valid = DEF_OK;
}
break;
case USBD_CDC_REQ_SET_LINE_CODING: /* ---------- SET_LINE_CODING (see Note #1d) ---------- */
(void)USBD_CtrlRx( dev_nbr,
(void *)&p_ctrl->ReqBufPtr[0],
7u,
USBD_ACM_CTRL_REQ_TIMEOUT_mS,
&err);
if (err == USBD_ERR_NONE) {
line_coding.BaudRate = MEM_VAL_GET_INT32U_LITTLE(&p_ctrl->ReqBufPtr[0]);
line_coding.StopBits = p_ctrl->ReqBufPtr[4];
line_coding.Parity = p_ctrl->ReqBufPtr[5];
line_coding.DataBits = p_ctrl->ReqBufPtr[6];
valid = DEF_OK;
if (p_ctrl->LineCodingChngdFnct != (USBD_ACM_SERIAL_LINE_CODING_CHNGD)0) {
valid = p_ctrl->LineCodingChngdFnct( p_ctrl->Nbr,
&line_coding,
p_ctrl->LineCtrlChngdArgPtr);
}
if (valid == DEF_OK) {
CPU_CRITICAL_ENTER();
p_ctrl->LineCoding.BaudRate = line_coding.BaudRate;
p_ctrl->LineCoding.DataBits = line_coding.DataBits;
p_ctrl->LineCoding.StopBits = line_coding.StopBits;
p_ctrl->LineCoding.Parity = line_coding.Parity;
CPU_CRITICAL_EXIT();
}
}
break;
case USBD_CDC_REQ_GET_LINE_CODING: /* ---------- GET_LINE_CODING (see Note #1e) ---------- */
MEM_VAL_SET_INT32U_LITTLE(&p_ctrl->ReqBufPtr[0], p_ctrl->LineCoding.BaudRate);
p_ctrl->ReqBufPtr[4] = p_ctrl->LineCoding.StopBits;
p_ctrl->ReqBufPtr[5] = p_ctrl->LineCoding.Parity;
p_ctrl->ReqBufPtr[6] = p_ctrl->LineCoding.DataBits;
(void)USBD_CtrlTx( dev_nbr,
(void *)&p_ctrl->ReqBufPtr[0],
7u,
USBD_ACM_CTRL_REQ_TIMEOUT_mS,
DEF_NO,
&err);
if (err == USBD_ERR_NONE) {
valid = DEF_OK;
}
break;
case USBD_CDC_REQ_SET_CTRL_LINE_STATE: /* ------ SET_CONTROL_LINE_STATE (see Note #1f) ------- */
event_state = (DEF_BIT_IS_SET(p_setup_req->wValue, USBD_ACM_SERIAL_REQ_RTS) == DEF_YES) ? USBD_ACM_SERIAL_CTRL_RTS
: DEF_BIT_NONE;
event_state |= (DEF_BIT_IS_SET(p_setup_req->wValue, USBD_ACM_SERIAL_REQ_DTR) == DEF_YES) ? USBD_ACM_SERIAL_CTRL_DTR
: DEF_BIT_NONE;
event_chngd = p_ctrl->LineCtrl
^ event_state;
if ((DEF_BIT_IS_CLR(p_ctrl->LineCtrl , USBD_ACM_SERIAL_CTRL_DTR) == DEF_YES) &&
(DEF_BIT_IS_SET(p_setup_req->wValue, USBD_ACM_SERIAL_REQ_DTR ) == DEF_YES)) {
CPU_CRITICAL_ENTER();
if (p_ctrl->LineStateSent == DEF_NO) {
p_ctrl->LineStateSent = DEF_YES;
p_ctrl->LineStateBufPtr[USBD_CDC_NOTIFICATION_HEADER] = p_ctrl->LineState;
CPU_CRITICAL_EXIT();
(void)USBD_CDC_Notify( p_ctrl->Nbr,
USBD_ACM_SERIAL_REQ_STATE,
0u,
&p_ctrl->LineStateBufPtr[0],
USBD_ACM_SERIAL_REQ_STATE_SIZE,
&err);
} else {
CPU_CRITICAL_EXIT();
}
}
if (event_chngd != DEF_BIT_NONE) {
CPU_CRITICAL_ENTER();
DEF_BIT_SET(p_ctrl->LineCtrl, ( event_state & event_chngd));
DEF_BIT_CLR(p_ctrl->LineCtrl, (~(CPU_INT32U)event_state & event_chngd));
CPU_CRITICAL_EXIT();
if (p_ctrl->LineCtrlChngdFnct != (USBD_ACM_SERIAL_LINE_CTRL_CHNGD)0) {
p_ctrl->LineCtrlChngdFnct(p_ctrl->Nbr,
event_state,
event_chngd,
p_ctrl->LineCtrlChngdArgPtr);
}
}
valid = DEF_OK;
break;
case USBD_CDC_REQ_SEND_BREAK: /* ------------- SEND_BREAK (see Note #1g) ------------ */
if ((p_setup_req->wValue == 0x0000u) &&
(DEF_BIT_IS_SET(p_ctrl->LineCtrl, USBD_ACM_SERIAL_CTRL_BREAK))) {
CPU_CRITICAL_ENTER();
DEF_BIT_CLR(p_ctrl->LineCtrl, USBD_ACM_SERIAL_CTRL_BREAK);
CPU_CRITICAL_EXIT();
if (p_ctrl->LineCtrlChngdFnct != (void *)0) {
p_ctrl->LineCtrlChngdFnct(p_ctrl->Nbr,
DEF_BIT_NONE,
USBD_ACM_SERIAL_CTRL_BREAK,
p_ctrl->LineCtrlChngdArgPtr);
}
} else if ((p_setup_req->wValue != 0x0000u) &&
(DEF_BIT_IS_CLR(p_ctrl->LineCtrl, USBD_ACM_SERIAL_CTRL_BREAK))) {
#if 0 /* Feature not implemented (see Note #2). */
if (p_setup_req->wValue != 0xFFFFu) {
valid = USBD_ACM_SerialOS_BreakTimeOutSet(p_steup_req->wValue);
if (valid == DEF_FAIL) {
break;
}
}
#endif
CPU_CRITICAL_ENTER();
DEF_BIT_SET(p_ctrl->LineCtrl, USBD_ACM_SERIAL_CTRL_BREAK);
CPU_CRITICAL_EXIT();
if (p_ctrl->LineCtrlChngdFnct != (void *)0) {
p_ctrl->LineCtrlChngdFnct(p_ctrl->Nbr,
USBD_ACM_SERIAL_CTRL_BREAK,
USBD_ACM_SERIAL_CTRL_BREAK,
p_ctrl->LineCtrlChngdArgPtr);
}
}
valid = DEF_OK;
break;
default:
break;
}
return (valid);
}
/*
*********************************************************************************************************
* USBD_ACM_SerialNotifyCmpl()
*
* Description : ACM subclass notification complete callback.
*
* Argument(s) : dev_nbr Device number.
*
* p_subclass_arg Pointer to ACM subclass notification complete callback argument.
*
* Return(s) : none.
*
* Note(s) : none.
*********************************************************************************************************
*/
static void USBD_ACM_SerialNotifyCmpl (CPU_INT08U dev_nbr,
void *p_subclass_arg)
{
USBD_ACM_SERIAL_CTRL *p_ctrl;
CPU_INT08U line_state_prev;
CPU_INT08U event_chngd;
USBD_ERR err;
CPU_SR_ALLOC();
(void)dev_nbr;
p_ctrl = (USBD_ACM_SERIAL_CTRL *)p_subclass_arg;
CPU_CRITICAL_ENTER();
/* Get prev state. */
line_state_prev = p_ctrl->LineStateBufPtr[USBD_CDC_NOTIFICATION_HEADER];
if (DEF_BIT_IS_SET_ANY(line_state_prev, USBD_ACM_SERIAL_EVENTS_IRRE)) {
/* Clr irregular events. */
DEF_BIT_CLR(line_state_prev, line_state_prev & USBD_ACM_SERIAL_EVENTS_IRRE);
}
event_chngd = line_state_prev ^ p_ctrl->LineState;
if (event_chngd != DEF_BIT_NONE) {
p_ctrl->LineStateBufPtr[USBD_CDC_NOTIFICATION_HEADER] = p_ctrl->LineState;
DEF_BIT_CLR(p_ctrl->LineState, p_ctrl->LineState & USBD_ACM_SERIAL_EVENTS_IRRE);
CPU_CRITICAL_EXIT();
(void)USBD_CDC_Notify( p_ctrl->Nbr,
USBD_ACM_SERIAL_REQ_STATE,
0u,
&p_ctrl->LineStateBufPtr[0],
USBD_ACM_SERIAL_REQ_STATE_SIZE,
&err);
} else {
p_ctrl->LineStateSent = DEF_NO;
CPU_CRITICAL_EXIT();
}
}
/*
*********************************************************************************************************
* USBD_ACM_SerialFnctDesc()
*
* Description : CDC Subclass interface descriptor callback.
*
* Argument(s) : dev_nbr Device number.
*
* p_subclass_arg Pointer to subclass argument.
*
* first_dci_if_nbr Interface number of the first Data Class Interface following a
* Communication Class Interface (see Note #3).
*
* Return(s) : none.
*
* Note(s) : (1) Table 4 of the PSTN specification describes the abstract control management functional
* descriptor. The 'bmCapabilities' (offset 3) field describes the requests supported by
* the device.
*
* BIT STATE DESCRIPTION
* ------- ------- -------------
* D0 '1' Device supports the request combination of SET_COMM_FEATURE,
* CLR_COMM_FEATURE, and GET_COMM_FEATURE.
*
* D1 '1' Device supports the request combination of SET_LINE_CODING,
* SET_CTRL_LINE_STATE, GET_LINE_CODING and the notification state.
*
* D2 '1' Device supports the request SEND_BREAK.
*
* D3 '1' Device supports the notification NETWORK_CONNECTION.
* Not required in ACM serial emulation subclass.
*
* (2) Table 3 of the PSTN specification describes the call management functional descriptor.
* The 'bmCapabilities' (offset 3) field describes how call management is handled by
* the device.
*
* BIT STATE DESCRIPTION
* ------- ------- -------------
* D0 '0' Device does not handle call management itself.
*
* '1' Device handles call management itself.
*
* D1 '0' Device send/receives call management information only over the
* communication class interface.
*
* '1' Device can send/receive call management information over a data
* class interface.
*
* (3) The Call Management Functional Descriptor contains the field 'bDataInterface' which
* represents the interface number of Data Class interface (DCI) optionally used for call
* management. In case the Communication Class Interface is followed by several DCIs,
* the interface number set for 'bDataInterface' will be the first DCI. It is NOT
* possible to use another DCI for handling the call management.
*********************************************************************************************************
*/
static void USBD_ACM_SerialFnctDesc (CPU_INT08U dev_nbr,
void *p_subclass_arg,
CPU_INT08U first_dci_if_nbr)
{
USBD_ACM_SERIAL_CTRL *p_ctrl = (USBD_ACM_SERIAL_CTRL *)p_subclass_arg;
/* --------- BUILD ABSTRACT CONTROL MGMT DESC --------- */
USBD_DescWr08(dev_nbr, 4u); /* Desc size. */
USBD_DescWr08(dev_nbr, USBD_CDC_DESC_TYPE_CS_IF); /* Desc type. */
USBD_DescWr08(dev_nbr, USBD_CDC_DESC_SUBTYPE_ACM); /* Desc subtype. */
/* Dev request capabilities (see Note #1). */
USBD_DescWr08(dev_nbr, DEF_BIT_00 |
DEF_BIT_01 |
DEF_BIT_02);
/* --------------- BUILD CALL MGMT DESC --------------- */
USBD_DescWr08(dev_nbr, 5u); /* Desc size. */
USBD_DescWr08(dev_nbr, USBD_CDC_DESC_TYPE_CS_IF); /* Desc type. */
USBD_DescWr08(dev_nbr, USBD_CDC_DESC_SUBTYPE_CALL_MGMT); /* Desc subtype. */
USBD_DescWr08(dev_nbr, p_ctrl->CallMgmtCapabilities); /* Dev call mgmt capabilities (see Note #2). */
/* IF nbr of data class IF optionally used for call ... */
/* ... mgmt. */
if (p_ctrl->CallMgmtCapabilities == USBD_ACM_SERIAL_CALL_MGMT_DATA_OVER_DCI) {
USBD_DescWr08(dev_nbr, first_dci_if_nbr); /* See Note #3. */
} else {
USBD_DescWr08(dev_nbr, 0u);
}
}
/*
*********************************************************************************************************
* USBD_ACM_SerialFnctDescSizeGet()
*
* Description : Retrieve the size of the CDC subclass interface descriptor.
*
* Argument(s) : dev_nbr Device number.
*
* p_subclass_arg Pointer to subclass argument.
*
* Return(s) : none.
*
* Note(s) : none.
*********************************************************************************************************
*/
static CPU_INT16U USBD_ACM_SerialFnctDescSizeGet (CPU_INT08U dev_nbr,
void *p_subclass_arg)
{
(void)dev_nbr;
(void)p_subclass_arg;
return (USBD_ACM_DESC_TOT_SIZE);
}