/* * This file is part of openauto project. * Copyright (C) 2018 f1x.studio (Michal Szwaj) * * openauto 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. * openauto 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 openauto. If not, see . */ #include #include #include #include #include #include #include #include "aasdk/USB/USBHub.hpp" #include "aasdk/USB/ConnectedAccessoriesEnumerator.hpp" #include "aasdk/USB/AccessoryModeQueryChain.hpp" #include "aasdk/USB/AccessoryModeQueryChainFactory.hpp" #include "aasdk/USB/AccessoryModeQueryFactory.hpp" #include "aasdk/TCP/TCPWrapper.hpp" #include "openauto/App.hpp" #include "openauto/Configuration/IConfiguration.hpp" #include "openauto/Configuration/RecentAddressesList.hpp" #include "openauto/Service/AndroidAutoEntityFactory.hpp" #include "openauto/Service/ServiceFactory.hpp" #include "openauto/Configuration/Configuration.hpp" #include "autoapp/UI/MainWindow.hpp" #include "autoapp/UI/SettingsWindow.hpp" #include "autoapp/UI/ConnectDialog.hpp" #include "OpenautoLog.hpp" using namespace openauto; using ThreadPool = std::vector; void startUSBWorkers(boost::asio::io_service &ioService, libusb_context *usbContext, ThreadPool &threadPool) { auto usbWorker = [&ioService, usbContext]() { timeval libusbEventTimeout{180, 0}; while (!ioService.stopped()) { libusb_handle_events_timeout_completed(usbContext, &libusbEventTimeout, nullptr); } }; threadPool.emplace_back(usbWorker); threadPool.emplace_back(usbWorker); threadPool.emplace_back(usbWorker); threadPool.emplace_back(usbWorker); } void startIOServiceWorkers(boost::asio::io_service &ioService, ThreadPool &threadPool) { auto ioServiceWorker = [&ioService]() { ioService.run(); }; threadPool.emplace_back(ioServiceWorker); threadPool.emplace_back(ioServiceWorker); threadPool.emplace_back(ioServiceWorker); threadPool.emplace_back(ioServiceWorker); } int main(int argc, char *argv[]) { libusb_context *usbContext; if (libusb_init(&usbContext) != 0) { OPENAUTO_LOG(error) << "[OpenAuto] libusb init failed."; return 1; } boost::asio::io_service ioService; boost::asio::io_service::work work(ioService); std::vector threadPool; startUSBWorkers(ioService, usbContext, threadPool); startIOServiceWorkers(ioService, threadPool); QApplication qApplication(argc, argv); autoapp::ui::MainWindow mainWindow; mainWindow.setWindowFlags(Qt::WindowStaysOnTopHint); auto configuration = std::make_shared(); autoapp::ui::SettingsWindow settingsWindow(configuration); settingsWindow.setWindowFlags(Qt::WindowStaysOnTopHint); openauto::configuration::RecentAddressesList recentAddressesList(7); recentAddressesList.read(); aasdk::tcp::TCPWrapper tcpWrapper; autoapp::ui::ConnectDialog connectDialog(ioService, tcpWrapper, recentAddressesList); connectDialog.setWindowFlags(Qt::WindowStaysOnTopHint); QObject::connect(&mainWindow, &autoapp::ui::MainWindow::exit, []() { std::exit(0); }); QObject::connect(&mainWindow, &autoapp::ui::MainWindow::openSettings, &settingsWindow, &autoapp::ui::SettingsWindow::showFullScreen); QObject::connect(&mainWindow, &autoapp::ui::MainWindow::openConnectDialog, &connectDialog, &autoapp::ui::ConnectDialog::exec); qApplication.setOverrideCursor(Qt::BlankCursor); QObject::connect(&mainWindow, &autoapp::ui::MainWindow::toggleCursor, [&qApplication]() { const auto cursor = qApplication.overrideCursor()->shape() == Qt::BlankCursor ? Qt::ArrowCursor : Qt::BlankCursor; qApplication.setOverrideCursor(cursor); }); mainWindow.showFullScreen(); aasdk::usb::USBWrapper usbWrapper(usbContext); aasdk::usb::AccessoryModeQueryFactory queryFactory(usbWrapper, ioService); aasdk::usb::AccessoryModeQueryChainFactory queryChainFactory(usbWrapper, ioService, queryFactory); openauto::service::ServiceFactory serviceFactory(ioService, configuration); openauto::service::AndroidAutoEntityFactory androidAutoEntityFactory(ioService, configuration, serviceFactory); auto usbHub(std::make_shared(usbWrapper, ioService, queryChainFactory)); auto connectedAccessoriesEnumerator(std::make_shared(usbWrapper, ioService, queryChainFactory)); auto app = std::make_shared(ioService, usbWrapper, tcpWrapper, androidAutoEntityFactory, std::move(usbHub), std::move(connectedAccessoriesEnumerator)); QObject::connect(&connectDialog, &autoapp::ui::ConnectDialog::connectionSucceed, [&app](auto socket) { app->start(std::move(socket)); }); app->waitForDevice(true); QWebSocket webSocket; QTimer reconnectTimer; const QUrl websocketUrl(QStringLiteral("ws://127.0.0.1:5959/ws")); auto tryConnect = [&webSocket, &websocketUrl]() { if (webSocket.state() != QAbstractSocket::ConnectedState && webSocket.state() != QAbstractSocket::ConnectingState) { qDebug() << "[WebSocket] Attempting to connect to" << websocketUrl.toString(); webSocket.open(websocketUrl); } }; // Connect events QObject::connect(&webSocket, &QWebSocket::connected, [&]() { qDebug() << "[WebSocket] Connected."; webSocket.sendTextMessage("Hello from OpenAuto WebSocket client!"); reconnectTimer.stop(); }); QObject::connect(&webSocket, &QWebSocket::disconnected, [&]() { qDebug() << "[WebSocket] Disconnected. Will retry..."; reconnectTimer.start(3000); }); QObject::connect(&webSocket, &QWebSocket::textMessageReceived, [&mainWindow, &connectDialog, &serviceFactory](const QString &message) { QJsonParseError error; QJsonDocument doc = QJsonDocument::fromJson(message.toUtf8(), &error); if (error.error != QJsonParseError::NoError) { qDebug() << "JSON parse error:" << error.errorString(); return; } QJsonObject rootObj = doc.object(); if (rootObj.contains("wireless_aa_ip")) { QString ipAddr = rootObj["wireless_aa_ip"].toString(); connectDialog.connectToAddress(ipAddr); } else if (rootObj.contains("button")) { QJsonObject btnObj = rootObj["button"].toObject(); QString btn = btnObj["btn"].toString(); int state = btnObj["state"].toInt(); serviceFactory.sendButtonPressFromString(btn.toStdString(), state); } else{ mainWindow.handleIncomingMessage(rootObj); } }); reconnectTimer.setInterval(3000); reconnectTimer.setSingleShot(true); QObject::connect(&reconnectTimer, &QTimer::timeout, tryConnect); tryConnect(); auto result = qApplication.exec(); std::for_each(threadPool.begin(), threadPool.end(), std::bind(&std::thread::join, std::placeholders::_1)); libusb_exit(usbContext); return result; }