1
0
mirror of https://bitbucket.org/librepilot/librepilot.git synced 2025-02-06 21:54:15 +01:00

Finally, a fix for the Mac UAVTalk issues: it was all caused by a wrong RunLoop pointer reference

because of multithreading.
This commit is contained in:
Edouard Lafargue 2011-10-11 00:10:27 +02:00
parent de8478718c
commit 6514ea5262
2 changed files with 63 additions and 59 deletions

View File

@ -37,8 +37,6 @@
#if defined( Q_OS_MAC) #if defined( Q_OS_MAC)
#include <QTimer>
// todo:
#elif defined(Q_OS_UNIX) #elif defined(Q_OS_UNIX)
//#elif defined(Q_OS_LINUX) //#elif defined(Q_OS_LINUX)
@ -106,16 +104,12 @@ public:
signals: signals:
void deviceUnplugged(int);//just to make pips changes compile void deviceUnplugged(int);//just to make pips changes compile
#if defined( Q_OS_MAC) #if defined( Q_OS_MAC)
public slots:
void timeout_callback();
#endif #endif
private: private:
#if defined( Q_OS_MAC) #if defined( Q_OS_MAC)
int timeout_occurred;
QTimer m_timer;
#elif defined(Q_OS_UNIX) #elif defined(Q_OS_UNIX)
//#elif defined(Q_OS_LINUX) //#elif defined(Q_OS_LINUX)

View File

@ -46,6 +46,7 @@
#include <QString> #include <QString>
#include <QThread> #include <QThread>
#include <QTimer> #include <QTimer>
#include <QCoreApplication>
class delay : public QThread class delay : public QThread
{ {
@ -65,6 +66,8 @@ typedef struct hid_struct hid_t;
typedef struct buffer_struct buffer_t; typedef struct buffer_struct buffer_t;
static hid_t *first_hid = NULL; static hid_t *first_hid = NULL;
static hid_t *last_hid = NULL; static hid_t *last_hid = NULL;
// Make sure we use the correct runloop
CFRunLoopRef the_correct_runloop = NULL;
struct hid_struct { struct hid_struct {
IOHIDDeviceRef ref; IOHIDDeviceRef ref;
int open; int open;
@ -88,6 +91,8 @@ static void attach_callback(void *, IOReturn, void *, IOHIDDeviceRef);
static void detach_callback(void *, IOReturn, void *hid_mgr, IOHIDDeviceRef dev); static void detach_callback(void *, IOReturn, void *hid_mgr, IOHIDDeviceRef dev);
static void input_callback(void *, IOReturn, void *, IOHIDReportType, uint32_t, uint8_t *, CFIndex); static void input_callback(void *, IOReturn, void *, IOHIDReportType, uint32_t, uint8_t *, CFIndex);
static void output_callback(hid_t *context, IOReturn ret, void *sender, IOHIDReportType type, uint32_t id, uint8_t *data, CFIndex len); static void output_callback(hid_t *context, IOReturn ret, void *sender, IOHIDReportType type, uint32_t id, uint8_t *data, CFIndex len);
static void timeout_callback(CFRunLoopTimerRef, void *);
pjrc_rawhid::pjrc_rawhid() pjrc_rawhid::pjrc_rawhid()
{ {
@ -119,8 +124,6 @@ int pjrc_rawhid::open(int max, int vid, int pid, int usage_page, int usage)
hid_t *p; hid_t *p;
int count=0; int count=0;
connect(&m_timer, SIGNAL(timeout()), this, SLOT(timeout_callback()));
if (first_hid) free_all_hid(); if (first_hid) free_all_hid();
//printf("pjrc_rawhid_open, max=%d\n", max); //printf("pjrc_rawhid_open, max=%d\n", max);
if (max < 1) return 0; if (max < 1) return 0;
@ -176,6 +179,8 @@ int pjrc_rawhid::open(int max, int vid, int pid, int usage_page, int usage)
CFRelease(hid_manager); CFRelease(hid_manager);
return 0; return 0;
} }
// Set the run loop reference:
the_correct_runloop = CFRunLoopGetCurrent();
printf("run loop\n"); printf("run loop\n");
// let it do the callback for all devices // let it do the callback for all devices
while (CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0, true) == kCFRunLoopRunHandledSource) ; while (CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0, true) == kCFRunLoopRunHandledSource) ;
@ -197,7 +202,9 @@ int pjrc_rawhid::receive(int num, void *buf, int len, int timeout)
{ {
hid_t *hid; hid_t *hid;
buffer_t *b; buffer_t *b;
int ret=0; CFRunLoopTimerRef timer=NULL;
CFRunLoopTimerContext context;
int ret=0, timeout_occurred=0;
if (len < 1) return 0; if (len < 1) return 0;
hid = get_hid(num); hid = get_hid(num);
@ -207,28 +214,29 @@ int pjrc_rawhid::receive(int num, void *buf, int len, int timeout)
memcpy(buf, b->buf, len); memcpy(buf, b->buf, len);
hid->first_buffer = b->next; hid->first_buffer = b->next;
free(b); free(b);
//printf("packet already, returning before loop");
return len; return len;
} }
memset(&context, 0, sizeof(context));
context.info = &timeout_occurred;
timer = CFRunLoopTimerCreate(NULL, CFAbsoluteTimeGetCurrent() +
(double)timeout / 1000.0, 0, 0, 0, timeout_callback, &context);
CFRunLoopAddTimer(CFRunLoopGetCurrent(), timer, kCFRunLoopDefaultMode);
the_correct_runloop = CFRunLoopGetCurrent();
//qDebug("--");
while (1) {
//qDebug(".");
CFRunLoopRun(); // Found the problem: somehow the input_callback does not
// stop this CFRunLoopRun because it is hooked to a different run loop !!!
// Hence the use of the "correct_runloop" variable above.
//qDebug(" ..");
// This does not work while in a "while" loop!! Come on...
// BEWARE: this area is broken.
// We need a way (probably thread?) to wait for USB data
// while also accepting a timeout.
timeout_occurred = 1;
m_timer.start(timeout);
while (true) {
// CFRunLoopRun does not work properly with Qt's event loop...
CFRunLoopRun();
printf(".");
delay::msleep(20);
if ((b = hid->first_buffer) != NULL) { if ((b = hid->first_buffer) != NULL) {
if (len > b->len) len = b->len; if (len > b->len) len = b->len;
memcpy(buf, b->buf, len); memcpy(buf, b->buf, len);
hid->first_buffer = b->next; hid->first_buffer = b->next;
free(b); free(b);
ret = len; ret = len;
// printf("got packet, exit waiting loop with %i bytes",ret); //qDebug("*************");
break; break;
} }
if (!hid->open) { if (!hid->open) {
@ -236,12 +244,11 @@ int pjrc_rawhid::receive(int num, void *buf, int len, int timeout)
ret = -1; ret = -1;
break; break;
} }
if (timeout_occurred) { if (timeout_occurred)
qDebug("Timeout while waiting for packet");
break; break;
} }
} CFRunLoopTimerInvalidate(timer);
m_timer.stop(); CFRelease(timer);
return ret; return ret;
} }
@ -354,7 +361,7 @@ static void input_callback(void *context, IOReturn ret, void *sender, IOHIDRepor
buffer_t *n; buffer_t *n;
hid_t *hid; hid_t *hid;
//printf("input_callback, ret: %i - report id: %i buf: %x %x, len: %d\n", ret, id, data[0], data[1], len); //qDebug("input_callback, ret: %i - report id: %i buf: %x %x, len: %d\n", ret, id, data[0], data[1], len);
if (ret != kIOReturnSuccess || len < 1) return; if (ret != kIOReturnSuccess || len < 1) return;
hid = (hid_t*)context; hid = (hid_t*)context;
if (!hid || hid->ref != sender) return; if (!hid || hid->ref != sender) return;
@ -372,13 +379,16 @@ static void input_callback(void *context, IOReturn ret, void *sender, IOHIDRepor
hid->last_buffer->next = n; hid->last_buffer->next = n;
hid->last_buffer = n; hid->last_buffer = n;
} }
CFRunLoopStop(CFRunLoopGetCurrent()); //qDebug() << "Stop CFRunLoop from input_callback" << CFRunLoopGetCurrent();
CFRunLoopStop(the_correct_runloop);
} }
void pjrc_rawhid::timeout_callback() static void timeout_callback(CFRunLoopTimerRef timer, void *info)
{ {
qDebug("[pjrc_rawhid_mac] timeout_callback"); //qDebug("timeout_callback\n");
timeout_occurred = 1; *(int *)info = 1;
//qDebug() << "Stop CFRunLoop from timeout_callback" << CFRunLoopGetCurrent();
CFRunLoopStop(CFRunLoopGetCurrent());
} }
static void add_hid(hid_t *h) static void add_hid(hid_t *h)