Implement application specific behavior of a Communication Device Class (CDC) USB Device using the sub-class Abstract Control Model (ACM).
More...
|
| User API |
| User API reference of the Communication Device Class (ACM).
|
|
| Configuration |
| Configuration of the USB Device CDC (ACM) Class.
|
|
Implement application specific behavior of a Communication Device Class (CDC) USB Device using the sub-class Abstract Control Model (ACM).
The CDC (ACM) class in the USB Component is used for data communication. You can typically use it in applications that previously used a serial COM or UART communication.
Refer to:
The USB Component allows multiple instances of the CDC class. This feature is used to create USB Composite Devices. Each CDC class instance has a separate files and interface functions:
- A CDC configuration file USBD_Config_CDC_n.h.
- An application-specific user source code file, which can be implemented with the USBD_User_CDC_ACM_n.c.
- Functions that start with the prefix USBD_CDCn_ACM are available for each instance of a CDC ACM class.
This documentation uses n as a placeholder for the instance number 0 - 7. Most applications only require one instance of a CDC ACM class. For the first CDC ACM class instance the instance number is 0:
- USBD_Config_CDC_0.h
- USBD_User_CDC_ACM_0.c
- The function prefix is USBD_CDC0_ACM
Descriptor Requirements
The following descriptors are required in an USB CDC ACM Device:
- Standard Device Descriptor
- Standard Configuration Descriptor
- Interface Association Descriptor
- CDC Header Functional Descriptor
- CDC Union Functional Descriptor
- Call Management Functional Descriptor
- Abstract Control Management Functional Descriptor
- Standard Interface Descriptor for the CDC Class communication interface
- Standard Endpoint Descriptor for Interrupt IN endpoint
- Standard Interface Descriptor for the CDC Class data interface
- Standard Endpoint Descriptors for Bulk IN and Bulk OUT endpoints
The necessary descriptors are automatically generated by the USB Middleware Component. The page USB Descriptors provides more information on the topic.
Software Structure
The handling for the CDC class endpoint events is implemented in USBD_CDCn_Int_Thread and USBD_CDCn_Bulk_Thread which are started by USBD_Initialize. Each instance of a CDC class runs an instance of USBD_CDCn_Int_Thread and USBD_CDCn_Bulk_Thread.
The thread USBD_CDCn_Int_Thread handles Interrupt IN Endpoint whereas the USBD_CDCn_Bulk_Thread handles the Bulk IN and Bulk OUT Endpoints.
Implementation
To create an USB Device with a CDC ACM class:
- Set the required number for USB:Device:CDC class instances during the RTE Component Selection.
- Set the parameters in the configuration file USBD_Config_CDC_n.h.
- Implement the application specific behavior using one of the following templates.
User Code Template USBD_User_CDC_ACM_n.c
The following source code contains all the required callback functions and can be used to implement the application specific behavior of a USB CDC (ACM) Device.
#include <stdint.h>
#include <stdbool.h>
void USBD_CDC%Instance%_ACM_Initialize (void) {
}
void USBD_CDC%Instance%_ACM_Uninitialize (void) {
}
void USBD_CDC%Instance%_ACM_Reset (void) {
}
bool USBD_CDC%Instance%_ACM_SendEncapsulatedCommand (const uint8_t *buf, uint16_t len) {
(void)buf;
(void)len;
return true;
}
bool USBD_CDC%Instance%_ACM_GetEncapsulatedResponse (uint16_t max_len, uint8_t **buf, uint16_t *len) {
(void)max_len;
(void)buf;
(void)len;
return true;
}
bool USBD_CDC%Instance%_ACM_SetLineCoding (
const CDC_LINE_CODING *line_coding) {
cdc_acm_line_coding = *line_coding;
return true;
}
*line_coding = cdc_acm_line_coding;
return true;
}
bool USBD_CDC%Instance%_ACM_SetControlLineState (uint16_t state) {
(void)(state);
return true;
}
void USBD_CDC%Instance%_ACM_DataReceived (uint32_t len) {
(void)len;
}
void USBD_CDC%Instance%_ACM_DataSent (void) {
}
User Code Template USBD_User_CDC_ACM_UART_n.c
The following source code contains all the required callback functions and can be used to implement the application specific behavior of a USB CDC (ACM) Device that can be used as a USB <-> UART bridge.
#include <stdio.h>
#include "Driver_USART.h"
#ifndef RTE_CMSIS_RTOS2
#error This user template requires CMSIS-RTOS2!
#else
#define UART_PORT %Instance%
#define UART_BUFFER_SIZE (512)
#define _UART_Driver_(n) Driver_USART##n
#define UART_Driver_(n) _UART_Driver_(n)
extern ARM_DRIVER_USART UART_Driver_(UART_PORT);
#define ptrUART (&UART_Driver_(UART_PORT))
static uint8_t uart_rx_buf[UART_BUFFER_SIZE];
static uint8_t uart_tx_buf[UART_BUFFER_SIZE];
static volatile int32_t uart_rx_cnt = 0;
static volatile int32_t usb_tx_cnt = 0;
static void *cdc_acm_bridge_tid = 0U;
static void UART_Callback (uint32_t event) {
int32_t cnt;
if (event & ARM_USART_EVENT_SEND_COMPLETE) {
if (cnt > 0) {
(void)ptrUART->Send(uart_tx_buf, (uint32_t)(cnt));
}
}
if (event & ARM_USART_EVENT_RECEIVE_COMPLETE) {
uart_rx_cnt += UART_BUFFER_SIZE;
(void)ptrUART->Receive(uart_rx_buf, UART_BUFFER_SIZE);
}
}
__NO_RETURN static void CDC%Instance%_ACM_UART_to_USB_Thread (void *arg) {
int32_t cnt, cnt_to_wrap;
(void)(arg);
for (;;) {
if (ptrUART->GetStatus().rx_busy != 0U) {
cnt = uart_rx_cnt;
cnt += (int32_t)ptrUART->GetRxCount();
cnt -= usb_tx_cnt;
if (cnt >= UART_BUFFER_SIZE) {
usb_tx_cnt += cnt;
cnt = 0U;
}
if (cnt > 0) {
cnt_to_wrap = (int32_t)(UART_BUFFER_SIZE - ((uint32_t)usb_tx_cnt & (UART_BUFFER_SIZE - 1)));
if (cnt > cnt_to_wrap) {
cnt = cnt_to_wrap;
}
cnt =
USBD_CDC_ACM_WriteData(%Instance%U, (uart_rx_buf + ((uint32_t)usb_tx_cnt & (UART_BUFFER_SIZE - 1))), cnt);
if (cnt > 0) {
usb_tx_cnt += cnt;
}
}
}
(void)osDelay(10U);
}
}
#ifdef RTE_CMSIS_RTOS2_RTX5
static osRtxThread_t cdc%Instance%_acm_uart_to_usb_thread_cb_mem __attribute__((section(".bss.os.thread.cb")));
static uint64_t cdc%Instance%_acm_uart_to_usb_thread_stack_mem[512U / 8U] __attribute__((section(".bss.os.thread.stack")));
#endif
static const osThreadAttr_t cdc%Instance%_acm_uart_to_usb_thread_attr = {
"CDC%Instance%_ACM_UART_to_USB_Thread",
0U,
#ifdef RTE_CMSIS_RTOS2_RTX5
&cdc%Instance%_acm_uart_to_usb_thread_cb_mem,
sizeof(osRtxThread_t),
&cdc%Instance%_acm_uart_to_usb_thread_stack_mem[0],
#else
NULL,
0U,
NULL,
#endif
512U,
osPriorityNormal,
0U,
0U
};
void USBD_CDC%Instance%_ACM_DataReceived (uint32_t len) {
int32_t cnt;
(void)(len);
if (ptrUART->GetStatus().tx_busy == 0U) {
if (cnt > 0) {
(void)ptrUART->Send(uart_tx_buf, (uint32_t)(cnt));
}
}
}
void USBD_CDC%Instance%_ACM_Initialize (void) {
(void)ptrUART->Initialize (UART_Callback);
(void)ptrUART->PowerControl (ARM_POWER_FULL);
cdc_acm_bridge_tid = osThreadNew (CDC%Instance%_ACM_UART_to_USB_Thread, NULL, &cdc%Instance%_acm_uart_to_usb_thread_attr);
}
void USBD_CDC%Instance%_ACM_Uninitialize (void) {
if (osThreadTerminate (cdc_acm_bridge_tid) == osOK) {
cdc_acm_bridge_tid = NULL;
}
(void)ptrUART->Control (ARM_USART_ABORT_RECEIVE, 0U);
(void)ptrUART->PowerControl (ARM_POWER_OFF);
(void)ptrUART->Uninitialize ();
}
void USBD_CDC%Instance%_ACM_Reset (void) {
(void)ptrUART->Control (ARM_USART_ABORT_SEND, 0U);
(void)ptrUART->Control (ARM_USART_ABORT_RECEIVE, 0U);
}
bool USBD_CDC%Instance%_ACM_SetLineCoding (
const CDC_LINE_CODING *line_coding) {
uint32_t data_bits = 0U, parity = 0U, stop_bits = 0U;
int32_t status;
(void)ptrUART->Control (ARM_USART_ABORT_SEND, 0U);
(void)ptrUART->Control (ARM_USART_ABORT_RECEIVE, 0U);
(void)ptrUART->Control (ARM_USART_CONTROL_TX, 0U);
(void)ptrUART->Control (ARM_USART_CONTROL_RX, 0U);
case 0:
stop_bits = ARM_USART_STOP_BITS_1;
break;
case 1:
stop_bits = ARM_USART_STOP_BITS_1_5;
break;
case 2:
stop_bits = ARM_USART_STOP_BITS_2;
break;
default:
return false;
}
case 0:
parity = ARM_USART_PARITY_NONE;
break;
case 1:
parity = ARM_USART_PARITY_ODD;
break;
case 2:
parity = ARM_USART_PARITY_EVEN;
break;
default:
return false;
}
case 5:
data_bits = ARM_USART_DATA_BITS_5;
break;
case 6:
data_bits = ARM_USART_DATA_BITS_6;
break;
case 7:
data_bits = ARM_USART_DATA_BITS_7;
break;
case 8:
data_bits = ARM_USART_DATA_BITS_8;
break;
default:
return false;
}
status = ptrUART->Control(ARM_USART_MODE_ASYNCHRONOUS |
data_bits |
parity |
stop_bits ,
if (status != ARM_DRIVER_OK) {
return false;
}
cdc_acm_line_coding = *line_coding;
uart_rx_cnt = 0;
usb_tx_cnt = 0;
(void)ptrUART->Control (ARM_USART_CONTROL_TX, 1U);
(void)ptrUART->Control (ARM_USART_CONTROL_RX, 1U);
(void)ptrUART->Receive (uart_rx_buf, UART_BUFFER_SIZE);
return true;
}
*line_coding = cdc_acm_line_coding;
return true;
}
bool USBD_CDC%Instance%_ACM_SetControlLineState (uint16_t state) {
(void)(state);
return true;
}
#endif
User Code Template USBD_User_CDC_ACM_RNDIS_VETH_n.c
The following source code contains all the required callback functions and can be used to implement the application specific behavior of a USB CDC (ACM) Device that can be used for virtual Ethernet using the RNDIS protocol.
#include <stdint.h>
#include <stdbool.h>
#include <string.h>
#include "Driver_ETH.h"
#include "Driver_ETH_MAC.h"
#include "Driver_ETH_PHY.h"
#include "USBD_Config_CDC_%Instance%.h"
#define RNDIS_MAC_ADDR "1E-30-6C-A2-45-5E"
#define RNDIS_MCAST_NUM 16
#define RNDIS_VENDOR_DESC "Keil NIC (USB <-> ETH)"
#define RNDIS_VENDOR_ID 0xFFFFFF
ARM_ETH_LINK_STATE RNDIS%Instance%_GetLinkState (void);
int32_t RNDIS%Instance%_SendFrame (const uint8_t *frame, uint32_t len);
int32_t RNDIS%Instance%_ReadFrame ( uint8_t *frame, uint32_t len);
uint32_t RNDIS%Instance%_GetRxFrameSize(void);
static void MAC_str_to_addr (const char *mac_str, uint8_t *mac_addr);
static void InitVars (void);
static void ResetVars (void);
static uint32_t rndis_state;
static ARM_ETH_LINK_STATE link_state;
static bool link_state_up;
static bool link_state_down;
static uint32_t packet_filter;
static ARM_ETH_MAC_ADDR mac_address;
static ARM_ETH_MAC_ADDR mcast_address[RNDIS_MCAST_NUM];
static uint32_t get_encapsulated_response_len;
static uint32_t get_encapsulated_response_buf[128/4];
static uint32_t xmit_ok;
static uint32_t rcv_ok;
static uint32_t xmit_error;
static uint32_t rcv_error;
static uint32_t rcv_no_buffer;
static uint32_t packet_in [(USBD_CDC%Instance%_ACM_SEND_BUF_SIZE +3)/4];
static uint32_t packet_out[(USBD_CDC%Instance%_ACM_RECEIVE_BUF_SIZE+3)/4];
static void MAC_str_to_addr (const char *mac_str, uint8_t *mac_addr) {
uint8_t c;
uint8_t n;
uint32_t i, j;
uint32_t str_len;
str_len = strlen(mac_str);
j = 0U;
for (i = 0U; i < str_len; i++) {
c = (uint8_t)mac_str[i];
if (c == '-') {
continue;
} else if ((c >= '0') && (c <= '9')) {
n = c - '0';
} else if ((c >= 'A') && (c <= 'F')) {
n = c - ('A' + 10U);
} else if ((c >= 'a') && (c <= 'f')) {
n = c - ('a' + 10U);
} else {
n = 0U;
}
if ((j & 1U) != 0U) {
mac_addr[j>>1] |= n;
} else {
mac_addr[j>>1] = (uint8_t)((uint32_t)n << 4);
}
j++;
}
}
static void InitVars (void) {
rndis_state = RNDIS_UNINITIALIZED;
link_state = ARM_ETH_LINK_DOWN;
packet_filter = 0U;
MAC_str_to_addr(RNDIS_MAC_ADDR, (uint8_t *)&mac_address);
memset((void *)mcast_address, 0, sizeof(mcast_address));
ResetVars();
}
static void ResetVars (void) {
link_state_up = false;
link_state_down = false;
get_encapsulated_response_len = 0U;
xmit_ok = 0U;
rcv_ok = 0U;
xmit_error = 0U;
rcv_error = 0U;
rcv_no_buffer = 0U;
}
void USBD_CDC%Instance%_ACM_Initialize (void) {
InitVars();
}
void USBD_CDC%Instance%_ACM_Uninitialize (void) {
InitVars();
}
void USBD_CDC%Instance%_ACM_Reset (void) {
InitVars();
}
bool USBD_CDC%Instance%_ACM_SendEncapsulatedCommand (const uint8_t *buf, uint16_t len) {
const REMOTE_NDIS_INITIALIZE_MSG_t *ptr_init_msg;
REMOTE_NDIS_INITIALIZE_CMPLT_t *ptr_init_cmplt;
const REMOTE_NDIS_HALT_MSG_t *ptr_halt_msg;
const REMOTE_NDIS_QUERY_MSG_t *ptr_query_msg;
REMOTE_NDIS_QUERY_CMPLT_t *ptr_query_cmplt;
const REMOTE_NDIS_SET_MSG_t *ptr_set_msg;
REMOTE_NDIS_SET_CMPLT_t *ptr_set_cmplt;
const REMOTE_NDIS_RESET_MSG_t *ptr_reset_msg;
REMOTE_NDIS_RESET_CMPLT_t *ptr_reset_cmplt;
const REMOTE_NDIS_KEEPALIVE_MSG_t *ptr_keepalive_msg;
REMOTE_NDIS_KEEPALIVE_CMPLT_t *ptr_keepalive_cmplt;
uint32_t status, val;
uint32_t i;
uint32_t num, by;
uint16_t msg_type;
(void)len;
msg_type = __UNALIGNED_UINT16_READ(buf);
if ((rndis_state == RNDIS_UNINITIALIZED) &&
(msg_type != REMOTE_NDIS_INITIALIZE_MSG) &&
(msg_type != REMOTE_NDIS_HALT_MSG)) {
return false;
}
if (((uint32_t)buf & 3) != 0) {
return false;
}
status = RNDIS_STATUS_SUCCESS;
get_encapsulated_response_len = 0U;
switch (msg_type) {
case REMOTE_NDIS_INITIALIZE_MSG:
ptr_init_msg = (const REMOTE_NDIS_INITIALIZE_MSG_t *)((const void *)buf);
if (ptr_init_msg->MessageLength != sizeof(REMOTE_NDIS_INITIALIZE_MSG_t)) { return false; }
if (ptr_init_msg->MajorVersion != RNDIS_MAJOR_VERSION) { return false; }
if (ptr_init_msg->MinorVersion != RNDIS_MINOR_VERSION) { return false; }
if (ptr_init_msg->MaxTransferSize != 16384U) { return false; }
rndis_state = RNDIS_INITIALIZED;
ptr_init_cmplt = (REMOTE_NDIS_INITIALIZE_CMPLT_t *)((void *)get_encapsulated_response_buf);
ptr_init_cmplt->MessageType = REMOTE_NDIS_INITIALIZE_CMPLT;
ptr_init_cmplt->MessageLength = sizeof(REMOTE_NDIS_INITIALIZE_CMPLT_t);
ptr_init_cmplt->RequestID = ptr_init_msg->RequestID;
ptr_init_cmplt->Status = status;
ptr_init_cmplt->MajorVersion = RNDIS_MAJOR_VERSION;
ptr_init_cmplt->MinorVersion = RNDIS_MINOR_VERSION;
ptr_init_cmplt->DeviceFlags = RNDIS_DF_CONNECTIONLESS;
ptr_init_cmplt->Medium = (uint32_t)NdisMedium802_3;
ptr_init_cmplt->MaxPacketsPerTransfer = 1U;
ptr_init_cmplt->MaxTransferSize = USBD_CDC%Instance%_ACM_RECEIVE_BUF_SIZE;
ptr_init_cmplt->PacketAlignmentFactor = 2U;
ptr_init_cmplt->Reserved[0] = 0U;
ptr_init_cmplt->Reserved[1] = 0U;
get_encapsulated_response_len = ptr_init_cmplt->MessageLength;
break;
case REMOTE_NDIS_HALT_MSG:
ptr_halt_msg = (const REMOTE_NDIS_HALT_MSG_t *)((const void *)buf);
if (ptr_halt_msg->MessageLength != sizeof(REMOTE_NDIS_HALT_MSG_t)) { return false; }
rndis_state = RNDIS_UNINITIALIZED;
return true;
case REMOTE_NDIS_QUERY_MSG:
ptr_query_msg = (const REMOTE_NDIS_QUERY_MSG_t *)((const void *)buf);
if (ptr_query_msg->MessageLength < 28U) { return false; }
ptr_query_cmplt = (REMOTE_NDIS_QUERY_CMPLT_t *)((void *)get_encapsulated_response_buf);
ptr_query_cmplt->MessageType = REMOTE_NDIS_QUERY_CMPLT;
ptr_query_cmplt->RequestID = ptr_query_msg->RequestID;
ptr_query_cmplt->InformationBufferOffset = 16U;
switch (ptr_query_msg->Oid) {
case OID_GEN_SUPPORTED_LIST:
ptr_query_cmplt->InformationBufferLength = 23U * 4U;
ptr_query_cmplt->OIDInputBuffer[0] = OID_GEN_SUPPORTED_LIST;
ptr_query_cmplt->OIDInputBuffer[1] = OID_GEN_HARDWARE_STATUS;
ptr_query_cmplt->OIDInputBuffer[2] = OID_GEN_MEDIA_SUPPORTED;
ptr_query_cmplt->OIDInputBuffer[3] = OID_GEN_MEDIA_IN_USE;
ptr_query_cmplt->OIDInputBuffer[4] = OID_GEN_MAXIMUM_FRAME_SIZE;
ptr_query_cmplt->OIDInputBuffer[5] = OID_GEN_LINK_SPEED;
ptr_query_cmplt->OIDInputBuffer[6] = OID_GEN_TRANSMIT_BLOCK_SIZE;
ptr_query_cmplt->OIDInputBuffer[7] = OID_GEN_RECEIVE_BLOCK_SIZE;
ptr_query_cmplt->OIDInputBuffer[8] = OID_GEN_VENDOR_ID;
ptr_query_cmplt->OIDInputBuffer[9] = OID_GEN_VENDOR_DESCRIPTION;
ptr_query_cmplt->OIDInputBuffer[10] = OID_GEN_CURRENT_PACKET_FILTER;
ptr_query_cmplt->OIDInputBuffer[11] = OID_GEN_MAXIMUM_TOTAL_SIZE;
ptr_query_cmplt->OIDInputBuffer[12] = OID_GEN_MEDIA_CONNECT_STATUS;
ptr_query_cmplt->OIDInputBuffer[13] = OID_GEN_PHYSICAL_MEDIUM;
ptr_query_cmplt->OIDInputBuffer[14] = OID_GEN_XMIT_OK;
ptr_query_cmplt->OIDInputBuffer[15] = OID_GEN_RCV_OK;
ptr_query_cmplt->OIDInputBuffer[16] = OID_GEN_XMIT_ERROR;
ptr_query_cmplt->OIDInputBuffer[17] = OID_GEN_RCV_ERROR;
ptr_query_cmplt->OIDInputBuffer[18] = OID_GEN_RCV_NO_BUFFER;
ptr_query_cmplt->OIDInputBuffer[19] = OID_802_3_PERMANENT_ADDRESS;
ptr_query_cmplt->OIDInputBuffer[20] = OID_802_3_CURRENT_ADDRESS;
ptr_query_cmplt->OIDInputBuffer[21] = OID_802_3_MULTICAST_LIST;
ptr_query_cmplt->OIDInputBuffer[22] = OID_802_3_MAXIMUM_LIST_SIZE;
break;
case OID_GEN_HARDWARE_STATUS:
ptr_query_cmplt->InformationBufferLength = 4U;
if (link_state == ARM_ETH_LINK_UP) {
ptr_query_cmplt->OIDInputBuffer[0] = (uint32_t)NdisHardwareStatusReady;
} else {
ptr_query_cmplt->OIDInputBuffer[0] = (uint32_t)NdisHardwareStatusNotReady;
}
break;
case OID_GEN_MEDIA_SUPPORTED:
case OID_GEN_MEDIA_IN_USE:
ptr_query_cmplt->InformationBufferLength = 4U;
ptr_query_cmplt->OIDInputBuffer[0] = (uint32_t)NdisMedium802_3;
break;
case OID_GEN_MAXIMUM_FRAME_SIZE:
ptr_query_cmplt->InformationBufferLength = 4U;
ptr_query_cmplt->OIDInputBuffer[0] = ETH_MTU_SIZE;
break;
case OID_GEN_LINK_SPEED:
ptr_query_cmplt->InformationBufferLength = 4U;
ptr_query_cmplt->OIDInputBuffer[0] = 100000000U / 100U;
break;
case OID_GEN_TRANSMIT_BLOCK_SIZE:
ptr_query_cmplt->InformationBufferLength = 4U;
ptr_query_cmplt->OIDInputBuffer[0] = USBD_CDC%Instance%_ACM_SEND_BUF_SIZE;
break;
case OID_GEN_RECEIVE_BLOCK_SIZE:
ptr_query_cmplt->InformationBufferLength = 4U;
ptr_query_cmplt->OIDInputBuffer[0] = USBD_CDC%Instance%_ACM_RECEIVE_BUF_SIZE;
break;
case OID_GEN_VENDOR_ID:
ptr_query_cmplt->InformationBufferLength = 4U;
ptr_query_cmplt->OIDInputBuffer[0] = RNDIS_VENDOR_ID;
break;
case OID_GEN_VENDOR_DESCRIPTION:
ptr_query_cmplt->InformationBufferLength = strlen(RNDIS_VENDOR_DESC) + 1;
memset((void *)&ptr_query_cmplt->OIDInputBuffer[0], 0, ptr_query_cmplt->InformationBufferLength + 1U);
memcpy((void *)&ptr_query_cmplt->OIDInputBuffer[0], RNDIS_VENDOR_DESC, strlen(RNDIS_VENDOR_DESC));
break;
case OID_GEN_CURRENT_PACKET_FILTER:
ptr_query_cmplt->InformationBufferLength = 4U;
val = 0U;
if ((packet_filter & ARM_ETH_MAC_ADDRESS_MULTICAST) != 0U) { val |= RNDIS_FILTER_ALL_MULTICAST; }
if ((packet_filter & ARM_ETH_MAC_ADDRESS_BROADCAST) != 0U) { val |= RNDIS_FILTER_BROADCAST; }
if ((packet_filter & ARM_ETH_MAC_ADDRESS_ALL) != 0U) { val |= RNDIS_FILTER_PROMISCUOUS; }
ptr_query_cmplt->OIDInputBuffer[0] = val;
break;
case OID_GEN_MAXIMUM_TOTAL_SIZE:
ptr_query_cmplt->InformationBufferLength = 4U;
ptr_query_cmplt->OIDInputBuffer[0] = 44U + ETH_MAX_SIZE;
break;
case OID_GEN_MEDIA_CONNECT_STATUS:
ptr_query_cmplt->InformationBufferLength = 4U;
if (link_state == ARM_ETH_LINK_UP) {
ptr_query_cmplt->OIDInputBuffer[0] = (uint32_t)NdisMediaStateConnected;
} else {
ptr_query_cmplt->OIDInputBuffer[0] = (uint32_t)NdisMediaStateDisconnected;
}
break;
case OID_GEN_PHYSICAL_MEDIUM:
ptr_query_cmplt->InformationBufferLength = 4U;
ptr_query_cmplt->OIDInputBuffer[0] = (uint32_t)NdisPhysicalMediumUnspecified;
break;
case OID_GEN_XMIT_OK:
ptr_query_cmplt->InformationBufferLength = 4U;
ptr_query_cmplt->OIDInputBuffer[0] = xmit_ok;
break;
case OID_GEN_RCV_OK:
ptr_query_cmplt->InformationBufferLength = 4U;
ptr_query_cmplt->OIDInputBuffer[0] = rcv_ok;
break;
case OID_GEN_XMIT_ERROR:
ptr_query_cmplt->InformationBufferLength = 4U;
ptr_query_cmplt->OIDInputBuffer[0] = xmit_error;
break;
case OID_GEN_RCV_ERROR:
ptr_query_cmplt->InformationBufferLength = 4U;
ptr_query_cmplt->OIDInputBuffer[0] = rcv_error;
break;
case OID_GEN_RCV_NO_BUFFER:
ptr_query_cmplt->InformationBufferLength = 4U;
ptr_query_cmplt->OIDInputBuffer[0] = rcv_no_buffer;
break;
case OID_802_3_PERMANENT_ADDRESS:
case OID_802_3_CURRENT_ADDRESS:
ptr_query_cmplt->InformationBufferLength = 6U;
memcpy((void *)&ptr_query_cmplt->OIDInputBuffer[0], &mac_address, sizeof(ARM_ETH_MAC_ADDR));
break;
case OID_802_3_MULTICAST_LIST:
for (i = 0U; i < RNDIS_MCAST_NUM; i++) {
if ((__UNALIGNED_UINT32_READ(&mcast_address[0]) == 0U) &&
(__UNALIGNED_UINT16_READ(&mcast_address[4]) == 0U)) {
break;
}
}
if (i == 0U) {
num = 0U;
ptr_query_cmplt->InformationBufferOffset = 0U;
} else {
num = i;
if (i < RNDIS_MCAST_NUM) {
num = i + 1U;
} else {
num = i;
}
memcpy((void *)&ptr_query_cmplt->OIDInputBuffer[0], mcast_address, num * sizeof(ARM_ETH_MAC_ADDR));
}
ptr_query_cmplt->InformationBufferLength = num * sizeof(ARM_ETH_MAC_ADDR);
break;
case OID_802_3_MAXIMUM_LIST_SIZE:
ptr_query_cmplt->InformationBufferLength = 4U;
ptr_query_cmplt->OIDInputBuffer[0] = RNDIS_MCAST_NUM;
break;
default:
ptr_query_cmplt->InformationBufferOffset = 0U;
ptr_query_cmplt->InformationBufferLength = 0U;
status = RNDIS_STATUS_NOT_SUPPORTED;
break;
}
ptr_query_cmplt->Status = status;
ptr_query_cmplt->MessageLength = ptr_query_cmplt->InformationBufferLength + 24U;
get_encapsulated_response_len = ptr_query_cmplt->MessageLength;
break;
case REMOTE_NDIS_SET_MSG:
ptr_set_msg = (const REMOTE_NDIS_SET_MSG_t *)((const void *)buf);
if (ptr_set_msg->MessageLength < 28U) { return false; }
ptr_set_cmplt = (REMOTE_NDIS_SET_CMPLT_t *)((void *)get_encapsulated_response_buf);
ptr_set_cmplt->MessageType = REMOTE_NDIS_SET_CMPLT;
ptr_set_cmplt->MessageLength = sizeof(REMOTE_NDIS_SET_CMPLT_t);
ptr_set_cmplt->RequestID = ptr_set_msg->RequestID;
switch (ptr_set_msg->Oid) {
case OID_802_3_MULTICAST_LIST:
by = ptr_set_msg->InformationBufferLength;
if (by > (sizeof(ARM_ETH_MAC_ADDR) * RNDIS_MCAST_NUM)) {
by = sizeof(ARM_ETH_MAC_ADDR) * RNDIS_MCAST_NUM;
}
if (by > 0U) {
memcpy(mcast_address, (const void *)&ptr_set_msg->OIDInputBuffer[0], by);
}
break;
case OID_GEN_CURRENT_PACKET_FILTER:
if ((ptr_set_msg->InformationBufferLength == 4U) &&
(ptr_set_msg->InformationBufferOffset != 0U)) {
val = __UNALIGNED_UINT32_READ(((const uint8_t *)&ptr_set_msg->RequestID) + ptr_set_msg->InformationBufferOffset);
if (val != 0U) {
if ((val & RNDIS_FILTER_ALL_MULTICAST) != 0U) { packet_filter |= ARM_ETH_MAC_ADDRESS_MULTICAST; }
if ((val & RNDIS_FILTER_BROADCAST) != 0U) { packet_filter |= ARM_ETH_MAC_ADDRESS_BROADCAST; }
if ((val & RNDIS_FILTER_PROMISCUOUS) != 0U) { packet_filter |= ARM_ETH_MAC_ADDRESS_ALL; }
if (link_state == ARM_ETH_LINK_DOWN) {
link_state = ARM_ETH_LINK_UP;
link_state_up = true;
}
rndis_state = RNDIS_DATA_INITIALIZED;
} else {
if (rndis_state == RNDIS_DATA_INITIALIZED) {
rndis_state = RNDIS_INITIALIZED;
}
}
} else {
status = RNDIS_STATUS_FAILURE;
}
break;
default:
status = RNDIS_STATUS_NOT_SUPPORTED;
break;
}
ptr_set_cmplt->Status = status;
get_encapsulated_response_len = ptr_set_cmplt->MessageLength;
break;
case REMOTE_NDIS_RESET_MSG:
ptr_reset_msg = (const REMOTE_NDIS_RESET_MSG_t *)((const void *)buf);
if (ptr_reset_msg->MessageLength != sizeof(REMOTE_NDIS_RESET_MSG_t)) { return false; }
ResetVars();
ptr_reset_cmplt = (REMOTE_NDIS_RESET_CMPLT_t *)((void *)get_encapsulated_response_buf);
ptr_reset_cmplt->MessageType = REMOTE_NDIS_RESET_CMPLT;
ptr_reset_cmplt->MessageLength = sizeof(REMOTE_NDIS_RESET_CMPLT_t);
ptr_reset_cmplt->Status = status;
ptr_reset_cmplt->AddressingReset = 0U;
get_encapsulated_response_len = ptr_reset_cmplt->MessageLength;
break;
case REMOTE_NDIS_KEEPALIVE_MSG:
ptr_keepalive_msg = (const REMOTE_NDIS_KEEPALIVE_MSG_t *)((const void *)buf);
if (ptr_keepalive_msg->MessageLength != sizeof(REMOTE_NDIS_KEEPALIVE_MSG_t)) { return false; }
ptr_keepalive_cmplt = (REMOTE_NDIS_KEEPALIVE_CMPLT_t *)((void *)get_encapsulated_response_buf);
ptr_keepalive_cmplt->MessageType = REMOTE_NDIS_KEEPALIVE_CMPLT;
ptr_keepalive_cmplt->MessageLength = sizeof(REMOTE_NDIS_KEEPALIVE_CMPLT_t);
ptr_keepalive_cmplt->RequestID = ptr_keepalive_msg->RequestID;
ptr_keepalive_cmplt->Status = status;
get_encapsulated_response_len = ptr_keepalive_cmplt->MessageLength;
break;
default:
return false;
}
if (get_encapsulated_response_len != 0U) {
}
return true;
}
bool USBD_CDC%Instance%_ACM_GetEncapsulatedResponse (uint16_t max_len, uint8_t **buf, uint16_t *len) {
REMOTE_NDIS_INDICATE_STATUS_MSG_t *ptr_indicate_status_msg;
uint32_t status;
(void)max_len;
if (link_state_up || link_state_down) {
if (link_state_up) {
status = RNDIS_STATUS_MEDIA_CONNECT;
} else {
status = RNDIS_STATUS_MEDIA_DISCONNECT;
}
ptr_indicate_status_msg = (REMOTE_NDIS_INDICATE_STATUS_MSG_t *)((void *)get_encapsulated_response_buf);
ptr_indicate_status_msg->MessageType = REMOTE_NDIS_INDICATE_STATUS_MSG;
ptr_indicate_status_msg->MessageLength = 20U;
ptr_indicate_status_msg->Status = status;
ptr_indicate_status_msg->StatusBufferLength = 0U;
ptr_indicate_status_msg->StatusBufferOffset = 0U;
get_encapsulated_response_len = 20U;
link_state_up = false;
link_state_down = false;
}
if (get_encapsulated_response_len != 0U) {
*buf = (uint8_t *)get_encapsulated_response_buf;
*len = (uint16_t) get_encapsulated_response_len;
get_encapsulated_response_len = 0U;
}
return true;
}
void USBD_CDC%Instance%_ACM_DataSent (void) {
}
void USBD_CDC%Instance%_ACM_DataReceived (uint32_t len) {
(void)len;
}
ARM_ETH_LINK_STATE RNDIS%Instance%_GetLinkState (void) {
if (rndis_state == RNDIS_DATA_INITIALIZED) {
return ARM_ETH_LINK_UP;
}
return ARM_ETH_LINK_DOWN;
}
int32_t RNDIS%Instance%_SendFrame (const uint8_t *frame, uint32_t len) {
REMOTE_NDIS_PACKET_MSG_t *ptr_packet_msg;
int32_t usb_cdc_acm_status;
ptr_packet_msg = (REMOTE_NDIS_PACKET_MSG_t *)((void *)packet_in);
if ((rndis_state == RNDIS_DATA_INITIALIZED) &&
(len >= ETH_MIN_SIZE) &&
(len <= ETH_MAX_SIZE)) {
memcpy((void *)&ptr_packet_msg->PayLoad[0], frame, len);
ptr_packet_msg->MessageType = REMOTE_NDIS_PACKET_MSG;
ptr_packet_msg->MessageLength = len + 44U;
ptr_packet_msg->DataOffset = 36U;
ptr_packet_msg->DataLength = len;
ptr_packet_msg->OutOfBandDataOffset = 0U;
ptr_packet_msg->OutOfBandDataLength = 0U;
ptr_packet_msg->NumOutOfBandDataElements = 0U;
ptr_packet_msg->PerPacketInfoOffset = 0U;
ptr_packet_msg->PerPacketInfoLength = 0U;
ptr_packet_msg->Reserved[0] = 0U;
ptr_packet_msg->Reserved[1] = 0U;
usb_cdc_acm_status =
USBD_CDC_ACM_WriteData (%Instance%, (
const uint8_t *)ptr_packet_msg, (int32_t)ptr_packet_msg->MessageLength);
if (usb_cdc_acm_status == (int32_t)ptr_packet_msg->MessageLength) {
rcv_ok++;
return ARM_DRIVER_OK;
}
if (usb_cdc_acm_status < 0) {
rcv_error++;
return ARM_DRIVER_ERROR;
}
if (usb_cdc_acm_status == 0) {
return ARM_DRIVER_ERROR_BUSY;
}
}
return ARM_DRIVER_ERROR;
}
int32_t RNDIS%Instance%_ReadFrame (uint8_t *frame, uint32_t len) {
REMOTE_NDIS_PACKET_MSG_t *ptr_packet_msg;
uint32_t data_len;
int32_t usb_cdc_acm_status;
ptr_packet_msg = (REMOTE_NDIS_PACKET_MSG_t *)((void *)packet_out);
if ((rndis_state == RNDIS_DATA_INITIALIZED) &&
(len >= ETH_MIN_SIZE) &&
(len <= ETH_MAX_SIZE)) {
usb_cdc_acm_status =
USBD_CDC_ACM_ReadData (%Instance%, (uint8_t *)ptr_packet_msg, USBD_CDC%Instance%_ACM_RECEIVE_BUF_SIZE);
if ((usb_cdc_acm_status != 0) && (usb_cdc_acm_status == (int32_t)ptr_packet_msg->MessageLength)) {
data_len = len;
if (data_len > ptr_packet_msg->DataLength) {
data_len = ptr_packet_msg->DataLength;
}
memcpy(frame, (const void *)&ptr_packet_msg->PayLoad[0], data_len);
xmit_ok++;
return (int32_t)data_len;
}
if (usb_cdc_acm_status < 0) {
xmit_error++;
return ARM_DRIVER_ERROR;
}
if (usb_cdc_acm_status == 0) {
return ARM_DRIVER_ERROR_BUSY;
}
}
return 0;
}
uint32_t RNDIS%Instance%_GetRxFrameSize (void) {
uint32_t avail_data_len;
if (avail_data_len > 44U) {
avail_data_len -= 44U;
}
return avail_data_len;
}
User Code Template USBD_User_CDC_ACM_RNDIS_ETH_n.c
The following source code contains all the required callback functions and can be used to implement the application specific behavior of a USB CDC (ACM) Device that can be used as a USB <-> Ethernet bridge using the RNDIS protocol.
#include "RTE_Components.h"
#include <stdint.h>
#include <stdbool.h>
#include <string.h>
#include "Driver_ETH.h"
#include "Driver_ETH_MAC.h"
#include "Driver_ETH_PHY.h"
#include "USBD_Config_CDC_%Instance%.h"
#ifndef RTE_CMSIS_RTOS2
#error This user template requires CMSIS-RTOS2!
#else
#define ETH_MAC_NUM 0
#define ETH_PHY_NUM 0
#define RNDIS_MAC_ADDR "1E-30-6C-A2-45-5E"
#define RNDIS_MCAST_NUM 16
#define RNDIS_VENDOR_DESC "Keil NIC (USB <-> ETH)"
#define RNDIS_VENDOR_ID 0xFFFFFF
extern ARM_DRIVER_ETH_MAC ARM_Driver_ETH_MAC_(ETH_MAC_NUM);
extern ARM_DRIVER_ETH_PHY ARM_Driver_ETH_PHY_(ETH_PHY_NUM);
static ARM_DRIVER_ETH_MAC *EthMac = &ARM_Driver_ETH_MAC_(ETH_MAC_NUM);
static ARM_DRIVER_ETH_PHY *EthPhy = &ARM_Driver_ETH_PHY_(ETH_PHY_NUM);
static void MAC_str_to_addr (const char *mac_str, uint8_t *mac_addr);
static void InitVars (void);
static void ResetVars (void);
static void EthMac_Notify (uint32_t event);
static uint32_t rndis_state;
static ARM_ETH_LINK_STATE link_state;
static ARM_ETH_LINK_INFO link_info;
static uint32_t link_speed;
static bool link_state_up;
static bool link_state_down;
static uint32_t packet_filter;
static ARM_ETH_MAC_ADDR mac_address;
static ARM_ETH_MAC_ADDR mcast_address[RNDIS_MCAST_NUM];
static uint32_t get_encapsulated_response_len;
static uint32_t get_encapsulated_response_buf[128/4];
static uint32_t xmit_ok;
static uint32_t rcv_ok;
static uint32_t xmit_error;
static uint32_t rcv_error;
static uint32_t rcv_no_buffer;
static uint32_t packet_in [(USBD_CDC%Instance%_ACM_SEND_BUF_SIZE +3)/4];
static uint32_t packet_out[(USBD_CDC%Instance%_ACM_RECEIVE_BUF_SIZE+3)/4];
static void ThreadConnection (void *arg);
static void ThreadDataIN (void *arg);
static void ThreadDataOUT (void *arg);
#ifdef RTE_CMSIS_RTOS2_RTX5
static osRtxThread_t thread_cb_mem_connection __attribute__((section(".bss.os.thread.cb")));
static uint64_t thread_stack_mem_connection[512/8] __attribute__((section(".bss.os.thread.stack")));
static osRtxThread_t thread_cb_mem_data_in __attribute__((section(".bss.os.thread.cb")));
static uint64_t thread_stack_mem_data_in [512/8] __attribute__((section(".bss.os.thread.stack")));
static osRtxThread_t thread_cb_mem_data_out __attribute__((section(".bss.os.thread.cb")));
static uint64_t thread_stack_mem_data_out [512/8] __attribute__((section(".bss.os.thread.stack")));
#endif
static const osThreadAttr_t thread_attr_connection = {
"ThreadConnection",
0U,
#ifdef RTE_CMSIS_RTOS2_RTX5
&thread_cb_mem_connection,
sizeof(osRtxThread_t),
&thread_stack_mem_connection[0],
#else
NULL,
0U,
NULL,
#endif
512U,
osPriorityNormal,
0U,
0U
};
static const osThreadAttr_t thread_attr_data_in = {
"ThreadDataIN",
0U,
#ifdef RTE_CMSIS_RTOS2_RTX5
&thread_cb_mem_data_in,
sizeof(osRtxThread_t),
&thread_stack_mem_data_in[0],
#else
NULL,
0U,
NULL,
#endif
512U,
osPriorityNormal,
0U,
0U
};
static const osThreadAttr_t thread_attr_data_out = {
"ThreadDataOUT",
0U,
#ifdef RTE_CMSIS_RTOS2_RTX5
&thread_cb_mem_data_out,
sizeof(osRtxThread_t),
&thread_stack_mem_data_out[0],
#else
NULL,
0U,
NULL,
#endif
512U,
osPriorityNormal,
0U,
0U
};
static void *thread_id_Connection;
static void *thread_id_DataIN;
static void *thread_id_DataOUT;
static void MAC_str_to_addr (const char *mac_str, uint8_t *mac_addr) {
uint8_t c;
uint8_t n;
uint32_t i, j;
uint32_t str_len;
str_len = strlen(mac_str);
j = 0U;
for (i = 0U; i < str_len; i++) {
c = (uint8_t)mac_str[i];
if (c == '-') {
continue;
} else if ((c >= '0') && (c <= '9')) {
n = c - '0';
} else if ((c >= 'A') && (c <= 'F')) {
n = c - ('A' + 10U);
} else if ((c >= 'a') && (c <= 'f')) {
n = c - ('a' + 10U);
} else {
n = 0U;
}
if ((j & 1U) != 0U) {
mac_addr[j>>1] |= n;
} else {
mac_addr[j>>1] = (uint8_t)((uint32_t)n << 4);
}
j++;
}
}
static void InitVars (void) {
rndis_state = RNDIS_UNINITIALIZED;
link_state = ARM_ETH_LINK_DOWN;
link_info.speed = 0U;
link_info.duplex = 0U;
link_speed = 0U;
packet_filter = 0U;
memset((void *)mcast_address, 0, sizeof(mcast_address));
ResetVars();
}
static void ResetVars (void) {
link_state_up = false;
link_state_down = false;
get_encapsulated_response_len = 0U;
xmit_ok = 0U;
rcv_ok = 0U;
xmit_error = 0U;
rcv_error = 0U;
rcv_no_buffer = 0U;
}
static bool ENET_Initialize (void) {
ARM_ETH_MAC_CAPABILITIES eth_capabilities;
packet_filter = ARM_ETH_MAC_ADDRESS_BROADCAST;
eth_capabilities = EthMac->GetCapabilities();
if (EthMac->Initialize(EthMac_Notify) != ARM_DRIVER_OK) { return false; }
if (EthMac->PowerControl(ARM_POWER_FULL) != ARM_DRIVER_OK) { return false; }
if (eth_capabilities.mac_address != 0U) {
if (EthMac->GetMacAddress(&mac_address) != ARM_DRIVER_OK) { return false; }
} else {
MAC_str_to_addr(RNDIS_MAC_ADDR, (uint8_t *)&mac_address);
if (EthMac->SetMacAddress(&mac_address) != ARM_DRIVER_OK) { return false; }
}
if (EthPhy->Initialize(EthMac->PHY_Read, EthMac->PHY_Write) != ARM_DRIVER_OK) { return false; }
if (EthPhy->PowerControl(ARM_POWER_FULL) != ARM_DRIVER_OK) { return false; }
if (EthPhy->SetInterface(eth_capabilities.media_interface) != ARM_DRIVER_OK) { return false; }
if (EthPhy->SetMode(ARM_ETH_PHY_AUTO_NEGOTIATE) != ARM_DRIVER_OK) { return false; }
thread_id_Connection = osThreadNew(ThreadConnection, NULL, &thread_attr_connection);
thread_id_DataIN = osThreadNew(ThreadDataIN, NULL, &thread_attr_data_in);
thread_id_DataOUT = osThreadNew(ThreadDataOUT, NULL, &thread_attr_data_out);
(void)osThreadFlagsSet(thread_id_Connection, 1U);
return true;
}
static void ENET_Uninitialize (void) {
packet_filter = ARM_ETH_MAC_ADDRESS_BROADCAST;
(void)EthMac->SetMacAddress(&mac_address);
(void)EthMac->SetAddressFilter(NULL, 0);
(void)EthMac->Control(ARM_ETH_MAC_CONFIGURE,
(uint32_t)(link_info.speed ) |
(uint32_t)(link_info.duplex << ARM_ETH_MAC_DUPLEX_Pos) |
packet_filter);
if (thread_id_Connection != NULL) { (void)osThreadTerminate(thread_id_Connection); thread_id_Connection = NULL; }
if (thread_id_DataIN != NULL) { (void)osThreadTerminate(thread_id_DataIN); thread_id_DataIN = NULL; }
if (thread_id_DataOUT != NULL) { (void)osThreadTerminate(thread_id_DataOUT); thread_id_DataOUT = NULL; }
(void)EthPhy->PowerControl(ARM_POWER_OFF);
(void)EthPhy->Uninitialize();
(void)EthMac->PowerControl(ARM_POWER_OFF);
(void)EthMac->Uninitialize();
}
void USBD_CDC%Instance%_ACM_Initialize (void) {
InitVars();
}
void USBD_CDC%Instance%_ACM_Uninitialize (void) {
InitVars();
ENET_Uninitialize();
}
void USBD_CDC%Instance%_ACM_Reset (void) {
InitVars();
}
bool USBD_CDC%Instance%_ACM_SendEncapsulatedCommand (const uint8_t *buf, uint16_t len) {
const REMOTE_NDIS_INITIALIZE_MSG_t *ptr_init_msg;
REMOTE_NDIS_INITIALIZE_CMPLT_t *ptr_init_cmplt;
const REMOTE_NDIS_HALT_MSG_t *ptr_halt_msg;
const REMOTE_NDIS_QUERY_MSG_t *ptr_query_msg;
REMOTE_NDIS_QUERY_CMPLT_t *ptr_query_cmplt;
const REMOTE_NDIS_SET_MSG_t *ptr_set_msg;
REMOTE_NDIS_SET_CMPLT_t *ptr_set_cmplt;
const REMOTE_NDIS_RESET_MSG_t *ptr_reset_msg;
REMOTE_NDIS_RESET_CMPLT_t *ptr_reset_cmplt;
const REMOTE_NDIS_KEEPALIVE_MSG_t *ptr_keepalive_msg;
REMOTE_NDIS_KEEPALIVE_CMPLT_t *ptr_keepalive_cmplt;
uint32_t status, val;
uint32_t i;
uint32_t num, by;
uint16_t msg_type;
(void)len;
msg_type = __UNALIGNED_UINT16_READ(buf);
if ((rndis_state == RNDIS_UNINITIALIZED) &&
(msg_type != REMOTE_NDIS_INITIALIZE_MSG) &&
(msg_type != REMOTE_NDIS_HALT_MSG)) {
return false;
}
if (((uint32_t)buf & 3) != 0) {
return false;
}
status = RNDIS_STATUS_SUCCESS;
get_encapsulated_response_len = 0U;
switch (msg_type) {
case REMOTE_NDIS_INITIALIZE_MSG:
ptr_init_msg = (const REMOTE_NDIS_INITIALIZE_MSG_t *)((const void *)buf);
if (ptr_init_msg->MessageLength != sizeof(REMOTE_NDIS_INITIALIZE_MSG_t)) { return false; }
if (ptr_init_msg->MajorVersion != RNDIS_MAJOR_VERSION) { return false; }
if (ptr_init_msg->MinorVersion != RNDIS_MINOR_VERSION) { return false; }
if (ptr_init_msg->MaxTransferSize != 16384U) { return false; }
(void)ENET_Initialize ();
rndis_state = RNDIS_INITIALIZED;
ptr_init_cmplt = (REMOTE_NDIS_INITIALIZE_CMPLT_t *)((void *)get_encapsulated_response_buf);
ptr_init_cmplt->MessageType = REMOTE_NDIS_INITIALIZE_CMPLT;
ptr_init_cmplt->MessageLength = sizeof(REMOTE_NDIS_INITIALIZE_CMPLT_t);
ptr_init_cmplt->RequestID = ptr_init_msg->RequestID;
ptr_init_cmplt->Status = status;
ptr_init_cmplt->MajorVersion = RNDIS_MAJOR_VERSION;
ptr_init_cmplt->MinorVersion = RNDIS_MINOR_VERSION;
ptr_init_cmplt->DeviceFlags = RNDIS_DF_CONNECTIONLESS;
ptr_init_cmplt->Medium = (uint32_t)NdisMedium802_3;
ptr_init_cmplt->MaxPacketsPerTransfer = 1U;
ptr_init_cmplt->MaxTransferSize = USBD_CDC%Instance%_ACM_RECEIVE_BUF_SIZE;
ptr_init_cmplt->PacketAlignmentFactor = 2U;
ptr_init_cmplt->Reserved[0] = 0U;
ptr_init_cmplt->Reserved[1] = 0U;
get_encapsulated_response_len = ptr_init_cmplt->MessageLength;
break;
case REMOTE_NDIS_HALT_MSG:
ptr_halt_msg = (const REMOTE_NDIS_HALT_MSG_t *)((const void *)buf);
if (ptr_halt_msg->MessageLength != sizeof(REMOTE_NDIS_HALT_MSG_t)) { return false; }
(void)ENET_Uninitialize ();
rndis_state = RNDIS_UNINITIALIZED;
return true;
case REMOTE_NDIS_QUERY_MSG:
ptr_query_msg = (const REMOTE_NDIS_QUERY_MSG_t *)((const void *)buf);
if (ptr_query_msg->MessageLength < 28U) { return false; }
ptr_query_cmplt = (REMOTE_NDIS_QUERY_CMPLT_t *)((void *)get_encapsulated_response_buf);
ptr_query_cmplt->MessageType = REMOTE_NDIS_QUERY_CMPLT;
ptr_query_cmplt->RequestID = ptr_query_msg->RequestID;
ptr_query_cmplt->InformationBufferOffset = 16U;
switch (ptr_query_msg->Oid) {
case OID_GEN_SUPPORTED_LIST:
ptr_query_cmplt->InformationBufferLength = 23U * 4U;
ptr_query_cmplt->OIDInputBuffer[0] = OID_GEN_SUPPORTED_LIST;
ptr_query_cmplt->OIDInputBuffer[1] = OID_GEN_HARDWARE_STATUS;
ptr_query_cmplt->OIDInputBuffer[2] = OID_GEN_MEDIA_SUPPORTED;
ptr_query_cmplt->OIDInputBuffer[3] = OID_GEN_MEDIA_IN_USE;
ptr_query_cmplt->OIDInputBuffer[4] = OID_GEN_MAXIMUM_FRAME_SIZE;
ptr_query_cmplt->OIDInputBuffer[5] = OID_GEN_LINK_SPEED;
ptr_query_cmplt->OIDInputBuffer[6] = OID_GEN_TRANSMIT_BLOCK_SIZE;
ptr_query_cmplt->OIDInputBuffer[7] = OID_GEN_RECEIVE_BLOCK_SIZE;
ptr_query_cmplt->OIDInputBuffer[8] = OID_GEN_VENDOR_ID;
ptr_query_cmplt->OIDInputBuffer[9] = OID_GEN_VENDOR_DESCRIPTION;
ptr_query_cmplt->OIDInputBuffer[10] = OID_GEN_CURRENT_PACKET_FILTER;
ptr_query_cmplt->OIDInputBuffer[11] = OID_GEN_MAXIMUM_TOTAL_SIZE;
ptr_query_cmplt->OIDInputBuffer[12] = OID_GEN_MEDIA_CONNECT_STATUS;
ptr_query_cmplt->OIDInputBuffer[13] = OID_GEN_PHYSICAL_MEDIUM;
ptr_query_cmplt->OIDInputBuffer[14] = OID_GEN_XMIT_OK;
ptr_query_cmplt->OIDInputBuffer[15] = OID_GEN_RCV_OK;
ptr_query_cmplt->OIDInputBuffer[16] = OID_GEN_XMIT_ERROR;
ptr_query_cmplt->OIDInputBuffer[17] = OID_GEN_RCV_ERROR;
ptr_query_cmplt->OIDInputBuffer[18] = OID_GEN_RCV_NO_BUFFER;
ptr_query_cmplt->OIDInputBuffer[19] = OID_802_3_PERMANENT_ADDRESS;
ptr_query_cmplt->OIDInputBuffer[20] = OID_802_3_CURRENT_ADDRESS;
ptr_query_cmplt->OIDInputBuffer[21] = OID_802_3_MULTICAST_LIST;
ptr_query_cmplt->OIDInputBuffer[22] = OID_802_3_MAXIMUM_LIST_SIZE;
break;
case OID_GEN_HARDWARE_STATUS:
ptr_query_cmplt->InformationBufferLength = 4U;
if (link_state == ARM_ETH_LINK_UP) {
ptr_query_cmplt->OIDInputBuffer[0] = (uint32_t)NdisHardwareStatusReady;
} else {
ptr_query_cmplt->OIDInputBuffer[0] = (uint32_t)NdisHardwareStatusNotReady;
}
break;
case OID_GEN_MEDIA_SUPPORTED:
case OID_GEN_MEDIA_IN_USE:
ptr_query_cmplt->InformationBufferLength = 4U;
ptr_query_cmplt->OIDInputBuffer[0] = (uint32_t)NdisMedium802_3;
break;
case OID_GEN_MAXIMUM_FRAME_SIZE:
ptr_query_cmplt->InformationBufferLength = 4U;
ptr_query_cmplt->OIDInputBuffer[0] = ETH_MTU_SIZE;
break;
case OID_GEN_LINK_SPEED:
ptr_query_cmplt->InformationBufferLength = 4U;
ptr_query_cmplt->OIDInputBuffer[0] = link_speed / 100U;
break;
case OID_GEN_TRANSMIT_BLOCK_SIZE:
ptr_query_cmplt->InformationBufferLength = 4U;
ptr_query_cmplt->OIDInputBuffer[0] = USBD_CDC%Instance%_ACM_SEND_BUF_SIZE;
break;
case OID_GEN_RECEIVE_BLOCK_SIZE:
ptr_query_cmplt->InformationBufferLength = 4U;
ptr_query_cmplt->OIDInputBuffer[0] = USBD_CDC%Instance%_ACM_RECEIVE_BUF_SIZE;
break;
case OID_GEN_VENDOR_ID:
ptr_query_cmplt->InformationBufferLength = 4U;
ptr_query_cmplt->OIDInputBuffer[0] = RNDIS_VENDOR_ID;
break;
case OID_GEN_VENDOR_DESCRIPTION:
ptr_query_cmplt->InformationBufferLength = strlen(RNDIS_VENDOR_DESC) + 1;
memset((void *)&ptr_query_cmplt->OIDInputBuffer[0], 0, ptr_query_cmplt->InformationBufferLength + 1U);
memcpy((void *)&ptr_query_cmplt->OIDInputBuffer[0], RNDIS_VENDOR_DESC, strlen(RNDIS_VENDOR_DESC));
break;
case OID_GEN_CURRENT_PACKET_FILTER:
ptr_query_cmplt->InformationBufferLength = 4U;
val = 0U;
if ((packet_filter & ARM_ETH_MAC_ADDRESS_MULTICAST) != 0U) { val |= RNDIS_FILTER_ALL_MULTICAST; }
if ((packet_filter & ARM_ETH_MAC_ADDRESS_BROADCAST) != 0U) { val |= RNDIS_FILTER_BROADCAST; }
if ((packet_filter & ARM_ETH_MAC_ADDRESS_ALL) != 0U) { val |= RNDIS_FILTER_PROMISCUOUS; }
ptr_query_cmplt->OIDInputBuffer[0] = val;
break;
case OID_GEN_MAXIMUM_TOTAL_SIZE:
ptr_query_cmplt->InformationBufferLength = 4U;
ptr_query_cmplt->OIDInputBuffer[0] = 44U + ETH_MAX_SIZE;
break;
case OID_GEN_MEDIA_CONNECT_STATUS:
ptr_query_cmplt->InformationBufferLength = 4U;
if (link_state == ARM_ETH_LINK_UP) {
ptr_query_cmplt->OIDInputBuffer[0] = (uint32_t)NdisMediaStateConnected;
} else {
ptr_query_cmplt->OIDInputBuffer[0] = (uint32_t)NdisMediaStateDisconnected;
}
break;
case OID_GEN_PHYSICAL_MEDIUM:
ptr_query_cmplt->InformationBufferLength = 4U;
ptr_query_cmplt->OIDInputBuffer[0] = (uint32_t)NdisPhysicalMediumUnspecified;
break;
case OID_GEN_XMIT_OK:
ptr_query_cmplt->InformationBufferLength = 4U;
ptr_query_cmplt->OIDInputBuffer[0] = xmit_ok;
break;
case OID_GEN_RCV_OK:
ptr_query_cmplt->InformationBufferLength = 4U;
ptr_query_cmplt->OIDInputBuffer[0] = rcv_ok;
break;
case OID_GEN_XMIT_ERROR:
ptr_query_cmplt->InformationBufferLength = 4U;
ptr_query_cmplt->OIDInputBuffer[0] = xmit_error;
break;
case OID_GEN_RCV_ERROR:
ptr_query_cmplt->InformationBufferLength = 4U;
ptr_query_cmplt->OIDInputBuffer[0] = rcv_error;
break;
case OID_GEN_RCV_NO_BUFFER:
ptr_query_cmplt->InformationBufferLength = 4U;
ptr_query_cmplt->OIDInputBuffer[0] = rcv_no_buffer;
break;
case OID_802_3_PERMANENT_ADDRESS:
case OID_802_3_CURRENT_ADDRESS:
ptr_query_cmplt->InformationBufferLength = 6U;
memcpy((void *)&ptr_query_cmplt->OIDInputBuffer[0], &mac_address, sizeof(ARM_ETH_MAC_ADDR));
break;
case OID_802_3_MULTICAST_LIST:
for (i = 0U; i < RNDIS_MCAST_NUM; i++) {
if ((__UNALIGNED_UINT32_READ(&mcast_address[0]) == 0U) &&
(__UNALIGNED_UINT16_READ(&mcast_address[4]) == 0U)) {
break;
}
}
if (i == 0U) {
num = 0U;
ptr_query_cmplt->InformationBufferOffset = 0U;
} else {
num = i;
if (i < RNDIS_MCAST_NUM) {
num = i + 1U;
} else {
num = i;
}
memcpy((void *)&ptr_query_cmplt->OIDInputBuffer[0], mcast_address, num * sizeof(ARM_ETH_MAC_ADDR));
}
ptr_query_cmplt->InformationBufferLength = num * sizeof(ARM_ETH_MAC_ADDR);
break;
case OID_802_3_MAXIMUM_LIST_SIZE:
ptr_query_cmplt->InformationBufferLength = 4U;
ptr_query_cmplt->OIDInputBuffer[0] = RNDIS_MCAST_NUM;
break;
default:
ptr_query_cmplt->InformationBufferOffset = 0U;
ptr_query_cmplt->InformationBufferLength = 0U;
status = RNDIS_STATUS_NOT_SUPPORTED;
break;
}
ptr_query_cmplt->Status = status;
ptr_query_cmplt->MessageLength = ptr_query_cmplt->InformationBufferLength + 24U;
get_encapsulated_response_len = ptr_query_cmplt->MessageLength;
break;
case REMOTE_NDIS_SET_MSG:
ptr_set_msg = (const REMOTE_NDIS_SET_MSG_t *)((const void *)buf);
if (ptr_set_msg->MessageLength < 28U) { return false; }
ptr_set_cmplt = (REMOTE_NDIS_SET_CMPLT_t *)((void *)get_encapsulated_response_buf);
ptr_set_cmplt->MessageType = REMOTE_NDIS_SET_CMPLT;
ptr_set_cmplt->MessageLength = sizeof(REMOTE_NDIS_SET_CMPLT_t);
ptr_set_cmplt->RequestID = ptr_set_msg->RequestID;
switch (ptr_set_msg->Oid) {
case OID_802_3_MULTICAST_LIST:
by = ptr_set_msg->InformationBufferLength;
if (by > (sizeof(ARM_ETH_MAC_ADDR) * RNDIS_MCAST_NUM)) {
by = sizeof(ARM_ETH_MAC_ADDR) * RNDIS_MCAST_NUM;
}
if (by > 0U) {
memcpy(mcast_address, (const void *)&ptr_set_msg->OIDInputBuffer[0], by);
num = by / sizeof(ARM_ETH_MAC_ADDR);
if (EthMac->SetAddressFilter(mcast_address, num) != ARM_DRIVER_OK) {
status = RNDIS_STATUS_FAILURE;
}
}
break;
case OID_GEN_CURRENT_PACKET_FILTER:
if ((ptr_set_msg->InformationBufferLength == 4U) &&
(ptr_set_msg->InformationBufferOffset != 0U)) {
val = __UNALIGNED_UINT32_READ(((const uint8_t *)&ptr_set_msg->RequestID) + ptr_set_msg->InformationBufferOffset);
if (val != 0U) {
if ((val & RNDIS_FILTER_ALL_MULTICAST) != 0U) { packet_filter |= ARM_ETH_MAC_ADDRESS_MULTICAST; }
if ((val & RNDIS_FILTER_BROADCAST) != 0U) { packet_filter |= ARM_ETH_MAC_ADDRESS_BROADCAST; }
if ((val & RNDIS_FILTER_PROMISCUOUS) != 0U) { packet_filter |= ARM_ETH_MAC_ADDRESS_ALL; }
(void)EthMac->Control(ARM_ETH_MAC_CONFIGURE,
(uint32_t)(link_info.speed ) |
(uint32_t)(link_info.duplex << ARM_ETH_MAC_DUPLEX_Pos) |
packet_filter);
rndis_state = RNDIS_DATA_INITIALIZED;
} else {
if (rndis_state == RNDIS_DATA_INITIALIZED) {
rndis_state = RNDIS_INITIALIZED;
}
}
} else {
status = RNDIS_STATUS_FAILURE;
}
break;
default:
status = RNDIS_STATUS_NOT_SUPPORTED;
break;
}
ptr_set_cmplt->Status = status;
get_encapsulated_response_len = ptr_set_cmplt->MessageLength;
break;
case REMOTE_NDIS_RESET_MSG:
ptr_reset_msg = (const REMOTE_NDIS_RESET_MSG_t *)((const void *)buf);
if (ptr_reset_msg->MessageLength != sizeof(REMOTE_NDIS_RESET_MSG_t)) { return false; }
ResetVars();
(void)osThreadFlagsSet(thread_id_DataIN, 1U);
(void)osThreadFlagsSet(thread_id_DataOUT, 1U);
ptr_reset_cmplt = (REMOTE_NDIS_RESET_CMPLT_t *)((void *)get_encapsulated_response_buf);
ptr_reset_cmplt->MessageType = REMOTE_NDIS_RESET_CMPLT;
ptr_reset_cmplt->MessageLength = sizeof(REMOTE_NDIS_RESET_CMPLT_t);
ptr_reset_cmplt->Status = status;
ptr_reset_cmplt->AddressingReset = 0U;
get_encapsulated_response_len = ptr_reset_cmplt->MessageLength;
break;
case REMOTE_NDIS_KEEPALIVE_MSG:
ptr_keepalive_msg = (const REMOTE_NDIS_KEEPALIVE_MSG_t *)((const void *)buf);
if (ptr_keepalive_msg->MessageLength != sizeof(REMOTE_NDIS_KEEPALIVE_MSG_t)) { return false; }
ptr_keepalive_cmplt = (REMOTE_NDIS_KEEPALIVE_CMPLT_t *)((void *)get_encapsulated_response_buf);
ptr_keepalive_cmplt->MessageType = REMOTE_NDIS_KEEPALIVE_CMPLT;
ptr_keepalive_cmplt->MessageLength = sizeof(REMOTE_NDIS_KEEPALIVE_CMPLT_t);
ptr_keepalive_cmplt->RequestID = ptr_keepalive_msg->RequestID;
ptr_keepalive_cmplt->Status = status;
get_encapsulated_response_len = ptr_keepalive_cmplt->MessageLength;
break;
default:
return false;
}
if (get_encapsulated_response_len != 0U) {
}
return true;
}
bool USBD_CDC%Instance%_ACM_GetEncapsulatedResponse (uint16_t max_len, uint8_t **buf, uint16_t *len) {
REMOTE_NDIS_INDICATE_STATUS_MSG_t *ptr_indicate_status_msg;
uint32_t status;
(void)max_len;
if (link_state_up || link_state_down) {
if (link_state_up) {
status = RNDIS_STATUS_MEDIA_CONNECT;
} else {
status = RNDIS_STATUS_MEDIA_DISCONNECT;
}
ptr_indicate_status_msg = (REMOTE_NDIS_INDICATE_STATUS_MSG_t *)((void *)get_encapsulated_response_buf);
ptr_indicate_status_msg->MessageType = REMOTE_NDIS_INDICATE_STATUS_MSG;
ptr_indicate_status_msg->MessageLength = 20U;
ptr_indicate_status_msg->Status = status;
ptr_indicate_status_msg->StatusBufferLength = 0U;
ptr_indicate_status_msg->StatusBufferOffset = 0U;
get_encapsulated_response_len = 20U;
link_state_up = false;
link_state_down = false;
}
if (get_encapsulated_response_len != 0U) {
*buf = (uint8_t *)get_encapsulated_response_buf;
*len = (uint16_t) get_encapsulated_response_len;
get_encapsulated_response_len = 0U;
}
return true;
}
void USBD_CDC%Instance%_ACM_DataSent (void) {
}
void USBD_CDC%Instance%_ACM_DataReceived (uint32_t len) {
(void)len;
(void)osThreadFlagsSet(thread_id_DataOUT, 1U);
}
static void EthMac_Notify (uint32_t event) {
switch (event) {
case ARM_ETH_MAC_EVENT_RX_FRAME:
(void)osThreadFlagsSet(thread_id_DataIN, 1U);
break;
default:
break;
}
}
__NO_RETURN static void ThreadConnection (void *arg) {
ARM_ETH_LINK_STATE link_state_local;
uint32_t speed_local;
(void)(arg);
for (;;) {
(void)osThreadFlagsWait(1U, osFlagsWaitAll, 500U);
link_state_local = EthPhy->GetLinkState();
if (link_state_local == ARM_ETH_LINK_UP) {
link_info = EthPhy->GetLinkInfo();
switch (link_info.speed) {
case 0: speed_local = 10000000U; break;
case 1: speed_local = 100000000U; break;
case 2: speed_local = 1000000000U; break;
default: speed_local = 0U;
}
} else {
speed_local = 0U;
}
if (link_speed != speed_local) {
link_speed = speed_local;
}
if (link_state != link_state_local) {
link_state = link_state_local;
if (link_state == ARM_ETH_LINK_UP) {
(void)EthMac->Control(ARM_ETH_MAC_CONFIGURE,
(uint32_t)(link_info.speed ) |
(uint32_t)(link_info.duplex << ARM_ETH_MAC_DUPLEX_Pos) |
packet_filter);
(void)EthMac->Control(ARM_ETH_MAC_CONTROL_TX, 1U);
(void)EthMac->Control(ARM_ETH_MAC_CONTROL_RX, 1U);
link_state_down = false;
link_state_up = true;
} else {
(void)EthMac->Control(ARM_ETH_MAC_FLUSH,
ARM_ETH_MAC_FLUSH_TX |
ARM_ETH_MAC_FLUSH_RX);
(void)EthMac->Control(ARM_ETH_MAC_CONTROL_TX, 0U);
(void)EthMac->Control(ARM_ETH_MAC_CONTROL_RX, 0U);
link_state_up = false;
link_state_down = true;
}
}
}
}
__NO_RETURN static void ThreadDataIN (void *arg) {
REMOTE_NDIS_PACKET_MSG_t *ptr_packet_msg;
uint32_t eth_rx_size;
int32_t usb_cdc_acm_status;
(void)(arg);
ptr_packet_msg = (REMOTE_NDIS_PACKET_MSG_t *)((void *)packet_in);
for (;;) {
(void)osThreadFlagsWait(1U, osFlagsWaitAll, osWaitForever);
for (;;) {
eth_rx_size = EthMac->GetRxFrameSize();
if (eth_rx_size == 0) {
break;
}
if ((link_state == ARM_ETH_LINK_UP) &&
(rndis_state == RNDIS_DATA_INITIALIZED) &&
(eth_rx_size >= ETH_MIN_SIZE) &&
(eth_rx_size <= ETH_MAX_SIZE)) {
(void)EthMac->ReadFrame((uint8_t *)&ptr_packet_msg->PayLoad[0], eth_rx_size);
ptr_packet_msg->MessageType = REMOTE_NDIS_PACKET_MSG;
ptr_packet_msg->MessageLength = eth_rx_size + 44U;
ptr_packet_msg->DataOffset = 36U;
ptr_packet_msg->DataLength = eth_rx_size;
ptr_packet_msg->OutOfBandDataOffset = 0U;
ptr_packet_msg->OutOfBandDataLength = 0U;
ptr_packet_msg->NumOutOfBandDataElements = 0U;
ptr_packet_msg->PerPacketInfoOffset = 0U;
ptr_packet_msg->PerPacketInfoLength = 0U;
ptr_packet_msg->Reserved[0] = 0U;
ptr_packet_msg->Reserved[1] = 0U;
do {
usb_cdc_acm_status =
USBD_CDC_ACM_WriteData (%Instance%, (
const uint8_t *)ptr_packet_msg, (int32_t)ptr_packet_msg->MessageLength);
} while (usb_cdc_acm_status == 0);
if (usb_cdc_acm_status == (int32_t)ptr_packet_msg->MessageLength) {
rcv_ok++;
} else {
rcv_error++;
}
} else {
(void)EthMac->ReadFrame(NULL, 0);
}
}
}
}
__NO_RETURN static void ThreadDataOUT (void *arg) {
REMOTE_NDIS_PACKET_MSG_t *ptr_packet_msg;
uint32_t eth_tx_size;
int32_t usb_cdc_acm_status, eth_mac_status;
(void)(arg);
eth_tx_size = 0U;
ptr_packet_msg = (REMOTE_NDIS_PACKET_MSG_t *)((void *)packet_out);
for (;;) {
(void)osThreadFlagsWait(1U, osFlagsWaitAll, osWaitForever);
for (;;) {
usb_cdc_acm_status =
USBD_CDC_ACM_ReadData (%Instance%, (uint8_t *)ptr_packet_msg, USBD_CDC0_ACM_RECEIVE_BUF_SIZE);
if (usb_cdc_acm_status == 0) {
break;
} else if (usb_cdc_acm_status > (int32_t)ptr_packet_msg->DataLength) {
eth_tx_size = ptr_packet_msg->DataLength;
}
if ((link_state == ARM_ETH_LINK_UP) &&
(rndis_state == RNDIS_DATA_INITIALIZED) &&
(eth_tx_size >= ETH_MIN_SIZE) &&
(eth_tx_size <= ETH_MAX_SIZE)) {
do {
eth_mac_status = EthMac->SendFrame((uint8_t *)&ptr_packet_msg->PayLoad[0], (uint32_t)(eth_tx_size), 0U);
} while (eth_mac_status == ARM_DRIVER_ERROR_BUSY);
if (eth_mac_status == ARM_DRIVER_OK) {
xmit_ok++;
} else {
xmit_error++;
}
}
}
}
}
#endif