235 lines
6.3 KiB
C
235 lines
6.3 KiB
C
#include "bsp/board_api.h"
|
|
#include "tusb.h"
|
|
#include "dhserver.h"
|
|
#include "dnserver.h"
|
|
#include "lwip/apps/httpd.h"
|
|
#include "lwip/init.h"
|
|
#include "lwip/timeouts.h"
|
|
|
|
#include "websocket.h"
|
|
#include "usb_device.h"
|
|
#include "aw410k.h"
|
|
|
|
#include "usb_server.h"
|
|
|
|
// ip address of the USB server and dhcp address(es) it will give out
|
|
static const ip4_addr_t usb_ip = INIT_IP4(192, 168, 40, 1);
|
|
static const ip4_addr_t usb_netmask = INIT_IP4(255, 255, 255, 0);
|
|
static const ip4_addr_t usb_gateway = INIT_IP4(0, 0, 0, 0);
|
|
static dhcp_entry_t dhcp_clients[] = {
|
|
{ {0}, INIT_IP4(192, 168, 40, 2), 4*3600 },
|
|
};
|
|
static const dhcp_config_t dhcp_config = {
|
|
.router = INIT_IP4(0,0,0,0),
|
|
.port = 67,
|
|
.dns = usb_ip,
|
|
"usb",
|
|
TU_ARRAY_SIZE(dhcp_clients),
|
|
dhcp_clients
|
|
};
|
|
|
|
static struct netif netif_data;
|
|
|
|
static err_t netif_init_cb(struct netif *netif);
|
|
static err_t ip4_output_fn(struct netif *netif, struct pbuf *p, const ip4_addr_t *addr);
|
|
static err_t linkoutput_fn(struct netif *netif, struct pbuf *p);
|
|
static void usb_server_netif_link_cb(struct netif *netif);
|
|
static bool dns_request(const char *name, ip4_addr_t *addr);
|
|
|
|
// called to initialize the USB network and HTTP server
|
|
void usb_server_init(void) {
|
|
struct netif *netif = &netif_data;
|
|
|
|
lwip_init();
|
|
|
|
// use 02 followed by last 10 digits from board serial as MAC address
|
|
uint8_t board_serial[16];
|
|
size_t count = board_get_unique_id(board_serial, sizeof(board_serial));
|
|
netif->hwaddr_len = 6;
|
|
memcpy(netif->hwaddr, &board_serial[count-6], 6);
|
|
netif->hwaddr[0]=0x02;
|
|
// lwip virtual MAC address msut differ from the host MAC - toggle last bit
|
|
netif->hwaddr[5] ^= 0x01;
|
|
|
|
netif = netif_add(netif, &usb_ip, &usb_netmask, &usb_gateway, NULL, netif_init_cb, ethernet_input);
|
|
netif_set_default(netif);
|
|
|
|
#if LWIP_NETIF_LINK_CALLBACK
|
|
netif_set_link_callback(netif, usb_server_netif_link_cb);
|
|
netif_set_link_up(netif);
|
|
#else
|
|
//tud_network_link_state(BOARD_TUD_RHPORT, true);
|
|
// unsupported in current version - add when Pico SDK updates TinyUSB version
|
|
#endif
|
|
|
|
while (!netif_is_up(&netif_data));
|
|
while (dhserv_init(&dhcp_config) != ERR_OK);
|
|
while (dnserv_init(IP_ADDR_ANY, 53, dns_request) != ERR_OK);
|
|
|
|
httpd_init();
|
|
|
|
// start the websocket server
|
|
ws_server_init();
|
|
ws_set_open_handler(ws_open_handler);
|
|
ws_set_receive_handler(ws_receive_handler);
|
|
}
|
|
|
|
// callback when data is received on USB network
|
|
// return true if the packet buffer was accepted
|
|
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;
|
|
}
|
|
|
|
// callback when network interface is initialized
|
|
// save the network configuration
|
|
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;
|
|
|
|
return ERR_OK;
|
|
}
|
|
|
|
// callback for sending data over USB network interface
|
|
// copy from network stack packet pointer to dst
|
|
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 err_t ip4_output_fn(struct netif *netif, struct pbuf *p, const ip4_addr_t *addr) {
|
|
return etharp_output(netif, p, addr);
|
|
}
|
|
|
|
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();
|
|
}
|
|
}
|
|
|
|
// notify USB host about link state changes
|
|
static void usb_server_netif_link_cb(struct netif *netif) {
|
|
bool link_up = netif_is_link_up(netif);
|
|
//tud_network_link_state(BOARD_TUD_RHPORT, link_up);
|
|
// unsupported in current version - add when Pico SDK updates TinyUSB version
|
|
}
|
|
|
|
// handle DNS requests and serve on designed domain
|
|
static bool dns_request(const char *name, ip4_addr_t *addr) {
|
|
if (0 == strcmp(name, "aw410k.usb")) {
|
|
*addr = usb_ip;
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
// handler called when websocket connection is opened
|
|
const void ws_open_handler(struct ws_state * wss) {
|
|
(void) wss;
|
|
|
|
// nothing to do
|
|
}
|
|
|
|
// handler for data received on websocket connection
|
|
const void ws_receive_handler(uint8_t *data, uint16_t len) {
|
|
if (strncmp(data, "S,", 2) == 0) {
|
|
// set color command
|
|
parse_colors(&data[2], len-2);
|
|
} else if ( strncmp(data, "G,", 2) == 0) {
|
|
// get color comand
|
|
get_color(&data[2], len-2);
|
|
} else if ( strncmp(data, "F,", 2) == 0) {
|
|
// save to flash memory
|
|
save_rgb_config();
|
|
} else if ( strncmp(data, "L,", 2) == 0) {
|
|
// load from flash memory
|
|
load_rgb_config();
|
|
}
|
|
}
|
|
|
|
// Pico specific routines needed by lwip
|
|
auto_init_mutex(lwip_mutex);
|
|
static int lwip_mutex_count = 0;
|
|
|
|
sys_prot_t sys_arch_protect(void)
|
|
{
|
|
uint32_t owner;
|
|
if (!mutex_try_enter(&lwip_mutex, &owner))
|
|
{
|
|
if (owner != get_core_num())
|
|
{
|
|
// Wait until other core releases mutex
|
|
mutex_enter_blocking(&lwip_mutex);
|
|
}
|
|
}
|
|
|
|
lwip_mutex_count++;
|
|
|
|
return 0;
|
|
}
|
|
|
|
void sys_arch_unprotect(sys_prot_t pval)
|
|
{
|
|
(void)pval;
|
|
|
|
if (lwip_mutex_count)
|
|
{
|
|
lwip_mutex_count--;
|
|
if (!lwip_mutex_count)
|
|
{
|
|
mutex_exit(&lwip_mutex);
|
|
}
|
|
}
|
|
}
|
|
|
|
uint32_t sys_now(void)
|
|
{
|
|
return to_ms_since_boot( get_absolute_time() );
|
|
}
|