#ifndef unixUsbDriver_H #define unixUsbDriver_H #include #include #include #include #include "genericusbdriver.h" #include "libusb.h" extern "C" { #include "libdfuprog.h" } #define MAX_ALLOWABLE_CUMULATIVE_FRAME_ERROR 50 //tcBlock is fed to the callback in the libusb user data section. typedef struct tcBlock{ int number; bool completed; qint64 timeReceived; } tcBlock; //Oddly, libusb requires you to make a blocking libusb_handle_events() call in order to execute the callbacks for an asynchronous transfer. //Since the call is blocking, this worker must exist in a separate, low priority thread! class worker : public QObject { Q_OBJECT public: worker(){}; ~worker(){}; libusb_context *ctx; bool stopTime = false; unsigned char cleanupRemaining = 4; public slots: void handle(){ qDebug() << "SUB THREAD ID" << QThread::currentThreadId(); while(cleanupRemaining){ //qDebug() << cleanupRemaining; if(libusb_event_handling_ok(ctx)){ libusb_handle_events_timeout(ctx, &tv); //qDebug() << "HANDLED"; } if(stopTime){ if(cleanupRemaining){ cleanupRemaining--; qDebug("Cleaning... #%hhu phases remain.\n", cleanupRemaining); } } } qDebug() << "Cleanup complete"; //THIS THREAD STILL EXISTS } }; //This is the actual unixUsbDriver //It handles the Mac/Linux specific parts of USB communication, through libusb. //See genericUsbDriver for the non-platform-specific parts. class unixUsbDriver : public genericUsbDriver { Q_OBJECT public: explicit unixUsbDriver(QWidget *parent = 0); ~unixUsbDriver(); void usbSendControl(uint8_t RequestType, uint8_t Request, uint16_t Value, uint16_t Index, uint16_t Length, unsigned char *LDATA); char *isoRead(unsigned int *newLength); void manualFirmwareRecovery(void); protected: //USB Vars libusb_context *ctx = NULL; libusb_device_handle *handle = NULL; //USBIso Vars unsigned char *midBuffer_current[NUM_ISO_ENDPOINTS]; unsigned char *midBuffer_prev[NUM_ISO_ENDPOINTS]; qint64 midBufferOffsets[NUM_ISO_ENDPOINTS]; libusb_transfer *isoCtx[NUM_ISO_ENDPOINTS][NUM_FUTURE_CTX]; tcBlock transferCompleted[NUM_ISO_ENDPOINTS][NUM_FUTURE_CTX]; unsigned char dataBuffer[NUM_ISO_ENDPOINTS][NUM_FUTURE_CTX][ISO_PACKET_SIZE*ISO_PACKETS_PER_CTX]; worker *isoHandler; QThread *workerThread; int cumulativeFramePhaseErrors = 0; //Generic Functions virtual unsigned char usbInit(unsigned long VIDin, unsigned long PIDin); unsigned char usbIsoInit(void); virtual int flashFirmware(void); bool allEndpointsComplete(int n); bool shutdownMode = false; int numCancelled = 0; signals: public slots: void isoTimerTick(void); void recoveryTick(void); void shutdownProcedure(void); void backupCleanup(void); }; //Callback on iso transfer complete. static void LIBUSB_CALL isoCallback(struct libusb_transfer * transfer){ tcBlockMutex.lock(); //int number = ((tcBlock *)transfer->user_data)->number; //bool completed = ((tcBlock *)transfer->user_data)->completed; //qDebug() << "CALLBACK" << number; //qDebug() << completed; if(transfer->status!=LIBUSB_TRANSFER_CANCELLED){ ((tcBlock *)transfer->user_data)->completed = true; ((tcBlock *)transfer->user_data)->timeReceived = QDateTime::currentMSecsSinceEpoch(); } //qDebug() << ((tcBlock *)transfer->user_data)->timeReceived; tcBlockMutex.unlock(); return; } #endif // unixUsbDriver_H