Files
xiaozhi-esp32/main/boards/common/rndis_board.cc
2026-04-26 21:35:04 +08:00

247 lines
7.8 KiB
C++

#include "rndis_board.h"
#include "display.h"
#include "application.h"
#include "system_info.h"
#include "settings.h"
#include "assets/lang_config.h"
#include <freertos/FreeRTOS.h>
#include <freertos/task.h>
#include <esp_network.h>
#include <esp_log.h>
#include <utility>
#include <font_awesome.h>
#if CONFIG_IDF_TARGET_ESP32P4 || CONFIG_IDF_TARGET_ESP32S3
static const char *TAG = "RndisBoard";
#define EVENT_GOT_IP_BIT (1 << 0)
RndisBoard::RndisBoard() {
}
RndisBoard::~RndisBoard() {
}
std::string RndisBoard::GetBoardType() {
return "rndis";
}
void RndisBoard::StartNetwork() {
esp_err_t ret = nvs_flash_init();
if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) {
/* NVS partition was truncated and needs to be erased
* Retry nvs_flash_init */
ESP_ERROR_CHECK(nvs_flash_erase());
ESP_ERROR_CHECK(nvs_flash_init());
}
/* Initialize default TCP/IP stack */
ESP_ERROR_CHECK(esp_netif_init());
ESP_ERROR_CHECK(esp_event_loop_create_default());
s_event_group = xEventGroupCreate();
esp_event_handler_register(IOT_ETH_EVENT, ESP_EVENT_ANY_ID, iot_event_handle, this);
esp_event_handler_register(IP_EVENT, IP_EVENT_ETH_GOT_IP, iot_event_handle, this);
// install usbh cdc driver
usbh_cdc_driver_config_t config = {
.task_stack_size = 1024 * 4,
.task_priority = configMAX_PRIORITIES - 1,
.task_coreid = 0,
.skip_init_usb_host_driver = false,
};
ESP_ERROR_CHECK(usbh_cdc_driver_install(&config));
install_rndis(USB_DEVICE_VENDOR_ANY, USB_DEVICE_PRODUCT_ANY, "USB RNDIS0");
xEventGroupWaitBits(s_event_group, EVENT_GOT_IP_BIT, pdFALSE, pdFALSE, portMAX_DELAY);
}
void RndisBoard::iot_event_handle(void *arg, esp_event_base_t event_base, int32_t event_id, void *event_data)
{
if (event_base == IOT_ETH_EVENT) {
switch (event_id) {
case IOT_ETH_EVENT_START:
ESP_LOGI(TAG, "IOT_ETH_EVENT_START");
break;
case IOT_ETH_EVENT_STOP:
ESP_LOGI(TAG, "IOT_ETH_EVENT_STOP");
break;
case IOT_ETH_EVENT_CONNECTED:
ESP_LOGI(TAG, "IOT_ETH_EVENT_CONNECTED");
static_cast<RndisBoard*>(arg)->OnNetworkEvent(NetworkEvent::Connected);
break;
case IOT_ETH_EVENT_DISCONNECTED:
ESP_LOGI(TAG, "IOT_ETH_EVENT_DISCONNECTED");
xEventGroupClearBits(static_cast<RndisBoard*>(arg)->s_event_group, EVENT_GOT_IP_BIT);
static_cast<RndisBoard*>(arg)->OnNetworkEvent(NetworkEvent::Disconnected);
break;
default:
ESP_LOGI(TAG, "IOT_ETH_EVENT_UNKNOWN");
break;
}
} else if (event_base == IP_EVENT) {
ESP_LOGI(TAG, "GOT_IP");
xEventGroupSetBits(static_cast<RndisBoard*>(arg)->s_event_group, EVENT_GOT_IP_BIT);
}
}
void RndisBoard::OnNetworkEvent(NetworkEvent event, const std::string& data) {
switch (event) {
case NetworkEvent::Connected:
ESP_LOGI(TAG, "Connected to WiFi: %s", data.c_str());
break;
case NetworkEvent::Scanning:
ESP_LOGI(TAG, "WiFi scanning");
break;
case NetworkEvent::Connecting:
ESP_LOGI(TAG, "WiFi connecting to %s", data.c_str());
break;
case NetworkEvent::Disconnected:
ESP_LOGW(TAG, "WiFi disconnected");
break;
default:
break;
}
// Notify external callback if set
if (network_event_callback_) {
network_event_callback_(event, data);
}
}
void RndisBoard::SetNetworkEventCallback(NetworkEventCallback callback) {
network_event_callback_ = std::move(callback);
}
void RndisBoard::install_rndis(uint16_t idVendor, uint16_t idProduct, const char *netif_name)
{
esp_err_t ret = ESP_OK;
iot_eth_handle_t eth_handle = nullptr;
iot_eth_netif_glue_handle_t glue = nullptr;
usb_device_match_id_t *dev_match_id = (usb_device_match_id_t*)calloc(2, sizeof(usb_device_match_id_t));
dev_match_id[0].match_flags = USB_DEVICE_ID_MATCH_VID_PID;
dev_match_id[0].idVendor = idVendor;
dev_match_id[0].idProduct = idProduct;
memset(&dev_match_id[1], 0, sizeof(usb_device_match_id_t)); // end of list
iot_usbh_rndis_config_t rndis_cfg = {
.match_id_list = dev_match_id,
};
ret = iot_eth_new_usb_rndis(&rndis_cfg, &rndis_eth_driver);
if (ret != ESP_OK || rndis_eth_driver == NULL) {
ESP_LOGE(TAG, "Failed to create USB RNDIS driver");
return;
}
iot_eth_config_t eth_cfg = {
.driver = rndis_eth_driver,
.stack_input = NULL,
};
ret = iot_eth_install(&eth_cfg, &eth_handle);
if (ret != ESP_OK) {
ESP_LOGE(TAG, "Failed to install USB RNDIS driver");
return;
}
esp_netif_inherent_config_t _inherent_eth_config = ESP_NETIF_INHERENT_DEFAULT_ETH();
_inherent_eth_config.if_key = netif_name;
_inherent_eth_config.if_desc = netif_name;
esp_netif_config_t netif_cfg = {
.base = &_inherent_eth_config,
.driver = NULL,
.stack = ESP_NETIF_NETSTACK_DEFAULT_ETH,
};
s_rndis_netif = esp_netif_new(&netif_cfg);
if (s_rndis_netif == NULL) {
ESP_LOGE(TAG, "Failed to create network interface");
return;
}
glue = iot_eth_new_netif_glue(eth_handle);
if (glue == NULL) {
ESP_LOGE(TAG, "Failed to create netif glue");
return;
}
esp_netif_attach(s_rndis_netif, glue);
iot_eth_start(eth_handle);
}
NetworkInterface* RndisBoard::GetNetwork() {
static EspNetwork network;
return &network;
}
const char* RndisBoard::GetNetworkStateIcon() {
return FONT_AWESOME_SIGNAL_STRONG;
}
std::string RndisBoard::GetBoardJson() {
std::string json = R"({"type":")" + std::string(BOARD_TYPE) + R"(",)";
json += R"("name":")" + std::string(BOARD_NAME) + R"(",)";
json += R"("mac":")" + SystemInfo::GetMacAddress() + R"("})";
return json;
}
void RndisBoard::SetPowerSaveLevel(PowerSaveLevel level) {
}
std::string RndisBoard::GetDeviceStatusJson() {
auto& board = Board::GetInstance();
auto root = cJSON_CreateObject();
// Audio speaker
auto audio_speaker = cJSON_CreateObject();
if (auto codec = board.GetAudioCodec()) {
cJSON_AddNumberToObject(audio_speaker, "volume", codec->output_volume());
}
cJSON_AddItemToObject(root, "audio_speaker", audio_speaker);
// Screen
auto screen = cJSON_CreateObject();
if (auto backlight = board.GetBacklight()) {
cJSON_AddNumberToObject(screen, "brightness", backlight->brightness());
}
if (auto display = board.GetDisplay(); display && display->height() > 64) {
if (auto theme = display->GetTheme()) {
cJSON_AddStringToObject(screen, "theme", theme->name().c_str());
}
}
cJSON_AddItemToObject(root, "screen", screen);
// Battery
int level = 0;
bool charging = false, discharging = false;
if (board.GetBatteryLevel(level, charging, discharging)) {
auto battery = cJSON_CreateObject();
cJSON_AddNumberToObject(battery, "level", level);
cJSON_AddBoolToObject(battery, "charging", charging);
cJSON_AddItemToObject(root, "battery", battery);
}
// Network
auto network = cJSON_CreateObject();
cJSON_AddStringToObject(network, "type", "rndis");
cJSON_AddItemToObject(root, "network", network);
// Chip temperature
float temp = 0.0f;
if (board.GetTemperature(temp)) {
auto chip = cJSON_CreateObject();
cJSON_AddNumberToObject(chip, "temperature", temp);
cJSON_AddItemToObject(root, "chip", chip);
}
auto str = cJSON_PrintUnformatted(root);
std::string result(str);
cJSON_free(str);
cJSON_Delete(root);
return result;
}
#endif // CONFIG_IDF_TARGET_ESP32P4 || CONFIG_IDF_TARGET_ESP32S3