| 1 | // Copyright (C) 2017 Ford Motor Company. | 
| 2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only | 
| 3 |  | 
| 4 | #ifndef PASSTHRUCAN_J2534PASSTHRU_H | 
| 5 | #define PASSTHRUCAN_J2534PASSTHRU_H | 
| 6 |  | 
| 7 | #include <QByteArray> | 
| 8 | #include <QLibrary> | 
| 9 | #include <QLoggingCategory> | 
| 10 | #include <QObject> | 
| 11 | #include <QString> | 
| 12 |  | 
| 13 | #ifdef Q_OS_WIN32 | 
| 14 | # define J2534_API __stdcall | 
| 15 | #else | 
| 16 | # define J2534_API | 
| 17 | #endif | 
| 18 |  | 
| 19 | Q_DECLARE_LOGGING_CATEGORY(QT_CANBUS_PLUGINS_PASSTHRU) | 
| 20 |  | 
| 21 | namespace J2534 { | 
| 22 |  | 
| 23 | class Message; | 
| 24 |  | 
| 25 | extern "C"  { | 
| 26 |  | 
| 27 | typedef long (J2534_API *PassThruOpenFunc)(const void *pName, ulong *pDeviceId); | 
| 28 | typedef long (J2534_API *PassThruCloseFunc)(ulong deviceId); | 
| 29 | typedef long (J2534_API *PassThruConnectFunc)(ulong deviceId, ulong protocolId, ulong flags, | 
| 30 |                                               ulong baudRate, ulong *pChannelId); | 
| 31 | typedef long (J2534_API *PassThruDisconnectFunc)(ulong channelId); | 
| 32 | typedef long (J2534_API *PassThruReadMsgsFunc)(ulong channelId, Message *pMsg, | 
| 33 |                                                ulong *pNumMsgs, ulong timeout); | 
| 34 | typedef long (J2534_API *PassThruWriteMsgsFunc)(ulong channelId, const Message *pMsg, | 
| 35 |                                                 ulong *pNumMsgs, ulong timeout); | 
| 36 | typedef long (J2534_API *PassThruStartMsgFilterFunc)(ulong channelID, ulong filterType, | 
| 37 |                                                      const Message *pMaskMsg, | 
| 38 |                                                      const Message *pPatternMsg, | 
| 39 |                                                      const Message *pFlowControlMsg, | 
| 40 |                                                      ulong *pFilterId); | 
| 41 | typedef long (J2534_API *PassThruGetLastErrorFunc)(char *pErrorDescription); | 
| 42 | typedef long (J2534_API *PassThruIoctlFunc)(ulong channelId, ulong ioctlId, | 
| 43 |                                             const void *pInput, void *pOutput); | 
| 44 | } // extern "C" | 
| 45 |  | 
| 46 | enum class Protocol : uint { | 
| 47 |     J1850VPW = 1, | 
| 48 |     J1850PWM, | 
| 49 |     ISO9141, | 
| 50 |     ISO14230, | 
| 51 |     CAN, | 
| 52 |     ISO15765, | 
| 53 |     SCIAEngine, | 
| 54 |     SCIATrans, | 
| 55 |     SCIBEngine, | 
| 56 |     SCIBTrans | 
| 57 | }; | 
| 58 |  | 
| 59 | class Message | 
| 60 | { | 
| 61 | public: | 
| 62 |     static const ulong maxSize = 4128; | 
| 63 |  | 
| 64 |     enum RxStatusBit { | 
| 65 |         InTxMsgType = 1 << 0, | 
| 66 |         InStartOfMessage = 1 << 1, | 
| 67 |         InRxBreak = 1 << 2, | 
| 68 |         InTxIndication = 1 << 3, | 
| 69 |         InISO15765PaddingError = 1 << 4, | 
| 70 |         InISO15765AddrType = 1 << 7, | 
| 71 |         InCAN29BitID = 1 << 8 | 
| 72 |     }; | 
| 73 |     Q_DECLARE_FLAGS(RxStatus, RxStatusBit) | 
| 74 |  | 
| 75 |     enum TxFlag { | 
| 76 |         OutISO15765FramePad = 1 << 6, | 
| 77 |         OutISO15765AddrType = 1 << 7, | 
| 78 |         OutCAN29BitID = 1 << 8, | 
| 79 |         OutWaitP3MinOnly = 1 << 9 | 
| 80 |     }; | 
| 81 |     Q_DECLARE_FLAGS(TxFlags, TxFlag) | 
| 82 |  | 
| 83 |     Message(); | 
| 84 |     explicit Message(Protocol proto); | 
| 85 |  | 
| 86 |     Protocol protocolId() const { return Protocol(m_protocolId); } | 
| 87 |     void setProtocolId(Protocol proto) { m_protocolId = uint(proto); } | 
| 88 |  | 
| 89 |     RxStatus rxStatus() const { return RxStatus(uint(m_rxStatus)); } | 
| 90 |     void setRxStatus(RxStatus status) { m_rxStatus = uint(status); } | 
| 91 |  | 
| 92 |     TxFlags txFlags() const { return TxFlags(uint(m_txFlags)); } | 
| 93 |     void setTxFlags(TxFlags flags) { m_txFlags = uint(flags); } | 
| 94 |  | 
| 95 |     ulong timestamp() const { return m_timestamp; } | 
| 96 |     void setTimestamp(ulong stamp) { m_timestamp = stamp; } | 
| 97 |  | 
| 98 |     ulong size() const { return m_dataSize; } | 
| 99 |     void setSize(ulong dataSize) { m_dataSize = dataSize; } | 
| 100 |  | 
| 101 |     ulong () const { return m_extraDataIndex; } | 
| 102 |     void (ulong index) { m_extraDataIndex = index; } | 
| 103 |  | 
| 104 |     char *data() { return m_data; } | 
| 105 |     const char *data() const { return m_data; } | 
| 106 |  | 
| 107 | private: | 
| 108 |     ulong m_protocolId = 0; | 
| 109 |     ulong m_rxStatus = 0; | 
| 110 |     ulong m_txFlags = 0; | 
| 111 |     ulong m_timestamp = 0; | 
| 112 |     ulong m_dataSize = 0; | 
| 113 |     ulong  = 0; | 
| 114 |     char  m_data[maxSize]; | 
| 115 | }; | 
| 116 |  | 
| 117 | Q_DECLARE_OPERATORS_FOR_FLAGS(Message::RxStatus) | 
| 118 | Q_DECLARE_OPERATORS_FOR_FLAGS(Message::TxFlags) | 
| 119 |  | 
| 120 | class Config | 
| 121 | { | 
| 122 | public: | 
| 123 |     enum Parameter { | 
| 124 |         DataRate = 1, | 
| 125 |  | 
| 126 |         Loopback = 3, | 
| 127 |         NodeAddress, | 
| 128 |         NetworkLine, | 
| 129 |         P1Min, | 
| 130 |         P1Max, | 
| 131 |         P2Min, | 
| 132 |         P2Max, | 
| 133 |         P3Min, | 
| 134 |         P3Max, | 
| 135 |         P4Min, | 
| 136 |         P4Max, | 
| 137 |         W1, | 
| 138 |         W2, | 
| 139 |         W3, | 
| 140 |         W4, | 
| 141 |         W5, | 
| 142 |         Tidle, | 
| 143 |         Tinil, | 
| 144 |         Twup, | 
| 145 |         Parity, | 
| 146 |         BitSamplePoint, | 
| 147 |         SyncJumpWidth, | 
| 148 |         W0, | 
| 149 |         T1Max, | 
| 150 |         T2Max, | 
| 151 |         T4Max, | 
| 152 |         T5Max, | 
| 153 |         ISO15765BS, | 
| 154 |         ISO15765STmin, | 
| 155 |         DataBits, | 
| 156 |         FiveBaudMod, | 
| 157 |         BSTx, | 
| 158 |         STminTx, | 
| 159 |         T3Max, | 
| 160 |         ISO15765WFTMax, | 
| 161 |  | 
| 162 |         CanMixedFormat = 0x8000, | 
| 163 |         J1962Pins, | 
| 164 |  | 
| 165 |         SWCANHSDataRate = 0x8010, | 
| 166 |         SWCANSpeedchangeEnable, | 
| 167 |         SWCANResSwitch, | 
| 168 |  | 
| 169 |         ActiveChannels = 0x8020, | 
| 170 |         SampleRate, | 
| 171 |         SamplesPerReading, | 
| 172 |         ReadingsPerMsg, | 
| 173 |         AveragingMethod, | 
| 174 |         SampleResolution, | 
| 175 |         InputRangeLow, | 
| 176 |         InputRangeHigh | 
| 177 |     }; | 
| 178 |  | 
| 179 |     Config() : m_parameter(0), m_value(0) {} | 
| 180 |     explicit Config(Parameter param, ulong val = 0) : m_parameter(param), m_value(val) {} | 
| 181 |  | 
| 182 |     Parameter parameter() const { return Parameter(m_parameter); } | 
| 183 |     ulong value() const { return m_value; } | 
| 184 |  | 
| 185 | private: | 
| 186 |     ulong m_parameter; | 
| 187 |     ulong m_value; | 
| 188 | }; | 
| 189 |  | 
| 190 | /** | 
| 191 |  * @brief J2534 pass-through interface, version 04.04. | 
| 192 |  * @internal | 
| 193 |  * @see http://www.drewtech.com/support/passthru.html | 
| 194 |  */ | 
| 195 | class PassThru : public QObject | 
| 196 | { | 
| 197 |     Q_OBJECT | 
| 198 |     Q_DISABLE_COPY(PassThru) | 
| 199 | public: | 
| 200 |     typedef ulong Handle; | 
| 201 |  | 
| 202 |     enum Status { | 
| 203 |         LoadFailed = -1, | 
| 204 |         NoError = 0, | 
| 205 |         NotSupported, | 
| 206 |         InvalidChannelID, | 
| 207 |         InvalidProtocolID, | 
| 208 |         NullParameter, | 
| 209 |         InvalidIoctlValue, | 
| 210 |         InvalidFlags, | 
| 211 |         Failed, | 
| 212 |         DeviceNotConnected, | 
| 213 |         Timeout, | 
| 214 |         InvalidMsg, | 
| 215 |         InvalidTimeInterval, | 
| 216 |         ExceededLimit, | 
| 217 |         InvalidMsgID, | 
| 218 |         DeviceInUse, | 
| 219 |         InvalidIoctlID, | 
| 220 |         BufferEmpty, | 
| 221 |         BufferFull, | 
| 222 |         BufferOverflow, | 
| 223 |         PinInvalid, | 
| 224 |         ChannelInUse, | 
| 225 |         MsgProtocolID, | 
| 226 |         InvalidFilterID, | 
| 227 |         NoFlowControl, | 
| 228 |         NotUnique, | 
| 229 |         InvalidBaudrate, | 
| 230 |         InvalidDeviceID | 
| 231 |     }; | 
| 232 |  | 
| 233 |     enum ConnectFlag { | 
| 234 |         CAN29BitID = 1 << 8, | 
| 235 |         ISO9141NoChecksum = 1 << 9, | 
| 236 |         CANIDBoth = 1 << 11, | 
| 237 |         ISO9141KLineOnly = 1 << 12 | 
| 238 |     }; | 
| 239 |     Q_DECLARE_FLAGS(ConnectFlags, ConnectFlag) | 
| 240 |  | 
| 241 |     enum FilterType { | 
| 242 |         PassFilter = 1, | 
| 243 |         BlockFilter, | 
| 244 |         FlowControlFilter | 
| 245 |     }; | 
| 246 |  | 
| 247 |     enum ClearTarget { | 
| 248 |         TxBuffer = 7, | 
| 249 |         RxBuffer, | 
| 250 |         PeriodicMsgs, | 
| 251 |         MsgFilters | 
| 252 |     }; | 
| 253 |  | 
| 254 |     explicit PassThru(const QString &libraryPath, QObject *parent = nullptr); | 
| 255 |     virtual ~PassThru(); | 
| 256 |  | 
| 257 |     Status open(const QByteArray &name, Handle *deviceId); | 
| 258 |     Status close(Handle deviceId); | 
| 259 |     Status connect(Handle deviceId, Protocol protocolId, ConnectFlags flags, | 
| 260 |                    uint baudRate, Handle *channelId); | 
| 261 |     Status disconnect(Handle channelId); | 
| 262 |     Status readMsgs(Handle channelId, Message *msgs, ulong *numMsgs, uint timeout = 0); | 
| 263 |     Status writeMsgs(Handle channelId, const Message *msgs, ulong *numMsgs, uint timeout = 0); | 
| 264 |     Status startMsgFilter(Handle channelId, FilterType filterType, | 
| 265 |                           const Message &maskMsg, const Message &patternMsg); | 
| 266 |     Status setConfig(Handle channelId, const Config *params, ulong numParams = 1); | 
| 267 |     Status clear(Handle channelId, ClearTarget target); | 
| 268 |  | 
| 269 |     Status lastError() const { return m_lastError; } | 
| 270 |     QString lastErrorString() const; | 
| 271 |  | 
| 272 | private: | 
| 273 |     Status handleResult(long statusCode); | 
| 274 |  | 
| 275 |     template <typename Func> | 
| 276 |     Func resolveApiFunction(Func *funcPtr, const char *name) { | 
| 277 |         *funcPtr = reinterpret_cast<Func>(m_libJ2534.resolve(symbol: name)); | 
| 278 |         return *funcPtr; | 
| 279 |     } | 
| 280 |  | 
| 281 |     QLibrary                    m_libJ2534; | 
| 282 |     PassThruOpenFunc            m_ptOpen            = nullptr; | 
| 283 |     PassThruCloseFunc           m_ptClose           = nullptr; | 
| 284 |     PassThruConnectFunc         m_ptConnect         = nullptr; | 
| 285 |     PassThruDisconnectFunc      m_ptDisconnect      = nullptr; | 
| 286 |     PassThruReadMsgsFunc        m_ptReadMsgs        = nullptr; | 
| 287 |     PassThruWriteMsgsFunc       m_ptWriteMsgs       = nullptr; | 
| 288 |     PassThruStartMsgFilterFunc  m_ptStartMsgFilter  = nullptr; | 
| 289 |     PassThruGetLastErrorFunc    m_ptGetLastError    = nullptr; | 
| 290 |     PassThruIoctlFunc           m_ptIoctl           = nullptr; | 
| 291 |     QString                     m_lastErrorString; | 
| 292 |     Status                      m_lastError         = NoError; | 
| 293 | }; | 
| 294 |  | 
| 295 | Q_DECLARE_OPERATORS_FOR_FLAGS(PassThru::ConnectFlags) | 
| 296 |  | 
| 297 | } // namespace J2534 | 
| 298 |  | 
| 299 | #endif // PASSTHRUCAN_J2534PASSTHRU_H | 
| 300 |  |