comparison HardwareOperations.cpp @ 12:ac837fe1d590

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
comparison
equal deleted inserted replaced
11:6fba58c4964b 12:ac837fe1d590
34 // THE POSSIBILITY OF SUCH DAMAGE. 34 // THE POSSIBILITY OF SUCH DAMAGE.
35 // 35 //
36 ////////////////////////////////////////////////////////////////////////////// 36 //////////////////////////////////////////////////////////////////////////////
37 37
38 #include "HardwareOperations.h" 38 #include "HardwareOperations.h"
39 #include <QSerialPortInfo>
39 #include "MainWindow.h" 40 #include "MainWindow.h"
40 #include "Utils/Log.h" 41 #include "Utils/Log.h"
41 #include <QSerialPortInfo> 42
43 #include <QRegularExpression>
42 44
43 #ifdef WIN32 45 #ifdef WIN32
44 # include <winreg.h> 46 #include <winreg.h>
45 #endif 47 #endif
46 48
47 #include <QDir> 49 #include <QDir>
48 50
49 ////////////////////////////////////////////////////////////////////////////// 51 //////////////////////////////////////////////////////////////////////////////
50 52
51 unsigned char HardwareOperations::retryCommand(Serial& serial, 53 unsigned char HardwareOperations::retryCommand(Serial &serial, unsigned char cmd, int retries)
52 unsigned char cmd,
53 int retries)
54 { 54 {
55 for(int retry=0; retry<retries; ++retry) 55 for (int retry = 0; retry < retries; ++retry) {
56 { 56 serial.writeByte(cmd); // Send command
57 serial.writeByte( cmd ); // Send command 57 serial.sleep(25); // Allow 25msec lag.
58 serial.sleep(25); // Allow 25msec lag.
59 58
60 try { 59 try {
61 unsigned char echo = serial.readByte(); 60 unsigned char echo = serial.readByte();
62 if( echo == cmd || echo == 'M' || echo == 'L' ) 61 if (echo == cmd || echo == 'M' || echo == 'L')
63 return echo; // Got it, or unknown command... 62 return echo; // Got it, or unknown command...
64 } 63 } catch (const ReadTimeout &) {
65 catch(const ReadTimeout&) {
66 continue; 64 continue;
67 } 65 }
68 66
69 serial.sleep(100); // Cleanup any pending stuff, 67 serial.sleep(100); // Cleanup any pending stuff,
70 serial.purge(); // and retry... 68 serial.purge(); // and retry...
71 } 69 }
72 70
73 return 0xFF; 71 return 0xFF;
74 } 72 }
75 73
76 ////////////////////////////////////////////////////////////////////////////// 74 //////////////////////////////////////////////////////////////////////////////
77 75
78 HardwareOperations::HardwareDescriptor 76 HardwareOperations::HardwareDescriptor HardwareOperations::hardwareDescriptor()
79 HardwareOperations::hardwareDescriptor()
80 { 77 {
81 unsigned char echo = 0; 78 unsigned char echo = 0;
82 unsigned int hardFeatures = 0xFF; // timeout response... 79 unsigned int hardFeatures = 0xFF; // timeout response...
83 unsigned int softFeatures = 0; 80 unsigned int softFeatures = 0;
84 unsigned int model = 0; 81 unsigned int model = 0;
85 unsigned char ok = 0; 82 unsigned char ok = 0;
86 83
87 try { 84 try {
88 //---- First: try the new extended hardware query -------------------- 85 //---- First: try the new extended hardware query --------------------
89 echo = retryCommand(_serial, 0x60, 1); // BACKQUOTE char 86 echo = retryCommand(_serial, 0x60, 1); // BACKQUOTE char
90 if( echo == 0x60 ) { 87 if (echo == 0x60) {
91 uchar extendedDescriptor[6]; 88 uchar extendedDescriptor[6];
92 _serial.readBlock(extendedDescriptor, sizeof extendedDescriptor); 89 _serial.readBlock(extendedDescriptor, sizeof extendedDescriptor);
93 90
94
95 hardFeatures = extendedDescriptor[0] * 256 + extendedDescriptor[1]; 91 hardFeatures = extendedDescriptor[0] * 256 + extendedDescriptor[1];
96 softFeatures = extendedDescriptor[2] * 256 + extendedDescriptor[3]; 92 softFeatures = extendedDescriptor[2] * 256 + extendedDescriptor[3];
97 model = extendedDescriptor[4]; 93 model = extendedDescriptor[4];
98 ok = extendedDescriptor[5]; 94 ok = extendedDescriptor[5];
99 } 95 } else {
100 else
101 {
102 // Did we have a timeout ? 96 // Did we have a timeout ?
103 // In that case, some hwOS versions fails and need a reset of 97 // In that case, some hwOS versions fails and need a reset of
104 // the connection mode... 98 // the connection mode...
105 if( echo == 0xFF ) 99 if (echo == 0xFF) {
106 { 100 echo = retryCommand(_serial, 0xBB); // Try to reconnect
107 echo = retryCommand(_serial, 0xBB); // Try to reconnect 101 if (echo == 0xBB)
108 if( echo == 0xBB ) 102 echo = _serial.readByte(); // Eat 4d prompt
109 echo = _serial.readByte(); // Eat 4d prompt
110 } 103 }
111 104
112 // Then try the OLD hardware descriptor command... 105 // Then try the OLD hardware descriptor command...
113 echo = retryCommand(_serial, 'j'); // 0x6A 106 echo = retryCommand(_serial, 'j'); // 0x6A
114 if( echo == 'j' ) { 107 if (echo == 'j') {
115 hardFeatures = _serial.readByte(); 108 hardFeatures = _serial.readByte();
116 ok = _serial.readByte(); 109 ok = _serial.readByte();
117 } 110 }
118 } 111 }
119 } 112 } catch (const ReadTimeout &) {
120 catch(const ReadTimeout&) {} 113 }
121 114
122 if( (echo != 0x60 && echo != 'j') 115 if ((echo != 0x60 && echo != 'j') || (ok != 'M' && ok != 'L')) {
123 || (ok != 'M' && ok != 'L')
124 ) {
125 LOG_TRACE("Old OSTC not responding..."); 116 LOG_TRACE("Old OSTC not responding...");
126 return HW_UNKNOWN_OSTC; 117 return HW_UNKNOWN_OSTC;
127 } 118 }
128 119
129 switch(hardFeatures) { 120 switch (hardFeatures) {
130 case HW_Frog : LOG_TRACE("Frog found"); break; 121 case HW_Frog:
131 case HW_OSTCSport_a : LOG_TRACE("OSTC Sport found"); break; 122 LOG_TRACE("Frog found");
132 case HW_OSTC2c : LOG_TRACE("OSTC 2c found"); break; 123 break;
124 case HW_OSTCSport_a:
125 LOG_TRACE("OSTC Sport found");
126 break;
127 case HW_OSTC2c:
128 LOG_TRACE("OSTC 2c found");
129 break;
133 case HW_OSTC2_a: 130 case HW_OSTC2_a:
134 case HW_OSTC2_c : LOG_TRACE("OSTC 2 found"); break; 131 case HW_OSTC2_c:
132 LOG_TRACE("OSTC 2 found");
133 break;
135 case HW_OSTCcR_a: 134 case HW_OSTCcR_a:
136 case HW_OSTCcR_b : LOG_TRACE("OSTC cR found"); break; 135 case HW_OSTCcR_b:
137 case HW_OSTC3 : LOG_TRACE("OSTC 3 found"); break; 136 LOG_TRACE("OSTC cR found");
138 case HW_OSTC3p_a : LOG_TRACE("OSTC 3+ found"); break; 137 break;
139 case HW_OSTC4 : LOG_TRACE("OSTC 4/5 found"); break; 138 case HW_OSTC3:
140 139 LOG_TRACE("OSTC 3 found");
141 case HW_OSTCSport_b : LOG_TRACE("OSTC Sport, OSTC 2 or OSTC 3 found."); break; 140 break;
142 141 case HW_OSTC3p_a:
143 case 0xFF: case 0x4C: case 0x4D: 142 LOG_TRACE("OSTC 3+ found");
143 break;
144 case HW_OSTC4:
145 LOG_TRACE("OSTC 4/5 found");
146 break;
147
148 case HW_OSTCSport_b:
149 LOG_TRACE("OSTC Sport, OSTC 2 or OSTC 3 found.");
150 break;
151
152 case 0xFF:
153 case 0x4C:
154 case 0x4D:
144 LOG_TRACE("old OSTC not responding..."); 155 LOG_TRACE("old OSTC not responding...");
145 return HW_UNKNOWN_OSTC; 156 return HW_UNKNOWN_OSTC;
146 157
147 default: 158 default:
148 // LOG_TRACE("Unknown hardware feature =" << QString().sprintf("0x%04x", hardFeatures)); 159 // LOG_TRACE("Unknown hardware feature =" << QString().sprintf("0x%04x", hardFeatures));
149 LOG_TRACE("Unknown hardware feature =" << QString::asprintf("0x%04x", hardFeatures)); 160 LOG_TRACE("Unknown hardware feature =" << QString::asprintf("0x%04x", hardFeatures));
150 break; 161 break;
151 } 162 }
152 163
153 if( echo == 0x60 ) { 164 if (echo == 0x60) {
154 LOG_TRACE(" software feature = " << QString::asprintf("0x%04x", softFeatures)); 165 LOG_TRACE(" software feature = " << QString::asprintf("0x%04x", softFeatures));
155 LOG_TRACE(" model = " << QString::asprintf("0x%02x", model)); 166 LOG_TRACE(" model = " << QString::asprintf("0x%02x", model));
156 } 167 }
157 168
158 return (HardwareDescriptor)hardFeatures; 169 return (HardwareDescriptor) hardFeatures;
159 } 170 }
160 171
161 ////////////////////////////////////////////////////////////////////////////// 172 //////////////////////////////////////////////////////////////////////////////
162 173
163 QStringList HardwareOperations::listBluetoothPorts() const 174 QStringList HardwareOperations::listBluetoothPorts() const
167 QString PortDesc; 178 QString PortDesc;
168 const auto serialPortInfos = QSerialPortInfo::availablePorts(); 179 const auto serialPortInfos = QSerialPortInfo::availablePorts();
169 180
170 #if defined(Q_OS_MAC) || defined(Q_OS_LINUX) 181 #if defined(Q_OS_MAC) || defined(Q_OS_LINUX)
171 // TODO: Linux USB search... 182 // TODO: Linux USB search...
172 QRegExp pTemplate = portTemplate(); 183 QRegularExpression pTemplate = portTemplate();
173 QDir dev("/dev"); 184 QDir dev("/dev");
174 QStringList all = dev.entryList(QStringList() << "tty.*", 185 QStringList all = dev.entryList(QStringList() << "rfcomm*" << "tty.*",
175 QDir::NoDotAndDotDot|QDir::System|QDir::Writable, 186 QDir::NoDotAndDotDot | QDir::Files | QDir::System | QDir::Writable,
176 QDir::Name); 187 QDir::Name);
177 188
178 for(int i=0; i<(int)all.count(); ++i) { 189 for (int i = 0; i < all.count(); ++i) {
179 if( pTemplate.indexIn(all[i]) >= 0 ) { 190 QRegularExpressionMatch match = pTemplate.match(all[i]);
191
192 if (match.hasMatch()) {
180 LOG_TRACE("Port " << all[i]); 193 LOG_TRACE("Port " << all[i]);
181 list += all[i]; 194 list += all[i];
182 } 195 } else {
183 else
184 LOG_DEBUG("... " << all[i]); 196 LOG_DEBUG("... " << all[i]);
197 }
185 } 198 }
186 #else 199 #else
187 /* Check the descriptors of the available COMs for Bluetooth tag */ 200 /* Check the descriptors of the available COMs for Bluetooth tag */
188 for (const QSerialPortInfo &serialPortInfo : serialPortInfos) { 201 for (const QSerialPortInfo &serialPortInfo : serialPortInfos) {
189 PortDesc = serialPortInfo.description(); 202 PortDesc = serialPortInfo.description();
190 if( PortDesc.contains("Bluetooth")) 203 if (PortDesc.contains("Bluetooth"))
191 list += serialPortInfo.portName(); 204 list += serialPortInfo.portName();
192 } 205 }
193 206
194 if( list.isEmpty() ) /* no port identified => fallback to old detection function */ 207 if (list.isEmpty()) /* no port identified => fallback to old detection function */
195 { 208 {
196 for(int i=1; i<300; ++i) 209 for (int i = 1; i < 300; ++i) {
197 {
198 QString port = QString("COM%1").arg(i); 210 QString port = QString("COM%1").arg(i);
199 211
200 // First: try to read default configuration... 212 // First: try to read default configuration...
201 COMMCONFIG config = {0}; 213 COMMCONFIG config = {0};
202 config.dwSize = sizeof config; 214 config.dwSize = sizeof config;
203 config.wVersion = 1; 215 config.wVersion = 1;
204 DWORD len = sizeof config; 216 DWORD len = sizeof config;
205 217
206 QByteArray fixed = "\\\\.\\" + port.toLocal8Bit(); 218 QByteArray fixed = "\\\\.\\" + port.toLocal8Bit();
207 if( GetDefaultCommConfigA(fixed.constData(), &config, &len) ) { 219 if (GetDefaultCommConfigA(fixed.constData(), &config, &len)) {
208 if( config.dwProviderSubType == PST_RS232 ) 220 if (config.dwProviderSubType == PST_RS232)
209 list += port; 221 list += port;
210 } 222 }
211 } 223 }
212 224
213 //---- Second chance 225 //---- Second chance
214 // overide usual MS bug, by looking into the registry for more 226 // overide usual MS bug, by looking into the registry for more
215 // BLUETOOTH ports... 227 // BLUETOOTH ports...
216 { 228 {
217 HKEY key; 229 HKEY key;
218 const char registryPath[] = "HARDWARE\\DEVICEMAP\\SERIALCOMM"; 230 const char registryPath[] = "HARDWARE\\DEVICEMAP\\SERIALCOMM";
219 if( RegOpenKeyExA(HKEY_LOCAL_MACHINE, // PWD 231 if (RegOpenKeyExA(HKEY_LOCAL_MACHINE, // PWD
220 registryPath, // "SOFTWARE\Intel\PSIB" 232 registryPath, // "SOFTWARE\Intel\PSIB"
221 0, // Options 233 0, // Options
222 KEY_READ, // Desired SAM: See 32bits view. 234 KEY_READ, // Desired SAM: See 32bits view.
223 &key) == ERROR_SUCCESS 235 &key)
224 ) { 236 == ERROR_SUCCESS) {
225 for(DWORD i = 0; ++i;) { 237 for (DWORD i = 0; ++i;) {
226 char nameBuffer[128] = {0}; 238 char nameBuffer[128] = {0};
227 DWORD nameLen = sizeof nameBuffer; 239 DWORD nameLen = sizeof nameBuffer;
228 unsigned char dataBuffer[128] = {0}; 240 unsigned char dataBuffer[128] = {0};
229 DWORD dataLen = sizeof dataBuffer; 241 DWORD dataLen = sizeof dataBuffer;
230 long rc = RegEnumValueA(key, i, 242 long rc = RegEnumValueA(key,
231 nameBuffer, &nameLen, 243 i,
232 nullptr, 244 nameBuffer,
233 nullptr, 245 &nameLen,
234 dataBuffer, &dataLen); 246 nullptr,
235 if( rc != ERROR_SUCCESS ) 247 nullptr,
248 dataBuffer,
249 &dataLen);
250 if (rc != ERROR_SUCCESS)
236 break; 251 break;
237 252
238 QString name = QString(nameBuffer); 253 QString name = QString(nameBuffer);
239 QString port = QString((char*)dataBuffer); 254 QString port = QString((char *) dataBuffer);
240 LOG_TRACE("Resource " << i << ": " << name << ", " << port); 255 LOG_TRACE("Resource " << i << ": " << name << ", " << port);
241 if( name.contains("\\BtModem") || name.contains("\\BthModem") || name.contains("\\BtPort") ) { 256 if (name.contains("\\BtModem") || name.contains("\\BthModem")
257 || name.contains("\\BtPort")) {
242 list += port + " (Bluetooth)"; 258 list += port + " (Bluetooth)";
243 LOG_TRACE("Port " << name); 259 LOG_TRACE("Port " << name);
244 } 260 } else
245 else
246 LOG_DEBUG("... " << name); 261 LOG_DEBUG("... " << name);
247 } 262 }
248 RegCloseKey(key); 263 RegCloseKey(key);
249 } 264 }
250 } 265 }
256 271
257 ////////////////////////////////////////////////////////////////////////////// 272 //////////////////////////////////////////////////////////////////////////////
258 273
259 QStringList HardwareOperations::listUSBPorts() const 274 QStringList HardwareOperations::listUSBPorts() const
260 { 275 {
261 assert( !(supported() & BLUETOOTH) ); 276 assert(!(supported() & BLUETOOTH));
262 QStringList list; 277 QStringList list;
263 278
264 #if defined(Q_OS_MAC) || defined(Q_OS_LINUX) 279 #if defined(Q_OS_MAC) || defined(Q_OS_LINUX)
265 // TODO: Linux USB search... 280 // TODO: Linux USB search...
266 QDir dev("/dev"); 281 QDir dev("/dev");
267 QRegExp pTemplate = portTemplate(); 282 QRegularExpression pTemplate = portTemplate(); // Hier bleibt alles gleich
268 QStringList all = dev.entryList(QStringList() << "tty.*", 283 QStringList all = dev.entryList(QStringList() << "tty.*",
269 QDir::System|QDir::Writable|QDir::NoDotAndDotDot, 284 QDir::System | QDir::Writable | QDir::NoDotAndDotDot,
270 QDir::Name); 285 QDir::Name);
271 for(int i=0; i<(int)all.count(); ++i) { 286
272 if( pTemplate.indexIn(all[i]) >= 0 ) { 287 for (int i = 0; i < all.count(); ++i) {
288 // Verwende QRegularExpression::match anstelle von indexIn
289 QRegularExpressionMatch match = pTemplate.match(all[i]);
290
291 if (match.hasMatch()) { // Überprüfe, ob eine Übereinstimmung gefunden wurde
273 LOG_TRACE("Port " << all[i]); 292 LOG_TRACE("Port " << all[i]);
274 list += all[i]; 293 list += all[i];
275 } 294 } else {
276 else
277 LOG_TRACE("... " << all[i]); 295 LOG_TRACE("... " << all[i]);
296 }
278 } 297 }
279 #else 298 #else
280 //---- First chance: Try the normal port list: 299 //---- First chance: Try the normal port list:
281 for(int i=1; i<300; ++i) 300 for (int i = 1; i < 300; ++i) {
282 {
283 QString port = QString("COM%1").arg(i); 301 QString port = QString("COM%1").arg(i);
284 302
285 // First: try to read default configuration... 303 // First: try to read default configuration...
286 COMMCONFIG config; 304 COMMCONFIG config;
287 memset(&config, 0, sizeof config); 305 memset(&config, 0, sizeof config);
288 config.dwSize = sizeof config; 306 config.dwSize = sizeof config;
289 config.wVersion = 1; 307 config.wVersion = 1;
290 DWORD len = sizeof config; 308 DWORD len = sizeof config;
291 309
292 QByteArray fixed = "\\\\.\\" + port.toLocal8Bit(); 310 QByteArray fixed = "\\\\.\\" + port.toLocal8Bit();
293 if( GetDefaultCommConfigA(fixed.constData(), &config, &len) ) { 311 if (GetDefaultCommConfigA(fixed.constData(), &config, &len)) {
294 LOG_TRACE("Port " << port << " subtype=" << int(config.dwProviderSubType) ); 312 LOG_TRACE("Port " << port << " subtype=" << int(config.dwProviderSubType));
295 if( config.dwProviderSubType == PST_RS232 ) 313 if (config.dwProviderSubType == PST_RS232)
296 list += port; 314 list += port;
297 } else if( len != sizeof config ) 315 } else if (len != sizeof config)
298 LOG_THROW("Required " << len << " bytes."); 316 LOG_THROW("Required " << len << " bytes.");
299 else if( HRESULT rc = GetLastError() ) 317 else if (HRESULT rc = GetLastError())
300 if( rc != 87 ) 318 if (rc != 87)
301 LOG_TRACE("Port " << port << " error=" << rc ); 319 LOG_TRACE("Port " << port << " error=" << rc);
302
303 } 320 }
304 //---- Second chance 321 //---- Second chance
305 // overide usual MS bug, by looking into the registry for more 322 // overide usual MS bug, by looking into the registry for more
306 // USB serial ports... 323 // USB serial ports...
307 { 324 {
308 HKEY key; 325 HKEY key;
309 const char registryPath[] = "HARDWARE\\DEVICEMAP\\SERIALCOMM"; 326 const char registryPath[] = "HARDWARE\\DEVICEMAP\\SERIALCOMM";
310 if( RegOpenKeyExA(HKEY_LOCAL_MACHINE, // PWD 327 if (RegOpenKeyExA(HKEY_LOCAL_MACHINE, // PWD
311 registryPath, // path 328 registryPath, // path
312 0, // Options 329 0, // Options
313 KEY_READ, // Desired SAM: See 32bits view. 330 KEY_READ, // Desired SAM: See 32bits view.
314 &key) == ERROR_SUCCESS 331 &key)
315 ) { 332 == ERROR_SUCCESS) {
316 for(DWORD i = 0;; ++i) { 333 for (DWORD i = 0;; ++i) {
317 char nameBuffer[128] = {0}; 334 char nameBuffer[128] = {0};
318 DWORD nameLen = sizeof nameBuffer; 335 DWORD nameLen = sizeof nameBuffer;
319 unsigned char dataBuffer[128] = {0}; 336 unsigned char dataBuffer[128] = {0};
320 DWORD dataLen = sizeof dataBuffer; 337 DWORD dataLen = sizeof dataBuffer;
321 long rc = RegEnumValueA(key, i, 338 long rc = RegEnumValueA(key,
322 nameBuffer, &nameLen, 339 i,
323 nullptr, 340 nameBuffer,
324 nullptr, 341 &nameLen,
325 dataBuffer, &dataLen); 342 nullptr,
326 343 nullptr,
327 if( rc == ERROR_NO_MORE_ITEMS ) 344 dataBuffer,
345 &dataLen);
346
347 if (rc == ERROR_NO_MORE_ITEMS)
328 break; 348 break;
329 349
330 if( rc != ERROR_SUCCESS ) 350 if (rc != ERROR_SUCCESS)
331 LOG_THROW( "Enumeration error" ); 351 LOG_THROW("Enumeration error");
332 352
333 QString name = QString(nameBuffer); 353 QString name = QString(nameBuffer);
334 QString port = QString((char*)dataBuffer); 354 QString port = QString((char *) dataBuffer);
335 LOG_TRACE("Resource " << i << ": " << name << ", " << port); 355 LOG_TRACE("Resource " << i << ": " << name << ", " << port);
336 356
337 if( name.contains("\\VCP") ) 357 if (name.contains("\\VCP"))
338 list += port + " (USB)"; 358 list += port + " (USB)";
339 } 359 }
340 RegCloseKey(key); 360 RegCloseKey(key);
341 } 361 }
342 } 362 }