247 lines
7.8 KiB
C++
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(ð_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
|