diff --git a/listenerworker.cpp b/cmaclient.cpp similarity index 83% rename from listenerworker.cpp rename to cmaclient.cpp index 3691e25..164de00 100644 --- a/listenerworker.cpp +++ b/cmaclient.cpp @@ -1,74 +1,64 @@ -/* - * QCMA: Cross-platform content manager assistant for the PS Vita - * - * Copyright (C) 2013 Codestation - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include "listenerworker.h" - -#include +#include "cmaclient.h" +#include "capability.h" +#include "utils.h" #include #include +#include #include #include #include #include -#include -#include -#include "utils.h" +const metadata_t CmaClient::g_thumbmeta = {0, 0, 0, NULL, NULL, 0, 0, 0, Thumbnail, {{18, 144, 80, 0, 1, 1.0f, 2}}, NULL}; -#define CALL_MEMBER_FUNC(obj,memberptr) ((obj).*(memberptr)) - -const metadata_t ListenerWorker::g_thumbmeta = {0, 0, 0, NULL, NULL, 0, 0, 0, Thumbnail, {{18, 144, 80, 0, 1, 1.0f, 2}}, NULL}; - -ListenerWorker::ListenerWorker(QObject *parent) : +CmaClient::CmaClient(QObject *parent) : BaseWorker(parent) { +} + +CmaClient::CmaClient(Database *database, vita_device_t *device, QObject *parent) : + BaseWorker(parent), db(database), device(device) +{ +} + +CmaClient::~CmaClient() +{ + if(device) { + close(); + } +} + +void CmaClient::close() +{ + VitaMTP_SendHostStatus(device, VITA_HOST_STATUS_EndConnection); + VitaMTP_Release_Device(device); + device = NULL; +} + +void CmaClient::process() +{ + 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(); + } + + // Conection successful, inform the user + emit deviceConnected(QString(tr("Connected to ")) + vita_info->getOnlineId()); connected = true; + enterEventLoop(); } -int ListenerWorker::rebuildDatabase() -{ - db.destroy(); - return db.create(); -} -void ListenerWorker::setDevice(vita_device_t *device) -{ - this->device = device; -} - -bool ListenerWorker::isConnected() -{ - return connected; -} - -void ListenerWorker::disconnect() -{ - qDebug("Stopping event listener"); - connected = false; -} - -void ListenerWorker::process() +void CmaClient::enterEventLoop() { vita_event_t event; - qDebug() << "From listener: "<< QThread::currentThreadId(); + qDebug() << "From listener:"<< QThread::currentThreadId(); while(connected) { if(VitaMTP_Read_Event(device, &event) < 0) { @@ -147,10 +137,11 @@ void ListenerWorker::process() vitaEventUnimplementated(&event, event.Param1); } } + qDebug() << "Finished event thread for:" << QThread::currentThreadId(); emit finished(); } -quint16 ListenerWorker::processAllObjects(CMAObject *parent, quint32 handle) +quint16 CmaClient::processAllObjects(CMAObject *parent, quint32 handle) { union { unsigned char *fileData; @@ -165,13 +156,12 @@ quint16 ListenerWorker::processAllObjects(CMAObject *parent, quint32 handle) return PTP_RC_VITA_Invalid_Data; } - - CMAObject *object = db.pathToObject(remote_meta.name, parent->metadata.ohfi); + CMAObject *object = db->pathToObject(remote_meta.name, parent->metadata.ohfi); if(object) { qDebug("Deleting %s", object->path.toStdString().c_str()); removeRecursively(object->path); - db.remove(object); + db->remove(object); } QDir dir(parent->path); @@ -200,7 +190,7 @@ quint16 ListenerWorker::processAllObjects(CMAObject *parent, quint32 handle) object = new CMAObject(parent); object->initObject(info); object->metadata.handle = remote_meta.handle; - db.append(parent->metadata.ohfi, object); + db->append(parent->metadata.ohfi, object); free(remote_meta.name); qDebug("Added object %s with OHFI %i to database", object->metadata.path, object->metadata.ohfi); @@ -211,7 +201,7 @@ quint16 ListenerWorker::processAllObjects(CMAObject *parent, quint32 handle) if(ret != PTP_RC_OK) { qDebug("Deleteting object with OHFI %d", object->metadata.ohfi); - db.remove(object); + db->remove(object); free(data.fileData); return ret; } @@ -222,7 +212,7 @@ quint16 ListenerWorker::processAllObjects(CMAObject *parent, quint32 handle) return PTP_RC_OK; } -void ListenerWorker::vitaEventGetTreatObject(vita_event_t *event, int eventId) +void CmaClient::vitaEventGetTreatObject(vita_event_t *event, int eventId) { qDebug("Event recieved in %s, code: 0x%x, id: %d", Q_FUNC_INFO, event->Code, eventId); @@ -233,9 +223,9 @@ void ListenerWorker::vitaEventGetTreatObject(vita_event_t *event, int eventId) return; } - QMutexLocker locker(&db.mutex); + QMutexLocker locker(&db->mutex); - CMAObject *parent = db.ohfiToObject(treatObject.ohfiParent); + CMAObject *parent = db->ohfiToObject(treatObject.ohfiParent); if(parent == NULL) { qWarning("Cannot find parent OHFI %d", treatObject.ohfiParent); @@ -246,7 +236,7 @@ void ListenerWorker::vitaEventGetTreatObject(vita_event_t *event, int eventId) VitaMTP_ReportResult(device, eventId, processAllObjects(parent, treatObject.handle)); } -void ListenerWorker::vitaEventSendCopyConfirmationInfo(vita_event_t *event, int eventId) +void CmaClient::vitaEventSendCopyConfirmationInfo(vita_event_t *event, int eventId) { qDebug("Event recieved in %s, code: 0x%x, id: %d", Q_FUNC_INFO, event->Code, eventId); @@ -256,14 +246,14 @@ void ListenerWorker::vitaEventSendCopyConfirmationInfo(vita_event_t *event, int return; } - QMutexLocker locker(&db.mutex); + QMutexLocker locker(&db->mutex); quint64 size = 0; for(quint32 i = 0; i < info->count; i++) { CMAObject *object; - if((object = db.ohfiToObject(info->ohfi[i])) == NULL) { + if((object = db->ohfiToObject(info->ohfi[i])) == NULL) { qWarning("Cannot find OHFI %d", info->ohfi[i]); free(info); return; @@ -281,7 +271,7 @@ void ListenerWorker::vitaEventSendCopyConfirmationInfo(vita_event_t *event, int free(info); } -void ListenerWorker::vitaEventSendObjectMetadataItems(vita_event_t *event, int eventId) +void CmaClient::vitaEventSendObjectMetadataItems(vita_event_t *event, int eventId) { qDebug("Event recieved in %s, code: 0x%x, id: %d", Q_FUNC_INFO, event->Code, eventId); @@ -291,9 +281,9 @@ void ListenerWorker::vitaEventSendObjectMetadataItems(vita_event_t *event, int e return; } - QMutexLocker locker(&db.mutex); + QMutexLocker locker(&db->mutex); - CMAObject *object = db.ohfiToObject(ohfi); + CMAObject *object = db->ohfiToObject(ohfi); if(object == NULL) { qWarning("Cannot find OHFI %d in database", ohfi); @@ -312,33 +302,34 @@ void ListenerWorker::vitaEventSendObjectMetadataItems(vita_event_t *event, int e } } -void ListenerWorker::vitaEventSendNPAccountInfo(vita_event_t *event, int eventId) +void CmaClient::vitaEventSendNPAccountInfo(vita_event_t *event, int eventId) { qDebug("Event recieved in %s, code: 0x%x, id: %d", Q_FUNC_INFO, event->Code, eventId); // AFAIK, Sony hasn't even implemented this in their CMA qWarning("Event 0x%x unimplemented!", event->Code); } -void ListenerWorker::vitaEventRequestTerminate(vita_event_t *event, int eventId) +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); + //qWarning("Event 0x%x unimplemented!", event->Code); + connected = false; } -void ListenerWorker::vitaEventUnimplementated(vita_event_t *event, int eventId) +void CmaClient::vitaEventUnimplementated(vita_event_t *event, int eventId) { qWarning("Unknown event not handled, code: 0x%x, id: %d", event->Code, eventId); qWarning("Param1: 0x%08X, Param2: 0x%08X, Param3: 0x%08X", event->Param1, event->Param2, event->Param3); } -void ListenerWorker::vitaEventSendNumOfObject(vita_event_t *event, int eventId) +void CmaClient::vitaEventSendNumOfObject(vita_event_t *event, int eventId) { qDebug("Event recieved in %s, code: 0x%x, id: %d", Q_FUNC_INFO, event->Code, eventId); - QMutexLocker locker(&db.mutex); + QMutexLocker locker(&db->mutex); uint ohfi = event->Param2; - int items = db.filterObjects(ohfi, NULL); + int items = db->filterObjects(ohfi, NULL); if(VitaMTP_SendNumOfObject(device, eventId, items) != PTP_RC_OK) { qWarning("Error occured receiving object count for OHFI parent %d", ohfi); @@ -348,7 +339,7 @@ void ListenerWorker::vitaEventSendNumOfObject(vita_event_t *event, int eventId) } } -void ListenerWorker::vitaEventSendObjectMetadata(vita_event_t *event, int eventId) +void CmaClient::vitaEventSendObjectMetadata(vita_event_t *event, int eventId) { qDebug("Event recieved in %s, code: 0x%x, id: %d", Q_FUNC_INFO, event->Code, eventId); @@ -358,10 +349,10 @@ void ListenerWorker::vitaEventSendObjectMetadata(vita_event_t *event, int eventI qWarning("GetBrowseInfo failed"); return; } - QMutexLocker locker(&db.mutex); + QMutexLocker locker(&db->mutex); metadata_t *meta; - int count = db.filterObjects(browse.ohfiParent, &meta); // if meta is null, will return empty XML + int count = db->filterObjects(browse.ohfiParent, &meta); // if meta is null, will return empty XML qDebug("Sending %i metadata filtered objects for OHFI %id", count, browse.ohfiParent); if(VitaMTP_SendObjectMetadata(device, eventId, meta) != PTP_RC_OK) { // send all objects with OHFI parent @@ -371,16 +362,16 @@ void ListenerWorker::vitaEventSendObjectMetadata(vita_event_t *event, int eventI } } -void ListenerWorker::vitaEventSendObject(vita_event_t *event, int eventId) +void CmaClient::vitaEventSendObject(vita_event_t *event, int eventId) { qDebug("Event recieved in %s, code: 0x%x, id: %d", Q_FUNC_INFO, event->Code, eventId); int ohfi = event->Param2; - QMutexLocker locker(&db.mutex); + QMutexLocker locker(&db->mutex); Database::find_data iters; - if(!db.find(ohfi, iters)) { + if(!db->find(ohfi, iters)) { qWarning("Failed to find OHFI %d", ohfi); VitaMTP_ReportResult(device, eventId, PTP_RC_VITA_Invalid_OHFI); return; @@ -435,7 +426,7 @@ void ListenerWorker::vitaEventSendObject(vita_event_t *event, int eventId) VitaMTP_ReportResult(device, eventId, PTP_RC_VITA_Invalid_Data); // TODO: Send thumbnail } -void ListenerWorker::vitaEventCancelTask(vita_event_t *event, int eventId) +void CmaClient::vitaEventCancelTask(vita_event_t *event, int eventId) { qDebug("Event recieved in %s, code: 0x%x, id: %d", Q_FUNC_INFO, event->Code, eventId); @@ -444,7 +435,7 @@ void ListenerWorker::vitaEventCancelTask(vita_event_t *event, int eventId) qWarning("Event CancelTask (0x%x) unimplemented!", event->Code); } -void ListenerWorker::vitaEventSendHttpObjectFromURL(vita_event_t *event, int eventId) +void CmaClient::vitaEventSendHttpObjectFromURL(vita_event_t *event, int eventId) { qDebug("Event recieved in %s, code: 0x%x, id: %d", Q_FUNC_INFO, event->Code, eventId); @@ -487,7 +478,7 @@ void ListenerWorker::vitaEventSendHttpObjectFromURL(vita_event_t *event, int eve free(url); } -void ListenerWorker::vitaEventSendObjectStatus(vita_event_t *event, int eventId) +void CmaClient::vitaEventSendObjectStatus(vita_event_t *event, int eventId) { qDebug("Event recieved in %s, code: 0x%x, id: %d", Q_FUNC_INFO, event->Code, eventId); @@ -498,9 +489,9 @@ void ListenerWorker::vitaEventSendObjectStatus(vita_event_t *event, int eventId) return; } - QMutexLocker locker(&db.mutex); + QMutexLocker locker(&db->mutex); - CMAObject *object = db.pathToObject(objectstatus.title, objectstatus.ohfiRoot); + CMAObject *object = db->pathToObject(objectstatus.title, objectstatus.ohfiRoot); if(object == NULL) { // not in database, don't return metadata qDebug("Object %s not in database (OHFI: %i). Sending OK response for non-existence", objectstatus.title, objectstatus.ohfiRoot); @@ -520,14 +511,14 @@ void ListenerWorker::vitaEventSendObjectStatus(vita_event_t *event, int eventId) free(objectstatus.title); } -void ListenerWorker::vitaEventSendObjectThumb(vita_event_t *event, int eventId) +void CmaClient::vitaEventSendObjectThumb(vita_event_t *event, int eventId) { qDebug("Event recieved in %s, code: 0x%x, id: %d", Q_FUNC_INFO, event->Code, eventId); - QMutexLocker locker(&db.mutex); + QMutexLocker locker(&db->mutex); int ohfi = event->Param2; - CMAObject *object = db.ohfiToObject(ohfi); + CMAObject *object = db->ohfiToObject(ohfi); if(object == NULL) { qWarning("Cannot find OHFI %d in database.", ohfi); @@ -579,14 +570,14 @@ void ListenerWorker::vitaEventSendObjectThumb(vita_event_t *event, int eventId) free(locale); } -void ListenerWorker::vitaEventDeleteObject(vita_event_t *event, int eventId) +void CmaClient::vitaEventDeleteObject(vita_event_t *event, int eventId) { qDebug("Event recieved in %s, code: 0x%x, id: %d", Q_FUNC_INFO, event->Code, eventId); - QMutexLocker locker(&db.mutex); + QMutexLocker locker(&db->mutex); int ohfi = event->Param2; - CMAObject *object = db.ohfiToObject(ohfi); + CMAObject *object = db->ohfiToObject(ohfi); if(object == NULL) { qWarning("OHFI %d not found", ohfi); @@ -595,13 +586,13 @@ void ListenerWorker::vitaEventDeleteObject(vita_event_t *event, int eventId) } qDebug("Deleting %s, OHFI: %i", object->metadata.path, object->metadata.ohfi); - removeRecursively(object->path); - db.remove(object); + removeRecursively(object->path); + db->remove(object); VitaMTP_ReportResult(device, eventId, PTP_RC_OK); } -void ListenerWorker::vitaEventGetSettingInfo(vita_event_t *event, int eventId) +void CmaClient::vitaEventGetSettingInfo(vita_event_t *event, int eventId) { qDebug("Event recieved in %s, code: 0x%x, id: %d", Q_FUNC_INFO, event->Code, eventId); @@ -613,9 +604,9 @@ void ListenerWorker::vitaEventGetSettingInfo(vita_event_t *event, int eventId) qDebug("Current account id: %s", settingsinfo->current_account.accountId); - db.setUUID(settingsinfo->current_account.accountId); + db->setUUID(settingsinfo->current_account.accountId); - // set the database to be updated ASAP + // set the database to be updated ASAP emit refreshDatabase(); // free all the information @@ -623,7 +614,7 @@ void ListenerWorker::vitaEventGetSettingInfo(vita_event_t *event, int eventId) VitaMTP_ReportResult(device, eventId, PTP_RC_OK); } -void ListenerWorker::vitaEventSendHttpObjectPropFromURL(vita_event_t *event, int eventId) +void CmaClient::vitaEventSendHttpObjectPropFromURL(vita_event_t *event, int eventId) { qDebug("Event recieved in %s, code: 0x%x, id: %d", Q_FUNC_INFO, event->Code, eventId); @@ -659,7 +650,7 @@ void ListenerWorker::vitaEventSendHttpObjectPropFromURL(vita_event_t *event, int free(url); } -void ListenerWorker::vitaEventSendPartOfObject(vita_event_t *event, int eventId) +void CmaClient::vitaEventSendPartOfObject(vita_event_t *event, int eventId) { qDebug("Event recieved in %s, code: 0x%x, id: %d", Q_FUNC_INFO, event->Code, eventId); @@ -670,9 +661,9 @@ void ListenerWorker::vitaEventSendPartOfObject(vita_event_t *event, int eventId) return; } - QMutexLocker locker(&db.mutex); + QMutexLocker locker(&db->mutex); - CMAObject *object = db.ohfiToObject(part_init.ohfi); + CMAObject *object = db->ohfiToObject(part_init.ohfi); if(object == NULL) { qWarning("Cannot find object for OHFI %d", part_init.ohfi); @@ -699,7 +690,7 @@ void ListenerWorker::vitaEventSendPartOfObject(vita_event_t *event, int eventId) } } -void ListenerWorker::vitaEventOperateObject(vita_event_t *event, int eventId) +void CmaClient::vitaEventOperateObject(vita_event_t *event, int eventId) { qDebug("Event recieved in %s, code: 0x%x, id: %d", Q_FUNC_INFO, event->Code, eventId); @@ -710,9 +701,9 @@ void ListenerWorker::vitaEventOperateObject(vita_event_t *event, int eventId) return; } - QMutexLocker locker(&db.mutex); + QMutexLocker locker(&db->mutex); - CMAObject *root = db.ohfiToObject(operateobject.ohfi); + CMAObject *root = db->ohfiToObject(operateobject.ohfi); // end for renaming only if(root == NULL) { @@ -731,7 +722,7 @@ void ListenerWorker::vitaEventOperateObject(vita_event_t *event, int eventId) } else { CMAObject *newobj = new CMAObject(root); newobj->initObject(QFileInfo(dir, operateobject.title)); - db.append(operateobject.ohfi, newobj); + db->append(operateobject.ohfi, newobj); qDebug("Created folder %s with OHFI %d under parent %s", newobj->metadata.path, newobj->metadata.ohfi, root->metadata.path); VitaMTP_ReportResultWithParam(device, eventId, PTP_RC_OK, newobj->metadata.ohfi); } @@ -747,7 +738,7 @@ void ListenerWorker::vitaEventOperateObject(vita_event_t *event, int eventId) } else { CMAObject *newobj = new CMAObject(root); newobj->initObject(file); - db.append(root->metadata.ohfi, newobj); + db->append(root->metadata.ohfi, newobj); qDebug("Created file %s with OHFI %d under parent %s", newobj->metadata.path, newobj->metadata.ohfi, root->metadata.path); VitaMTP_ReportResultWithParam(device, eventId, PTP_RC_OK, newobj->metadata.ohfi); } @@ -762,7 +753,7 @@ void ListenerWorker::vitaEventOperateObject(vita_event_t *event, int eventId) //rename the current object root->rename(operateobject.title); Database::find_data iters; - db.find(root->metadata.ohfi, iters); + db->find(root->metadata.ohfi, iters); // rename the rest of the list only if has the renamed parent in some part of the chain while(iters.it != iters.end) { @@ -794,7 +785,7 @@ void ListenerWorker::vitaEventOperateObject(vita_event_t *event, int eventId) free(operateobject.title); } -void ListenerWorker::vitaEventGetPartOfObject(vita_event_t *event, int eventId) +void CmaClient::vitaEventGetPartOfObject(vita_event_t *event, int eventId) { qDebug("Event recieved in %s, code: 0x%x, id: %d", Q_FUNC_INFO, event->Code, eventId); @@ -806,8 +797,8 @@ void ListenerWorker::vitaEventGetPartOfObject(vita_event_t *event, int eventId) return; } - QMutexLocker locker(&db.mutex); - CMAObject *object = db.ohfiToObject(part_init.ohfi); + QMutexLocker locker(&db->mutex); + CMAObject *object = db->ohfiToObject(part_init.ohfi); if(object == NULL) { qWarning("Cannot find OHFI %d", part_init.ohfi); @@ -834,14 +825,14 @@ void ListenerWorker::vitaEventGetPartOfObject(vita_event_t *event, int eventId) free(data); } -void ListenerWorker::vitaEventSendStorageSize(vita_event_t *event, int eventId) +void CmaClient::vitaEventSendStorageSize(vita_event_t *event, int eventId) { qDebug("Event recieved in %s, code: 0x%x, id: %d", Q_FUNC_INFO, event->Code, eventId); - QMutexLocker locker(&db.mutex); + QMutexLocker locker(&db->mutex); int ohfi = event->Param2; - CMAObject *object = db.ohfiToObject(ohfi); + CMAObject *object = db->ohfiToObject(ohfi); if(object == NULL) { qWarning("Error: Cannot find OHFI %d", ohfi); @@ -880,7 +871,7 @@ void ListenerWorker::vitaEventSendStorageSize(vita_event_t *event, int eventId) } } -void ListenerWorker::vitaEventCheckExistance(vita_event_t *event, int eventId) +void CmaClient::vitaEventCheckExistance(vita_event_t *event, int eventId) { qDebug("Event recieved in %s, code: 0x%x, id: %d", Q_FUNC_INFO, event->Code, eventId); @@ -892,9 +883,9 @@ void ListenerWorker::vitaEventCheckExistance(vita_event_t *event, int eventId) return; } - QMutexLocker locker(&db.mutex); + QMutexLocker locker(&db->mutex); - CMAObject *object = db.pathToObject(existance.name, 0); + CMAObject *object = db->pathToObject(existance.name, 0); if(object == NULL) { VitaMTP_ReportResult(device, eventId, PTP_RC_VITA_Different_Object); diff --git a/listenerworker.h b/cmaclient.h similarity index 62% rename from listenerworker.h rename to cmaclient.h index 27e1800..af40560 100644 --- a/listenerworker.h +++ b/cmaclient.h @@ -1,50 +1,28 @@ -/* - * QCMA: Cross-platform content manager assistant for the PS Vita - * - * Copyright (C) 2013 Codestation - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ +#ifndef CMACLIENT_H +#define CMACLIENT_H -#ifndef LISTENERWORKER_H -#define LISTENERWORKER_H - -#include "database.h" #include "baseworker.h" +#include "cmaobject.h" +#include "database.h" #include - -#include +#include extern "C" { #include } -class ListenerWorker : public BaseWorker +class CmaClient : public BaseWorker { Q_OBJECT public: - explicit ListenerWorker(QObject *parent = 0); - - void setDevice(vita_device_t *device); - bool isConnected(); - void disconnect(); - int rebuildDatabase(); - - Database db; + explicit CmaClient(QObject *parent = 0); + explicit CmaClient(Database *database, vita_device_t *device, QObject *parent = 0); + ~CmaClient(); private: + void enterEventLoop(); + uint16_t processAllObjects(CMAObject *parent, uint32_t handle); void vitaEventSendObject(vita_event_t *event, int eventId); void vitaEventSendObjectMetadata(vita_event_t *event, int eventId); @@ -68,15 +46,21 @@ private: void vitaEventSendNPAccountInfo(vita_event_t *event, int eventId); void vitaEventRequestTerminate(vita_event_t *event, int eventId); + Database *db; vita_device_t *device; volatile bool connected; static const metadata_t g_thumbmeta; signals: + void deviceConnected(QString); void refreshDatabase(); + void terminate(); + +public slots: + void close(); private slots: void process(); }; -#endif // LISTENERWORKER_H +#endif // CMACLIENT_H diff --git a/cmaserver.cpp b/cmaserver.cpp new file mode 100644 index 0000000..2969c53 --- /dev/null +++ b/cmaserver.cpp @@ -0,0 +1,72 @@ +#include "cmaserver.h" +#include "wirelessworker.h" + +#include +#include +#include +#include + +CmaServer::CmaServer(QObject *parent) : + QObject(parent), num_retries(0) +{ + strcpy(hostname, QHostInfo::localHostName().toStdString().c_str()); + BroadcastSignal::info.name = hostname; +} + +void CmaServer::listen() +{ + QThread *thread = new QThread(); + if(QSettings().value("wireless", false).toBool()) { + connect(&timer, SIGNAL(timeout()), this, SLOT(connectWireless())); + broadcast.start(); + timer.setSingleShot(true); + } else { + timer.setSingleShot(false); + connect(&timer, SIGNAL(timeout()), this, SLOT(connectUsb())); + } + moveToThread(thread); + connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater())); + timer.start(2000); + thread->start(); +} + +void CmaServer::connectUsb() +{ + qDebug() << "From connectUsb: "<< QThread::currentThreadId(); + + vita_device_t *vita = VitaMTP_Get_First_USB_Vita(); + if(vita) { + qDebug("Detected PS Vita via USB"); + timer.stop(); + emit newConnection(vita); + } else { + qDebug("No PS Vita found. Attempt %d", ++num_retries); + } +} + +void CmaServer::connectWireless() +{ + typedef BroadcastSignal BS; + + qDebug() << "From connectWireless: "<< QThread::currentThreadId(); + + vita_device_t *vita = VitaMTP_Get_First_Wireless_Vita(&BS::info, 0, 0, BS::deviceRegistered, BS::generatePin); + if(vita) { + qDebug("Detected PS Vita in wireless mode"); + emit newConnection(vita); + } else { + qDebug("PS Vita couldn't be detected. Attempt %d", ++num_retries); + } +} + +void CmaServer::continueProcess() +{ + qDebug("Restarting CmaServer thread"); + num_retries = 0; + timer.start(); +} + +void CmaServer::stopProcess() +{ + timer.stop(); +} diff --git a/cmaserver.h b/cmaserver.h new file mode 100644 index 0000000..95855eb --- /dev/null +++ b/cmaserver.h @@ -0,0 +1,45 @@ +#ifndef CMASERVER_H +#define CMASERVER_H + +#include "wirelessworker.h" + +extern "C" { +#include +} + +#include + +#include +#include +#include +#include + +class CmaServer : public QObject +{ + Q_OBJECT +public: + explicit CmaServer(QObject *parent = 0); + void listen(); + void close(); + + int num_retries; + QTimer timer; + QThread *thread; + char hostname[256]; + BroadcastSignal broadcast; + +signals: + void newConnection(vita_device_t *); + void createdPin(int); + void finished(); + +public slots: + void continueProcess(); + void stopProcess(); + +private slots: + void connectWireless(); + void connectUsb(); +}; + +#endif // CMASERVER_H diff --git a/main.cpp b/main.cpp index 652352d..45c562e 100644 --- a/main.cpp +++ b/main.cpp @@ -18,6 +18,7 @@ */ #include +#include #include "singleapplication.h" #include "mainwidget.h" @@ -42,12 +43,17 @@ int main(int argc, char *argv[]) SingleApplication app(argc, argv); + + if(!app.arguments().contains("--with-debug")) { + VitaMTP_Set_Logging(VitaMTP_NONE); #if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0) qInstallMessageHandler(noMessageOutput); #else qInstallMsgHandler(noMessageOutput); #endif + } else { + VitaMTP_Set_Logging(VitaMTP_DEBUG); } qDebug()<<"From main thread: "< #include +#include #include #include #include @@ -45,7 +47,7 @@ void MainWidget::checkSettings() return; } } - CmaWorker.start(); + startServer(); } void MainWidget::dialogResult(int result) @@ -53,13 +55,44 @@ void MainWidget::dialogResult(int result) if(result == QDialog::Accepted) { if(first_run) { first_run = false; - CmaWorker.start(); + startServer(); } } else if(first_run) { qApp->quit(); } } +void MainWidget::startServer() +{ + connect(&server, SIGNAL(newConnection(vita_device_t *)), this, SLOT(startClient(vita_device_t*))); + connect(&server, SIGNAL(createdPin(int)), this, SLOT(showPin(int))); + //connect(&server, SIGNAL(finished()), qApp, SLOT(quit())); + + qDebug("Starting cma server"); + server.listen(); +} + +void MainWidget::refreshDatabase() +{ + db.mutex.lock(); + db.destroy(); + db.create(); + db.mutex.unlock(); +} + +void MainWidget::startClient(vita_device_t *device) +{ + server.stopProcess(); + qDebug() << "From startClient: "<< QThread::currentThreadId(); + qDebug("Starting new client connection"); + CmaClient *client = new CmaClient(&db, device); + connect(client, SIGNAL(deviceConnected(QString)), this, SLOT(receiveMessage(QString))); + connect(client, SIGNAL(deviceConnected(QString)), this, SLOT(setTrayTooltip(QString))); + connect(client, SIGNAL(refreshDatabase()), this, SLOT(refreshDatabase())); + connect(client, SIGNAL(finished()), &server, SLOT(continueProcess())); + client->start(); +} + void MainWidget::deviceDisconnect() { setTrayTooltip(tr("Disconnected")); @@ -69,12 +102,6 @@ void MainWidget::deviceDisconnect() void MainWidget::connectSignals() { connect(&dialog, SIGNAL(finished(int)), this, SLOT(dialogResult(int))); - connect(&CmaWorker, SIGNAL(createdPin(int)), this, SLOT(showPin(int))); - connect(&CmaWorker, SIGNAL(deviceConnected(QString)), this, SLOT(receiveMessage(QString))); - connect(&CmaWorker, SIGNAL(deviceConnected(QString)), this, SLOT(setTrayTooltip(QString))); - connect(&CmaWorker, SIGNAL(statusUpdated(QString)), this, SLOT(receiveMessage(QString))); - connect(&CmaWorker, SIGNAL(deviceDisconnected()), this, SLOT(deviceDisconnect())); - connect(&CmaWorker, SIGNAL(finished()), qApp, SLOT(quit())); } void MainWidget::showPin(int pin) @@ -86,7 +113,6 @@ void MainWidget::prepareApplication() { connectSignals(); createTrayIcon(); - trayIcon->show(); checkSettings(); } @@ -105,7 +131,6 @@ void MainWidget::toggleWireless() wireless->setText(tr("&Wireless disabled")); settings.setValue("wireless", false); } - CmaWorker.reload(); } void MainWidget::createTrayIcon() @@ -126,8 +151,8 @@ void MainWidget::createTrayIcon() quit = new QAction(tr("&Quit"), this); connect(options, SIGNAL(triggered()), &dialog, SLOT(open())); - connect(reload, SIGNAL(triggered()), &CmaWorker, SLOT(allowRefresh()), Qt::DirectConnection); - connect(quit, SIGNAL(triggered()), &CmaWorker, SLOT(stop()), Qt::DirectConnection); + //connect(reload, SIGNAL(triggered()), &CmaWorker, SLOT(allowRefresh()), Qt::DirectConnection); + connect(quit, SIGNAL(triggered()), qApp, SLOT(quit())); connect(wireless, SIGNAL(triggered()), this, SLOT(toggleWireless())); QMenu *trayIconMenu = new QMenu(this); @@ -139,7 +164,10 @@ void MainWidget::createTrayIcon() trayIcon = new QSystemTrayIcon(this); trayIcon->setContextMenu(trayIconMenu); - trayIcon->setIcon(QIcon::fromTheme("image-loading")); + trayIcon->setIcon(QIcon(":/main/resources/psv_icon.png")); + trayIcon->show(); + // try to avoid the iconTray Qt bug + //Sleeper::sleep(1); } void MainWidget::receiveMessage(QString message) diff --git a/mainwidget.h b/mainwidget.h index c48ac2d..3184613 100644 --- a/mainwidget.h +++ b/mainwidget.h @@ -21,19 +21,20 @@ #define MAINWIDGET_H #include "configwidget.h" -#include "qcma.h" +#include "cmaserver.h" +#include "database.h" #include #include #include -class QMenu; - -namespace Ui -{ -class MainWidget; +extern "C" { +#include } + +class QMenu; + class MainWidget : public QWidget { Q_OBJECT @@ -49,13 +50,14 @@ private: void connectSignals(); bool first_run; - QCMA CmaWorker; ConfigWidget dialog; QSystemTrayIcon *trayIcon; QAction *quit; QAction *reload; QAction *options; QAction *wireless; + Database db; + CmaServer server; const static QStringList path_list; private slots: @@ -65,6 +67,9 @@ private slots: void setTrayTooltip(QString message); void toggleWireless(); void showPin(int pin); + void startClient(vita_device_t *device); + void refreshDatabase(); + void startServer(); }; #endif // MAINWIDGET_H diff --git a/qcma.cpp b/qcma.cpp deleted file mode 100644 index 41371f8..0000000 --- a/qcma.cpp +++ /dev/null @@ -1,174 +0,0 @@ -/* - * QCMA: Cross-platform content manager assistant for the PS Vita - * - * Copyright (C) 2013 Codestation - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include "qcma.h" - -#include "capability.h" -#include "listenerworker.h" -#include "wirelessworker.h" - -#include -#include -#include -#include -#include -#include -#include - -#include - -#define RETRY_TIMEOUT 2000 - -QCMA::QCMA(QObject *parent) : - BaseWorker(parent) -{ - exit_thread = false; -} - -vita_device_t *QCMA::connectWireless() -{ - int num_tries = 0; - vita_device_t *vita = NULL; - WirelessWorker *broadcast = new WirelessWorker(); - - // bubble up the pin received signal - connect(broadcast, SIGNAL(createdPin(int)), this, SIGNAL(createdPin(int))); - - qDebug("Starting broadcast"); - broadcast->start(); - - QMutex mutex; - QString hostname = QHostInfo::localHostName(); - WirelessWorker::info.name = hostname.toUtf8().data(); - - while(!break_loop && (vita = VitaMTP_Get_First_Wireless_Vita( - &WirelessWorker::info, 0, 10, - WirelessWorker::deviceRegistered, - WirelessWorker::generatePin)) == NULL) { - qDebug("Error connecting to device. Attempt %d", ++num_tries); - //FIXME: use a proper sleep function - mutex.lock(); - waitCondition.wait(&mutex, RETRY_TIMEOUT); - mutex.unlock(); - } - qDebug("Stopping broadcast"); - broadcast->stopBroadcast(); - return vita; -} - -vita_device_t *QCMA::connectUsb() -{ - int num_tries = 0; - vita_device_t *vita = NULL; - QMutex mutex; - while(!break_loop && (vita = VitaMTP_Get_First_USB_Vita()) == NULL) { - qDebug("No Vita found. Attempt %d", ++num_tries); - //FIXME: use a proper sleep function - mutex.lock(); - waitCondition.wait(&mutex, RETRY_TIMEOUT); - mutex.unlock(); - } - - return vita; -} - -void QCMA::process() -{ - QSettings settings; - - qDebug() << "From QCMA: "<< QThread::currentThreadId(); - - while(!exit_thread) { - break_loop = false; - VitaMTP_Set_Logging(VitaMTP_NONE); - bool wireless = settings.value("wireless", false).toBool(); - emit statusUpdated("Searching for device..."); - vita_device_t *device = wireless ? connectWireless() : connectUsb(); - if(!device) { - continue; - } - - qDebug("Vita connected: id %s", VitaMTP_Get_Identification(device)); - - // create a listener thread to receive the vita events - ListenerWorker *listener = new ListenerWorker(); - listener->setDevice(device); - connect(listener, SIGNAL(refreshDatabase()), this, SLOT(allowRefresh()), Qt::DirectConnection); - connect(listener, SIGNAL(finished()), this, SIGNAL(deviceDisconnected()), Qt::DirectConnection); - connect(listener, SIGNAL(finished()), this, SLOT(reload()), Qt::DirectConnection); - listener->start(); - qDebug("Exchanging info with vita"); - DeviceCapability *vita_info = new DeviceCapability(); - - if(!vita_info->exchangeInfo(device)) { - qCritical("Error while exchanging info with the vita"); - VitaMTP_SendHostStatus(device, VITA_HOST_STATUS_EndConnection); - VitaMTP_Release_Device(device); - sleep(RETRY_TIMEOUT); - continue; - } - - // Conection successful, inform the user - emit deviceConnected(QString(tr("Connected to ")) + vita_info->getOnlineId()); - - delete vita_info; - QElapsedTimer timer; - qint64 sec; - - while(listener->isConnected()) { - sema.acquire(); - if(break_loop) { - break; - } - qDebug("Updating database"); - timer.start(); - int scanned_objects = listener->rebuildDatabase(); - sec = timer.elapsed(); - qDebug("Scanned %i objects in %lli milliseconds", scanned_objects, sec); - emit statusUpdated(QString("Scanned %1 objects in %2 milliseconds").arg(scanned_objects, sec)); - } - - qDebug("Ending device connection..."); - VitaMTP_SendHostStatus(device, VITA_HOST_STATUS_EndConnection); - VitaMTP_Release_Device(device); - } - qDebug("QCMA thread end"); - emit finished(); -} - -void QCMA::allowRefresh() -{ - sema.release(); -} - -void QCMA::reload() -{ - qDebug("Stopping QCMA workers..."); - break_loop = true; - waitCondition.wakeAll(); - sema.release(); -} - -void QCMA::stop() -{ - exit_thread = true; - reload(); - qDebug("Stopping QCMA thread..."); - emit stopCMA(); -} diff --git a/qcma.h b/qcma.h deleted file mode 100644 index 9ebdea6..0000000 --- a/qcma.h +++ /dev/null @@ -1,70 +0,0 @@ -/* - * QCMA: Cross-platform content manager assistant for the PS Vita - * - * Copyright (C) 2013 Codestation - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#ifndef QCMA_H -#define QCMA_H - -#include "baseworker.h" - -#include -#include -#include -#include -#include -#include - -class QMenu; - -extern "C" { -#include -} - -#define QCMA_VERSION_STRING "QCMA 0.1" - -class QCMA : public BaseWorker -{ - Q_OBJECT -public: - explicit QCMA(QObject *parent = 0); - -private: - QSemaphore sema; - QWaitCondition waitCondition; - volatile bool break_loop; - volatile bool exit_thread; - vita_device_t *connectUsb(); - vita_device_t *connectWireless(); - -signals: - void createdPin(int); - void deviceConnected(QString); - void statusUpdated(QString); - void deviceDisconnected(); - void stopCMA(); - -public slots: - void stop(); - void reload(); - -protected slots: - void allowRefresh(); - virtual void process(); -}; - -#endif // QCMA_H diff --git a/qcma.pro b/qcma.pro index c09f266..09522fb 100644 --- a/qcma.pro +++ b/qcma.pro @@ -14,9 +14,7 @@ TARGET = qcma TEMPLATE = app SOURCES += main.cpp \ - qcma.cpp \ wirelessworker.cpp \ - listenerworker.cpp \ capability.cpp \ database.cpp \ cmaobject.cpp \ @@ -26,12 +24,12 @@ SOURCES += main.cpp \ configwidget.cpp \ singleapplication.cpp \ baseworker.cpp \ - sforeader.cpp + sforeader.cpp \ + cmaserver.cpp \ + cmaclient.cpp HEADERS += \ - qcma.h \ wirelessworker.h \ - listenerworker.h \ capability.h \ database.h \ cmaobject.h \ @@ -41,7 +39,9 @@ HEADERS += \ configwidget.h \ singleapplication.h \ baseworker.h \ - sforeader.h + sforeader.h \ + cmaserver.h \ + cmaclient.h CONFIG += link_pkgconfig PKGCONFIG += libvitamtp libmediainfo @@ -52,7 +52,8 @@ RESOURCES += \ qcmares.qrc OTHER_FILES += \ - psp2-updatelist.xml + resources/psp2-updatelist.xml \ + resources/psv_icon.png FORMS += \ configwidget.ui diff --git a/qcmares.qrc b/qcmares.qrc index b296c1b..54fcc53 100644 --- a/qcmares.qrc +++ b/qcmares.qrc @@ -1,5 +1,6 @@ - psp2-updatelist.xml + resources/psp2-updatelist.xml + resources/psv_icon.png diff --git a/psp2-updatelist.xml b/resources/psp2-updatelist.xml similarity index 100% rename from psp2-updatelist.xml rename to resources/psp2-updatelist.xml diff --git a/resources/psv_icon.png b/resources/psv_icon.png new file mode 100644 index 0000000..650ccaf Binary files /dev/null and b/resources/psv_icon.png differ diff --git a/singleapplication.cpp b/singleapplication.cpp index 0b5532f..3862d0a 100644 --- a/singleapplication.cpp +++ b/singleapplication.cpp @@ -20,7 +20,6 @@ #include "singleapplication.h" #include -#include const int SingleApplication::timeout = 500; const QString SingleApplication::SHARED_KEY = "QCMA_KEY"; @@ -30,15 +29,7 @@ SingleApplication::SingleApplication(int &argc, char **argv) : { server = new QLocalServer(this); connect(server, SIGNAL(newConnection()), this, SLOT(receiveMessage())); -#ifdef Q_OS_UNIX - // Make sure that the socket file is deleted - QFile address(QString("/tmp/" + SHARED_KEY)); - - if(address.exists()) { - address.remove(); - } - -#endif + QLocalServer::removeServer(SHARED_KEY); server->listen(SHARED_KEY); } diff --git a/utils.h b/utils.h index 2073677..632d22e 100644 --- a/utils.h +++ b/utils.h @@ -21,6 +21,20 @@ #define UTILS_H #include +#include + +// Qt4 doesn't have public methods for Thread::*sleep +#if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0) + typedef QThread Sleeper; +#else + class Sleeper : QThread + { + public: + static void sleep(unsigned long secs) { QThread::sleep(secs); } + static void msleep(unsigned long msecs) { QThread::msleep(msecs); } + static void usleep(unsigned long usecs) { QThread::usleep(usecs); } + }; +#endif bool removeRecursively(const QString &dirName); bool getDiskSpace(const QString &dir, quint64 *free, quint64 *total); diff --git a/wirelessworker.cpp b/wirelessworker.cpp index 30a94c6..1550a48 100644 --- a/wirelessworker.cpp +++ b/wirelessworker.cpp @@ -17,32 +17,38 @@ * along with this program. If not, see . */ -#include "qcma.h" #include "wirelessworker.h" +#include "utils.h" #include #include #define QCMA_REQUEST_PORT 9309 -wireless_host_info_t WirelessWorker::info = {"00000000-0000-0000-0000-000000000000", "win", NULL, QCMA_REQUEST_PORT}; +wireless_host_info_t BroadcastSignal::info = {"00000000-0000-0000-0000-000000000000", "win", NULL, QCMA_REQUEST_PORT}; -WirelessWorker *WirelessWorker::this_object = NULL; +BroadcastSignal *BroadcastSignal::this_object = NULL; -WirelessWorker::WirelessWorker(QObject *parent) : +BroadcastSignal::BroadcastSignal(QObject *parent) : BaseWorker(parent) { qsrand(QTime::currentTime().msec()); this_object = this; + started = false; } -int WirelessWorker::deviceRegistered(const char *deviceid) +BroadcastSignal::~BroadcastSignal() +{ + VitaMTP_Stop_Broadcast(); +} + +int BroadcastSignal::deviceRegistered(const char *deviceid) { qDebug("Got connection request from %s", deviceid); return 1; } -int WirelessWorker::generatePin(wireless_vita_info_t *info, int *p_err) +int BroadcastSignal::generatePin(wireless_vita_info_t *info, int *p_err) { qDebug("Registration request from %s (MAC: %s)", info->name, info->mac_addr); int pin = qrand() % 100000000; @@ -52,25 +58,24 @@ int WirelessWorker::generatePin(wireless_vita_info_t *info, int *p_err) return pin; } -void WirelessWorker::process() +void BroadcastSignal::process() { - qDebug() <<" Wireless thread ID: "<< QThread::currentThreadId(); - - wireless_host_info_t broadcast_info = info; - QString hostname = QHostInfo::localHostName(); - broadcast_info.name = hostname.toUtf8().data(); - + qDebug() <<"Broadcast thread ID: "<< QThread::currentThreadId(); qDebug("Starting CMA wireless broadcast..."); - if(VitaMTP_Broadcast_Host(&broadcast_info, 0) < 0) { + + started = true; + if(VitaMTP_Broadcast_Host(&info, 0) < 0) { qCritical( "An error occured during broadcast. Exiting."); } else { qDebug("Broadcast ended."); } - qDebug("WirelessrWorker thread end."); + qDebug("Broadcast thread end."); emit finished(); } -void WirelessWorker::stopBroadcast() +void BroadcastSignal::stopBroadcast() { + qDebug("Stopping broadcast"); VitaMTP_Stop_Broadcast(); + started = false; } diff --git a/wirelessworker.h b/wirelessworker.h index 4305e06..82c602c 100644 --- a/wirelessworker.h +++ b/wirelessworker.h @@ -29,21 +29,24 @@ extern "C" { #include } -class WirelessWorker : public BaseWorker +class BroadcastSignal : public BaseWorker { Q_OBJECT public: - explicit WirelessWorker(QObject *parent = 0); + explicit BroadcastSignal(QObject *parent = 0); + ~BroadcastSignal(); static int deviceRegistered(const char *deviceid); static int generatePin(wireless_vita_info_t *info, int *p_err); + bool isRunning() { return started; } static wireless_host_info_t info; private: + volatile bool started; //used to emit a signal from a static method - static WirelessWorker *this_object; + static BroadcastSignal *this_object; signals: void createdPin(int);