#include "VBluetooth.h" #include "BLEScanner.h" // Qt // Project using namespace View; VBluetooth::VBluetooth(QObject *parent) : QObject(parent) { // incoming connect(&_BLEScanner, SIGNAL(didReceiveScanForDevicesError(QBluetoothDeviceDiscoveryAgent::Error)), this, SLOT(onScanForDevicesError(QBluetoothDeviceDiscoveryAgent::Error))); connect(&_BLEScanner, SIGNAL(didFinishScan()), this, SLOT(onScanForDevicesFinished())); connect(&_BLEScanner, SIGNAL(didDiscoverDevice(QBluetoothDeviceInfo)), this, SLOT(onDeviceDiscovered(const QBluetoothDeviceInfo))); connect(&_BLEScanner, SIGNAL(didStartConnectingToDevice()), this, SLOT(onConnectingToDevice())); connect(&_BLEScanner, SIGNAL(didReceiveControllerError(QLowEnergyController::Error)), this, SLOT(onControllerError(QLowEnergyController::Error))); connect(&_BLEScanner, SIGNAL(didConnectToDevice(QBluetoothDeviceInfo)), this, SLOT(onConnectedToDevice(QBluetoothDeviceInfo))); // outgoing connect(this, SIGNAL(didSelectDevice(const QString)), &_BLEScanner, SLOT(doSelectDevice(const QString))); connect(this, SIGNAL(didRequestScanForDevices()), &_BLEScanner, SLOT(doScanForDevices())); } /*! * \brief VBluetooth::onScanForDevices * Slot for when the user starts scanning for devices. * Updates the status and emits a signal to the BLEScanner to * begin a new scan. */ void VBluetooth::doScanForDevices() { bleDevices.clear(); emit didDevicesChanged(); emit didRequestScanForDevices(); onUpdateStatus(tr("Scanning...")); } /*! * \brief VBluetooth::onScanForDevicesError * Slot called when the BLEScanner enounters an error * while scanning for devices * \param error */ void VBluetooth::onScanForDevicesError(QBluetoothDeviceDiscoveryAgent::Error error) { switch (error) { case QBluetoothDeviceDiscoveryAgent::PoweredOffError: onUpdateStatus(tr("Error: The bluetooth module is powered off.")); break; default: onUpdateStatus(tr("Error: Scan for devices error.")); break; } } /*! * \brief VBluetooth::onDeviceDiscovered * Slot for when a device is discovered by the BLEScanner. * \param device - the BLE Device info of the discovered device */ void VBluetooth::onDeviceDiscovered(const QBluetoothDeviceInfo &device) { VBluetoothDeviceInfo *info = new VBluetoothDeviceInfo(device); if (!isDeviceAlreadyPaired(device)) bleDevices.append(info); qDebug() << "VBluetooth: Discovered " << device.address(); emit didDevicesChanged(); } /*! * \brief VBluetooth::onScanForDevicesFinished * Slot called when the scan is finished. Updates the scanning status. */ void VBluetooth::onScanForDevicesFinished() { emit didScanFinished(); onUpdateStatus(tr("Scan Finished.")); } /*! * \brief VBluetooth::getDevices * Gets the BLE modelData for QML * \return QVariant - the modelData */ QVariant VBluetooth::doGetDevices() { return QVariant::fromValue(bleDevices); } /*! * \brief VBluetooth::getDevices * Gets the paired devices BLE modelData for QML * \return QVariant - the modelData */ QVariant VBluetooth::doGetPairedDevices() { return QVariant::fromValue(pairedDevices); } /*! * \brief VBluetooth::onSelectedDevice * Emits a signal that the device was selected * \param addr - the selected BLE mac address */ void VBluetooth::doSelectDevice(const QString &addr) { emit didSelectDevice(addr); } /*! * \brief onUpdateStatus * Updates the status and emits a signal to notify the QML * \param message */ void VBluetooth::onUpdateStatus(const QString &message) { status = message; emit didStatusChanged(); } /*! * \brief VBluetooth::onConnectingToDevice * Called when attempting to connect to a device */ void VBluetooth::onConnectingToDevice() { onUpdateStatus(tr("Connecting...")); } /*! * \brief VBluetooth::controllerErrorToString * Converts a QLowEnergyController::Error enum to QString * \param error - the QLowEnergyController::Error enum * \return QString - the enum converted to a QString */ QString VBluetooth::controllerErrorToString(QLowEnergyController::Error error) { switch (error) { case QLowEnergyController::NoError: return tr("No Error."); break; case QLowEnergyController::UnknownError: return tr("Unknown Error."); break; case QLowEnergyController::UnknownRemoteDeviceError: return tr("Unknown Remote Device Error."); break; case QLowEnergyController::NetworkError: return tr("Bluetooth Network Error."); break; case QLowEnergyController::InvalidBluetoothAdapterError: return tr("Bluetooth Adapter Error."); break; case QLowEnergyController::ConnectionError: case QLowEnergyController::AdvertisingError: case QLowEnergyController::RemoteHostClosedError: return tr("Connection Error."); break; default: const QMetaObject *mo = qt_getEnumMetaObject(error); int idx = mo->indexOfEnumerator(qt_getEnumName(error)); const char *text = mo->enumerator(idx).valueToKey(error); if (!QString(text).isEmpty()) { return tr(text); } } return tr("Unexpected Error."); } /*! * \brief VBluetooth::onControllerError * Called when BLE interface reports a controller error. Updates * the bluetooth status message according to the error reported. * \param error - the low energy controller error reported */ void VBluetooth::onControllerError(QLowEnergyController::Error error) { onUpdateStatus(controllerErrorToString(error)); } /*! * \brief VBluetooth::isDeviceAlreadyPaired * Determines if a device has already been paired * \param deviceInfo - the device info to check if paired * \return bool - true if already paired, false otherwise */ bool VBluetooth::isDeviceAlreadyPaired(const QBluetoothDeviceInfo &deviceInfo) { bool alreadyPaired = false; for (QObject *device : pairedDevices) { VBluetoothDeviceInfo *pairedDevice = static_cast(device); if (pairedDevice->getAddress() == deviceInfo.address().toString()) alreadyPaired = true; } return alreadyPaired; } /*! * \brief VBluetooth::removeFromDevices * Removes a device from the non-paired bluetooth devices list * Adds that devices to the non-paired bluetooth devices blacklist * \param info - the bluetooth device info object to remove */ void VBluetooth::removeFromDevices(const VBluetoothDeviceInfo *info) { QList idxs; int i = 0; for (QObject *bleDevice : bleDevices) { VBluetoothDeviceInfo *device = static_cast(bleDevice); if (device->getAddress() == info->getAddress()) idxs.append(i); ++i; } for (int i : idxs) bleDevices.removeAt(i); // update the QML emit didDevicesChanged(); } /*! * \brief VBluetooth::onConnectedToDevice * Slot called when BLEScanner connects to a device. Moves a device * from the devices list to the my devices list * \param deviceInfo - the device connected to */ void VBluetooth::onConnectedToDevice(const QBluetoothDeviceInfo &deviceInfo) { VBluetoothDeviceInfo *info = new VBluetoothDeviceInfo(deviceInfo); bool alreadyPaired = isDeviceAlreadyPaired(deviceInfo); if (!alreadyPaired) { pairedDevices.append(info); emit didPairedDevicesChanged(); removeFromDevices(info); } onUpdateStatus(tr("Connected.")); }