Page 1 of 1

esp s3 hid and log output

Posted: Tue Jul 01, 2025 9:22 pm
by linred
Hello everyone,

I'm a new member here and also quite new to the world of electronics and microcontroller programming.

I'm currently working on a university project where I need to program an ESP32-S3 board to act as a BadUSB device. However, I'm running into a serious issue: whenever I flash the code, the board goes into a bootloop.

After some research, I found that the problem seems to be caused by this line:

ESP_ERROR_CHECK(tinyusb_driver_install(&tusb_cfg));

I tried replacing it with a safer version:

esp_err_t err = tinyusb_driver_install(&tusb_cfg);
if (err != ESP_OK) {
ESP_LOGE(TAG, "tinyusb_driver_install failed! Code: 0x%x", err);
} else {
ESP_LOGI(TAG, "TinyUSB initialized successfully");
}

But with this change, nothing happens—no logs, no output, no crash, just silence.

Debugging issue:

When I switch the board to HID mode, the USB port stops showing logs from ESP_LOGD.
I also tried connecting via the USB-to-UART interface, but my PC doesn’t detect it. I think it’s because the board doesn't have a built-in USB-to-UART converter.

Is there any way to view logs or debug the code in this situation?
I'm a bit stuck and would really appreciate any help or advice to figure out what's going wrong.

I can share my code if needed.

Thanks in advance!

---------------------------------------------------------------------------------------------------

## CODE ##

---------------------------------------------------------------------------------------------------

#include <stdio.h>
#include <string.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_log.h"
#include "tusb.h"
#include "class/hid/hid_device.h"
#include "tinyusb.h"

// Tag pour les logs ESP
static const char *TAG = "HID_KEYBOARD";

// Le texte à taper (vous pouvez le modifier ici)
static const char *TEXT_TO_TYPE = "Hello World!\nCeci est un test du clavier ESP32-S3.\nMerci de votre attention !";

// Délai entre chaque caractère tapé (en millisecondes)
#define TYPING_DELAY_MS 100

// Délai avant de commencer à taper (en millisecondes)
#define START_DELAY_MS 3000

// Indicateur si USB est connecté et prêt
static bool g_usb_ready = false;

/**
* Configuration du descripteur HID pour le clavier
* Ce descripteur indique à l'ordinateur que notre device est un clavier
*/
static const uint8_t hid_report_descriptor[] = {
TUD_HID_REPORT_DESC_KEYBOARD() // Macro TinyUSB pour un clavier standard
};

/**
* Callback appelé quand le dispositif USB est connecté et reconnu
*/
void tud_mount_cb(void) {
ESP_LOGI(TAG, "USB connecté - Clavier HID prêt !");
g_usb_ready = true;
}

/**
* Callback appelé quand le dispositif USB est déconnecté
*/
void tud_umount_cb(void) {
ESP_LOGI(TAG, "USB déconnecté");
g_usb_ready = false;
}

/**
* Callback pour fournir le descripteur de rapport HID à l'hôte
* L'hôte utilise ce descripteur pour comprendre le format des données
*/
uint8_t const *tud_hid_descriptor_report_cb(uint8_t instance) {
(void) instance; // Paramètre non utilisé
return hid_report_descriptor;
}

/**
* Callback appelé quand l'hôte demande un rapport (non utilisé pour ce projet)
*/
uint16_t tud_hid_get_report_cb(uint8_t instance, uint8_t report_id,
hid_report_type_t report_type, uint8_t *buffer, uint16_t reqlen) {
// Non utilisé dans ce projet simple
(void) instance; (void) report_id; (void) report_type; (void) buffer; (void) reqlen;
return 0;
}

/**
* Callback appelé quand l'hôte envoie un rapport (LED du clavier, etc.)
*/
void tud_hid_set_report_cb(uint8_t instance, uint8_t report_id,
hid_report_type_t report_type, uint8_t const *buffer, uint16_t bufsize) {
// Non utilisé dans ce projet simple
(void) instance; (void) report_id; (void) report_type; (void) buffer; (void) bufsize;
}

/**
* Convertit un caractère ASCII en code de touche HID
* Retourne true si la conversion réussit
*/
static bool char_to_hid_keycode(char c, uint8_t *keycode, uint8_t *modifier) {
*modifier = 0; // Pas de modificateur par défaut
*keycode = 0; // Pas de touche par défaut

// Lettres minuscules (a-z)
if (c >= 'a' && c <= 'z') {
*keycode = HID_KEY_A + (c - 'a'); // HID_KEY_A = 4, HID_KEY_B = 5, etc.
return true;
}

// Lettres majuscules (A-Z) - nécessite Shift
if (c >= 'A' && c <= 'Z') {
*keycode = HID_KEY_A + (c - 'A');
*modifier = KEYBOARD_MODIFIER_LEFTSHIFT; // Appuie sur Shift
return true;
}

// Chiffres (0-9)
if (c >= '1' && c <= '9') {
*keycode = HID_KEY_1 + (c - '1'); // HID_KEY_1 = 30, HID_KEY_2 = 31, etc.
return true;
}
if (c == '0') {
*keycode = HID_KEY_0; // HID_KEY_0 = 39
return true;
}

// Caractères spéciaux les plus courants
switch (c) {
case ' ': // Espace
*keycode = HID_KEY_SPACE;
break;
case '\n': // Nouvelle ligne (Entrée)
*keycode = HID_KEY_ENTER;
break;
case '\t': // Tabulation
*keycode = HID_KEY_TAB;
break;
case '.': // Point
*keycode = HID_KEY_PERIOD;
break;
case ',': // Virgule
*keycode = HID_KEY_COMMA;
break;
case '!': // Point d'exclamation (Shift + 1)
*keycode = HID_KEY_1;
*modifier = KEYBOARD_MODIFIER_LEFTSHIFT;
break;
case '?': // Point d'interrogation (Shift + /)
*keycode = HID_KEY_SLASH;
*modifier = KEYBOARD_MODIFIER_LEFTSHIFT;
break;
case '-': // Tiret
*keycode = HID_KEY_MINUS;
break;
case '_': // Underscore (Shift + -)
*keycode = HID_KEY_MINUS;
*modifier = KEYBOARD_MODIFIER_LEFTSHIFT;
break;
case ':': // Deux points (Shift + ;)
*keycode = HID_KEY_SEMICOLON;
*modifier = KEYBOARD_MODIFIER_LEFTSHIFT;
break;
default:
// Caractère non supporté - on l'ignore
ESP_LOGW(TAG, "Caractère non supporté: '%c' (0x%02X)", c, c);
return false;
}

return true;
}

/**
* Envoie une touche via le protocole HID
* Simule l'appui puis le relâchement d'une touche
*/
static bool send_hid_key(uint8_t keycode, uint8_t modifier) {
// Vérifie que l'interface HID est prête à recevoir des données
if (!tud_hid_ready()) {
ESP_LOGW(TAG, "Interface HID non prête");
return false;
}

// Prépare le rapport clavier : 6 touches max simultanées
uint8_t keycodes[6] = {keycode, 0, 0, 0, 0, 0};

// Envoie la touche appuyée (avec modificateur si nécessaire)
if (!tud_hid_keyboard_report(HID_ITF_PROTOCOL_KEYBOARD, modifier, keycodes)) {
ESP_LOGE(TAG, "Échec envoi touche appuyée");
return false;
}

// Petit délai pour que l'hôte traite l'appui
vTaskDelay(pdMS_TO_TICKS(10));

// Attend que le rapport précédent soit traité
while (!tud_hid_ready()) {
vTaskDelay(pdMS_TO_TICKS(1));
}

// Envoie le relâchement (rapport vide = aucune touche appuyée)
uint8_t empty_keycodes[6] = {0, 0, 0, 0, 0, 0};
if (!tud_hid_keyboard_report(HID_ITF_PROTOCOL_KEYBOARD, 0, empty_keycodes)) {
ESP_LOGE(TAG, "Échec envoi touche relâchée");
return false;
}

return true;
}

/**
* Ouvre un éditeur de texte automatiquement
* Utilise Win+R puis tape "notepad" (Windows)
* Pour Linux/Mac, modifiez cette fonction
*/
static void open_text_editor(void) {
ESP_LOGI(TAG, "Ouverture de l'éditeur de texte...");

// Attend que le système soit stable
vTaskDelay(pdMS_TO_TICKS(1000));

// Windows: Touche Windows + R pour ouvrir "Exécuter"
ESP_LOGI(TAG, "Appui sur Win+R");
send_hid_key(HID_KEY_R, KEYBOARD_MODIFIER_LEFTGUI);
vTaskDelay(pdMS_TO_TICKS(800)); // Attend que la boîte s'ouvre

// Tape "notepad" pour ouvrir le Bloc-notes
ESP_LOGI(TAG, "Tape 'notepad'");
const char *editor_cmd = "notepad";
for (int i = 0; editor_cmd != '\0'; i++) {
uint8_t keycode, modifier;
if (char_to_hid_keycode(editor_cmd, &keycode, &modifier)) {
send_hid_key(keycode, modifier);
vTaskDelay(pdMS_TO_TICKS(50)); // Délai entre chaque lettre
}
}

// Appuie sur Entrée pour exécuter la commande
ESP_LOGI(TAG, "⏎ Appui sur Entrée");
send_hid_key(HID_KEY_ENTER, 0);

// Attend que l'éditeur s'ouvre complètement
ESP_LOGI(TAG, "Attente ouverture éditeur...");
vTaskDelay(pdMS_TO_TICKS(2000));

ESP_LOGI(TAG, "Éditeur ouvert !");
}

/**
* Tape le texte caractère par caractère
*/
static void type_text(const char *text) {
if (!text) {
ESP_LOGE(TAG, "Texte vide !");
return;
}

int text_length = strlen(text);
ESP_LOGI(TAG, "Début frappe : %d caractères", text_length);

// Parcourt chaque caractère du texte
for (int i = 0; i < text_length; i++) {
char c = text;
uint8_t keycode, modifier;

// Convertit le caractère en touche HID
if (char_to_hid_keycode(c, &keycode, &modifier)) {
// Envoie la touche
if (send_hid_key(keycode, modifier)) {
// Affiche le caractère tapé (sauf pour les caractères spéciaux)
if (c >= 32 && c <= 126) { // Caractères imprimables
ESP_LOGD(TAG, "Tapé: '%c'", c);
} else if (c == '\n') {
ESP_LOGD(TAG, "Tapé: [ENTRÉE]");
} else {
ESP_LOGD(TAG, "Tapé: [0x%02X]", c);
}

// Délai entre chaque caractère pour une frappe naturelle
vTaskDelay(pdMS_TO_TICKS(TYPING_DELAY_MS));
} else {
ESP_LOGE(TAG, "Échec envoi caractère '%c' à la position %d", c, i);
break; // Arrête en cas d'erreur
}
}
// Si le caractère n'est pas supporté, on continue (déjà loggé dans char_to_hid_keycode)

// Affiche la progression tous les 20 caractères
if ((i + 1) % 20 == 0) {
ESP_LOGI(TAG, "Progression: %d/%d caractères", i + 1, text_length);
}
}

ESP_LOGI(TAG, "Frappe terminée avec succès !");
}

/**
* Tâche principale qui gère le clavier HID
*/
static void keyboard_task(void *pvParameters) {
ESP_LOGI(TAG, "Démarrage de la tâche clavier HID");

// Attend que l'USB soit connecté et reconnu
while (!g_usb_ready) {
ESP_LOGI(TAG, "Attente connexion USB...");
vTaskDelay(pdMS_TO_TICKS(1000));
}

// Délai supplémentaire pour s'assurer que l'hôte est complètement prêt
ESP_LOGI(TAG, "Attente %d secondes avant de commencer...", START_DELAY_MS / 1000);
vTaskDelay(pdMS_TO_TICKS(START_DELAY_MS));

ESP_LOGI(TAG, "Début de la séquence automatique");

// Étape 1: Ouvre l'éditeur de texte
open_text_editor();

// Étape 2: Tape le texte prédéfini
type_text(TEXT_TO_TYPE);

ESP_LOGI(TAG, "Séquence terminée - En attente...");

// La tâche reste active pour maintenir la connexion USB
while (1) {
vTaskDelay(pdMS_TO_TICKS(5000));
ESP_LOGI(TAG, "Clavier toujours actif...");
}
}

/**
* Fonction principale de l'application
*/
void app_main(void) {
esp_log_level_set("*", ESP_LOG_VERBOSE); // Enable all logging
esp_log_level_set("TinyUSB", ESP_LOG_DEBUG);
esp_log_level_set("tusb", ESP_LOG_DEBUG);

ESP_LOGI(TAG, "");
ESP_LOGI(TAG, "================================");
ESP_LOGI(TAG, " ESP32-S3 HID Keyboard Demo ");
ESP_LOGI(TAG, " Version Simple v1.0 ");
ESP_LOGI(TAG, "================================");
ESP_LOGI(TAG, "");

// Initialise le stack TinyUSB
ESP_LOGI(TAG, "Initialisation TinyUSB...");

// Configuration de TinyUSB avec les paramètres par défaut
tinyusb_config_t tusb_cfg = {
.device_descriptor = NULL, // Utilise le descripteur par défaut
.string_descriptor = NULL, // Utilise les chaînes par défaut
.external_phy = false, // Utilise le PHY USB interne de l'ESP32-S3
.configuration_descriptor = NULL, // Utilise la configuration par défaut
};


esp_err_t err = tinyusb_driver_install(&tusb_cfg);
if (err != ESP_OK) {
ESP_LOGE(TAG, "tinyusb_driver_install failed! Code: 0x%x", err);
} else {
ESP_LOGI(TAG, "TinyUSB initialisé avec succès");
}

ESP_LOGI(TAG, "TinyUSB initialisé avec succès");

// Affiche les instructions à l'utilisateur
ESP_LOGI(TAG, "");
ESP_LOGI(TAG, "Instructions:");
ESP_LOGI(TAG, " 1. Connectez l'ESP32-S3 à votre PC via USB");
ESP_LOGI(TAG, " 2. Le PC reconnaîtra un nouveau clavier");
ESP_LOGI(TAG, " 3. Attendez 3 secondes après la connexion");
ESP_LOGI(TAG, " 4. L'ESP32 ouvrira automatiquement le Bloc-notes");
ESP_LOGI(TAG, " 5. Il tapera ensuite le message prédéfini");
ESP_LOGI(TAG, "");
ESP_LOGI(TAG, " Texte qui sera tapé:");
ESP_LOGI(TAG, " \"%s\"", TEXT_TO_TYPE);
ESP_LOGI(TAG, "");


// Crée la tâche principale du clavier
// Stack de 8192 bytes, priorité 5
xTaskCreate(keyboard_task, "keyboard_task", 8192, NULL, 5, NULL);

ESP_LOGI(TAG, "Application démarrée !");
ESP_LOGI(TAG, "Connectez maintenant l'ESP32-S3 à votre PC...");
}