Mercurial > public > ostc_companion
view HardwareOperations.cpp @ 12:ac837fe1d590 default tip
Switch implementation for reqex class and added RFCOMM as label for Bluetooth based connection by Linux
| author | Ideenmodellierer |
|---|---|
| date | Mon, 12 Jan 2026 13:58:41 +0000 |
| parents | e30f00f760d3 |
| children |
line wrap: on
line source
///////////////////////////////////////////////////////////////////////////// /// \file HardwareOperations.cpp /// \brief Abstract operations for HW dive computers. /// \author JD Gascuel. /// \sa OSTC3Operations.cpp /// /// \copyright (c) 2011-2016 JD Gascuel. All rights reserved. /// $Id$ /////////////////////////////////////////////////////////////////////////////// // // BSD 2-Clause License: // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions // are met: // // 1. Redistributions of source code must retain the above copyright notice, // this list of conditions and the following disclaimer. // // 2. Redistributions in binary form must reproduce the above copyright notice, // this list of conditions and the following disclaimer in the documentation // and/or other materials provided with the distribution. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF // THE POSSIBILITY OF SUCH DAMAGE. // ////////////////////////////////////////////////////////////////////////////// #include "HardwareOperations.h" #include <QSerialPortInfo> #include "MainWindow.h" #include "Utils/Log.h" #include <QRegularExpression> #ifdef WIN32 #include <winreg.h> #endif #include <QDir> ////////////////////////////////////////////////////////////////////////////// unsigned char HardwareOperations::retryCommand(Serial &serial, unsigned char cmd, int retries) { for (int retry = 0; retry < retries; ++retry) { serial.writeByte(cmd); // Send command serial.sleep(25); // Allow 25msec lag. try { unsigned char echo = serial.readByte(); if (echo == cmd || echo == 'M' || echo == 'L') return echo; // Got it, or unknown command... } catch (const ReadTimeout &) { continue; } serial.sleep(100); // Cleanup any pending stuff, serial.purge(); // and retry... } return 0xFF; } ////////////////////////////////////////////////////////////////////////////// HardwareOperations::HardwareDescriptor HardwareOperations::hardwareDescriptor() { unsigned char echo = 0; unsigned int hardFeatures = 0xFF; // timeout response... unsigned int softFeatures = 0; unsigned int model = 0; unsigned char ok = 0; try { //---- First: try the new extended hardware query -------------------- echo = retryCommand(_serial, 0x60, 1); // BACKQUOTE char if (echo == 0x60) { uchar extendedDescriptor[6]; _serial.readBlock(extendedDescriptor, sizeof extendedDescriptor); hardFeatures = extendedDescriptor[0] * 256 + extendedDescriptor[1]; softFeatures = extendedDescriptor[2] * 256 + extendedDescriptor[3]; model = extendedDescriptor[4]; ok = extendedDescriptor[5]; } else { // Did we have a timeout ? // In that case, some hwOS versions fails and need a reset of // the connection mode... if (echo == 0xFF) { echo = retryCommand(_serial, 0xBB); // Try to reconnect if (echo == 0xBB) echo = _serial.readByte(); // Eat 4d prompt } // Then try the OLD hardware descriptor command... echo = retryCommand(_serial, 'j'); // 0x6A if (echo == 'j') { hardFeatures = _serial.readByte(); ok = _serial.readByte(); } } } catch (const ReadTimeout &) { } if ((echo != 0x60 && echo != 'j') || (ok != 'M' && ok != 'L')) { LOG_TRACE("Old OSTC not responding..."); return HW_UNKNOWN_OSTC; } switch (hardFeatures) { case HW_Frog: LOG_TRACE("Frog found"); break; case HW_OSTCSport_a: LOG_TRACE("OSTC Sport found"); break; case HW_OSTC2c: LOG_TRACE("OSTC 2c found"); break; case HW_OSTC2_a: case HW_OSTC2_c: LOG_TRACE("OSTC 2 found"); break; case HW_OSTCcR_a: case HW_OSTCcR_b: LOG_TRACE("OSTC cR found"); break; case HW_OSTC3: LOG_TRACE("OSTC 3 found"); break; case HW_OSTC3p_a: LOG_TRACE("OSTC 3+ found"); break; case HW_OSTC4: LOG_TRACE("OSTC 4/5 found"); break; case HW_OSTCSport_b: LOG_TRACE("OSTC Sport, OSTC 2 or OSTC 3 found."); break; case 0xFF: case 0x4C: case 0x4D: LOG_TRACE("old OSTC not responding..."); return HW_UNKNOWN_OSTC; default: // LOG_TRACE("Unknown hardware feature =" << QString().sprintf("0x%04x", hardFeatures)); LOG_TRACE("Unknown hardware feature =" << QString::asprintf("0x%04x", hardFeatures)); break; } if (echo == 0x60) { LOG_TRACE(" software feature = " << QString::asprintf("0x%04x", softFeatures)); LOG_TRACE(" model = " << QString::asprintf("0x%02x", model)); } return (HardwareDescriptor) hardFeatures; } ////////////////////////////////////////////////////////////////////////////// QStringList HardwareOperations::listBluetoothPorts() const { assert(supported() & BLUETOOTH); QStringList list; QString PortDesc; const auto serialPortInfos = QSerialPortInfo::availablePorts(); #if defined(Q_OS_MAC) || defined(Q_OS_LINUX) // TODO: Linux USB search... QRegularExpression pTemplate = portTemplate(); QDir dev("/dev"); QStringList all = dev.entryList(QStringList() << "rfcomm*" << "tty.*", QDir::NoDotAndDotDot | QDir::Files | QDir::System | QDir::Writable, QDir::Name); for (int i = 0; i < all.count(); ++i) { QRegularExpressionMatch match = pTemplate.match(all[i]); if (match.hasMatch()) { LOG_TRACE("Port " << all[i]); list += all[i]; } else { LOG_DEBUG("... " << all[i]); } } #else /* Check the descriptors of the available COMs for Bluetooth tag */ for (const QSerialPortInfo &serialPortInfo : serialPortInfos) { PortDesc = serialPortInfo.description(); if (PortDesc.contains("Bluetooth")) list += serialPortInfo.portName(); } if (list.isEmpty()) /* no port identified => fallback to old detection function */ { for (int i = 1; i < 300; ++i) { QString port = QString("COM%1").arg(i); // First: try to read default configuration... COMMCONFIG config = {0}; config.dwSize = sizeof config; config.wVersion = 1; DWORD len = sizeof config; QByteArray fixed = "\\\\.\\" + port.toLocal8Bit(); if (GetDefaultCommConfigA(fixed.constData(), &config, &len)) { if (config.dwProviderSubType == PST_RS232) list += port; } } //---- Second chance // overide usual MS bug, by looking into the registry for more // BLUETOOTH ports... { HKEY key; const char registryPath[] = "HARDWARE\\DEVICEMAP\\SERIALCOMM"; if (RegOpenKeyExA(HKEY_LOCAL_MACHINE, // PWD registryPath, // "SOFTWARE\Intel\PSIB" 0, // Options KEY_READ, // Desired SAM: See 32bits view. &key) == ERROR_SUCCESS) { for (DWORD i = 0; ++i;) { char nameBuffer[128] = {0}; DWORD nameLen = sizeof nameBuffer; unsigned char dataBuffer[128] = {0}; DWORD dataLen = sizeof dataBuffer; long rc = RegEnumValueA(key, i, nameBuffer, &nameLen, nullptr, nullptr, dataBuffer, &dataLen); if (rc != ERROR_SUCCESS) break; QString name = QString(nameBuffer); QString port = QString((char *) dataBuffer); LOG_TRACE("Resource " << i << ": " << name << ", " << port); if (name.contains("\\BtModem") || name.contains("\\BthModem") || name.contains("\\BtPort")) { list += port + " (Bluetooth)"; LOG_TRACE("Port " << name); } else LOG_DEBUG("... " << name); } RegCloseKey(key); } } } #endif return list; } ////////////////////////////////////////////////////////////////////////////// QStringList HardwareOperations::listUSBPorts() const { assert(!(supported() & BLUETOOTH)); QStringList list; #if defined(Q_OS_MAC) || defined(Q_OS_LINUX) // TODO: Linux USB search... QDir dev("/dev"); QRegularExpression pTemplate = portTemplate(); // Hier bleibt alles gleich QStringList all = dev.entryList(QStringList() << "tty.*", QDir::System | QDir::Writable | QDir::NoDotAndDotDot, QDir::Name); for (int i = 0; i < all.count(); ++i) { // Verwende QRegularExpression::match anstelle von indexIn QRegularExpressionMatch match = pTemplate.match(all[i]); if (match.hasMatch()) { // Überprüfe, ob eine Übereinstimmung gefunden wurde LOG_TRACE("Port " << all[i]); list += all[i]; } else { LOG_TRACE("... " << all[i]); } } #else //---- First chance: Try the normal port list: for (int i = 1; i < 300; ++i) { QString port = QString("COM%1").arg(i); // First: try to read default configuration... COMMCONFIG config; memset(&config, 0, sizeof config); config.dwSize = sizeof config; config.wVersion = 1; DWORD len = sizeof config; QByteArray fixed = "\\\\.\\" + port.toLocal8Bit(); if (GetDefaultCommConfigA(fixed.constData(), &config, &len)) { LOG_TRACE("Port " << port << " subtype=" << int(config.dwProviderSubType)); if (config.dwProviderSubType == PST_RS232) list += port; } else if (len != sizeof config) LOG_THROW("Required " << len << " bytes."); else if (HRESULT rc = GetLastError()) if (rc != 87) LOG_TRACE("Port " << port << " error=" << rc); } //---- Second chance // overide usual MS bug, by looking into the registry for more // USB serial ports... { HKEY key; const char registryPath[] = "HARDWARE\\DEVICEMAP\\SERIALCOMM"; if (RegOpenKeyExA(HKEY_LOCAL_MACHINE, // PWD registryPath, // path 0, // Options KEY_READ, // Desired SAM: See 32bits view. &key) == ERROR_SUCCESS) { for (DWORD i = 0;; ++i) { char nameBuffer[128] = {0}; DWORD nameLen = sizeof nameBuffer; unsigned char dataBuffer[128] = {0}; DWORD dataLen = sizeof dataBuffer; long rc = RegEnumValueA(key, i, nameBuffer, &nameLen, nullptr, nullptr, dataBuffer, &dataLen); if (rc == ERROR_NO_MORE_ITEMS) break; if (rc != ERROR_SUCCESS) LOG_THROW("Enumeration error"); QString name = QString(nameBuffer); QString port = QString((char *) dataBuffer); LOG_TRACE("Resource " << i << ": " << name << ", " << port); if (name.contains("\\VCP")) list += port + " (USB)"; } RegCloseKey(key); } } #endif return list; } ////////////////////////////////////////////////////////////////////////////// //QString HardwareOperations::scanNewPort() //{ // static QStringList oldPorts; // //---- Get current ports, type-less (ie. strip (USB) or (Bluetooth) ------ // QStringList newPorts; // foreach(QString port, listPorts()) // newPorts += port.section(" ", 0, 0); // //---- Simplify all ports not in the list anymore ----------------------- // for(int p=0; p<oldPorts.count(); ++p) { // QString port = oldPorts[p]; // if( ! newPorts.contains(port) ) // oldPorts.removeAll(port); // } // //---- Check for new port in the list ----------------------------------- // for(int p=0; p<newPorts.count(); ++p) { // QString port = newPorts[p]; // // Did we find a new port ? // if( ! oldPorts.contains(port) ) { // oldPorts += port; // return port; // } // } // return QString::null; //}
