fx2_ll: check load_firmware return code. Added some progressbar. Allows caller to set the alternate setting for an interface. Expose windex in write_ctrl/read_ctrl

This commit is contained in:
Gwenhael Goavec-Merou 2026-05-13 16:25:54 +02:00
parent 22e782ac95
commit ef92800ac3
2 changed files with 46 additions and 12 deletions

View File

@ -14,7 +14,7 @@
#include "display.hpp"
#include "fx2_ll.hpp"
#include "ihexParser.hpp"
#include "progressBar.hpp"
#define FX2_FIRM_LOAD 0xA0
#define FX2_GCR_CPUCS 0xe600
@ -42,27 +42,36 @@ FX2_ll::FX2_ll(uint16_t uninit_vid, uint16_t uninit_pid,
throw std::runtime_error("claim interface failed");
}
/* load firmware */
load_firmware(firmware_path);
if (!load_firmware(firmware_path)) {
libusb_close(dev_handle);
libusb_exit(usb_ctx);
throw std::runtime_error("fx2 firmware load failed");
}
close();
reenum = true;
}
}
/* try to open an already init device
* since fx2 may be not immediately ready
* since fx2 may be not immediatly ready
* retry with a delay
*/
ProgressBar progress("Waiting reload", 100, 50, false);
int timeout = 100;
do {
dev_handle = libusb_open_device_with_vid_pid(usb_ctx,
vid, pid);
timeout--;
progress.display(100-timeout);
if (!dev_handle)
sleep(1);
} while (!dev_handle && timeout > 0 && reenum);
if (!dev_handle)
if (!dev_handle) {
progress.fail();
throw std::runtime_error("FX2: fail to open device");
}
progress.done();
ret = libusb_claim_interface(dev_handle, 0);
if (ret) {
@ -72,6 +81,18 @@ FX2_ll::FX2_ll(uint16_t uninit_vid, uint16_t uninit_pid,
}
}
bool FX2_ll::set_interface_alt_setting(const int if_num, const int alt_setting)
{
const int ret = libusb_set_interface_alt_setting(dev_handle, if_num,
alt_setting);
if (ret && ret != LIBUSB_ERROR_NOT_FOUND) {
printWarn("unable to select alternate interface 1: "
+ std::string(libusb_error_name(ret)));
return false;
}
return true;
}
/* destructor: close current device and
* destroy context
*/
@ -134,11 +155,11 @@ int FX2_ll::read(uint8_t endpoint, uint8_t *buff, uint16_t len)
/* write len data using control
*/
int FX2_ll::write_ctrl(uint8_t bRequest, uint16_t wValue,
uint8_t *buff, uint16_t len)
uint8_t *buff, uint16_t len, uint16_t wIndex)
{
int ret = libusb_control_transfer(dev_handle,
LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_ENDPOINT_OUT,
bRequest, wValue, 0x0000, buff, len, 100);
bRequest, wValue, wIndex, buff, len, 100);
if (ret < 0) {
printError("Unable to send control request: "
+ std::string(libusb_error_name(ret)));
@ -150,11 +171,11 @@ int FX2_ll::write_ctrl(uint8_t bRequest, uint16_t wValue,
/* read len data using control
*/
int FX2_ll::read_ctrl(uint8_t bRequest, uint16_t wValue,
uint8_t *buff, uint16_t len)
uint8_t *buff, uint16_t len, uint16_t wIndex)
{
int ret = libusb_control_transfer(dev_handle,
LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_ENDPOINT_IN,
bRequest, wValue, 0x0000, buff, len, 100);
bRequest, wValue, wIndex, buff, len, 100);
if (ret < 0) {
printError("Unable to read control request: "
+ std::string(libusb_error_name(ret)));
@ -177,6 +198,7 @@ bool FX2_ll::load_firmware(std::string firmware_path)
return false;
/* load */
std::vector<IhexParser::data_line_t> data = ihex.getDataArray();
ProgressBar progress("Loading firmware", data.size(), 50, false);
for (size_t i = 0; i < data.size(); i++) {
IhexParser::data_line_t data_line = data[i];
@ -186,14 +208,16 @@ bool FX2_ll::load_firmware(std::string firmware_path)
while (toSend > 0) {
uint16_t xfer_len = (toSend > 64) ? 64: toSend;
if (!write_ctrl(FX2_FIRM_LOAD, addr, tx_buff, xfer_len)) {
printError("load firmware failed\n");
progress.fail();
return false;
}
toSend -= xfer_len;
tx_buff += xfer_len;
addr += xfer_len;
}
progress.display(i);
}
progress.done();
/* unset reset */
if (!reset(0))

View File

@ -1,6 +1,6 @@
// SPDX-License-Identifier: Apache-2.0
/*
* Copyright (c) 2021 Gwenhael Goavec-Merou <gwenhael.goavec-merou@trabucayre.com>
* Copyright (c) 2021-2026 Gwenhael Goavec-Merou <gwenhael.goavec-merou@trabucayre.com>
*/
#ifndef SRC_FX2_LL_HPP_
@ -31,6 +31,14 @@ class FX2_ll {
uint16_t vid, uint16_t pid, const std::string &firmware_path);
~FX2_ll();
/*!
* \brief libusb_set_interface_alt_setting wrapper
* \param[in] if_num: Interface number
* \param[in] alt_setting: alternate setting
* \return true on success
*/
bool set_interface_alt_setting(const int if_num, const int alt_setting);
/*!
* \brief bulk write
* \param[in] endpoint: endpoint to use
@ -53,20 +61,22 @@ class FX2_ll {
* \param[in] wValue
* \param[in] buff: buffer to write
* \param[in] len: buffer length
* \param[in] wIndex: the index field for the setup packet
* \return false when transfer fails, true otherwise
*/
int write_ctrl(uint8_t bRequest, uint16_t wValue,
uint8_t *buff, uint16_t len);
uint8_t *buff, uint16_t len, uint16_t wIndex=0x0000);
/*!
* \brief control write
* \param[in] bRequest
* \param[in] wValue
* \param[in] buff: buffer to write
* \param[in] len: buffer length
* \param[in] wIndex: the index field for the setup packet
* \return false when transfer fails, true otherwise
*/
int read_ctrl(uint8_t bRequest, uint16_t wValue,
uint8_t *buff, uint16_t len);
uint8_t *buff, uint16_t len, uint16_t wIndex=0x0000);
private:
/*!