Unlocking Custom Programming Mode on Arduino Leonardo: Troubleshooting Code Upload with libusb

Hello, I'm not sure if I've posted in the right category. My goal is to put my Arduino Leonardo board into programming mode using libusb and upload code to it just like in the Arduino IDE. I'm encountering errors while doing this. Please help.

C++ code:

#include <iostream>
#include <libusb.h>

#define YOUR_VENDOR_ID 0x2341
#define YOUR_PRODUCT_ID 0x8036

int main() {
    libusb_device** devices;
    libusb_context* context = nullptr;
    size_t deviceCount;
    int rc;  // Variable to store error codes

    // Initialize Libusb
    rc = libusb_init(&context);
    if (rc != 0) {
        std::cerr << "libusb_init error: " << libusb_error_name(rc) << std::endl;
        return -1;
    }

    // List devices
    deviceCount = libusb_get_device_list(context, &devices);

    for (size_t i = 0; i < deviceCount; i++) {
        libusb_device_descriptor desc;
        rc = libusb_get_device_descriptor(devices[i], &desc);
        if (rc != 0) {
            std::cerr << "libusb_get_device_descriptor error: " << libusb_error_name(rc) << std::endl;
            continue;
        }

        // Identify Atmega32u4 by Vendor ID and Product ID
        if (desc.idVendor == YOUR_VENDOR_ID && desc.idProduct == YOUR_PRODUCT_ID) {
            std::cout << "Atmega32u4 found!" << std::endl;

            libusb_device_handle* handle;
            rc = libusb_open(devices[i], &handle);
            if (rc != 0) {
                std::cerr << "libusb_open error: " << libusb_error_name(rc) << std::endl;
                continue;
            }

            int interface_num = 0;  // Correct interface number for AVR programming

            // Detach kernel driver if it's active
            if (libusb_kernel_driver_active(handle, interface_num)) {
                rc = libusb_detach_kernel_driver(handle, interface_num);
                if (rc != 0) {
                    std::cerr << "libusb_detach_kernel_driver error: " << libusb_error_name(rc) << std::endl;
                    libusb_close(handle);
                    continue;
                }
            }

            // Request the interface
            rc = libusb_claim_interface(handle, interface_num);
            if (rc != 0) {
                std::cerr << "libusb_claim_interface error: " << libusb_error_name(rc) << std::endl;
                libusb_close(handle);
                continue;
            }

            // Send the 'P' command to put Leonardo into programming mode.
            unsigned char programModeCommand = 'P';
            int transferred;

            rc = libusb_bulk_transfer(handle, (2 | LIBUSB_ENDPOINT_OUT), &programModeCommand, 1, &transferred, 5000);
            if (rc != 0 || transferred != 1) {
                std::cerr << "libusb_bulk_transfer OUT error: " << libusb_error_name(rc) << ", transferred: " << transferred << std::endl;
                libusb_release_interface(handle, interface_num);
                libusb_attach_kernel_driver(handle, interface_num);
                libusb_close(handle);
                continue;
            }

            // Receive the device's response
            unsigned char buffer[4];

            rc = libusb_bulk_transfer(handle, (2 | LIBUSB_ENDPOINT_IN), buffer, sizeof(buffer), &transferred, 5000);
            if (rc != 0 || transferred != sizeof(buffer)) {
                std::cerr << "libusb_bulk_transfer IN error: " << libusb_error_name(rc) << ", transferred: " << transferred << std::endl;
                libusb_release_interface(handle, interface_num);
                libusb_attach_kernel_driver(handle, interface_num);
                libusb_close(handle);
                continue;
            }

            if (buffer[0] == '1' && buffer[1] == 'E' && buffer[2] == '9' && buffer[3] == '5') {
                std::cerr << "Arduino Leonardo in programming mode!" << std::endl;
            }
            else {
                std::cerr << "Failed to enter programming mode." << std::endl;
            }

            // Release the interface
            libusb_release_interface(handle, interface_num);
            libusb_attach_kernel_driver(handle, interface_num);
            libusb_close(handle);
        }
    }

    libusb_free_device_list(devices, 1);
    libusb_exit(context);
    return 0;
}

Output:

Atmega32u4 found!
libusb_detach_kernel_driver error: LIBUSB_ERROR_NOT_SUPPORTED

The IDE uses a command line program named avrdude to upload. avrdude is an open source program so you can modify it if desired.

My goal is to write or communicate without using Serial.

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.