From bdb854808b14e2ec22b9d1699b8909f2baed06dc Mon Sep 17 00:00:00 2001 From: codestation Date: Tue, 20 Aug 2013 16:53:38 -0430 Subject: [PATCH] Reimplemented CmaClient (again) to support concurrent connections. --- cmaclient.cpp | 166 ++++++++++++++++++++++++++++--------------------- cmaclient.h | 23 ++++--- mainwidget.cpp | 78 +++++++++++------------ mainwidget.h | 4 +- 4 files changed, 148 insertions(+), 123 deletions(-) diff --git a/cmaclient.cpp b/cmaclient.cpp index a2c431b..f8b1ef9 100644 --- a/cmaclient.cpp +++ b/cmaclient.cpp @@ -30,16 +30,97 @@ #include #include -#include -#include +QMutex CmaClient::mutex; +QMutex CmaClient::runner; +Database CmaClient::db; +bool CmaClient::is_running = true; metadata_t CmaClient::g_thumbmeta = {0, 0, 0, NULL, NULL, 0, 0, 0, Thumbnail, {{18, 144, 80, 0, 1, 1.0f, 2}}, NULL}; CmaClient *CmaClient::this_object = NULL; CmaClient::CmaClient(QObject *parent) : - BaseWorker(parent) + QObject(parent) { this_object = this; + device = NULL; +} + +bool CmaClient::isRunning() +{ + QMutexLocker locker(&runner); + return is_running; +} + +void CmaClient::setRunning(bool state) +{ + QMutexLocker locker(&runner); + is_running = state; +} + +void CmaClient::connectUsb() +{ + vita_device_t *vita; + int num_tries = 0; + + qDebug() << "Starting usb_thread:" << QThread::currentThreadId(); + + while(isRunning()) { + if((vita = VitaMTP_Get_First_USB_Vita()) !=NULL) { + processNewConnection(vita); + } else { + qDebug("No Vita detected via USB, attempt %i", ++num_tries); + if(mutex.tryLock()) { + mutex.unlock(); + Sleeper::msleep(2000); + } + } + } + + qDebug("Finishing usb_thread"); + emit finished(); +} + +void CmaClient::connectWireless() +{ + vita_device_t *vita; + wireless_host_info_t host; + host.port = QCMA_REQUEST_PORT; + typedef CmaClient CC; + + qDebug() << "Starting wireless_thread:" << QThread::currentThreadId(); + + while(isRunning()) { + if((vita = VitaMTP_Get_First_Wireless_Vita(&host, 0, 2, CC::deviceRegistered, CC::generatePin)) != NULL) { + processNewConnection(vita); + } else { + qDebug("Wireless listener was cancelled"); + mutex.lock(); + // wait until the event loop of the usb thread is finished + mutex.unlock(); + } + } + qDebug("Finishing wireless_thread"); + emit finished(); +} + +void CmaClient::processNewConnection(vita_device_t *device) +{ + QMutexLocker locker(&mutex); + + broadcast.setUnavailable(); + this->device = device; + qDebug("Vita connected: id %s", VitaMTP_Get_Identification(device)); + DeviceCapability *vita_info = new DeviceCapability(); + + if(!vita_info->exchangeInfo(device)) { + qCritical("Error while exchanging info with the vita"); + } else { + // Conection successful, inform the user + emit deviceConnected(QString(tr("Connected to ")) + vita_info->getOnlineId()); + enterEventLoop(); + } + + broadcast.setAvailable(); } int CmaClient::deviceRegistered(const char *deviceid) @@ -58,72 +139,16 @@ int CmaClient::generatePin(wireless_vita_info_t *info, int *p_err) return pin; } -vita_device_t *CmaClient::getDeviceConnection() -{ - int num_tries = 0; - vita_device_t *vita; - wireless_host_info_t host; - host.port = QCMA_REQUEST_PORT; - - while(active) { - vita = VitaMTP_Get_First_USB_Vita(); - if(vita || !active) { - break; - } - qDebug("No Vita detected via USB, attempt %i", ++num_tries); - vita = VitaMTP_Get_First_Wireless_Vita(&host, 0, 3, CmaClient::deviceRegistered, CmaClient::generatePin); - if(vita || !active) { - break; - } - qDebug("No Vita detected via wireless, attempt %i", ++num_tries); - } - - return vita; -} - -void CmaClient::process() -{ - qDebug() << "Starting CmaClient:" << QThread::currentThreadId(); - - connect(&broadcast, SIGNAL(receivedPin(int)), this, SIGNAL(receivedPin(int))); - - active = true; - - while(active) { - - if((device = getDeviceConnection()) == NULL) { - break; - } - broadcast.setUnavailable(); - qDebug("Vita connected: id %s", VitaMTP_Get_Identification(device)); - DeviceCapability *vita_info = new DeviceCapability(); - - if(!vita_info->exchangeInfo(device)) { - qCritical("Error while exchanging info with the vita"); - close(); - broadcast.setAvailable(); - continue; - } - - // Conection successful, inform the user - emit deviceConnected(QString(tr("Connected to ")) + vita_info->getOnlineId()); - connected = true; - enterEventLoop(); - broadcast.setAvailable(); - } - emit finished(); -} - void CmaClient::enterEventLoop() { vita_event_t event; qDebug("Starting event loop"); - while(connected) { + while(isRunning()) { if(VitaMTP_Read_Event(device, &event) < 0) { qWarning("Error reading event from Vita."); - connected = false; + setRunning(false); break; } @@ -372,7 +397,7 @@ void CmaClient::vitaEventRequestTerminate(vita_event_t *event, int eventId) { qDebug("Event recieved in %s, code: 0x%x, id: %d", Q_FUNC_INFO, event->Code, eventId); //qWarning("Event 0x%x unimplemented!", event->Code); - connected = false; + setRunning(false); } void CmaClient::vitaEventUnimplementated(vita_event_t *event, int eventId) @@ -505,7 +530,7 @@ void CmaClient::vitaEventCancelTask(vita_event_t *event, int eventId) int eventIdToCancel = event->Param2; VitaMTP_CancelTask(device, eventIdToCancel); qWarning("Event CancelTask (0x%x) unimplemented!", event->Code); - connected = false; + setRunning(false); } void CmaClient::vitaEventSendHttpObjectFromURL(vita_event_t *event, int eventId) @@ -951,20 +976,19 @@ void CmaClient::vitaEventCheckExistance(vita_event_t *event, int eventId) void CmaClient::close() { - VitaMTP_SendHostStatus(device, VITA_HOST_STATUS_EndConnection); - VitaMTP_Release_Device(device); + if(device) { + VitaMTP_SendHostStatus(device, VITA_HOST_STATUS_EndConnection); + VitaMTP_Release_Device(device); + device = NULL; + } } void CmaClient::stop() { - active = false; - connected = false; - waitCondition.wakeAll(); + CmaClient::setRunning(false); } CmaClient::~CmaClient() { - if(device) { - close(); - } + close(); } diff --git a/cmaclient.h b/cmaclient.h index 4147cc4..12a1247 100644 --- a/cmaclient.h +++ b/cmaclient.h @@ -33,18 +33,23 @@ extern "C" { #include } -class CmaClient : public BaseWorker +class CmaClient : public QObject { Q_OBJECT public: explicit CmaClient(QObject *parent = 0); ~CmaClient(); - Database db; + void launch(); + + static Database db; private: + static bool isRunning(); + static void setRunning(bool state); void enterEventLoop(); - vita_device_t *getDeviceConnection(); + + void processNewConnection(vita_device_t *device); uint16_t processAllObjects(CMAObject *parent, uint32_t handle); void vitaEventSendObject(vita_event_t *event, int eventId); @@ -72,13 +77,13 @@ private: static int deviceRegistered(const char *deviceid); static int generatePin(wireless_vita_info_t *info, int *p_err); - QWaitCondition waitCondition; CmaBroadcast broadcast; vita_device_t *device; - volatile bool active; - volatile bool connected; + static bool is_running; static metadata_t g_thumbmeta; static CmaClient *this_object; + static QMutex mutex; + static QMutex runner; signals: void receivedPin(int); @@ -86,13 +91,15 @@ signals: void deviceConnected(QString); void deviceDisconnected(); void refreshDatabase(); + void finished(); public slots: void close(); - void stop(); + static void stop(); private slots: - void process(); + void connectUsb(); + void connectWireless(); }; #endif // CMACLIENT_H diff --git a/mainwidget.cpp b/mainwidget.cpp index 268a058..fdb11c5 100644 --- a/mainwidget.cpp +++ b/mainwidget.cpp @@ -65,22 +65,46 @@ void MainWidget::dialogResult(int result) void MainWidget::startServer() { - qDebug("Starting cma event loop"); - clientLoop.start("CmaClient"); + qDebug("Starting cma threads"); + QThread *thread; + CmaClient *client; + + thread = new QThread(); + client = new CmaClient(); + thread->setObjectName("usb_thread"); + connect(thread, SIGNAL(started()), client, SLOT(connectUsb())); + connect(client, SIGNAL(receivedPin(int)), this, SLOT(showPin(int))); + connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater())); + connect(thread, SIGNAL(finished()), client, SLOT(deleteLater())); + connectClientSignals(client); + + client->moveToThread(thread); + thread->start(); + + thread = new QThread(); + client = new CmaClient(); + thread->setObjectName("wireless_thread"); + connect(thread, SIGNAL(started()), client, SLOT(connectWireless())); + connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater())); + connect(thread, SIGNAL(finished()), client, SLOT(deleteLater())); + connectClientSignals(client); + client->moveToThread(thread); + thread->start(); } void MainWidget::stopServer() { - clientLoop.stop(); + CmaClient::stop(); + qApp->quit(); } void MainWidget::refreshDatabase() { - clientLoop.db.mutex.lock(); - clientLoop.db.destroy(); - int count = clientLoop.db.create(); + QMutexLocker locker(&CmaClient::db.mutex); + + CmaClient::db.destroy(); + int count = CmaClient::db.create(); qDebug("Added %i entries to the database", count); - clientLoop.db.mutex.unlock(); } void MainWidget::deviceDisconnect() @@ -89,15 +113,12 @@ void MainWidget::deviceDisconnect() receiveMessage(tr("The device has been disconnected")); } -void MainWidget::connectSignals() +void MainWidget::connectClientSignals(CmaClient *client) { - connect(&dialog, SIGNAL(finished(int)), this, SLOT(dialogResult(int))); - connect(&clientLoop, SIGNAL(receivedPin(int)), this, SLOT(showPin(int))); - connect(&clientLoop, SIGNAL(deviceConnected(QString)), this, SLOT(receiveMessage(QString))); - connect(&clientLoop, SIGNAL(deviceConnected(QString)), this, SLOT(setTrayTooltip(QString))); - connect(&clientLoop, SIGNAL(deviceDisconnected()), this, SLOT(deviceDisconnect())); - connect(&clientLoop, SIGNAL(refreshDatabase()), this, SLOT(refreshDatabase())); - connect(&clientLoop, SIGNAL(finished()), qApp, SLOT(quit())); + connect(client, SIGNAL(deviceConnected(QString)), this, SLOT(receiveMessage(QString))); + connect(client, SIGNAL(deviceConnected(QString)), this, SLOT(setTrayTooltip(QString))); + connect(client, SIGNAL(deviceDisconnected()), this, SLOT(deviceDisconnect())); + connect(client, SIGNAL(refreshDatabase()), this, SLOT(refreshDatabase())); } void MainWidget::showPin(int pin) @@ -107,7 +128,7 @@ void MainWidget::showPin(int pin) void MainWidget::prepareApplication() { - connectSignals(); + connect(&dialog, SIGNAL(finished(int)), this, SLOT(dialogResult(int))); createTrayIcon(); checkSettings(); refreshDatabase(); @@ -118,31 +139,8 @@ void MainWidget::setTrayTooltip(QString message) trayIcon->setToolTip(message); } -void MainWidget::toggleWireless() -{ - QSettings settings; - if(wireless->isChecked()) { - wireless->setText(tr("&Wireless enabled")); - settings.setValue("wireless", true); - } else { - wireless->setText(tr("&Wireless disabled")); - settings.setValue("wireless", false); - } -} - void MainWidget::createTrayIcon() { - QSettings settings; - wireless = new QAction(this); - wireless->setCheckable(true); - - if(settings.value("wireless", false).toBool()) { - wireless->setText(tr("&Wireless enabled")); - wireless->setChecked(true); - } else { - wireless->setText(tr("&Wireless disabled")); - } - options = new QAction(tr("&Settings"), this); reload = new QAction(tr("&Refresh database"), this); quit = new QAction(tr("&Quit"), this); @@ -150,12 +148,10 @@ void MainWidget::createTrayIcon() connect(options, SIGNAL(triggered()), &dialog, SLOT(open())); //connect(reload, SIGNAL(triggered()), &CmaWorker, SLOT(allowRefresh()), Qt::DirectConnection); connect(quit, SIGNAL(triggered()), this, SLOT(stopServer())); - connect(wireless, SIGNAL(triggered()), this, SLOT(toggleWireless())); QMenu *trayIconMenu = new QMenu(this); trayIconMenu->addAction(options); trayIconMenu->addAction(reload); - trayIconMenu->addAction(wireless); trayIconMenu->addSeparator(); trayIconMenu->addAction(quit); diff --git a/mainwidget.h b/mainwidget.h index 30ad0af..e756a97 100644 --- a/mainwidget.h +++ b/mainwidget.h @@ -46,7 +46,7 @@ public: private: void createTrayIcon(); void checkSettings(); - void connectSignals(); + void connectClientSignals(CmaClient *client); bool first_run; ConfigWidget dialog; @@ -54,7 +54,6 @@ private: QAction *quit; QAction *reload; QAction *options; - QAction *wireless; CmaClient clientLoop; const static QStringList path_list; @@ -63,7 +62,6 @@ private slots: void dialogResult(int result); void receiveMessage(QString message); void setTrayTooltip(QString message); - void toggleWireless(); void showPin(int pin); void refreshDatabase(); void startServer();