esp-rs / esp-idf-sys

Bindings for ESP-IDF (Espressif's IoT Development Framework)
Apache License 2.0
275 stars 124 forks source link

Implementing tinyusb callbacks in rust #301

Closed StefanJo3107 closed 6 months ago

StefanJo3107 commented 6 months ago

I've been tinkering with remote components by including espressif/tinyusb and espressif/esp_tinyusb and generating bindings for them using custom bindings header since these are not in bindings.rs:

#if defined(ESP_IDF_COMP_ESPRESSIF__TINYUSB_ENABLED)
#include "tusb.h"
#include "class/hid/hid_device.h"
#endif

#if defined(ESP_IDF_COMP_ESPRESSIF__ESP_TINYUSB_ENABLED)
#include "tinyusb.h"
#endif

I've tried implementing simple key press report with the following code:

use std::ffi::CString;
use std::{ptr, thread};
use std::time::Duration;
use esp_idf_sys::esptinyusb::{HID_KEY_A, tinyusb_config_t, tinyusb_config_t__bindgen_ty_2, tinyusb_config_t__bindgen_ty_2__bindgen_ty_1, tinyusb_driver_install, tud_hid_n_keyboard_report};
use esp_idf_sys::tinyusb;
use esp_idf_sys::esptinyusb::tinyusb_config_t__bindgen_ty_1;
use esp_idf_sys::tinyusb::tud_mounted;

fn main() {
    // It is necessary to call this function once. Otherwise some patches to the runtime
    // implemented by esp-idf-sys might not link properly. See https://github.com/esp-rs/esp-idf-template/issues/71
    esp_idf_svc::sys::link_patches();

    // Bind the log crate to the ESP Logging facilities
    esp_idf_svc::log::EspLogger::initialize_default();

    log::info!("USB initialization!");

    let tusb_cfg = tinyusb_config_t {
        string_descriptor: unsafe { ptr::null_mut() },
        string_descriptor_count: 0,
        external_phy: false,
        __bindgen_anon_1: unsafe { tinyusb_config_t__bindgen_ty_1 { device_descriptor: ptr::null_mut() } },
        __bindgen_anon_2: unsafe { tinyusb_config_t__bindgen_ty_2 { __bindgen_anon_1: tinyusb_config_t__bindgen_ty_2__bindgen_ty_1 { configuration_descriptor: ptr::null_mut() } } },
        self_powered: false,
        vbus_monitor_io: 0,
    };
    //
    unsafe { tinyusb_driver_install(&tusb_cfg); }

    loop {
        unsafe {
            if tud_mounted() {
                tud_hid_n_keyboard_report(0, 1, 0, [HID_KEY_A as u8, 0, 0, 0, 0, 0].as_mut_ptr());
                thread::sleep(Duration::from_millis(1000));
                tud_hid_n_keyboard_report(0, 1, 0, *ptr::null());
            }
        }
    }
}

but i'm getting these linker errors:

 Error: Linker /home/stefan/Dev/BadUSB/test-remote-comps/.embuild/espressif/tools/xtensa-esp32s3-elf/esp-12.2.0_20230208/xtensa-esp32s3-elf/bin/xtensa-esp32s3-elf-gcc failed: exit status: 1
          STDERR OUTPUT:
          /home/stefan/Dev/BadUSB/test-remote-comps/.embuild/espressif/tools/xtensa-esp32s3-elf/esp-12.2.0_20230208/xtensa-esp32s3-elf/bin/../lib/gcc/xtensa-esp32s3-elf/12.2.0/../../../../xtensa-esp32s3-elf/bin/ld: esp-idf/espressif__tinyusb/libespressif__tinyusb.a(hid_device.c.obj):(.literal.hidd_control_xfer_cb+0x20): undefined reference to `tud_hid_descriptor_report_cb'
          /home/stefan/Dev/BadUSB/test-remote-comps/.embuild/espressif/tools/xtensa-esp32s3-elf/esp-12.2.0_20230208/xtensa-esp32s3-elf/bin/../lib/gcc/xtensa-esp32s3-elf/12.2.0/../../../../xtensa-esp32s3-elf/bin/ld: esp-idf/espressif__tinyusb/libespressif__tinyusb.a(hid_device.c.obj):(.literal.hidd_control_xfer_cb+0x24): undefined reference to `tud_hid_get_report_cb'
          /home/stefan/Dev/BadUSB/test-remote-comps/.embuild/espressif/tools/xtensa-esp32s3-elf/esp-12.2.0_20230208/xtensa-esp32s3-elf/bin/../lib/gcc/xtensa-esp32s3-elf/12.2.0/../../../../xtensa-esp32s3-elf/bin/ld: esp-idf/espressif__tinyusb/libespressif__tinyusb.a(hid_device.c.obj):(.literal.hidd_control_xfer_cb+0x28): undefined reference to `tud_hid_set_report_cb'
          /home/stefan/Dev/BadUSB/test-remote-comps/.embuild/espressif/tools/xtensa-esp32s3-elf/esp-12.2.0_20230208/xtensa-esp32s3-elf/bin/../lib/gcc/xtensa-esp32s3-elf/12.2.0/../../../../xtensa-esp32s3-elf/bin/ld: esp-idf/espressif__tinyusb/libespressif__tinyusb.a(hid_device.c.obj): in function `hidd_control_xfer_cb':
          /home/stefan/Dev/BadUSB/test-remote-comps/target/xtensa-esp32s3-espidf/debug/build/esp-idf-sys-43428ed0b07bdd6c/out/managed_components/espressif__tinyusb/src/class/hid/hid_device.c:262: undefined reference to `tud_hid_descriptor_report_cb'
          /home/stefan/Dev/BadUSB/test-remote-comps/.embuild/espressif/tools/xtensa-esp32s3-elf/esp-12.2.0_20230208/xtensa-esp32s3-elf/bin/../lib/gcc/xtensa-esp32s3-elf/12.2.0/../../../../xtensa-esp32s3-elf/bin/ld: /home/stefan/Dev/BadUSB/test-remote-comps/target/xtensa-esp32s3-espidf/debug/build/esp-idf-sys-43428ed0b07bdd6c/out/managed_components/espressif__tinyusb/src/class/hid/hid_device.c:296: undefined reference to `tud_hid_get_report_cb'
          /home/stefan/Dev/BadUSB/test-remote-comps/.embuild/espressif/tools/xtensa-esp32s3-elf/esp-12.2.0_20230208/xtensa-esp32s3-elf/bin/../lib/gcc/xtensa-esp32s3-elf/12.2.0/../../../../xtensa-esp32s3-elf/bin/ld: /home/stefan/Dev/BadUSB/test-remote-comps/target/xtensa-esp32s3-espidf/debug/build/esp-idf-sys-43428ed0b07bdd6c/out/managed_components/espressif__tinyusb/src/class/hid/hid_device.c:321: undefined reference to `tud_hid_set_report_cb'
          /home/stefan/Dev/BadUSB/test-remote-comps/.embuild/espressif/tools/xtensa-esp32s3-elf/esp-12.2.0_20230208/xtensa-esp32s3-elf/bin/../lib/gcc/xtensa-esp32s3-elf/12.2.0/../../../../xtensa-esp32s3-elf/bin/ld: esp-idf/espressif__tinyusb/libespressif__tinyusb.a(hid_device.c.obj): in function `hidd_xfer_cb':
          /home/stefan/Dev/BadUSB/test-remote-comps/target/xtensa-esp32s3-espidf/debug/build/esp-idf-sys-43428ed0b07bdd6c/out/managed_components/espressif__tinyusb/src/class/hid/hid_device.c:408: undefined reference to `tud_hid_set_report_cb'
          collect2: error: ld returned 1 exit status

          Stack backtrace:
             0: anyhow::error::<impl anyhow::Error>::msg
             1: ldproxy::main
             2: std::sys_common::backtrace::__rust_begin_short_backtrace
             3: std::rt::lang_start::{{closure}}
             4: std::rt::lang_start_internal
             5: main
             6: <unknown>
             7: __libc_start_main
             8: _start

As far as I understand, the problem is unimplemented callback functions which are defined in hid_device.h header, but are left to be implemented in user code. How would I go about implementing these functions in rust and resolving linking issue?

StefanJo3107 commented 6 months ago

It turns out, I just had to add extern "C" function with the same name as the one in C header and add the #[no_mangle] attribute. Huge thanks to a kind redditor: https://www.reddit.com/r/rust/comments/1cb2462/comment/l0vnrhe/?utm_source=share&utm_medium=web3x&utm_name=web3xcss&utm_term=1&utm_content=share_button