Visualizzazione post con etichetta IDF. Mostra tutti i post
Visualizzazione post con etichetta IDF. Mostra tutti i post

venerdì 14 novembre 2025

Lettura OTG di dispositivo HID con Esp32S3

 Un programma per leggere i messaggi HID da un volante Logitech con Esp32S3 Otg Host

 

## IDF Component Manager Manifest File
dependencies:
idf: '>=4.4'
usb_host_hid: ^1.0.1
m5stack/m5unified: '*'


 

 

/*
* SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Unlicense OR CC0-1.0
*/

#include <stdio.h>
#include <stdbool.h>
#include <string.h>
#include <unistd.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/event_groups.h"
#include "freertos/queue.h"
#include "esp_err.h"
#include "esp_log.h"
#include "usb/usb_host.h"
#include "errno.h"
#include "driver/gpio.h"

#include "usb/hid_host.h"
#include "usb/hid_usage_keyboard.h"
#include "usb/hid_usage_mouse.h"
#include "m5_wrapper.h"

/* GPIO Pin number for quit from example logic */
#define APP_QUIT_PIN GPIO_NUM_0

/* Logitech device VID:PID */
#define LOGITECH_VID 0x046D
#define LOGITECH_PID 0xC262

static const char *TAG = "logitech_hid";

QueueHandle_t app_event_queue = NULL;
static bool is_logitech_device = false;
static usb_host_client_handle_t usb_client_hdl = NULL;

/**
* @brief APP event group
*
* Application logic can be different. There is a one among other ways to distinguish the
* event by application event group.
* In this example we have two event groups:
* APP_EVENT - General event, which is APP_QUIT_PIN press event (Generally, it is IO0).
* APP_EVENT_HID_HOST - HID Host Driver event, such as device connection/disconnection or input report.
*/
typedef enum {
APP_EVENT = 0,
APP_EVENT_HID_HOST
} app_event_group_t;

/**
* @brief APP event queue
*
* This event is used for delivering the HID Host event from callback to a task.
*/
typedef struct {
app_event_group_t event_group;
/* HID Host - Device related info */
struct {
hid_host_device_handle_t handle;
hid_host_driver_event_t event;
void *arg;
} hid_host_device;
} app_event_queue_t;

/**
* @brief HID Protocol string names
*/
static const char *hid_proto_name_str[] = {
"NONE",
"KEYBOARD",
"MOUSE"
};

/**
* @brief USB HID Host Generic Interface report callback handler
*
* Prints raw data and checks for 10-byte messages from Logitech device
*
* @param[in] data Pointer to input report data buffer
* @param[in] length Length of input report data buffer
*/
static void hid_host_generic_report_callback(const uint8_t *const data, const int length)
{
// Print raw data
printf("Data [%d bytes]: ", length);
for (int i = 0; i < length; i++) {
printf("%02X ", data[i]);
}
// Check if it's the Logitech device and message is 10 bytes
if (is_logitech_device && length == 10) {
for (int i = 0; i < length; i++) {
int sterzo = data[5]*256 +data[4];
int acceleratore = data[6];
int freno = data[7];
m5_clear();
m5_set_text_size(2);
m5_set_cursor(5,5);
m5_print_int(sterzo);
m5_set_cursor(5,15);
m5_print_int(acceleratore);
m5_set_cursor(5,25);
m5_print_int(freno);
}
printf("logitech");
}
printf("\r\n");
fflush(stdout);
}

/**
* @brief USB HID Host interface callback
*
* @param[in] hid_device_handle HID Device handle
* @param[in] event HID Host interface event
* @param[in] arg Pointer to arguments, does not used
*/
void hid_host_interface_callback(hid_host_device_handle_t hid_device_handle,
const hid_host_interface_event_t event,
void *arg)
{
uint8_t data[64] = { 0 };
size_t data_length = 0;
hid_host_dev_params_t dev_params;
ESP_ERROR_CHECK(hid_host_device_get_params(hid_device_handle, &dev_params));

switch (event) {
case HID_HOST_INTERFACE_EVENT_INPUT_REPORT:
ESP_ERROR_CHECK(hid_host_device_get_raw_input_report_data(hid_device_handle,
data,
64,
&data_length));

hid_host_generic_report_callback(data, data_length);

break;
case HID_HOST_INTERFACE_EVENT_DISCONNECTED:
ESP_LOGI(TAG, "HID Device, protocol '%s' DISCONNECTED",
hid_proto_name_str[dev_params.proto]);
ESP_ERROR_CHECK(hid_host_device_close(hid_device_handle));
is_logitech_device = false;
break;
case HID_HOST_INTERFACE_EVENT_TRANSFER_ERROR:
ESP_LOGI(TAG, "HID Device, protocol '%s' TRANSFER_ERROR",
hid_proto_name_str[dev_params.proto]);
break;
default:
ESP_LOGE(TAG, "HID Device, protocol '%s' Unhandled event",
hid_proto_name_str[dev_params.proto]);
break;
}
}

/**
* @brief USB Host client event callback
* Used to get VID/PID during enumeration
*/
static void client_event_cb(const usb_host_client_event_msg_t *event_msg, void *arg)
{
usb_host_client_handle_t client_hdl = (usb_host_client_handle_t)arg;
if (event_msg->event == USB_HOST_CLIENT_EVENT_NEW_DEV) {
usb_device_handle_t dev_hdl;
ESP_ERROR_CHECK(usb_host_device_open(client_hdl, event_msg->new_dev.address, &dev_hdl));
const usb_device_desc_t *dev_desc;
ESP_ERROR_CHECK(usb_host_get_device_descriptor(dev_hdl, &dev_desc));
uint16_t vid = dev_desc->idVendor;
uint16_t pid = dev_desc->idProduct;
ESP_LOGI(TAG, "USB Device detected - VID:PID %04X:%04X", vid, pid);
if (vid == LOGITECH_VID && pid == LOGITECH_PID) {
is_logitech_device = true;
ESP_LOGI(TAG, "Logitech device 046D:C262 detected!");
}
usb_host_device_close(client_hdl, dev_hdl);
}
}

/**
* @brief USB HID Host Device event
*
* @param[in] hid_device_handle HID Device handle
* @param[in] event HID Host Device event
* @param[in] arg Pointer to arguments, does not used
*/
void hid_host_device_event(hid_host_device_handle_t hid_device_handle,
const hid_host_driver_event_t event,
void *arg)
{
hid_host_dev_params_t dev_params;
ESP_ERROR_CHECK(hid_host_device_get_params(hid_device_handle, &dev_params));

switch (event) {
case HID_HOST_DRIVER_EVENT_CONNECTED:
ESP_LOGI(TAG, "HID Device CONNECTED - Protocol '%s'",
hid_proto_name_str[dev_params.proto]);

const hid_host_device_config_t dev_config = {
.callback = hid_host_interface_callback,
.callback_arg = NULL
};

ESP_ERROR_CHECK(hid_host_device_open(hid_device_handle, &dev_config));
ESP_ERROR_CHECK(hid_host_device_start(hid_device_handle));
break;
default:
break;
}
}

/**
* @brief USB Host client task
*/
static void usb_host_client_task(void *arg)
{
usb_host_client_handle_t client_hdl;
usb_host_client_config_t client_config = {
.is_synchronous = false,
.max_num_event_msg = 5,
.async = {
.client_event_callback = client_event_cb,
.callback_arg = NULL // Will be set after registration
}
};
ESP_ERROR_CHECK(usb_host_client_register(&client_config, &client_hdl));
// Update callback arg with client handle
client_config.async.callback_arg = (void *)client_hdl;
while (1) {
usb_host_client_handle_events(client_hdl, portMAX_DELAY);
}
}

/**
* @brief Start USB Host install and handle common USB host library events while app pin not low
*
* @param[in] arg Not used
*/
static void usb_lib_task(void *arg)
{
const usb_host_config_t host_config = {
.skip_phy_setup = false,
.intr_flags = ESP_INTR_FLAG_LEVEL1,
};

ESP_ERROR_CHECK(usb_host_install(&host_config));
xTaskNotifyGive(arg);

while (true) {
uint32_t event_flags;
usb_host_lib_handle_events(portMAX_DELAY, &event_flags);
// In this example, there is only one client registered
// So, once we deregister the client, this call must succeed with ESP_OK
if (event_flags & USB_HOST_LIB_EVENT_FLAGS_NO_CLIENTS) {
ESP_ERROR_CHECK(usb_host_device_free_all());
break;
}
}

ESP_LOGI(TAG, "USB shutdown");
// Clean up USB Host
vTaskDelay(10); // Short delay to allow clients clean-up
ESP_ERROR_CHECK(usb_host_uninstall());
vTaskDelete(NULL);
}

/**
* @brief BOOT button pressed callback
*
* Signal application to exit the HID Host task
*
* @param[in] arg Unused
*/
static void gpio_isr_cb(void *arg)
{
BaseType_t xTaskWoken = pdFALSE;
const app_event_queue_t evt_queue = {
.event_group = APP_EVENT,
};

if (app_event_queue) {
xQueueSendFromISR(app_event_queue, &evt_queue, &xTaskWoken);
}

if (xTaskWoken == pdTRUE) {
portYIELD_FROM_ISR();
}
}

/**
* @brief HID Host Device callback
*
* Puts new HID Device event to the queue
*
* @param[in] hid_device_handle HID Device handle
* @param[in] event HID Device event
* @param[in] arg Not used
*/
void hid_host_device_callback(hid_host_device_handle_t hid_device_handle,
const hid_host_driver_event_t event,
void *arg)
{
const app_event_queue_t evt_queue = {
.event_group = APP_EVENT_HID_HOST,
// HID Host Device related info
.hid_host_device.handle = hid_device_handle,
.hid_host_device.event = event,
.hid_host_device.arg = arg
};

if (app_event_queue) {
xQueueSend(app_event_queue, &evt_queue, 0);
}
}

void app_main(void)
{
BaseType_t task_created;
app_event_queue_t evt_queue;
ESP_LOGI(TAG, "HID Host for Logitech Device 046D:C262");
m5_init();

// Init BOOT button: Pressing the button simulates app request to exit
// It will disconnect the USB device and uninstall the HID driver and USB Host Lib
const gpio_config_t input_pin = {
.pin_bit_mask = BIT64(APP_QUIT_PIN),
.mode = GPIO_MODE_INPUT,
.pull_up_en = GPIO_PULLUP_ENABLE,
.intr_type = GPIO_INTR_NEGEDGE,
};
ESP_ERROR_CHECK(gpio_config(&input_pin));
ESP_ERROR_CHECK(gpio_install_isr_service(ESP_INTR_FLAG_LEVEL1));
ESP_ERROR_CHECK(gpio_isr_handler_add(APP_QUIT_PIN, gpio_isr_cb, NULL));

/*
* Create usb_lib_task to:
* - initialize USB Host library
* - Handle USB Host events while APP pin in in HIGH state
*/
task_created = xTaskCreatePinnedToCore(usb_lib_task,
"usb_events",
4096,
xTaskGetCurrentTaskHandle(),
2, NULL, 0);
assert(task_created == pdTRUE);

// Wait for notification from usb_lib_task to proceed
ulTaskNotifyTake(false, 1000);

// Create USB host client task to detect VID/PID
task_created = xTaskCreate(usb_host_client_task,
"usb_client",
4096,
NULL,
3, NULL);
assert(task_created == pdTRUE);

/*
* HID host driver configuration
* - create background task for handling low level event inside the HID driver
* - provide the device callback to get new HID Device connection event
*/
const hid_host_driver_config_t hid_host_driver_config = {
.create_background_task = true,
.task_priority = 5,
.stack_size = 4096,
.core_id = 0,
.callback = hid_host_device_callback,
.callback_arg = NULL
};

ESP_ERROR_CHECK(hid_host_install(&hid_host_driver_config));

// Create queue
app_event_queue = xQueueCreate(10, sizeof(app_event_queue_t));

ESP_LOGI(TAG, "Waiting for HID Device to be connected");

while (1) {
// Wait queue
if (xQueueReceive(app_event_queue, &evt_queue, portMAX_DELAY)) {
if (APP_EVENT == evt_queue.event_group) {
// User pressed button
usb_host_lib_info_t lib_info;
ESP_ERROR_CHECK(usb_host_lib_info(&lib_info));
if (lib_info.num_devices == 0) {
// End while cycle
break;
} else {
ESP_LOGW(TAG, "To shutdown example, remove all USB devices and press button again.");
// Keep polling
}
}

if (APP_EVENT_HID_HOST == evt_queue.event_group) {
hid_host_device_event(evt_queue.hid_host_device.handle,
evt_queue.hid_host_device.event,
evt_queue.hid_host_device.arg);
}
}
}

ESP_LOGI(TAG, "HID Driver uninstall");
ESP_ERROR_CHECK(hid_host_uninstall());
gpio_isr_handler_remove(APP_QUIT_PIN);
xQueueReset(app_event_queue);
vQueueDelete(app_event_queue);
}

 

 

 

 

SmartConfig Esp32

SmartConfig e' un metodo per configurare il WiFi di una Esp32 utilizzando una app su smartphone scaricabile dagli store o personalizzabile tramite sorgenti  (EspTouch, Github

https://docs.espressif.com/projects/esp-idf/en/stable/esp32/api-reference/network/esp_smartconfig.html 

Esistono due versioni. In V1 vengono configurati inviando le credenziali di rete a tutti i dispositivi in ascolto 

V1
In V2 si puo' usare il Custom Data per inviare un codice riconosciuto da un solo dispositivo
 
V2

Dopo la configurazione i dati vengono salvati nella memoria NVS cosi' che al prossimo riavvio l'Esp32 riesca a connettersi in automatico al WiFi. Per cancellare la NVS si usa

idf.py erase-flash
 

 // Change from:
ESP_ERROR_CHECK( esp_smartconfig_set_type(SC_TYPE_ESPTOUCH) );

// To:
ESP_ERROR_CHECK( esp_smartconfig_set_type(SC_TYPE_ESPTOUCH_V2) );

menu "SmartConfig Example Configuration"

config LED_GPIO
int "LED GPIO Pin"
default 2
help
GPIO pin for LED status indicator.
Default is GPIO 2 for most ESP32 boards.
ESP32-C3: Try GPIO 8
ESP32-S2/S3: Try GPIO 18 or 48

endmenu


 

 

/*
* ESP32 SmartConfig Example - ESP-IDF
*
* File: main/smartconfig_main.c
*/

#include <string.h>
#include <stdlib.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/event_groups.h"
#include "esp_wifi.h"
#include "esp_event.h"
#include "esp_log.h"
#include "esp_system.h"
#include "nvs_flash.h"
#include "esp_netif.h"
#include "esp_smartconfig.h"
#include "driver/gpio.h"

/* LED GPIO */
#define LED_GPIO CONFIG_LED_GPIO
#define LED_GPIO_DEFAULT 2

/* FreeRTOS event group to signal when we are connected/disconnected */
static EventGroupHandle_t s_wifi_event_group;

/* Event bits */
#define CONNECTED_BIT BIT0
#define ESPTOUCH_DONE_BIT BIT1

static const char *TAG = "smartconfig";

static void smartconfig_task(void * parm);

/* Event handler for WiFi and SmartConfig events */
static void event_handler(void* arg, esp_event_base_t event_base,
int32_t event_id, void* event_data)
{
if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_START) {
ESP_LOGI(TAG, "WiFi station started");
} else if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_DISCONNECTED) {
ESP_LOGI(TAG, "Disconnected from AP");
esp_wifi_connect();
xEventGroupClearBits(s_wifi_event_group, CONNECTED_BIT);
} else if (event_base == IP_EVENT && event_id == IP_EVENT_STA_GOT_IP) {
ip_event_got_ip_t* event = (ip_event_got_ip_t*) event_data;
ESP_LOGI(TAG, "Got IP:" IPSTR, IP2STR(&event->ip_info.ip));
xEventGroupSetBits(s_wifi_event_group, CONNECTED_BIT);
} else if (event_base == SC_EVENT && event_id == SC_EVENT_SCAN_DONE) {
ESP_LOGI(TAG, "Scan done");
} else if (event_base == SC_EVENT && event_id == SC_EVENT_FOUND_CHANNEL) {
ESP_LOGI(TAG, "Found channel");
} else if (event_base == SC_EVENT && event_id == SC_EVENT_GOT_SSID_PSWD) {
ESP_LOGI(TAG, "Got SSID and password");

smartconfig_event_got_ssid_pswd_t *evt = (smartconfig_event_got_ssid_pswd_t *)event_data;
wifi_config_t wifi_config;
uint8_t ssid[33] = { 0 };
uint8_t password[65] = { 0 };
uint8_t rvd_data[33] = { 0 };

bzero(&wifi_config, sizeof(wifi_config_t));
memcpy(wifi_config.sta.ssid, evt->ssid, sizeof(wifi_config.sta.ssid));
memcpy(wifi_config.sta.password, evt->password, sizeof(wifi_config.sta.password));
wifi_config.sta.bssid_set = evt->bssid_set;
if (wifi_config.sta.bssid_set == true) {
memcpy(wifi_config.sta.bssid, evt->bssid, sizeof(wifi_config.sta.bssid));
}

memcpy(ssid, evt->ssid, sizeof(evt->ssid));
memcpy(password, evt->password, sizeof(evt->password));
ESP_LOGI(TAG, "SSID:%s", ssid);
ESP_LOGI(TAG, "PASSWORD:%s", password);
if (evt->type == SC_TYPE_ESPTOUCH_V2) {
ESP_ERROR_CHECK( esp_smartconfig_get_rvd_data(rvd_data, sizeof(rvd_data)) );
ESP_LOGI(TAG, "RVD_DATA:");
for (int i=0; i<33; i++) {
printf("%02x ", rvd_data[i]);
}
printf("\n");
}

ESP_ERROR_CHECK( esp_wifi_disconnect() );
ESP_ERROR_CHECK( esp_wifi_set_config(WIFI_IF_STA, &wifi_config) );
esp_wifi_connect();
} else if (event_base == SC_EVENT && event_id == SC_EVENT_SEND_ACK_DONE) {
xEventGroupSetBits(s_wifi_event_group, ESPTOUCH_DONE_BIT);
}
}

/* Initialize WiFi in station mode */
static void initialise_wifi(void)
{
ESP_ERROR_CHECK(esp_netif_init());
s_wifi_event_group = xEventGroupCreate();
ESP_ERROR_CHECK(esp_event_loop_create_default());
esp_netif_t *sta_netif = esp_netif_create_default_wifi_sta();
assert(sta_netif);

wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
ESP_ERROR_CHECK( esp_wifi_init(&cfg) );

ESP_ERROR_CHECK( esp_event_handler_register(WIFI_EVENT, ESP_EVENT_ANY_ID, &event_handler, NULL) );
ESP_ERROR_CHECK( esp_event_handler_register(IP_EVENT, IP_EVENT_STA_GOT_IP, &event_handler, NULL) );
ESP_ERROR_CHECK( esp_event_handler_register(SC_EVENT, ESP_EVENT_ANY_ID, &event_handler, NULL) );

ESP_ERROR_CHECK( esp_wifi_set_mode(WIFI_MODE_STA) );
ESP_ERROR_CHECK( esp_wifi_start() );
}

/* SmartConfig task */
static void smartconfig_task(void * parm)
{
EventBits_t uxBits;
ESP_ERROR_CHECK( esp_smartconfig_set_type(SC_TYPE_ESPTOUCH) );
smartconfig_start_config_t cfg = SMARTCONFIG_START_CONFIG_DEFAULT();
ESP_ERROR_CHECK( esp_smartconfig_start(&cfg) );
ESP_LOGI(TAG, "SmartConfig started");
ESP_LOGI(TAG, "Use ESPTouch app to configure WiFi");
while (1) {
uxBits = xEventGroupWaitBits(s_wifi_event_group, CONNECTED_BIT | ESPTOUCH_DONE_BIT, true, false, portMAX_DELAY);
if(uxBits & CONNECTED_BIT) {
ESP_LOGI(TAG, "WiFi Connected to AP");
}
if(uxBits & ESPTOUCH_DONE_BIT) {
ESP_LOGI(TAG, "SmartConfig over");
esp_smartconfig_stop();
vTaskDelete(NULL);
}
}
}

/* LED blink task */
static void led_task(void *pvParameters)
{
gpio_reset_pin(LED_GPIO);
gpio_set_direction(LED_GPIO, GPIO_MODE_OUTPUT);
while(1) {
EventBits_t bits = xEventGroupGetBits(s_wifi_event_group);
if (bits & CONNECTED_BIT) {
/* Slow blink when connected */
gpio_set_level(LED_GPIO, 1);
vTaskDelay(100 / portTICK_PERIOD_MS);
gpio_set_level(LED_GPIO, 0);
vTaskDelay(900 / portTICK_PERIOD_MS);
} else {
/* Fast blink during configuration */
gpio_set_level(LED_GPIO, 1);
vTaskDelay(200 / portTICK_PERIOD_MS);
gpio_set_level(LED_GPIO, 0);
vTaskDelay(200 / portTICK_PERIOD_MS);
}
}
}

void app_main(void)
{
ESP_LOGI(TAG, "=== ESP32 SmartConfig Example ===");
/* Initialize NVS */
esp_err_t ret = nvs_flash_init();
if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) {
ESP_ERROR_CHECK(nvs_flash_erase());
ret = nvs_flash_init();
}
ESP_ERROR_CHECK(ret);

/* Initialize WiFi */
initialise_wifi();
/* Try to connect with saved credentials */
ESP_LOGI(TAG, "Attempting connection with saved credentials...");
esp_wifi_connect();
/* Wait 10 seconds for connection */
EventBits_t bits = xEventGroupWaitBits(s_wifi_event_group,
CONNECTED_BIT,
pdFALSE,
pdFALSE,
10000 / portTICK_PERIOD_MS);
if (bits & CONNECTED_BIT) {
ESP_LOGI(TAG, "Connected with saved credentials!");
} else {
ESP_LOGI(TAG, "No saved credentials or connection failed");
ESP_LOGI(TAG, "Starting SmartConfig...");
xTaskCreate(smartconfig_task, "smartconfig_task", 4096, NULL, 3, NULL);
}
/* Start LED task */
xTaskCreate(led_task, "led_task", 2048, NULL, 2, NULL);
}


 

 

 

 

 

Analisi MNF su spettri di riflettanza di plastica

Devo cerca di lavorare su spettri di riflettanza di plastica e la prima domanda e': quale sono le bande significative? Sono partito dal ...