Skip to content

Commit

Permalink
Implement USB NCM (#37)
Browse files Browse the repository at this point in the history
  • Loading branch information
buglloc authored Jan 6, 2024
1 parent a2464a7 commit f28e173
Show file tree
Hide file tree
Showing 13 changed files with 279 additions and 64 deletions.
3 changes: 2 additions & 1 deletion components/hardware/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,13 @@ idf_component_register(
SRCS
"src/manager.cc"
"src/net_eth.cc"
"src/net_usb.cc"
"src/net_wifi.cc"
"src/net.cc"
INCLUDE_DIRS
"include"
REQUIRES
esp_netif lilygo
PRIV_REQUIRES
driver esp_eth esp_wifi esp_timer nvs_flash
driver esp_eth esp_wifi esp_timer esp_tinyusb nvs_flash
)
21 changes: 11 additions & 10 deletions components/hardware/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -59,21 +59,19 @@ menu "BoundBox Hardware"
default 15
depends on BBHW_HAS_ETH

config BBHW_HAS_WIFI
bool "Has WiFi"
default y

choice BBHW_NETKIND
prompt "Default network implementation"
default BBHW_NETKIND_ETH
prompt "Network implementation"
default BBHW_NETKIND_USB

config BBHW_NETKIND_ETH
bool "Ethernet"
depends on BBHW_HAS_ETH
config BBHW_NETKIND_USB
bool "USB"

config BBHW_NETKIND_WIFI_STA
bool "WiFi"
depends on BBHW_HAS_WIFI

config BBHW_NETKIND_ETH
bool "Ethernet"
depends on BBHW_HAS_ETH
endchoice

config BBHW_HOSTNAME
Expand All @@ -86,14 +84,17 @@ menu "BoundBox Hardware"

config BBHW_NET_IP
string "Static IP to use"
default "192.168.8.1"
depends on BBHW_NET_USE_STATIC_IP

config BBHW_NET_SUBNET
string "Static Subnet to use"
default "255.255.255.0"
depends on BBHW_NET_USE_STATIC_IP

config BBHW_NET_GW
string "Static Gateway to use"
default "0.0.0.0"
depends on BBHW_NET_USE_STATIC_IP

config BBHW_NET_DNS
Expand Down
4 changes: 4 additions & 0 deletions components/hardware/idf_component.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
dependencies:
espressif/esp_tinyusb: "^1.4.2"
idf: "^5.1.0"

4 changes: 2 additions & 2 deletions components/hardware/src/config.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@
#define BBHW_SPI_HOSTID NeedTooChooseSpiHost
#ifdef CONFIG_BBHW_USE_SPI2_HOST
#undef BBHW_SPI_HOSTID
#define BBHW_SPI_HOSTID SPI3_HOST
#define BBHW_SPI_HOSTID SPI2_HOST
#endif
#ifdef CONFIG_BBHW_USE_SPI3_HOST
#undef BBHW_SPI_HOSTID
#define BBHW_SPI_HOSTID SPI3_HOST
#endif
#endif
45 changes: 35 additions & 10 deletions components/hardware/src/net.cc
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
#include "hardware/net.h"
#include "config.h"

#include "net_usb.h"
#include "net_wifi.h"
#if CONFIG_BBHW_HAS_ETH
#include "net_eth.h"
#endif
#if CONFIG_BBHW_HAS_WIFI
#include "net_wifi.h"
#endif

#include <esp_netif.h>
#include <esp_event.h>
Expand Down Expand Up @@ -38,13 +37,36 @@ namespace
netReady = true;
localIP = ip_info->ip;

ESP_LOGI(TAG, "%s IP Address", event_id == IP_EVENT_ETH_GOT_IP ? "Ethernet" : "WiFi");
switch (event_id) {
case IP_EVENT_ETH_GOT_IP:
ESP_LOGI(TAG, "Ethernet connected");
break;
case IP_EVENT_STA_GOT_IP:
ESP_LOGI(TAG, "Wifi connected");
break;
default:
ESP_LOGI(TAG, "Something connected");
}

ESP_LOGI(TAG, "~~~~~~~~~~~");
ESP_LOGI(TAG, "IP: " IPSTR, IP2STR(&ip_info->ip));
ESP_LOGI(TAG, "Mask: " IPSTR, IP2STR(&ip_info->netmask));
ESP_LOGI(TAG, "Gateway: " IPSTR, IP2STR(&ip_info->gw));

if (!ip4_addr_isany_val(ip_info->ip)) {
ESP_LOGI(TAG, "IP: " IPSTR, IP2STR(&ip_info->ip));
}

if (!ip4_addr_isany_val(ip_info->netmask)) {
ESP_LOGI(TAG, "Mask: " IPSTR, IP2STR(&ip_info->netmask));
}

if (!ip4_addr_isany_val(ip_info->gw)) {
ESP_LOGI(TAG, "Gateway: " IPSTR, IP2STR(&ip_info->gw));
}

ESP_LOGI(TAG, "~~~~~~~~~~~");
break;
case IP_EVENT_AP_STAIPASSIGNED:
ESP_LOGI(TAG, "New client connected");
ESP_LOGI(TAG, "IP: " IPSTR, IP2STR(&ip_info->ip));
default:
return;
}
Expand All @@ -53,7 +75,11 @@ namespace

esp_err_t Net::Initialize()
{
#if CONFIG_BBHW_NETKIND_ETH
#if CONFIG_BBHW_NETKIND_USB
impl = std::make_unique<NetUsb>();
ESP_RETURN_ON_ERROR(impl->Initialize(), TAG, "failed to initialize usb network");

#elif CONFIG_BBHW_NETKIND_ETH
impl = std::make_unique<NetEth>();
ESP_RETURN_ON_ERROR(impl->Initialize(), TAG, "failed to initialize ethernet network");

Expand All @@ -62,8 +88,7 @@ esp_err_t Net::Initialize()
ESP_RETURN_ON_ERROR(impl->Initialize(), TAG, "failed to initialize wifi network");

#else
ESP_LOGE(TAG, "no network configured");
return ESP_FAIL;
#error No network configured
#endif

ESP_RETURN_ON_ERROR(esp_netif_init(), TAG, "failed to initialize netif");
Expand Down
21 changes: 18 additions & 3 deletions components/hardware/src/net_common.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,23 @@ namespace Hardware
#endif
}

inline void BuildIPInfo(esp_netif_ip_info_t *ip, bool force)
{
#if !CONFIG_BBHW_NET_USE_STATIC_IP
if (!force) {
// doesn't use static IP - nothing to do
return;
}
#else
assert(ip);

memset(ip, 0 , sizeof(esp_netif_ip_info_t));
ip->ip.addr = ipaddr_addr(CONFIG_BBHW_NET_IP);
ip->netmask.addr = ipaddr_addr(CONFIG_BBHW_NET_SUBNET);
ip->gw.addr = ipaddr_addr(CONFIG_BBHW_NET_GW);
#endif
}

inline void SetIPInfo(esp_netif_t *netif)
{
#if !CONFIG_BBHW_NET_USE_STATIC_IP
Expand All @@ -40,9 +57,7 @@ namespace Hardware

esp_netif_ip_info_t ip;
memset(&ip, 0 , sizeof(esp_netif_ip_info_t));
ip.ip.addr = ipaddr_addr(CONFIG_BBHW_NET_IP);
ip.netmask.addr = ipaddr_addr(CONFIG_BBHW_NET_SUBNET);
ip.gw.addr = ipaddr_addr(CONFIG_BBHW_NET_GW);
BuildIPInfo(&ip, false);
ESP_ERROR_CHECK(esp_netif_set_ip_info(netif, &ip));

SetDnsServer(netif, ESP_NETIF_DNS_MAIN);
Expand Down
10 changes: 2 additions & 8 deletions components/hardware/src/net_eth.cc
Original file line number Diff line number Diff line change
Expand Up @@ -130,14 +130,8 @@ esp_err_t NetEth::Initialize()
.phy_addr = CONFIG_BBHW_ETH_PHY_ADDR,
};

// The SPI Ethernet module(s) might not have a burned factory MAC address, hence use manually configured address(es).
// In this example, Locally Administered MAC address derived from ESP32x base MAC address is used.
// Note that Locally Administered OUI range should be used only when testing on a LAN under your control!
uint8_t base_mac_addr[ETH_ADDR_LEN];
ESP_RETURN_ON_ERROR(esp_efuse_mac_get_default(base_mac_addr), TAG, "get EFUSE MAC failed");
uint8_t local_mac_1[ETH_ADDR_LEN];
esp_derive_local_mac(local_mac_1, base_mac_addr);
spi_eth_module_config.mac_addr = local_mac_1;
esp_err_t err = esp_read_mac(spi_eth_module_config.mac_addr, ESP_MAC_WIFI_STA);
ESP_RETURN_ON_ERROR(err, TAG, "read sta mac");

ethHandle = ethInitSpi(spi_eth_module_config, nullptr, nullptr);
ESP_RETURN_ON_FALSE(ethHandle, ESP_FAIL, TAG, "SPI Ethernet init failed");
Expand Down
6 changes: 1 addition & 5 deletions components/hardware/src/net_eth.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,18 +20,14 @@ namespace Hardware

~NetEth()
{
if (netif != nullptr) {
esp_eth_stop(netif);
}

if (ethHandle != nullptr) {
esp_eth_stop(ethHandle);
esp_eth_driver_uninstall(ethHandle);
}
}

private:
esp_eth_handle_t ethHandle = nullptr;
esp_netif_inherent_config_t netifCfg;
esp_netif_t* netif;
};
}
133 changes: 133 additions & 0 deletions components/hardware/src/net_usb.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
#include "config.h"
#include "net_usb.h"
#include "net_common.h"

#include <assert.h>

#include <tinyusb.h>
#include <tinyusb_net.h>

#include <esp_netif.h>
#include <esp_eth.h>
#include <esp_eth_driver.h>
#include <esp_mac.h>
#include <esp_log.h>
#include <esp_check.h>
#include <esp_event.h>


using namespace Hardware;

namespace
{
static const char* TAG = "hardware::net::usb";

esp_err_t wired_send(void *buffer, uint16_t len, void *buff_free_arg)
{
return tinyusb_net_send_sync(buffer, len, buff_free_arg, pdMS_TO_TICKS(100));
}

static void l2_free(void *h, void *buffer)
{
free(buffer);
}

static esp_err_t netif_transmit (void *h, void *buffer, size_t len)
{
if (wired_send(buffer, len, NULL) != ESP_OK) {
ESP_LOGE(TAG, "Failed to send buffer to USB!");
}
return ESP_OK;
}

esp_err_t netif_recv_callback(void *buffer, uint16_t len, void *ctx)
{
esp_netif_t* netif = reinterpret_cast<esp_netif_t *>(ctx);
if (!netif) {
return ESP_OK;
}

void *buf_copy = malloc(len);
if (!buf_copy) {
return ESP_ERR_NO_MEM;
}
memcpy(buf_copy, buffer, len);
return esp_netif_receive(netif, buf_copy, len, NULL);
}
}

esp_err_t NetUsb::Initialize()
{
const tinyusb_config_t usbCfg = {
.external_phy = false,
};
esp_err_t err = tinyusb_driver_install(&usbCfg);
ESP_RETURN_ON_ERROR(err, TAG, "install TinyUSB driver");

BuildIPInfo(&this->ipInfo, true);
this->netifCfg = {
.flags = static_cast<esp_netif_flags_t>(ESP_NETIF_DHCP_SERVER | ESP_NETIF_FLAG_AUTOUP | ESP_NETIF_FLAG_EVENT_IP_MODIFIED),
.ip_info = &this->ipInfo,
.get_ip_event = IP_EVENT_ETH_GOT_IP,
.lost_ip_event = IP_EVENT_ETH_LOST_IP,
.if_key = "wired",
.if_desc = "usb ncm config device",
};
PatchNetifCfg(this->netifCfg);

this->driverCfg = {
.handle = (void *)1, // not using an instance, USB-NCM is a static singleton (must be != NULL)
.transmit = netif_transmit, // point to static Tx function
.driver_free_rx_buffer = l2_free // point to Free Rx buffer function
};

this->stackCfg = {
.lwip = {
.init_fn = ethernetif_init,
.input_fn = ethernetif_input
}
};

return ESP_OK;
}

esp_netif_config_t NetUsb::NetifConfig() const
{
return {
.base = &netifCfg,
.driver = &driverCfg,
.stack = &stackCfg,
};
}

esp_err_t NetUsb::Attach(esp_netif_t* netif)
{
assert(netif);

tinyusb_net_config_t netCfg = {
.on_recv_callback = netif_recv_callback,
.user_context = netif,
};

esp_err_t err = esp_read_mac(netCfg.mac_addr, ESP_MAC_WIFI_SOFTAP);
ESP_RETURN_ON_ERROR(err, TAG, "read softap mac");

err = tinyusb_net_init(TINYUSB_USBDEV_0, &netCfg);
ESP_RETURN_ON_ERROR(err, TAG, "initialize USB Net device");

err = esp_netif_set_mac(netif, netCfg.mac_addr);
ESP_RETURN_ON_ERROR(err, TAG, "set netif mac");

// start the interface manually (as the driver has been started already)
esp_netif_action_start(netif, 0, 0, 0);

// TODO(buglloc): do smth better plz
ip_event_got_ip_t evt = {
.esp_netif = netif,
.ip_changed = true,
};
BuildIPInfo(&evt.ip_info, true);
esp_event_post(IP_EVENT, IP_EVENT_ETH_GOT_IP, &evt, sizeof(evt), 0);

return ESP_OK;
}
Loading

0 comments on commit f28e173

Please sign in to comment.