#include "rndis_board.h" #include "display.h" #include "application.h" #include "system_info.h" #include "settings.h" #include "assets/lang_config.h" #include #include #include #include #include #include #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(arg)->OnNetworkEvent(NetworkEvent::Connected); break; case IOT_ETH_EVENT_DISCONNECTED: ESP_LOGI(TAG, "IOT_ETH_EVENT_DISCONNECTED"); xEventGroupClearBits(static_cast(arg)->s_event_group, EVENT_GOT_IP_BIT); static_cast(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(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(ð_cfg, ð_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