wfview/include/usbcontroller.h
Elliott Liggett 3d76218247 wfview now "gives up" on USB controllers after two connection attempts.
Prior version could block and get stuck infinitely trying to use a
device which is not available.
2026-05-31 20:03:58 -07:00

322 lines
9.3 KiB
C++

#ifndef usbController_H
#define usbController_H
#include "cachingqueue.h"
#include <iostream>
#include <QThread>
#include <QCoreApplication>
#include <QTimer>
#include <QDateTime>
#include <QRect>
#include <QColor>
#include <QVector>
#include <QList>
#include <QMap>
#include <QMutex>
#include <QIODevice>
#include <QtEndian>
#include <QUuid>
#include <QImage>
#include <QPainter>
#include <QImageWriter>
#include <QBuffer>
#include <QSettings>
#include <memory>
#if defined(USB_CONTROLLER) && QT_VERSION < QT_VERSION_CHECK(6,0,0)
#include <QGamepad>
#endif
#if defined(USB_CONTROLLER)
#ifndef Q_OS_WIN
#include "hidapi/hidapi.h"
#else
#include "hidapi.h"
#endif
#ifdef HID_API_VERSION_MAJOR
#ifndef HID_API_MAKE_VERSION
#define HID_API_MAKE_VERSION(mj, mn, p) (((mj) << 24) | ((mn) << 8) | (p))
#endif
#ifndef HID_API_VERSION
#define HID_API_VERSION HID_API_MAKE_VERSION(HID_API_VERSION_MAJOR, HID_API_VERSION_MINOR, HID_API_VERSION_PATCH)
#endif
#if defined(__APPLE__) && HID_API_VERSION >= HID_API_MAKE_VERSION(0, 12, 0)
#include <hidapi/hidapi_darwin.h>
#endif
#if defined(USING_HIDAPI_LIBUSB) && HID_API_VERSION >= HID_API_MAKE_VERSION(0, 12, 0)
#include <hidapi_libusb.h>
#endif
#endif
#endif
#ifndef Q_OS_WIN
#include <unistd.h>
#endif
// Include these so we have the various enums
#include "rigidentities.h"
using namespace std;
#define HIDDATALENGTH 64
#define MAX_STR 255
struct USBTYPE {
USBTYPE(): model(usbNone), manufacturerId(0), productId(0), usage(0), usagePage(0), buttons(0), cols(0), knobs(0), leds(0), maxPayload(0), iconSize(0) {}
USBTYPE(usbDeviceType model,quint32 manufacturerId, quint32 productId , quint32 usage, quint32 usagePage, int buttons, int cols, int knobs, int leds, int maxPayload, int iconSize) :
model(model), manufacturerId(manufacturerId), productId(productId), usage(usage), usagePage(usagePage), buttons(buttons), cols(cols), knobs(knobs), leds(leds), maxPayload(maxPayload), iconSize(iconSize) {}
usbDeviceType model;
quint32 manufacturerId;
quint32 productId;
quint32 usage;
quint32 usagePage;
int buttons; // How many buttons
int cols; // How many columns of buttons
int knobs; // How many knobs
int leds; // how many leds
int maxPayload; // Max allowed payload
int iconSize;
};
struct KNOBVALUE {
int value=0;
int previous=0;
quint8 send=0;
qint64 lastChanged=0;
QString name="";
};
struct USBDEVICE {
USBDEVICE() : detected(false), remove(false), connected(false), uiCreated(false), disabled(false), openAttempts(0), speed(2), timeout(30), brightness(2),orientation(0),
color(Qt::darkGray), lcd(funcNone), sensitivity(1),jogpos(0),shutpos(0),shutMult(0),jogCounter(0),buttons(0),knobs(0),lastusbController(QTime::currentTime()),
lastData(QByteArray(8,0x0)), lastDialPos(0), pages(1),currentPage(1), ledStatus(0x07) {}
USBDEVICE(USBTYPE type) : type(type), detected(false), remove(false), connected(false), uiCreated(false), disabled(false), openAttempts(0), speed(2), timeout(30), brightness(2),orientation(0),
color(Qt::darkGray), lcd(funcNone), sensitivity(1),jogpos(0),shutpos(0),shutMult(0),jogCounter(0),buttons(0),knobs(0),lastusbController(QTime::currentTime()),
lastData(QByteArray(8,0x0)), lastDialPos(0), pages(1),currentPage(1), ledStatus(0x07) {}
USBTYPE type;
bool detected;
bool remove;
bool connected;
bool uiCreated;
bool disabled;
int openAttempts;
quint8 speed;
quint8 timeout;
quint8 brightness;
quint8 orientation;
QColor color;
funcs lcd;
#if defined(USB_CONTROLLER)
hid_device* handle = NULL;
#endif
QString product ;
QString manufacturer;
QString serial;
QString deviceId;
QString path;
int sensitivity;
quint8 jogpos;
quint8 shutpos;
quint8 shutMult;
int jogCounter;
quint32 buttons;
quint32 knobs;
QList<KNOBVALUE> knobValues;
QTime lastusbController;
QByteArray lastData;
quint8 lastDialPos;
QUuid uuid;
int pages;
int currentPage;
QImage image;
quint8 ledStatus;
};
Q_DECLARE_METATYPE(USBDEVICE)
Q_DECLARE_METATYPE(const USBDEVICE*)
enum cmdValueType {cmdValueInc, cmdValueDec, cmdValueAbs };
struct COMMAND {
COMMAND() {}
COMMAND(int index, QString text, usbCommandType cmdType, int command, int value) :
index(index), text(text), cmdType(cmdType), command(command), value(value) {}
COMMAND(int index, QString text, usbCommandType cmdType, int command, quint8 suffix) :
index(index), text(text), cmdType(cmdType), command(command), suffix(suffix) {}
COMMAND(int index, QString text, usbCommandType cmdType, int command, availableBands band) :
index(index), text(text), cmdType(cmdType), command(command), band(band) {}
COMMAND(int index, QString text, usbCommandType cmdType, int command, rigMode_t mode) :
index(index), text(text), cmdType(cmdType), command(command), mode(mode) {}
int index=0;
QString text;
usbCommandType cmdType = commandButton;
int command=funcNone;
quint8 suffix=0x0;
int value=0;
availableBands band=bandGen;
rigMode_t mode=modeLSB;
cmdValueType cmdValue=cmdValueAbs;
};
Q_DECLARE_METATYPE(COMMAND)
Q_DECLARE_METATYPE(QVector<COMMAND>*)
Q_DECLARE_METATYPE(const COMMAND*)
struct BUTTON {
BUTTON() {}
BUTTON(usbDeviceType dev, int num, QRect pos, const QColor textColour, COMMAND* on, COMMAND* off, bool graphics=false, int led=0) :
dev(dev), num(num), name(""), pos(pos), textColour(textColour), onCommand(on), offCommand(off), on(onCommand->text), off(offCommand->text), graphics(graphics), led(led){}
BUTTON(usbDeviceType dev, QString name, QRect pos, const QColor textColour, COMMAND* on, COMMAND* off) :
dev(dev), num(-1), name(name), pos(pos), textColour(textColour), onCommand(on), offCommand(off), on(onCommand->text), off(offCommand->text) {}
usbDeviceType dev;
USBDEVICE* parent = nullptr;
int page=1;
int num;
QString name;
QRect pos;
QColor textColour;
const COMMAND* onCommand = nullptr;
const COMMAND* offCommand = nullptr;
QString on;
QString off;
QString path;
QColor backgroundOn = Qt::lightGray;
QColor backgroundOff = Qt::blue;
QString iconName = "";
QImage* icon = nullptr;
bool toggle = false;
bool isOn = false;
bool graphics = false;
int led = 0;
};
Q_DECLARE_METATYPE(BUTTON)
Q_DECLARE_METATYPE(QVector<BUTTON>*)
struct KNOB {
KNOB() {}
KNOB(usbDeviceType dev, int num, QRect pos, const QColor textColour, COMMAND* command) :
dev(dev), num(num), name(""), pos(pos), textColour(textColour), command(command), cmd(command->text) {}
usbDeviceType dev;
USBDEVICE* parent = nullptr;
int page=1;
int num;
QString name;
QRect pos;
QColor textColour;
const COMMAND* command = nullptr;
QString cmd;
QString path;
int value=0;
};
Q_DECLARE_METATYPE(KNOB)
Q_DECLARE_METATYPE(QVector<KNOB>*)
typedef QMap<QString,USBDEVICE> usbDevMap;
#if defined(USB_CONTROLLER)
class usbController : public QObject
{
Q_OBJECT
public:
usbController();
~usbController();
bool hotPlugEvent(const QByteArray & eventType, void * message, long * result);
public slots:
void init(QMutex* mut,usbDevMap* prefs ,QVector<BUTTON>* buts,QVector<KNOB>* knobs);
void run();
void runTimer();
void receivePTTStatus(bool on);
void programPages(USBDEVICE* dev, int pages);
void programDisable(USBDEVICE* dev, bool disabled);
void sendRequest(USBDEVICE *dev, usbFeatureType feature, int val=0, QString text="", QImage* img=nullptr, QColor* color=nullptr);
void sendToLCD(QImage *img);
void backupController(USBDEVICE* dev, QString file);
void restoreController(USBDEVICE* dev, QString file);
void receiveRigCaps(rigCapabilities* caps);
void receiveCacheItem(cacheItem cache);
signals:
void jogPlus();
void jogMinus();
void sendJog(int counter);
void doShuttle(bool plus, quint8 level);
void button(const COMMAND* cmd);
void initUI(usbDevMap* devs, QVector<BUTTON>* but, QVector<KNOB>* kb, QVector<COMMAND>* cmd, QMutex* mut);
void newDevice(USBDEVICE* dev);
void removeDevice(USBDEVICE* dev);
void setConnected(USBDEVICE* dev);
void changePage(USBDEVICE* dev, int page);
private:
void checkForGamePad();
void checkForControllers();
bool initDevice(USBDEVICE* dev);
void loadButtons();
void loadKnobs();
void loadCommands();
// Process controllers:
void processShuttle(QByteArray data);
int hidStatus = 1;
bool isOpen=false;
int devicesConnected=0;
QVector<BUTTON>* buttonList;
QVector<KNOB>* knobList;
QVector<BUTTON> defaultButtons;
QVector<KNOB> defaultKnobs;
QVector<USBTYPE> knownDevices;
QVector<COMMAND> commands;
usbDevMap* devices;
cachingQueue *queue;
rigCapabilities* rigCaps = nullptr;
#if (QT_VERSION < QT_VERSION_CHECK(6,0,0))
QGamepad* gamepad=nullptr;
#endif
void buttonState(QString but, bool val);
void buttonState(QString but, double val);
QColor currentColour;
QMutex* mutex=nullptr;
COMMAND sendCommand;
QTimer* dataTimer = nullptr;
protected:
};
class usbControllerDev : public QObject
{
Q_OBJECT
};
#endif
#endif