Implement application specific behavior of a Communication Device Class (CDC) USB Device using the sub-class Network Control Model (NCM) for Ethernet-over-USB applications.
More...
Implement application specific behavior of a Communication Device Class (CDC) USB Device using the sub-class Network Control Model (NCM) for Ethernet-over-USB applications.
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:
The necessary descriptors are automatically generated by the USB Middleware Component. The page USB Descriptors provides more information on the topic.
The thread USBD_CDCn_Int_Thread handles Interrupt IN Endpoint whereas the USBD_CDCn_Bulk_Thread handles the Bulk IN and Bulk OUT Endpoints.
The following source code contains all the required callback functions and can be used to implement the application specific behavior of a USB CDC (NCM) Device.
#include <string.h>
#include "cmsis_os.h"
#include "rl_usb.h"
#include "RTE\USB\USBD_Config_CDC_n.h"
#define USB_CDC_NUM n
#define MAX_IN_DATAGRAMS 10
static const uint16_t *wsMacAddress = USBD_CDCn_NCM_MAC_ADDRESS;
static uint8_t MacAddress[6];
static uint16_t LinkState;
static uint32_t LinkSpeed;
static struct {
uint16_t ntb_format;
uint32_t ntb_input_size;
uint16_t max_datagram_size;
uint16_t crc_mode;
#if ((USBD_CDCn_NCM_BM_NETWORK_CAPABILITIES & 0x02) != 0)
uint8_t net_address[6];
#endif
#if (USBD_CDCn_NCM_W_NUMBER_MC_FILTERS != 0)
uint8_t mc_filters[6*(USBD_CDCn_NCM_W_NUMBER_MC_FILTERS & 0x7FFF)];
#endif
#if (USBD_CDCn_NCM_B_NUMBER_POWER_FILTERS != 0)
uint8_t power_filter_active[(USBD_CDCn_NCM_B_NUMBER_POWER_FILTERS + 7)/8];
#endif
uint16_t packet_filter_bitmap;
#if (USBD_CDCn_NCM_BM_ETHERNET_STATISTICS != 0)
uint32_t eth_statistics[29];
#endif
} NCM_State;
static uint32_t FrameIN_Size;
static uint8_t FrameIN [USBD_CDCn_NCM_W_MAX_SEGMENT_SIZE];
static uint8_t FrameOUT[USBD_CDCn_NCM_W_MAX_SEGMENT_SIZE];
static void Connection_Thread (void const *arg);
static void DataIN_Thread (void const *arg);
static void DataOUT_Thread (void const *arg);
static osThreadId Connection_ThreadId;
static osThreadId DataIN_ThreadId;
static osThreadId DataOUT_ThreadId;
osThreadDef(Connection_Thread, osPriorityNormal, 1, NULL);
osThreadDef(DataIN_Thread, osPriorityNormal, 1, NULL);
osThreadDef(DataOUT_Thread, osPriorityNormal, 1, NULL);
static void MAC_wstr_to_addr (const uint16_t *wstr, uint8_t *addr) {
uint8_t c;
uint8_t n;
int32_t i;
for (i = 0; i < 12; i++) {
c = (uint8_t)wstr[i];
if ((c >= '0') && (c <= '9')) {
n = c - '0';
} else if ((c >= 'A') && (c <= 'F')) {
n = c - 'A' + 10;
} else if ((c >= 'a') && (c <= 'f')) {
n = c - 'a' + 10;
} else {
n = 0;
}
if (i & 1) {
addr[i>>1] |= n;
} else {
addr[i>>1] = n << 4;
}
}
}
MAC_wstr_to_addr(wsMacAddress, (uint8_t *)&MacAddress);
memset(&NCM_State, 0, sizeof(NCM_State));
NCM_State.ntb_input_size = USBD_CDCn_NCM_DW_NTB_IN_MAX_SIZE;
NCM_State.max_datagram_size = USBD_CDCn_NCM_W_MAX_SEGMENT_SIZE;
#if ((USBD_CDCn_NCM_BM_NETWORK_CAPABILITIES & 0x02) != 0)
memcpy(&NCM_State.net_address, &MacAddress, 6);
#endif
NCM_State.packet_filter_bitmap = 0x0CU;
LinkState = 0U;
LinkSpeed = 0U;
FrameIN_Size = 0U;
Connection_ThreadId = osThreadCreate(osThread(Connection_Thread), NULL);
DataIN_ThreadId = osThreadCreate(osThread(DataIN_Thread), NULL);
DataOUT_ThreadId = osThreadCreate(osThread(DataOUT_Thread), NULL);
}
osThreadTerminate(Connection_ThreadId);
osThreadTerminate(DataIN_ThreadId);
osThreadTerminate(DataOUT_ThreadId);
}
}
osSignalSet(Connection_ThreadId, 1U);
osSignalSet(DataIN_ThreadId, 1U);
}
FrameIN_Size = 0U;
osSignalClear(DataIN_ThreadId, 1U);
memset(&NCM_State, 0, sizeof(NCM_State));
NCM_State.ntb_input_size = USBD_CDCn_NCM_DW_NTB_IN_MAX_SIZE;
NCM_State.max_datagram_size = USBD_CDCn_NCM_W_MAX_SEGMENT_SIZE;
#if ((USBD_CDCn_NCM_BM_NETWORK_CAPABILITIES & 0x02) != 0)
memcpy(&NCM_State.net_address, &MacAddress, 6);
#endif
NCM_State.packet_filter_bitmap = 0x0CU;
}
#if (USBD_CDCn_NCM_W_NUMBER_MC_FILTERS != 0)
if (num_of_filters > (USBD_CDCn_NCM_W_NUMBER_MC_FILTERS & 0x7FFF)) { return false; }
memcpy(&NCM_State.mc_filters, addr_list, num_of_filters * 6);
return true;
#else
return false;
#endif
}
#if (USBD_CDCn_NCM_B_NUMBER_POWER_FILTERS != 0)
if (filter_number >= USBD_CDCn_NCM_B_NUMBER_POWER_FILTERS) { return false; }
NCM_State.power_filter_active[filter_number / 8] |= 1U << (filter_number % 8);
return true;
#else
return false;
#endif
}
#if (USBD_CDCn_NCM_B_NUMBER_POWER_FILTERS != 0)
*pattern_active = (NCM_State.power_filter_active[filter_number / 8] & (1U << (filter_number % 8))) ? 1 : 0;
return true;
#else
return false;
#endif
}
#if ((USBD_CDCn_NCM_BM_NETWORK_CAPABILITIES & 0x01) != 0)
NCM_State.packet_filter_bitmap = packet_filter_bitmap;
return true;
#else
return false;
#endif
}
#if (USBD_CDCn_NCM_BM_ETHERNET_STATISTICS != 0)
if (feature_selector == 0x00U) { return true; }
if (feature_selector > 0x1DU) { return false; }
*data = NCM_State.eth_statistics[feature_selector - 1];
return true;
#else
return false;
#endif
}
ntb_params->wLength = sizeof(CDC_NCM_NTB_PARAM);
ntb_params->bmNtbFormatsSupported = USBD_CDCn_NCM_BM_NTB_FORMATS_SUPPORTED;
ntb_params->dwNtbInMaxSize = USBD_CDCn_NCM_DW_NTB_IN_MAX_SIZE;
ntb_params->wNdpInDivisor = USBD_CDCn_NCM_W_NDP_IN_DIVISOR;
ntb_params->wNdpInPayloadRemainder = USBD_CDCn_NCM_W_NDP_IN_PAYLOAD_REMINDER;
ntb_params->wNdpInAlignment = USBD_CDCn_NCM_W_NDP_IN_ALIGNMENT;
ntb_params->Reserved0 = 0U;
ntb_params->dwNtbOutMaxSize = USBD_CDCn_NCM_DW_NTB_OUT_MAX_SIZE;
ntb_params->wNdpOutDivisor = USBD_CDCn_NCM_W_NDP_OUT_DIVISOR;
ntb_params->wNdpOutPayloadRemainder = USBD_CDCn_NCM_W_NDP_OUT_PAYLOAD_REMINDER;
ntb_params->wNdpOutAlignment = USBD_CDCn_NCM_W_NDP_OUT_ALIGNMENT;
ntb_params->Reserved1 = 0U;
return true;
}
#if ((USBD_CDCn_NCM_BM_NETWORK_CAPABILITIES & 0x02) != 0)
memcpy(net_addr, &NCM_State.net_address, 6);
return true;
#else
return false;
#endif
}
#if ((USBD_CDCn_NCM_BM_NETWORK_CAPABILITIES & 0x02) != 0)
memcpy(&NCM_State.net_address, net_addr, 6);
return true;
#else
return false;
#endif
}
*ntb_format = NCM_State.ntb_format;
return true;
}
#if (USBD_CDCn_NCM_BM_NTB_FORMATS_SUPPORTED > 1)
if (ntb_format > 1) { return false; }
#else
if (ntb_format > 0) { return false; }
#endif
NCM_State.ntb_format = ntb_format;
return true;
}
*ntb_input_size = NCM_State.ntb_input_size;
return true;
}
if (ntb_input_size > USBD_CDCn_NCM_DW_NTB_IN_MAX_SIZE) { return false; }
NCM_State.ntb_input_size = ntb_input_size;
return true;
}
#if ((USBD_CDCn_NCM_BM_NETWORK_CAPABILITIES & 0x08) != 0)
*max_datagram_size = NCM_State.max_datagram_size;
return true;
#else
return false;
#endif
}
#if ((USBD_CDCn_NCM_BM_NETWORK_CAPABILITIES & 0x08) != 0)
if (max_datagram_size > USBD_CDCn_NCM_W_MAX_SEGMENT_SIZE) { return false; }
NCM_State.max_datagram_size = max_datagram_size;
return true;
#else
return false;
#endif
}
#if ((USBD_CDCn_NCM_BM_NETWORK_CAPABILITIES & 0x10) != 0)
*crc_mode = NCM_State.crc_mode;
return true;
#else
return false;
#endif
}
#if ((USBD_CDCn_NCM_BM_NETWORK_CAPABILITIES & 0x10) != 0)
if (crc_mode > 1) { return false; }
NCM_State.crc_mode = crc_mode;
return true;
#else
return false;
#endif
}
osSignalSet(DataIN_ThreadId, 1U);
}
osSignalSet(DataOUT_ThreadId, 1U);
}
static void Connection_Thread (void const *arg) {
osEvent event;
uint32_t speed;
uint16_t state;
int32_t status;
while (1) {
event = osSignalWait(1U, 500U);
state = 1U;
if (state == 1U) {
speed = 100000000U;
} else {
speed = 0U;
}
if (speed != LinkSpeed) {
LinkSpeed = speed;
if (state == 1U) {
do {
}
}
if (state != LinkState) {
LinkState = state;
do {
}
if (event.status == osEventSignal) {
if (LinkState == 1U) {
do {
}
do {
}
}
}
static void DataIN_Thread (void const *arg) {
uint32_t size;
int32_t len, status;
while (1) {
osSignalWait(3U, osWaitForever);
if (status !=
usbOK) {
continue; }
if (status !=
usbOK) {
continue; }
while (1) {
if (FrameIN_Size != 0) {
FrameIN_Size = 0;
}
size = 0U;
if (size == 0U) { break; }
if ((size < 14U) || (size > NCM_State.max_datagram_size)) {
continue;
}
len = 0U;
if (len > 0) {
FrameIN_Size = len;
osSignalSet(DataIN_ThreadId, 2U);
break;
}
}
}
}
}
static void DataOUT_Thread (void const *arg) {
uint32_t size;
int32_t len, status;
while (1) {
osSignalWait(1U, osWaitForever);
while (1) {
if (status !=
usbOK) {
break; }
while (1) {
if (size == 0U) { break; }
if ((size < 14U) || (size > NCM_State.max_datagram_size)) {
continue;
}
if (len > 0) {
}
}
}
}
}
The following source code contains all the required callback functions and can be used to implement the application specific behavior of a USB CDC (NCM) Device with Ethernet-over-USB functionality.
#include <string.h>
#include "cmsis_os.h"
#include "rl_usb.h"
#include "Driver_ETH_MAC.h"
#include "Driver_ETH_PHY.h"
#include "RTE\USB\USBD_Config_CDC_n.h"
#define ETH_MAC_NUM 0
#define ETH_PHY_NUM 0
#define USB_CDC_NUM n
#define MAX_IN_DATAGRAMS 10
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 const uint16_t *wsMacAddress = USBD_CDCn_NCM_MAC_ADDRESS;
static ARM_ETH_MAC_ADDR MacAddress;
static ARM_ETH_LINK_STATE LinkState;
static ARM_ETH_LINK_INFO LinkInfo;
static uint32_t LinkSpeed;
static uint32_t PacketFilter;
static struct {
uint16_t ntb_format;
uint32_t ntb_input_size;
uint16_t max_datagram_size;
uint16_t crc_mode;
#if ((USBD_CDCn_NCM_BM_NETWORK_CAPABILITIES & 0x02) != 0)
uint8_t net_address[6];
#endif
#if (USBD_CDCn_NCM_W_NUMBER_MC_FILTERS != 0)
uint8_t mc_filters[6*(USBD_CDCn_NCM_W_NUMBER_MC_FILTERS & 0x7FFF)];
#endif
#if (USBD_CDCn_NCM_B_NUMBER_POWER_FILTERS != 0)
uint8_t power_filter_active[(USBD_CDCn_NCM_B_NUMBER_POWER_FILTERS + 7)/8];
#endif
uint16_t packet_filter_bitmap;
#if (USBD_CDCn_NCM_BM_ETHERNET_STATISTICS != 0)
uint32_t eth_statistics[29];
#endif
} NCM_State;
static uint32_t FrameIN_Size;
static uint8_t FrameIN [USBD_CDCn_NCM_W_MAX_SEGMENT_SIZE];
static uint8_t FrameOUT[USBD_CDCn_NCM_W_MAX_SEGMENT_SIZE];
static void EthMac_Notify (uint32_t event);
static void Connection_Thread (void const *arg);
static void DataIN_Thread (void const *arg);
static void DataOUT_Thread (void const *arg);
static osThreadId Connection_ThreadId;
static osThreadId DataIN_ThreadId;
static osThreadId DataOUT_ThreadId;
osThreadDef(Connection_Thread, osPriorityNormal, 1, NULL);
osThreadDef(DataIN_Thread, osPriorityNormal, 1, NULL);
osThreadDef(DataOUT_Thread, osPriorityNormal, 1, NULL);
static void MAC_wstr_to_addr (const uint16_t *wstr, uint8_t *addr) {
uint8_t c;
uint8_t n;
int32_t i;
for (i = 0; i < 12; i++) {
c = (uint8_t)wstr[i];
if ((c >= '0') && (c <= '9')) {
n = c - '0';
} else if ((c >= 'A') && (c <= 'F')) {
n = c - 'A' + 10;
} else if ((c >= 'a') && (c <= 'f')) {
n = c - 'a' + 10;
} else {
n = 0;
}
if (i & 1) {
addr[i>>1] |= n;
} else {
addr[i>>1] = n << 4;
}
}
}
ARM_ETH_MAC_CAPABILITIES capabilities;
int32_t status;
MAC_wstr_to_addr(wsMacAddress, (uint8_t *)&MacAddress);
memset(&NCM_State, 0, sizeof(NCM_State));
NCM_State.ntb_input_size = USBD_CDCn_NCM_DW_NTB_IN_MAX_SIZE;
NCM_State.max_datagram_size = USBD_CDCn_NCM_W_MAX_SEGMENT_SIZE;
#if ((USBD_CDCn_NCM_BM_NETWORK_CAPABILITIES & 0x02) != 0)
memcpy(&NCM_State.net_address, &MacAddress, 6);
#endif
NCM_State.packet_filter_bitmap = 0x0CU;
LinkState = ARM_ETH_LINK_DOWN;
LinkInfo.speed = 0U;
LinkInfo.duplex = 0U;
LinkSpeed = 0U;
PacketFilter = ARM_ETH_MAC_ADDRESS_BROADCAST;
FrameIN_Size = 0U;
capabilities = EthMac->GetCapabilities();
status = EthMac->Initialize(EthMac_Notify);
if (status != ARM_DRIVER_OK) { return; }
status = EthMac->PowerControl(ARM_POWER_FULL);
if (status != ARM_DRIVER_OK) { return; }
status = EthMac->SetMacAddress(&MacAddress);
if (status != ARM_DRIVER_OK) { return; }
status = EthPhy->Initialize(EthMac->PHY_Read, EthMac->PHY_Write);
if (status != ARM_DRIVER_OK) { return; }
status = EthPhy->PowerControl(ARM_POWER_FULL);
if (status != ARM_DRIVER_OK) { return; }
status = EthPhy->SetInterface(capabilities.media_interface);
if (status != ARM_DRIVER_OK) { return; }
status = EthPhy->SetMode(ARM_ETH_PHY_AUTO_NEGOTIATE);
if (status != ARM_DRIVER_OK) { return; }
Connection_ThreadId = osThreadCreate(osThread(Connection_Thread), NULL);
DataIN_ThreadId = osThreadCreate(osThread(DataIN_Thread), NULL);
DataOUT_ThreadId = osThreadCreate(osThread(DataOUT_Thread), NULL);
}
osThreadTerminate(Connection_ThreadId);
osThreadTerminate(DataIN_ThreadId);
osThreadTerminate(DataOUT_ThreadId);
EthPhy->PowerControl(ARM_POWER_OFF);
EthPhy->Uninitialize();
EthMac->PowerControl(ARM_POWER_OFF);
EthMac->Uninitialize();
}
}
osSignalSet(Connection_ThreadId, 1U);
osSignalSet(DataIN_ThreadId, 1U);
}
FrameIN_Size = 0U;
osSignalClear(DataIN_ThreadId, 1U);
memset(&NCM_State, 0, sizeof(NCM_State));
NCM_State.ntb_input_size = USBD_CDCn_NCM_DW_NTB_IN_MAX_SIZE;
NCM_State.max_datagram_size = USBD_CDCn_NCM_W_MAX_SEGMENT_SIZE;
#if ((USBD_CDCn_NCM_BM_NETWORK_CAPABILITIES & 0x02) != 0)
memcpy(&NCM_State.net_address, &MacAddress, 6);
#endif
NCM_State.packet_filter_bitmap = 0x0CU;
PacketFilter = ARM_ETH_MAC_ADDRESS_BROADCAST;
EthMac->SetMacAddress(&MacAddress);
EthMac->SetAddressFilter(NULL, 0);
EthMac->Control(ARM_ETH_MAC_CONFIGURE,
LinkInfo.speed << ARM_ETH_MAC_SPEED_Pos |
LinkInfo.duplex << ARM_ETH_MAC_DUPLEX_Pos |
PacketFilter);
}
#if (USBD_CDCn_NCM_W_NUMBER_MC_FILTERS != 0)
int32_t status;
if (num_of_filters > (USBD_CDCn_NCM_W_NUMBER_MC_FILTERS & 0x7FFF)) { return false; }
status = EthMac->SetAddressFilter((ARM_ETH_MAC_ADDR *)addr_list, num_of_filters);
if (status != ARM_DRIVER_OK) { return false; }
memcpy(&NCM_State.mc_filters, addr_list, num_of_filters * 6);
return true;
#else
return false;
#endif
}
#if (USBD_CDCn_NCM_B_NUMBER_POWER_FILTERS != 0)
if (filter_number >= USBD_CDCn_NCM_B_NUMBER_POWER_FILTERS) { return false; }
NCM_State.power_filter_active[filter_number / 8] |= 1U << (filter_number % 8);
return true;
#else
return false;
#endif
}
#if (USBD_CDCn_NCM_B_NUMBER_POWER_FILTERS != 0)
*pattern_active = (NCM_State.power_filter_active[filter_number / 8] & (1U << (filter_number % 8))) ? 1 : 0;
return true;
#else
return false;
#endif
}
#if ((USBD_CDCn_NCM_BM_NETWORK_CAPABILITIES & 0x01) != 0)
int32_t status;
PacketFilter = ((packet_filter_bitmap & 0x01U) ? ARM_ETH_MAC_ADDRESS_ALL : 0) |
((packet_filter_bitmap & 0x02U) ? ARM_ETH_MAC_ADDRESS_MULTICAST : 0) |
((packet_filter_bitmap & 0x08U) ? ARM_ETH_MAC_ADDRESS_BROADCAST : 0);
status = EthMac->Control(ARM_ETH_MAC_CONFIGURE,
LinkInfo.speed << ARM_ETH_MAC_SPEED_Pos |
LinkInfo.duplex << ARM_ETH_MAC_DUPLEX_Pos |
PacketFilter);
if (status != ARM_DRIVER_OK) { return false; }
NCM_State.packet_filter_bitmap = packet_filter_bitmap;
return true;
#else
return false;
#endif
}
#if (USBD_CDCn_NCM_BM_ETHERNET_STATISTICS != 0)
if (feature_selector == 0x00U) { return true; }
if (feature_selector > 0x1DU) { return false; }
*data = NCM_State.eth_statistics[feature_selector - 1];
return true;
#else
return false;
#endif
}
ntb_params->wLength = sizeof(CDC_NCM_NTB_PARAM);
ntb_params->bmNtbFormatsSupported = USBD_CDCn_NCM_BM_NTB_FORMATS_SUPPORTED;
ntb_params->dwNtbInMaxSize = USBD_CDCn_NCM_DW_NTB_IN_MAX_SIZE;
ntb_params->wNdpInDivisor = USBD_CDCn_NCM_W_NDP_IN_DIVISOR;
ntb_params->wNdpInPayloadRemainder = USBD_CDCn_NCM_W_NDP_IN_PAYLOAD_REMINDER;
ntb_params->wNdpInAlignment = USBD_CDCn_NCM_W_NDP_IN_ALIGNMENT;
ntb_params->Reserved0 = 0U;
ntb_params->dwNtbOutMaxSize = USBD_CDCn_NCM_DW_NTB_OUT_MAX_SIZE;
ntb_params->wNdpOutDivisor = USBD_CDCn_NCM_W_NDP_OUT_DIVISOR;
ntb_params->wNdpOutPayloadRemainder = USBD_CDCn_NCM_W_NDP_OUT_PAYLOAD_REMINDER;
ntb_params->wNdpOutAlignment = USBD_CDCn_NCM_W_NDP_OUT_ALIGNMENT;
ntb_params->Reserved1 = 0U;
return true;
}
#if ((USBD_CDCn_NCM_BM_NETWORK_CAPABILITIES & 0x02) != 0)
memcpy(net_addr, &NCM_State.net_address, 6);
return true;
#else
return false;
#endif
}
#if ((USBD_CDCn_NCM_BM_NETWORK_CAPABILITIES & 0x02) != 0)
int32_t status;
status = EthMac->SetMacAddress((ARM_ETH_MAC_ADDR *)net_addr);
if (status != ARM_DRIVER_OK) { return false; }
memcpy(&NCM_State.net_address, net_addr, 6);
return true;
#else
return false;
#endif
}
*ntb_format = NCM_State.ntb_format;
return true;
}
#if (USBD_CDCn_NCM_BM_NTB_FORMATS_SUPPORTED > 1)
if (ntb_format > 1) { return false; }
#else
if (ntb_format > 0) { return false; }
#endif
NCM_State.ntb_format = ntb_format;
return true;
}
*ntb_input_size = NCM_State.ntb_input_size;
return true;
}
if (ntb_input_size > USBD_CDCn_NCM_DW_NTB_IN_MAX_SIZE) { return false; }
NCM_State.ntb_input_size = ntb_input_size;
return true;
}
#if ((USBD_CDCn_NCM_BM_NETWORK_CAPABILITIES & 0x08) != 0)
*max_datagram_size = NCM_State.max_datagram_size;
return true;
#else
return false;
#endif
}
#if ((USBD_CDCn_NCM_BM_NETWORK_CAPABILITIES & 0x08) != 0)
if (max_datagram_size > USBD_CDCn_NCM_W_MAX_SEGMENT_SIZE) { return false; }
NCM_State.max_datagram_size = max_datagram_size;
return true;
#else
return false;
#endif
}
#if ((USBD_CDCn_NCM_BM_NETWORK_CAPABILITIES & 0x10) != 0)
*crc_mode = NCM_State.crc_mode;
return true;
#else
return false;
#endif
}
#if ((USBD_CDCn_NCM_BM_NETWORK_CAPABILITIES & 0x10) != 0)
if (crc_mode > 1) { return false; }
NCM_State.crc_mode = crc_mode;
return true;
#else
return false;
#endif
}
osSignalSet(DataIN_ThreadId, 1U);
}
osSignalSet(DataOUT_ThreadId, 1U);
}
static void EthMac_Notify (uint32_t event) {
switch (event) {
case ARM_ETH_MAC_EVENT_RX_FRAME:
osSignalSet(DataIN_ThreadId, 2U);
break;
default:
break;
}
}
static void Connection_Thread (void const *arg) {
ARM_ETH_LINK_STATE link_state;
osEvent event;
uint32_t speed;
uint16_t state;
int32_t status;
while (1) {
event = osSignalWait(1U, 500U);
link_state = EthPhy->GetLinkState();
if (link_state == ARM_ETH_LINK_UP) {
LinkInfo = EthPhy->GetLinkInfo();
switch (LinkInfo.speed) {
case 0: speed = 10000000U; break;
case 1: speed = 100000000U; break;
case 2: speed = 1000000000U; break;
default: speed = 0U;
}
} else {
speed = 0U;
}
if (speed != LinkSpeed) {
LinkSpeed = speed;
if (link_state == ARM_ETH_LINK_UP) {
do {
}
}
if (link_state != LinkState) {
LinkState = link_state;
if (link_state == ARM_ETH_LINK_UP) {
EthMac->Control(ARM_ETH_MAC_CONFIGURE,
LinkInfo.speed << ARM_ETH_MAC_SPEED_Pos |
LinkInfo.duplex << ARM_ETH_MAC_DUPLEX_Pos |
PacketFilter);
EthMac->Control(ARM_ETH_MAC_CONTROL_TX, 1U);
EthMac->Control(ARM_ETH_MAC_CONTROL_RX, 1U);
} else {
EthMac->Control(ARM_ETH_MAC_FLUSH,
ARM_ETH_MAC_FLUSH_TX |
ARM_ETH_MAC_FLUSH_RX);
EthMac->Control(ARM_ETH_MAC_CONTROL_TX, 0U);
EthMac->Control(ARM_ETH_MAC_CONTROL_RX, 0U);
}
state = (link_state == ARM_ETH_LINK_UP) ? 1U : 0U;
do {
}
if (event.status == osEventSignal) {
if (LinkState == ARM_ETH_LINK_UP) {
do {
}
state = (LinkState == ARM_ETH_LINK_UP) ? 1U : 0U;
do {
}
}
}
static void DataIN_Thread (void const *arg) {
uint32_t size;
int32_t status;
while (1) {
osSignalWait(3U, osWaitForever);
do {
if (status !=
usbOK) {
break; }
if (status !=
usbOK) {
break; }
while (1) {
if (FrameIN_Size != 0) {
FrameIN_Size = 0;
}
size = EthMac->GetRxFrameSize();
if (size == 0U) { break; }
if ((size < 14U) || (size > NCM_State.max_datagram_size)) {
EthMac->ReadFrame(NULL, 0U);
continue;
}
EthMac->ReadFrame(FrameIN, size);
if (size > 0) {
#if ((USBD_CDCn_NCM_BM_ETHERNET_STATISTICS & 0x00000002) != 0)
NCM_State.eth_statistics[1]++;
#endif
FrameIN_Size = size;
break;
}
}
}
} while (FrameIN_Size);
}
}
static void DataOUT_Thread (void const *arg) {
uint32_t size;
int32_t len, status;
while (1) {
osSignalWait(1U, osWaitForever);
while (1) {
if (status !=
usbOK) {
break; }
while (1) {
if (size == 0U) { break; }
if ((size < 14U) || (size > NCM_State.max_datagram_size)) {
continue;
}
if (len > 0) {
do {
status = EthMac->SendFrame(FrameOUT, len, 0U);
} while (status == ARM_DRIVER_ERROR_BUSY);
#if ((USBD_CDCn_NCM_BM_ETHERNET_STATISTICS & 0x00000001) != 0)
NCM_State.eth_statistics[0]++;
#endif
}
}
}
}
}