mirror of
https://github.com/davidgiven/fluxengine.git
synced 2025-10-31 11:17:01 -07:00
171 lines
4.1 KiB
C++
171 lines
4.1 KiB
C++
#include "globals.h"
|
|
#include "flags.h"
|
|
#include "usb.h"
|
|
#include "protocol.h"
|
|
#include "fluxmap.h"
|
|
#include "bytes.h"
|
|
#include <libusb.h>
|
|
#include "fmt/format.h"
|
|
#include "greaseweazle.h"
|
|
|
|
FlagGroup usbFlags;
|
|
|
|
static StringFlag device(
|
|
{ "--device" },
|
|
"serial number of hardware device to use",
|
|
"");
|
|
|
|
static USB* usb = NULL;
|
|
|
|
enum
|
|
{
|
|
DEV_FLUXENGINE,
|
|
DEV_GREASEWEAZLE,
|
|
};
|
|
|
|
struct CandidateDevice
|
|
{
|
|
libusb_device* device;
|
|
libusb_device_descriptor desc;
|
|
int type;
|
|
std::string serial;
|
|
};
|
|
|
|
USB::~USB()
|
|
{}
|
|
|
|
std::string USB::usberror(int i)
|
|
{
|
|
return libusb_strerror((libusb_error) i);
|
|
}
|
|
|
|
static const char* device_type(int i)
|
|
{
|
|
switch (i)
|
|
{
|
|
case DEV_FLUXENGINE: return "FluxEngine";
|
|
case DEV_GREASEWEAZLE: return "GreaseWeazle";
|
|
default: assert(false);
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
static const std::string get_serial_number(libusb_device* device, libusb_device_descriptor* desc)
|
|
{
|
|
std::string serial;
|
|
|
|
libusb_device_handle* handle;
|
|
if (libusb_open(device, &handle) == 0)
|
|
{
|
|
unsigned char buffer[64];
|
|
libusb_get_string_descriptor_ascii(handle, desc->iSerialNumber, buffer, sizeof(buffer));
|
|
serial = (const char*) buffer;
|
|
libusb_close(handle);
|
|
}
|
|
|
|
return serial;
|
|
}
|
|
|
|
static std::map<std::string, std::unique_ptr<CandidateDevice>> get_candidates(libusb_device** devices, int numdevices)
|
|
{
|
|
std::map<std::string, std::unique_ptr<CandidateDevice>> candidates;
|
|
for (int i=0; i<numdevices; i++)
|
|
{
|
|
std::unique_ptr<CandidateDevice> candidate(new CandidateDevice());
|
|
candidate->device = devices[i];
|
|
(void) libusb_get_device_descriptor(devices[i], &candidate->desc);
|
|
|
|
uint32_t id = (candidate->desc.idVendor << 16) | candidate->desc.idProduct;
|
|
switch (id)
|
|
{
|
|
case (FLUXENGINE_VID<<16) | FLUXENGINE_PID:
|
|
{
|
|
candidate->type = DEV_FLUXENGINE;
|
|
candidate->serial = get_serial_number(candidate->device, &candidate->desc);
|
|
candidates[candidate->serial] = std::move(candidate);
|
|
break;
|
|
}
|
|
|
|
case (GREASEWEAZLE_VID<<16) | GREASEWEAZLE_PID:
|
|
{
|
|
candidate->type = DEV_GREASEWEAZLE;
|
|
candidate->serial = get_serial_number(candidate->device, &candidate->desc);
|
|
candidates[candidate->serial] = std::move(candidate);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
return candidates;
|
|
}
|
|
|
|
static void open_device(CandidateDevice& candidate)
|
|
{
|
|
libusb_device_handle* handle;
|
|
int i = libusb_open(candidate.device, &handle);
|
|
if (i < 0)
|
|
Error() << "cannot open USB device: " << libusb_strerror((libusb_error) i);
|
|
|
|
std::cout << "Using " << device_type(candidate.type) << " with serial number " << candidate.serial << '\n';
|
|
switch (candidate.type)
|
|
{
|
|
case DEV_FLUXENGINE:
|
|
usb = createFluxengineUsb(handle);
|
|
break;
|
|
|
|
case DEV_GREASEWEAZLE:
|
|
usb = createGreaseWeazleUsb(handle);
|
|
break;
|
|
}
|
|
}
|
|
|
|
static CandidateDevice& select_candidate(const std::map<std::string, std::unique_ptr<CandidateDevice>>& devices)
|
|
{
|
|
if (devices.size() == 0)
|
|
Error() << "no USB devices found (is one plugged in? Do you have permission to access USB devices?)";
|
|
|
|
if (device.get() == "")
|
|
{
|
|
if (devices.size() == 1)
|
|
return *devices.begin()->second;
|
|
|
|
std::cout << "More than one USB device detected. Use --device to specify which one to use:\n";
|
|
for (auto& i : devices)
|
|
std::cout << " " << device_type(i.second->type) << ": " << i.first << '\n';
|
|
Error() << "specify USB device";
|
|
}
|
|
else
|
|
{
|
|
const auto& i = devices.find(device);
|
|
if (i != devices.end())
|
|
return *i->second;
|
|
|
|
Error() << "device with serial number '" << device.get() << "' not found";
|
|
}
|
|
}
|
|
|
|
USB& getUsb()
|
|
{
|
|
if (!usb)
|
|
{
|
|
int i = libusb_init(NULL);
|
|
if (i < 0)
|
|
Error() << "could not start libusb: " << libusb_strerror((libusb_error) i);
|
|
|
|
libusb_device** devices;
|
|
int numdevices = libusb_get_device_list(NULL, &devices);
|
|
if (numdevices < 0)
|
|
Error() << "could not enumerate USB bus: " << libusb_strerror((libusb_error) numdevices);
|
|
|
|
auto candidates = get_candidates(devices, numdevices);
|
|
auto candidate = select_candidate(candidates);
|
|
open_device(candidate);
|
|
|
|
libusb_free_device_list(devices, true);
|
|
|
|
}
|
|
|
|
return *usb;
|
|
}
|
|
|