fx2_ll: cypress fx2 low level
This commit is contained in:
parent
c09bc0662b
commit
dc884b86c8
|
|
@ -0,0 +1,219 @@
|
|||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
/*
|
||||
* Copyright (c) 2021 Gwenhael Goavec-Merou <gwenhael.goavec-merou@trabucayre.com>
|
||||
*/
|
||||
|
||||
#include <libusb.h>
|
||||
#include <stdint.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "display.hpp"
|
||||
#include "fx2_ll.hpp"
|
||||
#include "ihexParser.hpp"
|
||||
|
||||
using namespace std;
|
||||
|
||||
#define FX2_FIRM_LOAD 0xA0
|
||||
#define FX2_GCR_CPUCS 0xe600
|
||||
#define FX2_GCR_CPUCS_8051_RES (1 << 0)
|
||||
|
||||
FX2_ll::FX2_ll(uint16_t uninit_vid, uint16_t uninit_pid,
|
||||
uint16_t vid, uint16_t pid, const string &firmware_path)
|
||||
{
|
||||
int ret;
|
||||
bool reenum = false;
|
||||
|
||||
if (libusb_init(&usb_ctx) < 0) {
|
||||
throw std::runtime_error("libusb init failed");
|
||||
}
|
||||
|
||||
/* try to open uninitialized device */
|
||||
if (uninit_vid != -1 && uninit_pid != -1) {
|
||||
dev_handle = libusb_open_device_with_vid_pid(usb_ctx,
|
||||
uninit_vid, uninit_pid);
|
||||
if (dev_handle) {
|
||||
ret = libusb_claim_interface(dev_handle, 0);
|
||||
if (ret) {
|
||||
libusb_close(dev_handle);
|
||||
libusb_exit(usb_ctx);
|
||||
throw std::runtime_error("claim interface failed");
|
||||
}
|
||||
/* load firmware */
|
||||
load_firmware(firmware_path);
|
||||
close();
|
||||
reenum = true;
|
||||
}
|
||||
}
|
||||
|
||||
/* try to open an already init device
|
||||
* since fx2 may be not immediatly ready
|
||||
* retry with a delay
|
||||
*/
|
||||
int timeout = 100;
|
||||
do {
|
||||
dev_handle = libusb_open_device_with_vid_pid(usb_ctx,
|
||||
vid, pid);
|
||||
timeout--;
|
||||
if (!dev_handle)
|
||||
sleep(1);
|
||||
} while (!dev_handle && timeout > 0 && reenum);
|
||||
|
||||
if (!dev_handle)
|
||||
throw std::runtime_error("FX2: fail to open device");
|
||||
|
||||
ret = libusb_claim_interface(dev_handle, 0);
|
||||
if (ret) {
|
||||
libusb_close(dev_handle);
|
||||
libusb_exit(usb_ctx);
|
||||
throw std::runtime_error("claim interface failed");
|
||||
}
|
||||
}
|
||||
|
||||
/* destructor: close current device and
|
||||
* destroy context
|
||||
*/
|
||||
FX2_ll::~FX2_ll()
|
||||
{
|
||||
close();
|
||||
libusb_exit(usb_ctx);
|
||||
}
|
||||
|
||||
/* close device after releasing interface
|
||||
*/
|
||||
bool FX2_ll::close()
|
||||
{
|
||||
if (dev_handle) {
|
||||
int ret;
|
||||
ret = libusb_release_interface(dev_handle, 0);
|
||||
if (ret != 0) {
|
||||
/* device is already disconnected ... */
|
||||
if (ret == LIBUSB_ERROR_NO_DEVICE) {
|
||||
return true;
|
||||
} else {
|
||||
printError("Error: Fail to release interface");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
libusb_close(dev_handle);
|
||||
dev_handle = NULL;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/* write len byte in bulk using endpoint
|
||||
*/
|
||||
int FX2_ll::write(uint8_t endpoint, uint8_t *buff, uint16_t len)
|
||||
{
|
||||
int ret, actual_length;
|
||||
ret = libusb_bulk_transfer(dev_handle, LIBUSB_ENDPOINT_OUT | endpoint,
|
||||
buff, len, &actual_length, 1000);
|
||||
if (ret != LIBUSB_SUCCESS) {
|
||||
printError("FX2 write error: " + std::string(libusb_error_name(ret)));
|
||||
return -1;
|
||||
}
|
||||
return actual_length;
|
||||
}
|
||||
|
||||
/* read len byte in bulk using endpoint
|
||||
*/
|
||||
int FX2_ll::read(uint8_t endpoint, uint8_t *buff, uint16_t len)
|
||||
{
|
||||
int ret, actual_length;
|
||||
ret = libusb_bulk_transfer(dev_handle, LIBUSB_ENDPOINT_IN | endpoint,
|
||||
buff, len, &actual_length, 1000);
|
||||
if (ret != LIBUSB_SUCCESS) {
|
||||
printError("FX2 read error: " + std::string(libusb_error_name(ret)));
|
||||
return -1;
|
||||
}
|
||||
return actual_length;
|
||||
}
|
||||
|
||||
/* write len data using control
|
||||
*/
|
||||
int FX2_ll::write_ctrl(uint8_t bRequest, uint16_t wValue,
|
||||
uint8_t *buff, uint16_t len)
|
||||
{
|
||||
int ret = libusb_control_transfer(dev_handle,
|
||||
LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_ENDPOINT_OUT,
|
||||
bRequest, wValue, 0x0000, buff, len, 100);
|
||||
if (ret < 0) {
|
||||
printError("Unable to send control request: "
|
||||
+ std::string(libusb_error_name(ret)));
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/* read len data using control
|
||||
*/
|
||||
int FX2_ll::read_ctrl(uint8_t bRequest, uint16_t wValue,
|
||||
uint8_t *buff, uint16_t len)
|
||||
{
|
||||
int ret = libusb_control_transfer(dev_handle,
|
||||
LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_ENDPOINT_IN,
|
||||
bRequest, wValue, 0x0000, buff, len, 100);
|
||||
if (ret < 0) {
|
||||
printError("Unable to read control request: "
|
||||
+ std::string(libusb_error_name(ret)));
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/* load firmware section by section
|
||||
* and 64B by 64B
|
||||
* set CPU in reset state before and restart after
|
||||
*/
|
||||
bool FX2_ll::load_firmware(string firmware_path)
|
||||
{
|
||||
IhexParser ihex(firmware_path, false, true);
|
||||
ihex.parse();
|
||||
|
||||
/* reset */
|
||||
if (!reset(1))
|
||||
return false;
|
||||
/* load */
|
||||
vector<IhexParser::data_line_t> data = ihex.getDataArray();
|
||||
for (size_t i = 0; i < data.size(); i++) {
|
||||
IhexParser::data_line_t data_line = data[i];
|
||||
|
||||
uint16_t toSend = data_line.length;
|
||||
uint8_t *tx_buff = data_line.line_data.data();
|
||||
uint16_t addr = data_line.addr;
|
||||
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");
|
||||
return false;
|
||||
}
|
||||
toSend -= xfer_len;
|
||||
tx_buff += xfer_len;
|
||||
addr += xfer_len;
|
||||
}
|
||||
}
|
||||
|
||||
/* unset reset */
|
||||
if (!reset(0))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
/* set or unset 8051RES in CPUCS register
|
||||
*/
|
||||
bool FX2_ll::reset(uint8_t res8051)
|
||||
{
|
||||
unsigned char buf[1];
|
||||
int ret;
|
||||
|
||||
buf[0] = res8051;
|
||||
if (!(ret = write_ctrl(FX2_FIRM_LOAD, FX2_GCR_CPUCS, buf, 1))) {
|
||||
printError("Unable to send control request: "
|
||||
+ std::string(libusb_error_name(ret)));
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
|
@ -0,0 +1,90 @@
|
|||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
/*
|
||||
* Copyright (c) 2021 Gwenhael Goavec-Merou <gwenhael.goavec-merou@trabucayre.com>
|
||||
*/
|
||||
|
||||
#ifndef SRC_FX2_LL_HPP_
|
||||
#define SRC_FX2_LL_HPP_
|
||||
|
||||
#include <libusb.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include <string>
|
||||
|
||||
/*!
|
||||
* \file fx2_ll
|
||||
* \class FX2_ll
|
||||
* \brief low level driver for cypress fx2 device
|
||||
* \author Gwenhael Goavec-Merou
|
||||
*/
|
||||
class FX2_ll {
|
||||
public:
|
||||
/*!
|
||||
* \brief constructor
|
||||
* \param[in] uninit_vid: vendor ID for uninitialized device
|
||||
* \param[in] uninit_pid: product ID for uninitialized device
|
||||
* \param[in] vid: vendor ID for initialized device
|
||||
* \param[in] pid: product ID for initialized device
|
||||
* \param[in] firmware_path: firmware to load
|
||||
*/
|
||||
FX2_ll(uint16_t uninit_vid, uint16_t uninit_pid,
|
||||
uint16_t vid, uint16_t pid, const std::string &firmware_path);
|
||||
~FX2_ll();
|
||||
|
||||
/*!
|
||||
* \brief bulk write
|
||||
* \param[in] endpoint: endpoint to use
|
||||
* \param[in] buff: buffer to write
|
||||
* \param[in] len: buffer length
|
||||
* \return -1 when transfer fails, number of bytes otherwise
|
||||
*/
|
||||
int write(uint8_t endpoint, uint8_t *buff, uint16_t len);
|
||||
/*!
|
||||
* \brief bulk read
|
||||
* \param[in] endpoint: endpoint to use
|
||||
* \param[in] buff: buffer to fill
|
||||
* \param[in] len: buffer length
|
||||
* \return -1 when transfer fails, number of bytes otherwise
|
||||
*/
|
||||
int read(uint8_t endpoint, uint8_t *buff, uint16_t len);
|
||||
/*!
|
||||
* \brief control write
|
||||
* \param[in] bRequest
|
||||
* \param[in] wValue
|
||||
* \param[in] buff: buffer to write
|
||||
* \param[in] len: buffer length
|
||||
* \return false when transfer fails, true otherwise
|
||||
*/
|
||||
int write_ctrl(uint8_t bRequest, uint16_t wValue,
|
||||
uint8_t *buff, uint16_t len);
|
||||
/*!
|
||||
* \brief control write
|
||||
* \param[in] bRequest
|
||||
* \param[in] wValue
|
||||
* \param[in] buff: buffer to write
|
||||
* \param[in] len: buffer length
|
||||
* \return false when transfer fails, true otherwise
|
||||
*/
|
||||
int read_ctrl(uint8_t bRequest, uint16_t wValue,
|
||||
uint8_t *buff, uint16_t len);
|
||||
|
||||
private:
|
||||
/*!
|
||||
* \brief load firmware into device
|
||||
* \param[in] firmware_path: firmware to load
|
||||
* \return false if reset or firmware load fail
|
||||
*/
|
||||
bool load_firmware(std::string firmware_path);
|
||||
/*!
|
||||
* \brief set/unset reset bit in CPUCS register
|
||||
* \param[in] res8051: set or reset
|
||||
* \return false if something fails
|
||||
*/
|
||||
bool reset(uint8_t res8051);
|
||||
bool close();
|
||||
|
||||
libusb_device_handle *dev_handle;
|
||||
libusb_context *usb_ctx;
|
||||
};
|
||||
#endif // SRC_FX2_LL_HPP_
|
||||
|
||||
Loading…
Reference in New Issue