1/****************************************************************************
2**
3** Copyright (C) 2017 Denis Shienkov <denis.shienkov@gmail.com>
4** Copyright (C) 2017 The Qt Company Ltd.
5** Contact: http://www.qt.io/licensing/
6**
7** This file is part of the QtSerialBus module of the Qt Toolkit.
8**
9** $QT_BEGIN_LICENSE:LGPL3$
10** Commercial License Usage
11** Licensees holding valid commercial Qt licenses may use this file in
12** accordance with the commercial license agreement provided with the
13** Software or, alternatively, in accordance with the terms contained in
14** a written agreement between you and The Qt Company. For licensing terms
15** and conditions see http://www.qt.io/terms-conditions. For further
16** information use the contact form at http://www.qt.io/contact-us.
17**
18** GNU Lesser General Public License Usage
19** Alternatively, this file may be used under the terms of the GNU Lesser
20** General Public License version 3 as published by the Free Software
21** Foundation and appearing in the file LICENSE.LGPLv3 included in the
22** packaging of this file. Please review the following information to
23** ensure the GNU Lesser General Public License version 3 requirements
24** will be met: https://www.gnu.org/licenses/lgpl.html.
25**
26** GNU General Public License Usage
27** Alternatively, this file may be used under the terms of the GNU
28** General Public License version 2.0 or later as published by the Free
29** Software Foundation and appearing in the file LICENSE.GPL included in
30** the packaging of this file. Please review the following information to
31** ensure the GNU General Public License version 2.0 requirements will be
32** met: http://www.gnu.org/licenses/gpl-2.0.html.
33**
34** $QT_END_LICENSE$
35**
36****************************************************************************/
37
38#include "peakcanbackend.h"
39#include "peakcanbackend_p.h"
40#include "peakcan_symbols_p.h"
41
42#include <QtSerialBus/qcanbusdevice.h>
43
44#include <QtCore/qtimer.h>
45#include <QtCore/qcoreevent.h>
46#include <QtCore/qloggingcategory.h>
47
48#include <algorithm>
49
50#ifdef Q_OS_WIN32
51# include <QtCore/qwineventnotifier.h>
52#else
53# include <QtCore/qsocketnotifier.h>
54#endif
55
56QT_BEGIN_NAMESPACE
57
58Q_DECLARE_LOGGING_CATEGORY(QT_CANBUS_PLUGINS_PEAKCAN)
59
60#ifndef LINK_LIBPCANBASIC
61Q_GLOBAL_STATIC(QLibrary, pcanLibrary)
62#endif
63
64bool PeakCanBackend::canCreate(QString *errorReason)
65{
66#ifdef LINK_LIBPCANBASIC
67 return true;
68#else
69 static bool symbolsResolved = resolvePeakCanSymbols(pcanLibrary: pcanLibrary());
70 if (Q_UNLIKELY(!symbolsResolved)) {
71 qCCritical(QT_CANBUS_PLUGINS_PEAKCAN, "Cannot load library: %ls",
72 qUtf16Printable(pcanLibrary()->errorString()));
73 *errorReason = pcanLibrary()->errorString();
74 return false;
75 }
76 return true;
77#endif
78}
79
80struct PcanChannel{
81 char name[6];
82 TPCANHandle index;
83};
84static const PcanChannel pcanChannels[] = {
85 { .name: "usb0", PCAN_USBBUS1 },
86 { .name: "usb1", PCAN_USBBUS2 },
87 { .name: "usb2", PCAN_USBBUS3 },
88 { .name: "usb3", PCAN_USBBUS4 },
89 { .name: "usb4", PCAN_USBBUS5 },
90 { .name: "usb5", PCAN_USBBUS6 },
91 { .name: "usb6", PCAN_USBBUS7 },
92 { .name: "usb7", PCAN_USBBUS8 },
93 { .name: "usb8", PCAN_USBBUS9 },
94 { .name: "usb9", PCAN_USBBUS10 },
95 { .name: "usb10", PCAN_USBBUS11 },
96 { .name: "usb11", PCAN_USBBUS12 },
97 { .name: "usb12", PCAN_USBBUS13 },
98 { .name: "usb13", PCAN_USBBUS14 },
99 { .name: "usb14", PCAN_USBBUS15 },
100 { .name: "usb15", PCAN_USBBUS16 },
101 { .name: "pci0", PCAN_PCIBUS1 },
102 { .name: "pci1", PCAN_PCIBUS2 },
103 { .name: "pci2", PCAN_PCIBUS3 },
104 { .name: "pci3", PCAN_PCIBUS4 },
105 { .name: "pci4", PCAN_PCIBUS5 },
106 { .name: "pci5", PCAN_PCIBUS6 },
107 { .name: "pci6", PCAN_PCIBUS7 },
108 { .name: "pci7", PCAN_PCIBUS8 },
109 { .name: "pci8", PCAN_PCIBUS9 },
110 { .name: "pci9", PCAN_PCIBUS10 },
111 { .name: "pci10", PCAN_PCIBUS11 },
112 { .name: "pci11", PCAN_PCIBUS12 },
113 { .name: "pci12", PCAN_PCIBUS13 },
114 { .name: "pci13", PCAN_PCIBUS14 },
115 { .name: "pci14", PCAN_PCIBUS15 },
116 { .name: "pci15", PCAN_PCIBUS16 },
117 { .name: "none", PCAN_NONEBUS }
118};
119
120QList<QCanBusDeviceInfo> PeakCanBackend::interfaces()
121{
122 QList<QCanBusDeviceInfo> result;
123
124 for (int i = 0; pcanChannels[i].index != PCAN_NONEBUS; ++i) {
125 uint value = 0;
126 const TPCANHandle index = pcanChannels[i].index;
127 const TPCANStatus stat = ::CAN_GetValue(index, PCAN_CHANNEL_CONDITION,
128 &value, sizeof(value));
129 if ((stat == PCAN_ERROR_OK) && (value & PCAN_CHANNEL_AVAILABLE)) {
130 const TPCANStatus fdStat = ::CAN_GetValue(index, PCAN_CHANNEL_FEATURES,
131 &value, sizeof(value));
132 const bool isFd = (fdStat == PCAN_ERROR_OK) && (value & FEATURE_FD_CAPABLE);
133
134 char description[256] = {0};
135 const TPCANStatus descStat = ::CAN_GetValue(index, PCAN_HARDWARE_NAME,
136 description, sizeof(description));
137 if (descStat != PCAN_ERROR_OK)
138 description[0] = 0;
139
140 int channel = 0;
141 const TPCANStatus chnStat = ::CAN_GetValue(index, PCAN_CONTROLLER_NUMBER,
142 &channel, sizeof(channel));
143 if (chnStat != PCAN_ERROR_OK)
144 channel = 0;
145
146 result.append(t: std::move(createDeviceInfo(name: QLatin1String(pcanChannels[i].name),
147 serialNumber: QString(), description: QLatin1String(description),
148 channel, isVirtual: false, isFlexibleDataRateCapable: isFd)));
149 }
150 }
151
152 return result;
153}
154
155#if defined(Q_OS_WIN32)
156class PeakCanReadNotifier : public QWinEventNotifier
157{
158 // no Q_OBJECT macro!
159public:
160 explicit PeakCanReadNotifier(PeakCanBackendPrivate *d, QObject *parent)
161 : QWinEventNotifier(parent)
162 , dptr(d)
163 {
164 setHandle(dptr->readHandle);
165 }
166
167protected:
168 bool event(QEvent *e) override
169 {
170 if (e->type() == QEvent::WinEventAct) {
171 dptr->startRead();
172 return true;
173 }
174 return QWinEventNotifier::event(e);
175 }
176
177private:
178 PeakCanBackendPrivate * const dptr;
179};
180#else
181class PeakCanReadNotifier : public QSocketNotifier
182{
183 // no Q_OBJECT macro!
184public:
185 explicit PeakCanReadNotifier(PeakCanBackendPrivate *d, QObject *parent)
186 : QSocketNotifier(d->readHandle, QSocketNotifier::Read, parent)
187 , dptr(d)
188 {
189 }
190
191protected:
192 bool event(QEvent *e) override
193 {
194 if (e->type() == QEvent::SockAct) {
195 dptr->startRead();
196 return true;
197 }
198 return QSocketNotifier::event(e);
199 }
200
201private:
202 PeakCanBackendPrivate * const dptr;
203};
204#endif
205
206class PeakCanWriteNotifier : public QTimer
207{
208 // no Q_OBJECT macro!
209public:
210 PeakCanWriteNotifier(PeakCanBackendPrivate *d, QObject *parent)
211 : QTimer(parent)
212 , dptr(d)
213 {
214 }
215
216protected:
217 void timerEvent(QTimerEvent *e) override
218 {
219 if (e->timerId() == timerId()) {
220 dptr->startWrite();
221 return;
222 }
223 QTimer::timerEvent(e);
224 }
225
226private:
227 PeakCanBackendPrivate * const dptr;
228};
229
230PeakCanBackendPrivate::PeakCanBackendPrivate(PeakCanBackend *q)
231 : q_ptr(q)
232{
233}
234
235struct BitrateItem
236{
237 int bitrate;
238 TPCANBaudrate code;
239};
240
241struct BitrateLessFunctor
242{
243 bool operator()( const BitrateItem &item1, const BitrateItem &item2) const
244 {
245 return item1.bitrate < item2.bitrate;
246 }
247};
248
249static TPCANBaudrate bitrateCodeFromBitrate(int bitrate)
250{
251 static const BitrateItem bitratetable[] = {
252 { .bitrate: 5000, PCAN_BAUD_5K },
253 { .bitrate: 10000, PCAN_BAUD_10K },
254 { .bitrate: 20000, PCAN_BAUD_20K },
255 { .bitrate: 33000, PCAN_BAUD_33K },
256 { .bitrate: 47000, PCAN_BAUD_47K },
257 { .bitrate: 50000, PCAN_BAUD_50K },
258 { .bitrate: 83000, PCAN_BAUD_83K },
259 { .bitrate: 95000, PCAN_BAUD_95K },
260 { .bitrate: 100000, PCAN_BAUD_100K },
261 { .bitrate: 125000, PCAN_BAUD_125K },
262 { .bitrate: 250000, PCAN_BAUD_250K },
263 { .bitrate: 500000, PCAN_BAUD_500K },
264 { .bitrate: 800000, PCAN_BAUD_800K },
265 { .bitrate: 1000000, PCAN_BAUD_1M }
266 };
267
268 static const BitrateItem *endtable = bitratetable + (sizeof(bitratetable) / sizeof(*bitratetable));
269
270 const BitrateItem item = { .bitrate: bitrate , .code: 0 };
271 const BitrateItem *where = std::lower_bound(first: bitratetable, last: endtable, val: item, comp: BitrateLessFunctor());
272 return where != endtable ? where->code : PCAN_BAUD_INVALID;
273}
274
275static QByteArray nominalBitrateString(int nominalBitrate)
276{
277 switch (nominalBitrate) {
278 case 125000:
279 return "f_clock=80000000, nom_brp=40, nom_tseg1=12, nom_tseg2=3, nom_sjw=1";
280 case 250000:
281 return "f_clock=80000000, nom_brp=20, nom_tseg1=12, nom_tseg2=3, nom_sjw=1";
282 case 500000:
283 return "f_clock=80000000, nom_brp=10, nom_tseg1=12, nom_tseg2=3, nom_sjw=1";
284 case 1000000:
285 return "f_clock=80000000, nom_brp=10, nom_tseg1=5, nom_tseg2=2, nom_sjw=1";
286 default:
287 return QByteArray();
288 }
289}
290
291static QByteArray dataBitrateString(int dataBitrate)
292{
293 switch (dataBitrate) {
294 case 2000000:
295 return ", data_brp=4, data_tseg1=7, data_tseg2=2, data_sjw=1";
296 case 4000000:
297 return ", data_brp=2, data_tseg1=7, data_tseg2=2, data_sjw=1";
298 case 8000000:
299 return ", data_brp=1, data_tseg1=7, data_tseg2=2, data_sjw=1";
300 case 10000000:
301 return ", data_brp=1, data_tseg1=5, data_tseg2=2, data_sjw=1";
302 default:
303 return QByteArray();
304 }
305}
306
307static QByteArray bitrateStringFromBitrate(int nominalBitrate, int dataBitrate)
308{
309 QByteArray result = nominalBitrateString(nominalBitrate);
310
311 if (result.isEmpty())
312 return QByteArray();
313
314 result += dataBitrateString(dataBitrate);
315
316 return result;
317}
318
319bool PeakCanBackendPrivate::open()
320{
321 Q_Q(PeakCanBackend);
322
323 const int nominalBitrate = q->configurationParameter(key: QCanBusDevice::BitRateKey).toInt();
324 TPCANStatus st = PCAN_ERROR_OK;
325
326 if (isFlexibleDatarateEnabled) {
327 const int dataBitrate = q->configurationParameter(key: QCanBusDevice::DataBitRateKey).toInt();
328 const QByteArray bitrateStr = bitrateStringFromBitrate(nominalBitrate, dataBitrate);
329 st = ::CAN_InitializeFD(channelIndex, const_cast<char *>(bitrateStr.data()));
330 } else {
331 const TPCANBaudrate bitrateCode = bitrateCodeFromBitrate(bitrate: nominalBitrate);
332 st = ::CAN_Initialize(channelIndex, bitrateCode, 0, 0, 0);
333 }
334
335 if (Q_UNLIKELY(st != PCAN_ERROR_OK)) {
336 const QString errorString = systemErrorString(errorCode: st);
337 qCCritical(QT_CANBUS_PLUGINS_PEAKCAN, "Cannot initialize hardware: %ls",
338 qUtf16Printable(errorString));
339 q->setError(errorText: errorString, QCanBusDevice::ConnectionError);
340 return false;
341 }
342
343#if defined(Q_OS_WIN32)
344 if (readHandle == INVALID_HANDLE_VALUE) {
345 readHandle = ::CreateEvent(nullptr, FALSE, FALSE, nullptr);
346 if (Q_UNLIKELY(!readHandle)) {
347 const QString errorString = qt_error_string(int(::GetLastError()));
348 qCCritical(QT_CANBUS_PLUGINS_PEAKCAN, "Cannot create receive event handler: %ls",
349 qUtf16Printable(errorString));
350 q->setError(errorString, QCanBusDevice::ConnectionError);
351 return false;
352 }
353 }
354
355 const TPCANStatus err = ::CAN_SetValue(channelIndex, PCAN_RECEIVE_EVENT, &readHandle, sizeof(readHandle));
356 if (Q_UNLIKELY(err != PCAN_ERROR_OK)) {
357 q->setError(systemErrorString(err), QCanBusDevice::ConnectionError);
358 return false;
359 }
360
361#else
362 const TPCANStatus err = ::CAN_GetValue(channelIndex, PCAN_RECEIVE_EVENT, &readHandle, sizeof(readHandle));
363 if (Q_UNLIKELY(err != PCAN_ERROR_OK)) {
364 const QString errorString = systemErrorString(errorCode: err);
365 qCCritical(QT_CANBUS_PLUGINS_PEAKCAN, "Cannot create receive event handler: %ls",
366 qUtf16Printable(errorString));
367 q->setError(errorText: errorString, QCanBusDevice::ConnectionError);
368 return false;
369 }
370#endif
371
372 writeNotifier = new PeakCanWriteNotifier(this, q);
373 writeNotifier->setInterval(0);
374
375 readNotifier = new PeakCanReadNotifier(this, q);
376 readNotifier->setEnabled(true);
377
378 isOpen = true;
379 return true;
380}
381
382void PeakCanBackendPrivate::close()
383{
384 Q_Q(PeakCanBackend);
385
386 delete readNotifier;
387 readNotifier = nullptr;
388
389 delete writeNotifier;
390 writeNotifier = nullptr;
391
392 quint32 value = 0;
393 const TPCANStatus err = ::CAN_SetValue(channelIndex, PCAN_RECEIVE_EVENT, &value, sizeof(value));
394 if (Q_UNLIKELY(err != PCAN_ERROR_OK)) {
395 const QString errorString = systemErrorString(errorCode: err);
396 qCCritical(QT_CANBUS_PLUGINS_PEAKCAN, "Cannot unregister receive event handler: %ls",
397 qUtf16Printable(errorString));
398 q->setError(errorText: errorString, QCanBusDevice::ConnectionError);
399 }
400
401 const TPCANStatus st = ::CAN_Uninitialize(channelIndex);
402 if (Q_UNLIKELY(st != PCAN_ERROR_OK))
403 q->setError(errorText: systemErrorString(errorCode: st), QCanBusDevice::ConnectionError);
404
405#if defined(Q_OS_WIN32)
406 if (readHandle && (readHandle != INVALID_HANDLE_VALUE)) {
407 const QString errorString = qt_error_string(int(::GetLastError()));
408 if (Q_UNLIKELY(!::CloseHandle(readHandle))) {
409 qCCritical(QT_CANBUS_PLUGINS_PEAKCAN, "Cannot close read handle: %ls",
410 qUtf16Printable(errorString));
411 q->setError(errorString, QCanBusDevice::ConnectionError);
412 }
413 readHandle = INVALID_HANDLE_VALUE;
414 }
415#else
416 readHandle = -1;
417#endif
418
419 isOpen = false;
420}
421
422bool PeakCanBackendPrivate::setConfigurationParameter(int key, const QVariant &value)
423{
424 Q_Q(PeakCanBackend);
425
426 switch (key) {
427 case QCanBusDevice::BitRateKey:
428 return verifyBitRate(bitrate: value.toInt());
429 case QCanBusDevice::CanFdKey:
430 isFlexibleDatarateEnabled = value.toBool();
431 return true;
432 case QCanBusDevice::DataBitRateKey: {
433 const int dataBitrate = value.toInt();
434 if (Q_UNLIKELY(dataBitrateString(dataBitrate).isEmpty())) {
435 qCWarning(QT_CANBUS_PLUGINS_PEAKCAN, "Unsupported data bitrate value: %d", dataBitrate);
436 q->setError(errorText: PeakCanBackend::tr(s: "Unsupported data bitrate value: %1.").arg(a: dataBitrate),
437 QCanBusDevice::ConfigurationError);
438 return false;
439 }
440 return true;
441 }
442 default:
443 qCWarning(QT_CANBUS_PLUGINS_PEAKCAN, "Unsupported configuration key: %d", key);
444 q->setError(errorText: PeakCanBackend::tr(s: "Unsupported configuration key: %1").arg(a: key),
445 QCanBusDevice::ConfigurationError);
446 return false;
447 }
448}
449
450void PeakCanBackendPrivate::setupChannel(const QByteArray &interfaceName)
451{
452 const PcanChannel *chn = pcanChannels;
453 while (chn->index != PCAN_NONEBUS && chn->name != interfaceName)
454 ++chn;
455 channelIndex = chn->index;
456}
457
458// Calls only when the device is closed
459void PeakCanBackendPrivate::setupDefaultConfigurations()
460{
461 Q_Q(PeakCanBackend);
462
463 q->setConfigurationParameter(key: QCanBusDevice::BitRateKey, value: 500000);
464}
465
466QString PeakCanBackendPrivate::systemErrorString(TPCANStatus errorCode)
467{
468 QByteArray buffer(256, 0);
469 if (Q_UNLIKELY(::CAN_GetErrorText(errorCode, 0, buffer.data()) != PCAN_ERROR_OK))
470 return PeakCanBackend::tr(s: "Unable to retrieve an error string");
471 return QString::fromLatin1(str: buffer);
472}
473
474enum CanFrameDlc {
475 Dlc00 = 0,
476 Dlc01 = 1,
477 Dlc02 = 2,
478 Dlc03 = 3,
479 Dlc04 = 4,
480 Dlc05 = 5,
481 Dlc06 = 6,
482 Dlc07 = 7,
483 Dlc08 = 8,
484 Dlc12 = 9,
485 Dlc16 = 10,
486 Dlc20 = 11,
487 Dlc24 = 12,
488 Dlc32 = 13,
489 Dlc48 = 14,
490 Dlc64 = 15
491};
492
493static CanFrameDlc sizeToDlc(int size)
494{
495 switch (size) {
496 case 12:
497 return Dlc12;
498 case 16:
499 return Dlc16;
500 case 20:
501 return Dlc20;
502 case 24:
503 return Dlc24;
504 case 32:
505 return Dlc32;
506 case 48:
507 return Dlc48;
508 case 64:
509 return Dlc64;
510 default:
511 if (size >= 0 && size <= 8)
512 return static_cast<CanFrameDlc>(size);
513
514 return Dlc00;
515 }
516}
517
518static int dlcToSize(CanFrameDlc dlc)
519{
520 switch (dlc) {
521 case Dlc00:
522 case Dlc01:
523 case Dlc02:
524 case Dlc03:
525 case Dlc04:
526 case Dlc05:
527 case Dlc06:
528 case Dlc07:
529 case Dlc08:
530 return static_cast<int>(dlc);
531 case Dlc12:
532 return 12;
533 case Dlc16:
534 return 16;
535 case Dlc20:
536 return 20;
537 case Dlc24:
538 return 24;
539 case Dlc32:
540 return 32;
541 case Dlc48:
542 return 48;
543 case Dlc64:
544 return 64;
545 }
546 return 0;
547}
548
549void PeakCanBackendPrivate::startWrite()
550{
551 Q_Q(PeakCanBackend);
552
553 if (!q->hasOutgoingFrames()) {
554 writeNotifier->stop();
555 return;
556 }
557
558 const QCanBusFrame frame = q->dequeueOutgoingFrame();
559 const QByteArray payload = frame.payload();
560 TPCANStatus st = PCAN_ERROR_OK;
561
562 if (isFlexibleDatarateEnabled) {
563 const int size = payload.size();
564 TPCANMsgFD message = {};
565 message.ID = frame.frameId();
566 message.DLC = sizeToDlc(size);
567 message.MSGTYPE = frame.hasExtendedFrameFormat() ? PCAN_MESSAGE_EXTENDED
568 : PCAN_MESSAGE_STANDARD;
569
570 if (frame.hasFlexibleDataRateFormat())
571 message.MSGTYPE |= PCAN_MESSAGE_FD;
572 if (frame.hasBitrateSwitch())
573 message.MSGTYPE |= PCAN_MESSAGE_BRS;
574
575 if (frame.frameType() == QCanBusFrame::RemoteRequestFrame)
576 message.MSGTYPE |= PCAN_MESSAGE_RTR; // we do not care about the payload
577 else
578 ::memcpy(dest: message.DATA, src: payload.constData(), n: sizeof(message.DATA));
579 st = ::CAN_WriteFD(channelIndex, &message);
580 } else if (frame.hasFlexibleDataRateFormat()) {
581 const char errorString[] = "Cannot send CAN FD frame format as CAN FD is not enabled.";
582 qCWarning(QT_CANBUS_PLUGINS_PEAKCAN(), errorString);
583 q->setError(errorText: PeakCanBackend::tr(s: errorString), QCanBusDevice::WriteError);
584 } else {
585 TPCANMsg message = {};
586 message.ID = frame.frameId();
587 message.LEN = static_cast<quint8>(payload.size());
588 message.MSGTYPE = frame.hasExtendedFrameFormat() ? PCAN_MESSAGE_EXTENDED
589 : PCAN_MESSAGE_STANDARD;
590
591 if (frame.frameType() == QCanBusFrame::RemoteRequestFrame)
592 message.MSGTYPE |= PCAN_MESSAGE_RTR; // we do not care about the payload
593 else
594 ::memcpy(dest: message.DATA, src: payload.constData(), n: sizeof(message.DATA));
595 st = ::CAN_Write(channelIndex, &message);
596 }
597
598 if (Q_UNLIKELY(st != PCAN_ERROR_OK)) {
599 const QString errorString = systemErrorString(errorCode: st);
600 qCWarning(QT_CANBUS_PLUGINS_PEAKCAN, "Cannot write frame: %ls",
601 qUtf16Printable(errorString));
602 q->setError(errorText: errorString, QCanBusDevice::WriteError);
603 } else {
604 emit q->framesWritten(framesCount: qint64(1));
605 }
606
607 if (q->hasOutgoingFrames() && !writeNotifier->isActive())
608 writeNotifier->start();
609}
610
611void PeakCanBackendPrivate::startRead()
612{
613 Q_Q(PeakCanBackend);
614
615 QVector<QCanBusFrame> newFrames;
616
617 for (;;) {
618 if (isFlexibleDatarateEnabled) {
619 TPCANMsgFD message = {};
620 TPCANTimestampFD timestamp = {};
621
622 const TPCANStatus st = ::CAN_ReadFD(channelIndex, &message, &timestamp);
623 if (st != PCAN_ERROR_OK) {
624 if (Q_UNLIKELY(st != PCAN_ERROR_QRCVEMPTY))
625 q->setError(errorText: systemErrorString(errorCode: st), QCanBusDevice::ReadError);
626 break;
627 }
628
629 // Filter out PCAN status frames, to avoid turning them
630 // into QCanBusFrame::DataFrames with random canId
631 if (Q_UNLIKELY(message.MSGTYPE & PCAN_MESSAGE_STATUS))
632 continue;
633
634 const int size = dlcToSize(dlc: static_cast<CanFrameDlc>(message.DLC));
635 QCanBusFrame frame(TPCANLongToFrameID(message.ID),
636 QByteArray(reinterpret_cast<const char *>(message.DATA), size));
637 frame.setTimeStamp(QCanBusFrame::TimeStamp::fromMicroSeconds(usec: static_cast<qint64>(timestamp)));
638 frame.setExtendedFrameFormat(message.MSGTYPE & PCAN_MESSAGE_EXTENDED);
639 frame.setFrameType((message.MSGTYPE & PCAN_MESSAGE_RTR)
640 ? QCanBusFrame::RemoteRequestFrame : QCanBusFrame::DataFrame);
641 frame.setFlexibleDataRateFormat(message.MSGTYPE & PCAN_MESSAGE_FD);
642 frame.setBitrateSwitch(message.MSGTYPE & PCAN_MESSAGE_BRS);
643 frame.setErrorStateIndicator(message.MSGTYPE & PCAN_MESSAGE_ESI);
644
645 newFrames.append(t: std::move(frame));
646 } else {
647 TPCANMsg message = {};
648 TPCANTimestamp timestamp = {};
649
650 const TPCANStatus st = ::CAN_Read(channelIndex, &message, &timestamp);
651 if (st != PCAN_ERROR_OK) {
652 if (Q_UNLIKELY(st != PCAN_ERROR_QRCVEMPTY))
653 q->setError(errorText: systemErrorString(errorCode: st), QCanBusDevice::ReadError);
654 break;
655 }
656
657 // Filter out PCAN status frames, to avoid turning them
658 // into QCanBusFrame::DataFrames with random canId
659 if (Q_UNLIKELY(message.MSGTYPE & PCAN_MESSAGE_STATUS))
660 continue;
661
662 const int size = static_cast<int>(message.LEN);
663 QCanBusFrame frame(TPCANLongToFrameID(message.ID),
664 QByteArray(reinterpret_cast<const char *>(message.DATA), size));
665 const quint64 millis = timestamp.millis + Q_UINT64_C(0xFFFFFFFF) * timestamp.millis_overflow;
666 const quint64 micros = Q_UINT64_C(1000) * millis + timestamp.micros;
667 frame.setTimeStamp(QCanBusFrame::TimeStamp::fromMicroSeconds(usec: static_cast<qint64>(micros)));
668 frame.setExtendedFrameFormat(message.MSGTYPE & PCAN_MESSAGE_EXTENDED);
669 frame.setFrameType((message.MSGTYPE & PCAN_MESSAGE_RTR)
670 ? QCanBusFrame::RemoteRequestFrame : QCanBusFrame::DataFrame);
671
672 newFrames.append(t: std::move(frame));
673 }
674 }
675
676 q->enqueueReceivedFrames(newFrames);
677}
678
679bool PeakCanBackendPrivate::verifyBitRate(int bitrate)
680{
681 Q_Q(PeakCanBackend);
682
683 if (Q_UNLIKELY(isOpen)) {
684 const char errorString[] = "Cannot change bitrate for already opened device.";
685 qCWarning(QT_CANBUS_PLUGINS_PEAKCAN, errorString);
686 q->setError(errorText: PeakCanBackend::tr(s: errorString), QCanBusDevice::ConfigurationError);
687 return false;
688 }
689
690 bool isValidBitrate = false;
691 if (q->configurationParameter(key: QCanBusDevice::CanFdKey).toBool())
692 isValidBitrate = !nominalBitrateString(nominalBitrate: bitrate).isEmpty();
693 else
694 isValidBitrate = bitrateCodeFromBitrate(bitrate) != PCAN_BAUD_INVALID;
695
696 if (Q_UNLIKELY(!isValidBitrate)) {
697 qCWarning(QT_CANBUS_PLUGINS_PEAKCAN, "Unsupported bitrate value: %d.", bitrate);
698 q->setError(errorText: PeakCanBackend::tr(s: "Unsupported bitrate value: %1.").arg(a: bitrate),
699 QCanBusDevice::ConfigurationError);
700 }
701
702 return isValidBitrate;
703}
704
705PeakCanBackend::PeakCanBackend(const QString &name, QObject *parent)
706 : QCanBusDevice(parent)
707 , d_ptr(new PeakCanBackendPrivate(this))
708{
709 Q_D(PeakCanBackend);
710
711 d->setupChannel(name.toLatin1());
712 d->setupDefaultConfigurations();
713
714 std::function<void()> f = std::bind(f: &PeakCanBackend::resetController, args: this);
715 setResetControllerFunction(f);
716
717 std::function<CanBusStatus()> g = std::bind(f: &PeakCanBackend::busStatus, args: this);
718 setCanBusStatusGetter(g);
719}
720
721PeakCanBackend::~PeakCanBackend()
722{
723 Q_D(PeakCanBackend);
724
725 if (d->isOpen)
726 close();
727
728 delete d_ptr;
729}
730
731bool PeakCanBackend::open()
732{
733 Q_D(PeakCanBackend);
734
735 if (!d->isOpen) {
736 if (Q_UNLIKELY(!d->open()))
737 return false;
738
739 // Apply all stored configurations except bitrate, because
740 // the bitrate cannot be changed after opening the device
741 const auto keys = configurationKeys();
742 for (int key : keys) {
743 if (key == QCanBusDevice::BitRateKey || key == QCanBusDevice::DataBitRateKey)
744 continue;
745 const QVariant param = configurationParameter(key);
746 const bool success = d->setConfigurationParameter(key, value: param);
747 if (Q_UNLIKELY(!success)) {
748 qCWarning(QT_CANBUS_PLUGINS_PEAKCAN, "Cannot apply parameter: %d with value: %ls.",
749 key, qUtf16Printable(param.toString()));
750 }
751 }
752 }
753
754 setState(QCanBusDevice::ConnectedState);
755 return true;
756}
757
758void PeakCanBackend::close()
759{
760 Q_D(PeakCanBackend);
761
762 d->close();
763
764 setState(QCanBusDevice::UnconnectedState);
765}
766
767void PeakCanBackend::setConfigurationParameter(int key, const QVariant &value)
768{
769 Q_D(PeakCanBackend);
770
771 if (d->setConfigurationParameter(key, value))
772 QCanBusDevice::setConfigurationParameter(key, value);
773}
774
775bool PeakCanBackend::writeFrame(const QCanBusFrame &newData)
776{
777 Q_D(PeakCanBackend);
778
779 if (Q_UNLIKELY(state() != QCanBusDevice::ConnectedState))
780 return false;
781
782 if (Q_UNLIKELY(!newData.isValid())) {
783 setError(errorText: tr(s: "Cannot write invalid QCanBusFrame"), QCanBusDevice::WriteError);
784 return false;
785 }
786
787 if (Q_UNLIKELY(newData.frameType() != QCanBusFrame::DataFrame
788 && newData.frameType() != QCanBusFrame::RemoteRequestFrame)) {
789 setError(errorText: tr(s: "Unable to write a frame with unacceptable type"),
790 QCanBusDevice::WriteError);
791 return false;
792 }
793
794 enqueueOutgoingFrame(newFrame: newData);
795
796 if (!d->writeNotifier->isActive())
797 d->writeNotifier->start();
798
799 return true;
800}
801
802// TODO: Implement me
803QString PeakCanBackend::interpretErrorFrame(const QCanBusFrame &errorFrame)
804{
805 Q_UNUSED(errorFrame);
806
807 return QString();
808}
809
810void PeakCanBackend::resetController()
811{
812 close();
813 open();
814}
815
816QCanBusDevice::CanBusStatus PeakCanBackend::busStatus() const
817{
818 const TPCANStatus status = ::CAN_GetStatus(d_ptr->channelIndex);
819
820 switch (status & PCAN_ERROR_ANYBUSERR) {
821 case PCAN_ERROR_OK:
822 return QCanBusDevice::CanBusStatus::Good;
823 case PCAN_ERROR_BUSWARNING:
824 return QCanBusDevice::CanBusStatus::Warning;
825 case PCAN_ERROR_BUSPASSIVE:
826 return QCanBusDevice::CanBusStatus::Error;
827 case PCAN_ERROR_BUSOFF:
828 return QCanBusDevice::CanBusStatus::BusOff;
829 default:
830 qCWarning(QT_CANBUS_PLUGINS_PEAKCAN, "Unknown CAN bus status: %lu.", ulong(status));
831 return QCanBusDevice::CanBusStatus::Unknown;
832 }
833}
834
835QT_END_NAMESPACE
836

source code of qtserialbus/src/plugins/canbus/peakcan/peakcanbackend.cpp