Initial project setup

This commit is contained in:
2025-12-13 11:59:11 +02:00
commit 3218e6039f
2176 changed files with 355321 additions and 0 deletions

View File

@@ -0,0 +1,101 @@
cmake_minimum_required(VERSION 3.20)
include(${CMAKE_CURRENT_LIST_DIR}/../../../hw/bsp/family_support.cmake)
# gets PROJECT name for the example (e.g. <BOARD>-<DIR_NAME>)
family_get_project_name(PROJECT ${CMAKE_CURRENT_LIST_DIR})
# Prefer the tinyusb lwip
set(LWIP ${TOP}/lib/lwip)
# If we can't find one from tinyusb then check cmake var before giving up
if (NOT EXISTS ${LWIP}/src)
set(LWIP ${TINYUSB_LWIP_PATH})
endif()
if (NOT EXISTS ${LWIP}/src)
family_example_missing_dependency(${PROJECT} "lib/lwip")
return()
endif()
project(${PROJECT} C CXX ASM)
# Checks this example is valid for the family and initializes the project
family_initialize_project(${PROJECT} ${CMAKE_CURRENT_LIST_DIR})
add_executable(${PROJECT})
# Example source
target_sources(${PROJECT} PUBLIC
${CMAKE_CURRENT_LIST_DIR}/src/main.c
${CMAKE_CURRENT_LIST_DIR}/src/usb_descriptors.c
)
# Example include
target_include_directories(${PROJECT} PUBLIC
${CMAKE_CURRENT_LIST_DIR}/src
${LWIP}/src/include
${LWIP}/src/include/ipv4
${LWIP}/src/include/lwip/apps
${TOP}/lib/networking
)
# lib/networking sources
target_sources(${PROJECT} PUBLIC
${TOP}/lib/networking/dhserver.c
${TOP}/lib/networking/dnserver.c
${TOP}/lib/networking/rndis_reports.c
)
# lwip sources
target_sources(${PROJECT} PUBLIC
${LWIP}/src/core/altcp.c
${LWIP}/src/core/altcp_alloc.c
${LWIP}/src/core/altcp_tcp.c
${LWIP}/src/core/def.c
${LWIP}/src/core/dns.c
${LWIP}/src/core/inet_chksum.c
${LWIP}/src/core/init.c
${LWIP}/src/core/ip.c
${LWIP}/src/core/mem.c
${LWIP}/src/core/memp.c
${LWIP}/src/core/netif.c
${LWIP}/src/core/pbuf.c
${LWIP}/src/core/raw.c
${LWIP}/src/core/stats.c
${LWIP}/src/core/sys.c
${LWIP}/src/core/tcp.c
${LWIP}/src/core/tcp_in.c
${LWIP}/src/core/tcp_out.c
${LWIP}/src/core/timeouts.c
${LWIP}/src/core/udp.c
${LWIP}/src/core/ipv4/autoip.c
${LWIP}/src/core/ipv4/dhcp.c
${LWIP}/src/core/ipv4/etharp.c
${LWIP}/src/core/ipv4/icmp.c
${LWIP}/src/core/ipv4/igmp.c
${LWIP}/src/core/ipv4/ip4.c
${LWIP}/src/core/ipv4/ip4_addr.c
${LWIP}/src/core/ipv4/ip4_frag.c
${LWIP}/src/netif/ethernet.c
${LWIP}/src/netif/slipif.c
${LWIP}/src/apps/http/httpd.c
${LWIP}/src/apps/http/fs.c
${LWIP}/src/apps/lwiperf/lwiperf.c
)
# due to warnings from other net source, we need to prevent error from some of the warnings options
if (CMAKE_C_COMPILER_ID STREQUAL "GNU")
target_compile_options(${PROJECT} PUBLIC
-Wno-error=null-dereference
-Wno-error=conversion
-Wno-error=sign-conversion
-Wno-error=sign-compare
)
elseif (CMAKE_C_COMPILER_ID STREQUAL "IAR")
endif ()
# Configure compilation flags and libraries for the example without RTOS.
# See the corresponding function in hw/bsp/FAMILY/family.cmake for details.
family_configure_device_example(${PROJECT} noos)

View File

@@ -0,0 +1,6 @@
{
"version": 6,
"include": [
"../../../hw/bsp/BoardPresets.json"
]
}

View File

@@ -0,0 +1,69 @@
include ../../build_system/make/make.mk
# suppress warning caused by lwip
CFLAGS_GCC += \
-Wno-error=null-dereference \
-Wno-error=unused-parameter \
-Wno-error=unused-variable
INC += \
src \
$(TOP)/hw \
$(TOP)/lib/lwip/src/include \
$(TOP)/lib/lwip/src/include/ipv4 \
$(TOP)/lib/lwip/src/include/lwip/apps \
$(TOP)/lib/networking
# Example source
EXAMPLE_SOURCE += $(wildcard src/*.c)
SRC_C += $(addprefix $(CURRENT_PATH)/, $(EXAMPLE_SOURCE))
# lwip sources
SRC_C += \
lib/lwip/src/core/altcp.c \
lib/lwip/src/core/altcp_alloc.c \
lib/lwip/src/core/altcp_tcp.c \
lib/lwip/src/core/def.c \
lib/lwip/src/core/dns.c \
lib/lwip/src/core/inet_chksum.c \
lib/lwip/src/core/init.c \
lib/lwip/src/core/ip.c \
lib/lwip/src/core/mem.c \
lib/lwip/src/core/memp.c \
lib/lwip/src/core/netif.c \
lib/lwip/src/core/pbuf.c \
lib/lwip/src/core/raw.c \
lib/lwip/src/core/stats.c \
lib/lwip/src/core/sys.c \
lib/lwip/src/core/tcp.c \
lib/lwip/src/core/tcp_in.c \
lib/lwip/src/core/tcp_out.c \
lib/lwip/src/core/timeouts.c \
lib/lwip/src/core/udp.c \
lib/lwip/src/core/ipv4/autoip.c \
lib/lwip/src/core/ipv4/dhcp.c \
lib/lwip/src/core/ipv4/etharp.c \
lib/lwip/src/core/ipv4/icmp.c \
lib/lwip/src/core/ipv4/igmp.c \
lib/lwip/src/core/ipv4/ip4.c \
lib/lwip/src/core/ipv4/ip4_addr.c \
lib/lwip/src/core/ipv4/ip4_frag.c \
lib/lwip/src/core/ipv6/dhcp6.c \
lib/lwip/src/core/ipv6/ethip6.c \
lib/lwip/src/core/ipv6/icmp6.c \
lib/lwip/src/core/ipv6/inet6.c \
lib/lwip/src/core/ipv6/ip6.c \
lib/lwip/src/core/ipv6/ip6_addr.c \
lib/lwip/src/core/ipv6/ip6_frag.c \
lib/lwip/src/core/ipv6/mld6.c \
lib/lwip/src/core/ipv6/nd6.c \
lib/lwip/src/netif/ethernet.c \
lib/lwip/src/netif/slipif.c \
lib/lwip/src/apps/http/httpd.c \
lib/lwip/src/apps/http/fs.c \
lib/lwip/src/apps/lwiperf/lwiperf.c \
lib/networking/dhserver.c \
lib/networking/dnserver.c \
lib/networking/rndis_reports.c
include ../../build_system/make/rules.mk

View File

@@ -0,0 +1,22 @@
mcu:CH32V103
mcu:CH32V20X
mcu:LPC11UXX
mcu:LPC13XX
mcu:LPC15XX
mcu:MCXA15
mcu:MSP430x5xx
mcu:NUC121
mcu:SAMD11
mcu:STM32L0
mcu:STM32F0
mcu:KINETIS_KL
mcu:STM32H7RS
mcu:STM32N6
family:broadcom_64bit
family:broadcom_32bit
family:espressif
board:at_start_f425
board:curiosity_nano
board:frdm_kl25z
# lpc55 has weird error 'ncm_interface' causes a section type conflict with 'ntb_parameters'
family:lpc55

View File

@@ -0,0 +1,35 @@
/*
* Copyright (c) 2001-2003 Swedish Institute of Computer Science.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*
* This file is part of the lwIP TCP/IP stack.
*
* Author: Adam Dunkels <adam@sics.se>
*
*/
#if defined(__ICCARM__)
#pragma pack(1)
#endif

View File

@@ -0,0 +1,75 @@
/*
* Copyright (c) 2001-2003 Swedish Institute of Computer Science.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*
* This file is part of the lwIP TCP/IP stack.
*
* Author: Adam Dunkels <adam@sics.se>
*
*/
#ifndef __CC_H__
#define __CC_H__
//#include "cpu.h"
typedef int sys_prot_t;
/* define compiler specific symbols */
#if defined (__ICCARM__)
#define PACK_STRUCT_BEGIN
#define PACK_STRUCT_STRUCT
#define PACK_STRUCT_END
#define PACK_STRUCT_FIELD(x) x
#define PACK_STRUCT_USE_INCLUDES
#elif defined (__CC_ARM)
#define PACK_STRUCT_BEGIN __packed
#define PACK_STRUCT_STRUCT
#define PACK_STRUCT_END
#define PACK_STRUCT_FIELD(x) x
#elif defined (__GNUC__)
#define PACK_STRUCT_BEGIN
#define PACK_STRUCT_STRUCT __attribute__ ((__packed__))
#define PACK_STRUCT_END
#define PACK_STRUCT_FIELD(x) x
#elif defined (__TASKING__)
#define PACK_STRUCT_BEGIN
#define PACK_STRUCT_STRUCT
#define PACK_STRUCT_END
#define PACK_STRUCT_FIELD(x) x
#endif
#define LWIP_PLATFORM_ASSERT(x) do { if(!(x)) while(1); } while(0)
#endif /* __CC_H__ */

View File

@@ -0,0 +1,35 @@
/*
* Copyright (c) 2001-2003 Swedish Institute of Computer Science.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*
* This file is part of the lwIP TCP/IP stack.
*
* Author: Adam Dunkels <adam@sics.se>
*
*/
#if defined(__ICCARM__)
#pragma pack()
#endif

View File

@@ -0,0 +1,72 @@
/*
* Copyright (c) 2001-2003 Swedish Institute of Computer Science.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*
* This file is part of the lwIP TCP/IP stack.
*
* Author: Simon Goldschmidt
*
*/
#ifndef __LWIPOPTS_H__
#define __LWIPOPTS_H__
/* Prevent having to link sys_arch.c (we don't test the API layers in unit tests) */
#define NO_SYS 1
#define MEM_ALIGNMENT 4
#define LWIP_RAW 0
#define LWIP_NETCONN 0
#define LWIP_SOCKET 0
#define LWIP_DHCP 0
#define LWIP_ICMP 1
#define LWIP_UDP 1
#define LWIP_TCP 1
#define LWIP_IPV4 1
#define LWIP_IPV6 0
#define ETH_PAD_SIZE 0
#define LWIP_IP_ACCEPT_UDP_PORT(p) ((p) == PP_NTOHS(67))
#define TCP_MSS (1500 /*mtu*/ - 20 /*iphdr*/ - 20 /*tcphhr*/)
#define TCP_SND_BUF (4 * TCP_MSS)
#define TCP_WND (4 * TCP_MSS)
#define ETHARP_SUPPORT_STATIC_ENTRIES 1
#define LWIP_HTTPD_CGI 0
#define LWIP_HTTPD_SSI 0
#define LWIP_HTTPD_SSI_INCLUDE_TAG 0
#define LWIP_SINGLE_NETIF 1
#define LWIP_NETIF_LINK_CALLBACK 1
#define PBUF_POOL_SIZE 4
#define HTTPD_USE_CUSTOM_FSDATA 0
#define LWIP_MULTICAST_PING 1
#define LWIP_BROADCAST_PING 1
#define LWIP_IPV6_MLD 0
#define LWIP_IPV6_SEND_ROUTER_SOLICIT 0
#endif /* __LWIPOPTS_H__ */

View File

@@ -0,0 +1,294 @@
/*
* The MIT License (MIT)
*
* Copyright (c) 2020 Peter Lawrence
*
* influenced by lrndis https://github.com/fetisov/lrndis
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*/
/*
this appears as either a RNDIS or CDC-ECM USB virtual network adapter; the OS picks its preference
RNDIS should be valid on Linux and Windows hosts, and CDC-ECM should be valid on Linux and macOS hosts
The MCU appears to the host as IP address 192.168.7.1, and provides a DHCP server, DNS server, and web server.
Link State Control:
- Press the user button to toggle the network link state (UP/DOWN)
- This simulates "ethernet cable unplugged/plugged" events
- The host OS will see the network interface as disconnected/connected accordingly
- Use this to test network error handling and recovery in host applications
*/
/*
Some smartphones *may* work with this implementation as well, but likely have limited (broken) drivers,
and likely their manufacturer has not tested such functionality. Some code workarounds could be tried:
The smartphone may only have an ECM driver, but refuse to automatically pick ECM (unlike the OSes above);
try modifying ./examples/devices/net_lwip_webserver/usb_descriptors.c so that CONFIG_ID_ECM is default.
The smartphone may be artificially picky about which Ethernet MAC address to recognize; if this happens,
try changing the first byte of tud_network_mac_address[] below from 0x02 to 0x00 (clearing bit 1).
*/
#include "bsp/board_api.h"
#include "tusb.h"
#include "dhserver.h"
#include "dnserver.h"
#include "httpd.h"
#include "lwip/ethip6.h"
#include "lwip/init.h"
#include "lwip/timeouts.h"
#ifdef INCLUDE_IPERF
#include "lwip/apps/lwiperf.h"
#endif
#define INIT_IP4(a, b, c, d) \
{ PP_HTONL(LWIP_MAKEU32(a, b, c, d)) }
/* lwip context */
static struct netif netif_data;
/* this is used by this code, ./class/net/net_driver.c, and usb_descriptors.c */
/* ideally speaking, this should be generated from the hardware's unique ID (if available) */
/* it is suggested that the first byte is 0x02 to indicate a link-local address */
uint8_t tud_network_mac_address[6] = {0x02, 0x02, 0x84, 0x6A, 0x96, 0x00};
/* network parameters of this MCU */
static const ip4_addr_t ipaddr = INIT_IP4(192, 168, 7, 1);
static const ip4_addr_t netmask = INIT_IP4(255, 255, 255, 0);
static const ip4_addr_t gateway = INIT_IP4(0, 0, 0, 0);
/* database IP addresses that can be offered to the host; this must be in RAM to store assigned MAC addresses */
static dhcp_entry_t entries[] = {
/* mac ip address lease time */
{{0}, INIT_IP4(192, 168, 7, 2), 24 * 60 * 60},
{{0}, INIT_IP4(192, 168, 7, 3), 24 * 60 * 60},
{{0}, INIT_IP4(192, 168, 7, 4), 24 * 60 * 60},
};
static const dhcp_config_t dhcp_config = {
.router = INIT_IP4(0, 0, 0, 0), /* router address (if any) */
.port = 67, /* listen port */
.dns = INIT_IP4(192, 168, 7, 1), /* dns server (if any) */
"usb", /* dns suffix */
TU_ARRAY_SIZE(entries), /* num entry */
entries /* entries */
};
static err_t linkoutput_fn(struct netif *netif, struct pbuf *p) {
(void) netif;
for (;;) {
/* if TinyUSB isn't ready, we must signal back to lwip that there is nothing we can do */
if (!tud_ready())
return ERR_USE;
/* if the network driver can accept another packet, we make it happen */
if (tud_network_can_xmit(p->tot_len)) {
tud_network_xmit(p, 0 /* unused for this example */);
return ERR_OK;
}
/* transfer execution to TinyUSB in the hopes that it will finish transmitting the prior packet */
tud_task();
}
}
static err_t ip4_output_fn(struct netif *netif, struct pbuf *p, const ip4_addr_t *addr) {
return etharp_output(netif, p, addr);
}
#if LWIP_IPV6
static err_t ip6_output_fn(struct netif *netif, struct pbuf *p, const ip6_addr_t *addr) {
return ethip6_output(netif, p, addr);
}
#endif
static err_t netif_init_cb(struct netif *netif) {
LWIP_ASSERT("netif != NULL", (netif != NULL));
netif->mtu = CFG_TUD_NET_MTU;
netif->flags = NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP | NETIF_FLAG_LINK_UP | NETIF_FLAG_UP;
netif->state = NULL;
netif->name[0] = 'E';
netif->name[1] = 'X';
netif->linkoutput = linkoutput_fn;
netif->output = ip4_output_fn;
#if LWIP_IPV6
netif->output_ip6 = ip6_output_fn;
#endif
return ERR_OK;
}
/* notifies the USB host about the link state change. */
static void usbnet_netif_link_callback(struct netif *netif) {
bool link_up = netif_is_link_up(netif);
tud_network_link_state(BOARD_TUD_RHPORT, link_up);
}
static void init_lwip(void) {
struct netif *netif = &netif_data;
lwip_init();
/* the lwip virtual MAC address must be different from the host's; to ensure this, we toggle the LSbit */
netif->hwaddr_len = sizeof(tud_network_mac_address);
memcpy(netif->hwaddr, tud_network_mac_address, sizeof(tud_network_mac_address));
netif->hwaddr[5] ^= 0x01;
netif = netif_add(netif, &ipaddr, &netmask, &gateway, NULL, netif_init_cb, ethernet_input);
#if LWIP_IPV6
netif_create_ip6_linklocal_address(netif, 1);
#endif
netif_set_default(netif);
#if LWIP_NETIF_LINK_CALLBACK
// Set the link callback to notify USB host about link state changes
netif_set_link_callback(netif, usbnet_netif_link_callback);
netif_set_link_up(netif);
#else
tud_network_link_state(BOARD_TUD_RHPORT, true);
#endif
}
/* handle any DNS requests from dns-server */
bool dns_query_proc(const char *name, ip4_addr_t *addr) {
if (0 == strcmp(name, "tiny.usb")) {
*addr = ipaddr;
return true;
}
return false;
}
bool tud_network_recv_cb(const uint8_t *src, uint16_t size) {
struct netif *netif = &netif_data;
if (size) {
struct pbuf *p = pbuf_alloc(PBUF_RAW, size, PBUF_POOL);
if (p == NULL) {
printf("ERROR: Failed to allocate pbuf of size %d\n", size);
return false;
}
/* Copy buf to pbuf */
pbuf_take(p, src, size);
// Surrender ownership of our pbuf unless there was an error
// Only call pbuf_free if not Ok else it will panic with "pbuf_free: p->ref > 0"
// or steal it from whatever took ownership of it with undefined consequences.
// See: https://savannah.nongnu.org/patch/index.php?10121
if (netif->input(p, netif) != ERR_OK) {
printf("ERROR: netif input failed\n");
pbuf_free(p);
}
// Signal tinyusb that the current frame has been processed.
tud_network_recv_renew();
}
return true;
}
uint16_t tud_network_xmit_cb(uint8_t *dst, void *ref, uint16_t arg) {
struct pbuf *p = (struct pbuf *) ref;
(void) arg; /* unused for this example */
return pbuf_copy_partial(p, dst, p->tot_len, 0);
}
static void handle_link_state_switch(void) {
/* Check for button press to toggle link state */
static bool last_link_state = true;
static bool last_button_state = false;
bool current_button_state = board_button_read();
if (current_button_state && !last_button_state) {
/* Button pressed - toggle link state */
last_link_state = !last_link_state;
if (last_link_state) {
printf("Link state: UP\n");
netif_set_link_up(&netif_data);
} else {
printf("Link state: DOWN\n");
netif_set_link_down(&netif_data);
}
/* LWIP callback will notify USB host about the change */
}
last_button_state = current_button_state;
}
int main(void) {
/* initialize TinyUSB */
board_init();
// init device stack on configured roothub port
tusb_rhport_init_t dev_init = {
.role = TUSB_ROLE_DEVICE,
.speed = TUSB_SPEED_AUTO
};
tusb_init(BOARD_TUD_RHPORT, &dev_init);
board_init_after_tusb();
/* initialize lwip, dhcp-server, dns-server, and http */
init_lwip();
while (!netif_is_up(&netif_data));
while (dhserv_init(&dhcp_config) != ERR_OK);
while (dnserv_init(IP_ADDR_ANY, 53, dns_query_proc) != ERR_OK);
httpd_init();
#ifdef INCLUDE_IPERF
// test with: iperf -c 192.168.7.1 -e -i 1 -M 5000 -l 8192 -r
lwiperf_start_tcp_server_default(NULL, NULL);
#endif
#if CFG_TUD_NCM
printf("USB NCM network interface initialized\n");
#elif CFG_TUD_ECM_RNDIS
printf("USB RNDIS/ECM network interface initialized\n");
#endif
while (1) {
tud_task();
sys_check_timeouts(); // service lwip
handle_link_state_switch();
}
return 0;
}
/* lwip has provision for using a mutex, when applicable */
/* This implementation is for single-threaded use only */
sys_prot_t sys_arch_protect(void) {
return 0;
}
void sys_arch_unprotect(sys_prot_t pval) {
(void) pval;
}
/* lwip needs a millisecond time source, and the TinyUSB board support code has one available */
uint32_t sys_now(void) {
return board_millis();
}

View File

@@ -0,0 +1,144 @@
/*
* The MIT License (MIT)
*
* Copyright (c) 2019 Ha Thach (tinyusb.org)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*/
#ifndef _TUSB_CONFIG_H_
#define _TUSB_CONFIG_H_
#ifdef __cplusplus
extern "C" {
#endif
#include "lwipopts.h"
//--------------------------------------------------------------------+
// Board Specific Configuration
//--------------------------------------------------------------------+
// RHPort number used for device can be defined by board.mk, default to port 0
#ifndef BOARD_TUD_RHPORT
#define BOARD_TUD_RHPORT 0
#endif
// RHPort max operational speed can defined by board.mk
#ifndef BOARD_TUD_MAX_SPEED
#define BOARD_TUD_MAX_SPEED OPT_MODE_DEFAULT_SPEED
#endif
//--------------------------------------------------------------------
// Common Configuration
//--------------------------------------------------------------------
// defined by compiler flags for flexibility
#ifndef CFG_TUSB_MCU
#error CFG_TUSB_MCU must be defined
#endif
#ifndef CFG_TUSB_OS
#define CFG_TUSB_OS OPT_OS_NONE
#endif
#ifndef CFG_TUSB_DEBUG
#define CFG_TUSB_DEBUG 0
#endif
// Enable Device stack
#define CFG_TUD_ENABLED 1
// Default is max speed that hardware controller could support with on-chip PHY
#define CFG_TUD_MAX_SPEED BOARD_TUD_MAX_SPEED
/* USB DMA on some MCUs can only access a specific SRAM region with restriction on alignment.
* Tinyusb use follows macros to declare transferring memory so that they can be put
* into those specific section.
* e.g
* - CFG_TUSB_MEM SECTION : __attribute__ (( section(".usb_ram") ))
* - CFG_TUSB_MEM_ALIGN : __attribute__ ((aligned(4)))
*/
#ifndef CFG_TUSB_MEM_SECTION
#define CFG_TUSB_MEM_SECTION
#endif
#ifndef CFG_TUSB_MEM_ALIGN
#define CFG_TUSB_MEM_ALIGN __attribute__((aligned(4)))
#endif
// Use different configurations to test all net devices (also due to resource limitations)
#ifndef USE_ECM
#if TU_CHECK_MCU(OPT_MCU_LPC15XX, OPT_MCU_LPC40XX, OPT_MCU_LPC51UXX, OPT_MCU_LPC54)
#define USE_ECM 1
#elif TU_CHECK_MCU(OPT_MCU_SAMD21, OPT_MCU_SAML21, OPT_MCU_SAML22)
#define USE_ECM 1
#elif TU_CHECK_MCU(OPT_MCU_STM32F0, OPT_MCU_STM32F1)
#define USE_ECM 1
#elif TU_CHECK_MCU(OPT_MCU_MAX32690, OPT_MCU_MAX32650, OPT_MCU_MAX32666, OPT_MCU_MAX78002)
#define USE_ECM 1
#else
#define USE_ECM 0
#define INCLUDE_IPERF
#endif
#endif
//--------------------------------------------------------------------
// NCM CLASS CONFIGURATION, SEE "ncm.h" FOR PERFORMANCE TUNING
//--------------------------------------------------------------------
// Must be >> MTU
// Can be set to 2048 without impact
#define CFG_TUD_NCM_IN_NTB_MAX_SIZE (2 * TCP_MSS + 100)
// Must be >> MTU
// Can be set to smaller values if wNtbOutMaxDatagrams==1
#define CFG_TUD_NCM_OUT_NTB_MAX_SIZE (2 * TCP_MSS + 100)
// Number of NCM transfer blocks for reception side
#ifndef CFG_TUD_NCM_OUT_NTB_N
#define CFG_TUD_NCM_OUT_NTB_N 1
#endif
// Number of NCM transfer blocks for transmission side
#ifndef CFG_TUD_NCM_IN_NTB_N
#define CFG_TUD_NCM_IN_NTB_N 1
#endif
//--------------------------------------------------------------------
// DEVICE CONFIGURATION
//--------------------------------------------------------------------
#ifndef CFG_TUD_ENDPOINT0_SIZE
#define CFG_TUD_ENDPOINT0_SIZE 64
#endif
//------------- CLASS -------------//
// Network class has 2 drivers: ECM/RNDIS and NCM.
// Only one of the drivers can be enabled
#define CFG_TUD_ECM_RNDIS USE_ECM
#define CFG_TUD_NCM (1 - CFG_TUD_ECM_RNDIS)
#ifdef __cplusplus
}
#endif
#endif /* _TUSB_CONFIG_H_ */

View File

@@ -0,0 +1,364 @@
/*
* The MIT License (MIT)
*
* Copyright (c) 2019 Ha Thach (tinyusb.org)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*/
#include "bsp/board_api.h"
#include "tusb.h"
/* A combination of interfaces must have a unique product id, since PC will save device driver after the first plug.
* Same VID/PID with different interface e.g MSC (first), then CDC (later) will possibly cause system error on PC.
*
* Auto ProductID layout's Bitmap:
* [MSB] NET | VENDOR | MIDI | HID | MSC | CDC [LSB]
*/
#define _PID_MAP(itf, n) ( (CFG_TUD_##itf) << (n) )
#define USB_PID (0x4000 | _PID_MAP(CDC, 0) | _PID_MAP(MSC, 1) | _PID_MAP(HID, 2) | \
_PID_MAP(MIDI, 3) | _PID_MAP(VENDOR, 4) | _PID_MAP(ECM_RNDIS, 5) | _PID_MAP(NCM, 5) )
// String Descriptor Index
enum
{
STRID_LANGID = 0,
STRID_MANUFACTURER,
STRID_PRODUCT,
STRID_SERIAL,
STRID_INTERFACE,
STRID_MAC
};
enum
{
ITF_NUM_CDC = 0,
ITF_NUM_CDC_DATA,
ITF_NUM_TOTAL
};
enum
{
#if CFG_TUD_ECM_RNDIS
CONFIG_ID_RNDIS = 0,
CONFIG_ID_ECM = 1,
#else
CONFIG_ID_NCM = 0,
#endif
CONFIG_ID_COUNT
};
//--------------------------------------------------------------------+
// Device Descriptors
//--------------------------------------------------------------------+
tusb_desc_device_t const desc_device =
{
.bLength = sizeof(tusb_desc_device_t),
.bDescriptorType = TUSB_DESC_DEVICE,
#if CFG_TUD_NCM
.bcdUSB = 0x0201,
#else
.bcdUSB = 0x0200,
#endif
// Use Interface Association Descriptor (IAD) device class
.bDeviceClass = TUSB_CLASS_MISC,
.bDeviceSubClass = MISC_SUBCLASS_COMMON,
.bDeviceProtocol = MISC_PROTOCOL_IAD,
.bMaxPacketSize0 = CFG_TUD_ENDPOINT0_SIZE,
.idVendor = 0xCafe,
.idProduct = USB_PID,
.bcdDevice = 0x0101,
.iManufacturer = STRID_MANUFACTURER,
.iProduct = STRID_PRODUCT,
.iSerialNumber = STRID_SERIAL,
.bNumConfigurations = CONFIG_ID_COUNT // multiple configurations
};
// Invoked when received GET DEVICE DESCRIPTOR
// Application return pointer to descriptor
uint8_t const * tud_descriptor_device_cb(void)
{
return (uint8_t const *) &desc_device;
}
//--------------------------------------------------------------------+
// Configuration Descriptor
//--------------------------------------------------------------------+
#define MAIN_CONFIG_TOTAL_LEN (TUD_CONFIG_DESC_LEN + TUD_RNDIS_DESC_LEN)
#define ALT_CONFIG_TOTAL_LEN (TUD_CONFIG_DESC_LEN + TUD_CDC_ECM_DESC_LEN)
#define NCM_CONFIG_TOTAL_LEN (TUD_CONFIG_DESC_LEN + TUD_CDC_NCM_DESC_LEN)
#if CFG_TUSB_MCU == OPT_MCU_LPC175X_6X || CFG_TUSB_MCU == OPT_MCU_LPC177X_8X || CFG_TUSB_MCU == OPT_MCU_LPC40XX
// LPC 17xx and 40xx endpoint type (bulk/interrupt/iso) are fixed by its number
// 0 control, 1 In, 2 Bulk, 3 Iso, 4 In etc ...
#define EPNUM_NET_NOTIF 0x81
#define EPNUM_NET_OUT 0x02
#define EPNUM_NET_IN 0x82
#elif CFG_TUSB_MCU == OPT_MCU_CXD56
// CXD56 USB driver has fixed endpoint type (bulk/interrupt/iso) and direction (IN/OUT) by its number
// 0 control (IN/OUT), 1 Bulk (IN), 2 Bulk (OUT), 3 In (IN), 4 Bulk (IN), 5 Bulk (OUT), 6 In (IN)
#define EPNUM_NET_NOTIF 0x83
#define EPNUM_NET_OUT 0x02
#define EPNUM_NET_IN 0x81
#elif defined(TUD_ENDPOINT_ONE_DIRECTION_ONLY)
// MCUs that don't support a same endpoint number with different direction IN and OUT defined in tusb_mcu.h
// e.g EP1 OUT & EP1 IN cannot exist together
#define EPNUM_NET_NOTIF 0x81
#define EPNUM_NET_OUT 0x02
#define EPNUM_NET_IN 0x83
#else
#define EPNUM_NET_NOTIF 0x81
#define EPNUM_NET_OUT 0x02
#define EPNUM_NET_IN 0x82
#endif
#if CFG_TUD_ECM_RNDIS
static uint8_t const rndis_configuration[] =
{
// Config number (index+1), interface count, string index, total length, attribute, power in mA
TUD_CONFIG_DESCRIPTOR(CONFIG_ID_RNDIS+1, ITF_NUM_TOTAL, 0, MAIN_CONFIG_TOTAL_LEN, 0, 100),
// Interface number, string index, EP notification address and size, EP data address (out, in) and size.
TUD_RNDIS_DESCRIPTOR(ITF_NUM_CDC, STRID_INTERFACE, EPNUM_NET_NOTIF, 8, EPNUM_NET_OUT, EPNUM_NET_IN, CFG_TUD_NET_ENDPOINT_SIZE),
};
static uint8_t const ecm_configuration[] =
{
// Config number (index+1), interface count, string index, total length, attribute, power in mA
TUD_CONFIG_DESCRIPTOR(CONFIG_ID_ECM+1, ITF_NUM_TOTAL, 0, ALT_CONFIG_TOTAL_LEN, 0, 100),
// Interface number, description string index, MAC address string index, EP notification address and size, EP data address (out, in), and size, max segment size.
TUD_CDC_ECM_DESCRIPTOR(ITF_NUM_CDC, STRID_INTERFACE, STRID_MAC, EPNUM_NET_NOTIF, 64, EPNUM_NET_OUT, EPNUM_NET_IN, CFG_TUD_NET_ENDPOINT_SIZE, CFG_TUD_NET_MTU),
};
#else
static uint8_t const ncm_configuration[] =
{
// Config number (index+1), interface count, string index, total length, attribute, power in mA
TUD_CONFIG_DESCRIPTOR(CONFIG_ID_NCM+1, ITF_NUM_TOTAL, 0, NCM_CONFIG_TOTAL_LEN, 0, 100),
// Interface number, description string index, MAC address string index, EP notification address and size, EP data address (out, in), and size, max segment size.
TUD_CDC_NCM_DESCRIPTOR(ITF_NUM_CDC, STRID_INTERFACE, STRID_MAC, EPNUM_NET_NOTIF, 64, EPNUM_NET_OUT, EPNUM_NET_IN, CFG_TUD_NET_ENDPOINT_SIZE, CFG_TUD_NET_MTU),
};
#endif
// Configuration array: RNDIS and CDC-ECM
// - Windows only works with RNDIS
// - MacOS only works with CDC-ECM
// - Linux will work on both
static uint8_t const * const configuration_arr[2] =
{
#if CFG_TUD_ECM_RNDIS
[CONFIG_ID_RNDIS] = rndis_configuration,
[CONFIG_ID_ECM ] = ecm_configuration
#else
[CONFIG_ID_NCM ] = ncm_configuration
#endif
};
// Invoked when received GET CONFIGURATION DESCRIPTOR
// Application return pointer to descriptor
// Descriptor contents must exist long enough for transfer to complete
uint8_t const * tud_descriptor_configuration_cb(uint8_t index)
{
return (index < CONFIG_ID_COUNT) ? configuration_arr[index] : NULL;
}
#if CFG_TUD_NCM
//--------------------------------------------------------------------+
// BOS Descriptor
//--------------------------------------------------------------------+
/* Used to automatically load the NCM driver on Windows 10, otherwise manual driver install is needed.
Associate NCM interface with WINNCM driver. */
/* Microsoft OS 2.0 registry property descriptor
Per MS requirements https://msdn.microsoft.com/en-us/library/windows/hardware/hh450799(v=vs.85).aspx
device should create DeviceInterfaceGUIDs. It can be done by driver and
in case of real PnP solution device should expose MS "Microsoft OS 2.0
registry property descriptor". Such descriptor can insert any record
into Windows registry per device/configuration/interface. In our case it
will insert "DeviceInterfaceGUIDs" multistring property.
GUID is freshly generated and should be OK to use.
https://developers.google.com/web/fundamentals/native-hardware/build-for-webusb/
(Section Microsoft OS compatibility descriptors)
*/
#define BOS_TOTAL_LEN (TUD_BOS_DESC_LEN + TUD_BOS_MICROSOFT_OS_DESC_LEN)
#define MS_OS_20_DESC_LEN 0xB2
// BOS Descriptor is required for webUSB
uint8_t const desc_bos[] =
{
// total length, number of device caps
TUD_BOS_DESCRIPTOR(BOS_TOTAL_LEN, 1),
// Microsoft OS 2.0 descriptor
TUD_BOS_MS_OS_20_DESCRIPTOR(MS_OS_20_DESC_LEN, 1)
};
uint8_t const * tud_descriptor_bos_cb(void)
{
return desc_bos;
}
uint8_t const desc_ms_os_20[] =
{
// Set header: length, type, windows version, total length
U16_TO_U8S_LE(0x000A), U16_TO_U8S_LE(MS_OS_20_SET_HEADER_DESCRIPTOR), U32_TO_U8S_LE(0x06030000), U16_TO_U8S_LE(MS_OS_20_DESC_LEN),
// Configuration subset header: length, type, configuration index, reserved, configuration total length
U16_TO_U8S_LE(0x0008), U16_TO_U8S_LE(MS_OS_20_SUBSET_HEADER_CONFIGURATION), 0, 0, U16_TO_U8S_LE(MS_OS_20_DESC_LEN-0x0A),
// Function Subset header: length, type, first interface, reserved, subset length
U16_TO_U8S_LE(0x0008), U16_TO_U8S_LE(MS_OS_20_SUBSET_HEADER_FUNCTION), ITF_NUM_CDC, 0, U16_TO_U8S_LE(MS_OS_20_DESC_LEN-0x0A-0x08),
// MS OS 2.0 Compatible ID descriptor: length, type, compatible ID, sub compatible ID
U16_TO_U8S_LE(0x0014), U16_TO_U8S_LE(MS_OS_20_FEATURE_COMPATBLE_ID), 'W', 'I', 'N', 'N', 'C', 'M', 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // sub-compatible
// MS OS 2.0 Registry property descriptor: length, type
U16_TO_U8S_LE(MS_OS_20_DESC_LEN-0x0A-0x08-0x08-0x14), U16_TO_U8S_LE(MS_OS_20_FEATURE_REG_PROPERTY),
U16_TO_U8S_LE(0x0007), U16_TO_U8S_LE(0x002A), // wPropertyDataType, wPropertyNameLength and PropertyName "DeviceInterfaceGUIDs\0" in UTF-16
'D', 0x00, 'e', 0x00, 'v', 0x00, 'i', 0x00, 'c', 0x00, 'e', 0x00, 'I', 0x00, 'n', 0x00, 't', 0x00, 'e', 0x00,
'r', 0x00, 'f', 0x00, 'a', 0x00, 'c', 0x00, 'e', 0x00, 'G', 0x00, 'U', 0x00, 'I', 0x00, 'D', 0x00, 's', 0x00, 0x00, 0x00,
U16_TO_U8S_LE(0x0050), // wPropertyDataLength
//bPropertyData: {12345678-0D08-43FD-8B3E-127CA8AFFF9D}
'{', 0x00, '1', 0x00, '2', 0x00, '3', 0x00, '4', 0x00, '5', 0x00, '6', 0x00, '7', 0x00, '8', 0x00, '-', 0x00,
'0', 0x00, 'D', 0x00, '0', 0x00, '8', 0x00, '-', 0x00, '4', 0x00, '3', 0x00, 'F', 0x00, 'D', 0x00, '-', 0x00,
'8', 0x00, 'B', 0x00, '3', 0x00, 'E', 0x00, '-', 0x00, '1', 0x00, '2', 0x00, '7', 0x00, 'C', 0x00, 'A', 0x00,
'8', 0x00, 'A', 0x00, 'F', 0x00, 'F', 0x00, 'F', 0x00, '9', 0x00, 'D', 0x00, '}', 0x00, 0x00, 0x00, 0x00, 0x00
};
TU_VERIFY_STATIC(sizeof(desc_ms_os_20) == MS_OS_20_DESC_LEN, "Incorrect size");
// Invoked when a control transfer occurred on an interface of this class
// Driver response accordingly to the request and the transfer stage (setup/data/ack)
// return false to stall control endpoint (e.g unsupported request)
bool tud_vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const* request) {
// nothing to with DATA & ACK stage
if (stage != CONTROL_STAGE_SETUP) return true;
switch (request->bmRequestType_bit.type) {
case TUSB_REQ_TYPE_VENDOR:
switch (request->bRequest) {
case 1:
if (request->wIndex == 7) {
// Get Microsoft OS 2.0 compatible descriptor
uint16_t total_len;
memcpy(&total_len, desc_ms_os_20 + 8, 2);
return tud_control_xfer(rhport, request, (void*)(uintptr_t)desc_ms_os_20, total_len);
} else {
return false;
}
default: break;
}
break;
default: break;
}
// stall unknown request
return false;
}
#endif
//--------------------------------------------------------------------+
// String Descriptors
//--------------------------------------------------------------------+
// array of pointer to string descriptors
static char const* string_desc_arr [] =
{
[STRID_LANGID] = (const char[]) { 0x09, 0x04 }, // supported language is English (0x0409)
[STRID_MANUFACTURER] = "TinyUSB", // Manufacturer
[STRID_PRODUCT] = "TinyUSB Device", // Product
[STRID_SERIAL] = NULL, // Serials will use unique ID if possible
[STRID_INTERFACE] = "TinyUSB Network Interface" // Interface Description
// STRID_MAC index is handled separately
};
static uint16_t _desc_str[32 + 1];
// Invoked when received GET STRING DESCRIPTOR request
// Application return pointer to descriptor, whose contents must exist long enough for transfer to complete
uint16_t const* tud_descriptor_string_cb(uint8_t index, uint16_t langid) {
(void) langid;
unsigned int chr_count = 0;
switch ( index ) {
case STRID_LANGID:
memcpy(&_desc_str[1], string_desc_arr[0], 2);
chr_count = 1;
break;
case STRID_SERIAL:
chr_count = board_usb_get_serial(_desc_str + 1, 32);
break;
case STRID_MAC:
// Convert MAC address into UTF-16
for (unsigned i=0; i<sizeof(tud_network_mac_address); i++) {
_desc_str[1+chr_count++] = "0123456789ABCDEF"[(tud_network_mac_address[i] >> 4) & 0xf];
_desc_str[1+chr_count++] = "0123456789ABCDEF"[(tud_network_mac_address[i] >> 0) & 0xf];
}
break;
default:
// Note: the 0xEE index string is a Microsoft OS 1.0 Descriptors.
// https://docs.microsoft.com/en-us/windows-hardware/drivers/usbcon/microsoft-defined-usb-descriptors
if ( !(index < sizeof(string_desc_arr) / sizeof(string_desc_arr[0])) ) return NULL;
const char *str = string_desc_arr[index];
// Cap at max char
chr_count = strlen(str);
size_t const max_count = sizeof(_desc_str) / sizeof(_desc_str[0]) - 1; // -1 for string type
if ( chr_count > max_count ) chr_count = max_count;
// Convert ASCII string into UTF-16
for ( size_t i = 0; i < chr_count; i++ ) {
_desc_str[1 + i] = str[i];
}
break;
}
// first byte is length (including header), second byte is string type
_desc_str[0] = (uint16_t) ((TUSB_DESC_STRING << 8 ) | (2*chr_count + 2));
return _desc_str;
}