|
19 | 19 |
|
20 | 20 | #include "arduino_compat.h"
|
21 | 21 |
|
| 22 | +#include <dhserver.h> |
| 23 | +#include <dnserver.h> |
| 24 | +#include <httpd.h> |
| 25 | +#include <lwip/ethip6.h> |
| 26 | +#include <lwip/init.h> |
| 27 | +#include <lwip/timeouts.h> |
| 28 | + |
| 29 | + |
| 30 | +#ifdef INCLUDE_IPERF |
| 31 | + #include "lwip/apps/lwiperf.h" |
| 32 | +#endif |
| 33 | + |
22 | 34 | // Audio Buffer (Size is set in lib/audio/include/audio_subsystem.h)
|
23 | 35 | audio_buffer_pool_t *audio_pool;
|
24 | 36 |
|
@@ -66,6 +78,168 @@ TaskHandle_t usb_task_handle;
|
66 | 78 | extern "C" {
|
67 | 79 | #endif
|
68 | 80 |
|
| 81 | + |
| 82 | + // IP |
| 83 | + |
| 84 | + |
| 85 | + |
| 86 | +#define INIT_IP4(a, b, c, d) \ |
| 87 | + { PP_HTONL(LWIP_MAKEU32(a, b, c, d)) } |
| 88 | + |
| 89 | +/* lwip context */ |
| 90 | +static struct netif netif_data; |
| 91 | + |
| 92 | +/* shared between tud_network_recv_cb() and service_traffic() */ |
| 93 | +static struct pbuf *received_frame; |
| 94 | + |
| 95 | +/* this is used by this code, ./class/net/net_driver.c, and usb_descriptors.c */ |
| 96 | +/* ideally speaking, this should be generated from the hardware's unique ID (if available) */ |
| 97 | +/* it is suggested that the first byte is 0x02 to indicate a link-local address */ |
| 98 | +uint8_t tud_network_mac_address[6] = {0x02, 0x02, 0x84, 0x6A, 0x96, 0x00}; |
| 99 | + |
| 100 | +/* network parameters of this MCU */ |
| 101 | +static const ip4_addr_t ipaddr = INIT_IP4(192, 168, 7, 1); |
| 102 | +static const ip4_addr_t netmask = INIT_IP4(255, 255, 255, 0); |
| 103 | +static const ip4_addr_t gateway = INIT_IP4(0, 0, 0, 0); |
| 104 | + |
| 105 | +/* database IP addresses that can be offered to the host; this must be in RAM to store assigned MAC addresses */ |
| 106 | +static dhcp_entry_t entries[] = { |
| 107 | + /* mac ip address lease time */ |
| 108 | + {{0}, INIT_IP4(192, 168, 7, 2), 24 * 60 * 60}, |
| 109 | + {{0}, INIT_IP4(192, 168, 7, 3), 24 * 60 * 60}, |
| 110 | + {{0}, INIT_IP4(192, 168, 7, 4), 24 * 60 * 60}, |
| 111 | +}; |
| 112 | + |
| 113 | +static const dhcp_config_t dhcp_config = { |
| 114 | + .router = INIT_IP4(0, 0, 0, 0), /* router address (if any) */ |
| 115 | + .port = 67, /* listen port */ |
| 116 | + .dns = INIT_IP4(192, 168, 7, 1), /* dns server (if any) */ |
| 117 | + "usb", /* dns suffix */ |
| 118 | + TU_ARRAY_SIZE(entries), /* num entry */ |
| 119 | + entries /* entries */ |
| 120 | +}; |
| 121 | + |
| 122 | +static err_t linkoutput_fn(struct netif *netif, struct pbuf *p) { |
| 123 | + (void) netif; |
| 124 | + |
| 125 | + for (;;) { |
| 126 | + /* if TinyUSB isn't ready, we must signal back to lwip that there is nothing we can do */ |
| 127 | + if (!tud_ready()) |
| 128 | + return ERR_USE; |
| 129 | + |
| 130 | + /* if the network driver can accept another packet, we make it happen */ |
| 131 | + if (tud_network_can_xmit(p->tot_len)) { |
| 132 | + tud_network_xmit(p, 0 /* unused for this example */); |
| 133 | + return ERR_OK; |
| 134 | + } |
| 135 | + |
| 136 | + /* transfer execution to TinyUSB in the hopes that it will finish transmitting the prior packet */ |
| 137 | + tud_task(); |
| 138 | + } |
| 139 | +} |
| 140 | + |
| 141 | +static err_t ip4_output_fn(struct netif *netif, struct pbuf *p, const ip4_addr_t *addr) { |
| 142 | + return etharp_output(netif, p, addr); |
| 143 | +} |
| 144 | + |
| 145 | +#if LWIP_IPV6 |
| 146 | +static err_t ip6_output_fn(struct netif *netif, struct pbuf *p, const ip6_addr_t *addr) { |
| 147 | + return ethip6_output(netif, p, addr); |
| 148 | +} |
| 149 | +#endif |
| 150 | + |
| 151 | +static err_t netif_init_cb(struct netif *netif) { |
| 152 | + LWIP_ASSERT("netif != NULL", (netif != NULL)); |
| 153 | + netif->mtu = CFG_TUD_NET_MTU; |
| 154 | + netif->flags = NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP | NETIF_FLAG_LINK_UP | NETIF_FLAG_UP; |
| 155 | + netif->state = NULL; |
| 156 | + netif->name[0] = 'E'; |
| 157 | + netif->name[1] = 'X'; |
| 158 | + netif->linkoutput = linkoutput_fn; |
| 159 | + netif->output = ip4_output_fn; |
| 160 | +#if LWIP_IPV6 |
| 161 | + netif->output_ip6 = ip6_output_fn; |
| 162 | +#endif |
| 163 | + return ERR_OK; |
| 164 | +} |
| 165 | + |
| 166 | +static void init_lwip(void) { |
| 167 | + struct netif *netif = &netif_data; |
| 168 | + |
| 169 | + lwip_init(); |
| 170 | + |
| 171 | + /* the lwip virtual MAC address must be different from the host's; to ensure this, we toggle the LSbit */ |
| 172 | + netif->hwaddr_len = sizeof(tud_network_mac_address); |
| 173 | + memcpy(netif->hwaddr, tud_network_mac_address, sizeof(tud_network_mac_address)); |
| 174 | + netif->hwaddr[5] ^= 0x01; |
| 175 | + |
| 176 | + netif = netif_add(netif, &ipaddr, &netmask, &gateway, NULL, netif_init_cb, ip_input); |
| 177 | +#if LWIP_IPV6 |
| 178 | + netif_create_ip6_linklocal_address(netif, 1); |
| 179 | +#endif |
| 180 | + netif_set_default(netif); |
| 181 | +} |
| 182 | + |
| 183 | +/* handle any DNS requests from dns-server */ |
| 184 | +bool dns_query_proc(const char *name, ip4_addr_t *addr) { |
| 185 | + if (0 == strcmp(name, "tiny.usb")) { |
| 186 | + *addr = ipaddr; |
| 187 | + return true; |
| 188 | + } |
| 189 | + return false; |
| 190 | +} |
| 191 | + |
| 192 | +bool tud_network_recv_cb(const uint8_t *src, uint16_t size) { |
| 193 | + /* this shouldn't happen, but if we get another packet before |
| 194 | + parsing the previous, we must signal our inability to accept it */ |
| 195 | + if (received_frame) return false; |
| 196 | + |
| 197 | + if (size) { |
| 198 | + struct pbuf *p = pbuf_alloc(PBUF_RAW, size, PBUF_POOL); |
| 199 | + |
| 200 | + if (p) { |
| 201 | + /* pbuf_alloc() has already initialized struct; all we need to do is copy the data */ |
| 202 | + memcpy(p->payload, src, size); |
| 203 | + |
| 204 | + /* store away the pointer for service_traffic() to later handle */ |
| 205 | + received_frame = p; |
| 206 | + } |
| 207 | + } |
| 208 | + |
| 209 | + return true; |
| 210 | +} |
| 211 | + |
| 212 | +uint16_t tud_network_xmit_cb(uint8_t *dst, void *ref, uint16_t arg) { |
| 213 | + struct pbuf *p = (struct pbuf *) ref; |
| 214 | + |
| 215 | + (void) arg; /* unused for this example */ |
| 216 | + |
| 217 | + return pbuf_copy_partial(p, dst, p->tot_len, 0); |
| 218 | +} |
| 219 | + |
| 220 | +static void service_traffic(void) { |
| 221 | + /* handle any packet received by tud_network_recv_cb() */ |
| 222 | + if (received_frame) { |
| 223 | + ethernet_input(received_frame, &netif_data); |
| 224 | + pbuf_free(received_frame); |
| 225 | + received_frame = NULL; |
| 226 | + tud_network_recv_renew(); |
| 227 | + } |
| 228 | + |
| 229 | + sys_check_timeouts(); |
| 230 | +} |
| 231 | + |
| 232 | +void tud_network_init_cb(void) { |
| 233 | + /* if the network is re-initializing and we have a leftover packet, we must do a cleanup */ |
| 234 | + if (received_frame) { |
| 235 | + pbuf_free(received_frame); |
| 236 | + received_frame = NULL; |
| 237 | + } |
| 238 | +} |
| 239 | + |
| 240 | + |
| 241 | + // IP END |
| 242 | + |
69 | 243 | /**
|
70 | 244 | * Task to handle USB MIDI input processing.
|
71 | 245 | *
|
@@ -155,9 +329,22 @@ extern "C" {
|
155 | 329 | // Start the FreeRTOS scheduler
|
156 | 330 | vTaskStartScheduler();
|
157 | 331 |
|
| 332 | + /* initialize lwip, dhcp-server, dns-server, and http */ |
| 333 | + init_lwip(); |
| 334 | + while (!netif_is_up(&netif_data)); |
| 335 | + while (dhserv_init(&dhcp_config) != ERR_OK); |
| 336 | + while (dnserv_init(IP_ADDR_ANY, 53, dns_query_proc) != ERR_OK); |
| 337 | + httpd_init(); |
| 338 | + |
| 339 | +#ifdef INCLUDE_IPERF |
| 340 | + // test with: iperf -c 192.168.7.1 -e -i 1 -M 5000 -l 8192 -r |
| 341 | + lwiperf_start_tcp_server_default(NULL, NULL); |
| 342 | +#endif |
| 343 | + |
158 | 344 | // Idle loop (this is fine for Cortex-M33)
|
159 | 345 | while (1)
|
160 | 346 | {
|
| 347 | + service_traffic(); |
161 | 348 | __wfi();
|
162 | 349 | }
|
163 | 350 | }
|
|
0 commit comments