J2534 の仕様と機能の説明 ›
ELM327 の仕様とコマンドの説明 ›
ELM327 インターフェースは Nano ET アダプターで利用できます。その他の ScanDoc アダプターは J2534 PassThru プロトコルを使用します。
J2534 DLL、ELM327、ScanDoc アダプターのファームウェアにおける、インテグレーションに関わる変更:新機能、プロトコル、パラメーター - 使用例付き。
J2534 ライブラリ 2.0.0.213 をダウンロード - Windows x86/x64/ARM64(Windows 7 向け別ビルド)、macOS(universal)、Linux(x64、x86、ARM、ARM64)、Android(arm64-v8a、armeabi-v7a、x86、x86_64)、iOS(XCFramework)。docs/ フォルダーに SDK ドキュメント(はじめに、API リファレンス、設定、エラー処理、DoIP、ファームウェア更新、ログ形式、Android、iOS)を同梱。静的 .a は iOS と Linux x64 サーバービルドのみに付属し、その他のプラットフォームはライブラリを動的にロードします。
修正
CAN_PS、ISO15765_PS、J1939_PS および _PS チャネルのピン設定 - これら 3 つのプロトコルの接続をデバイスが拒否していました。現在は TP2_0_PS、ISO9141_PS と同様に動作します。ピン設定を J2534-2 に合わせて 3 点修正しました:
PassThruConnect の時点でデフォルトのピン上に立ち上がっていましたが、_PS チャネルは SET_CONFIG(J1962_PINS) まで沈黙していなければなりません。現在はピン設定後にのみバスへ出ます。SET_CONFIG(J1962_PINS) を再度呼ぶと、セッション中に稼働中のチャネルが別の接点へ切り替わっていました。規格ではピンはチャネルごとに一度だけ設定します:再呼び出しは ERR_CHANNEL_IN_USE を返し、別のピンは PassThruDisconnect 後にのみ可能です。ERR_PIN_NOT_SUPPORTED で拒否されます。uint32_t ch;
pt_config_t pins = { J1962_PINS, 0x0000060EU }; /* ピン 6 と 14 */
pt_config_list_t cfg = { 1, &pins };
PassThruConnect(dev, ISO15765_PS, 0, 500000, &ch);
/* チャネルはまだバス上にない */
if (PassThruIoctl(ch, SET_CONFIG, &cfg, NULL) != STATUS_NOERROR) {
/* ERR_PIN_NOT_SUPPORTED - この組み合わせはデバイスの配線にない */
}
/* ここで初めて PassThruWriteMsgs / PassThruReadMsgs;
SET_CONFIG(J1962_PINS) の再呼び出し - ERR_CHANNEL_IN_USE */
PassThruWriteMsgs は成功を返し、PassThruReadMsgs は空、CONNECTION_LOST フラグも立ちませんでした。TP2.0 経由の ECU プログラミングをベンチで確認済みです。REQUEST_CONNECTION 失敗後にチャネル内部のフィルターが解除されず、無応答の ECU への十数回の試行でフィルタースロットを使い切りチャネルが沈黙していました。TP1_6_PS の TEARDOWN_CONNECTION が拒否され、アプリ側から接続を閉じられませんでした。TP2.0 は ECU 側から確立された接続を受け付けず、接続外で受信したフレームをアプリへ渡していませんでした(J2534-2 §19.3.1)。PassThruReadMsgs に届きません。ここはポイント・ツー・ポイント接続で、テスターアドレスは routing activation で登録済みのため、選別するものがありません:チャネルは全メッセージをアプリへ渡し、PassThruStartMsgFilter は ERR_NOT_SUPPORTED を返します。CAN ドライバーの障害で DoIP セッション中にデバイスが再起動していました。受信タスクのウォッチドッグを 5 s から 30 s に延長 - DoIP 接続の確立は正常でも最大 20 s かかります。PassThruConnect が最初のメッセージでキューあふれになっていました。基本の CAN と ISO15765 が別の CAN コントローラーへ向かい、バスに届いていませんでした。破損したエントリの後、受信キューの読み出しが回復しませんでした - CAN ベースの全プロトコルでフラグの判定が誤っていました。GET_NDIS_ADAPTER_INFO - STATUS_NOERROR のもとで未初期化データが返されていました。現在はアダプター識別子、MAC、ECU から見たデバイスの IPv4 アドレス、アクティベーション線の状態を返します。Ethernet のないデバイスでは ERR_NOT_SUPPORTED。GET_PROTOCOL_INFO - 一部のプロトコルにしか応答せず、形式も誤っていました。現在は開いている任意のチャネルで動作します:タイムスタンプ分解能(1 µs)、対応パリティ、UART データビット数。デバイスが応答できないパラメーターは supported フィールドで示され、呼び出し自体は STATUS_NOERROR を返します。PassThruDisconnect - すでに終了したチャネルタスクへのアクセスがデバイスのメモリを破壊していました。新機能
libj2534.xcframework はデバイス(arm64)とシミュレーター(arm64/x86_64)のスライスを含み、最低 iOS 12.0。各スライスにヘッダー j2534.h、j2534_ota.h、module map(Swift import J2534、CoreBluetooth を自動リンク)、privacy manifest を同梱。Pass-Thru API のプロトタイプは j2534.h 自体で宣言されます - 全プラットフォーム共通。mbedTLS は組み込み済みで外部依存はありません。Xcode 設定:Embed = Do Not Embed(静的ライブラリ)、Other Linker Flags に -lc++、Info.plist に NSBluetoothAlwaysUsageDescription(BLE)と NSLocalNetworkUsageDescription(WLAN)- これらがないと iOS はトランスポートの初回使用時にアプリを終了します。
import J2534
var deviceId: UInt32 = 0
// PassThruOpen は mutable な char* を受け取る - 文字列のコピーを渡す
var cstr = Array("ScanDoc;b:N4999".utf8CString) // 名前プレフィックスで BLE
let ret = cstr.withUnsafeMutableBufferPointer { PassThruOpen($0.baseAddress, &deviceId) }
if ret == 0 {
var fw = [CChar](repeating: 0, count: 80)
var dll = [CChar](repeating: 0, count: 80)
var api = [CChar](repeating: 0, count: 80)
PassThruReadVersion(deviceId, &fw, &dll, &api)
PassThruClose(deviceId)
}
/* プロトコルと IOCTL の ID は型キャスト付きマクロで Swift にインポートされない:
数値で指定する、let CAN: UInt32 = 5, let ISO15765: UInt32 = 6 */
ptOtaUpdate(devId, firmwarePath, callback) と ptOtaAbort(devId) を追加。従来 OtaUpdate/OtaAbort は C API からのみ利用可能でした。進捗は onProgress(current, total) で通知 - ブロック単位、1 始まり。
// update.bin は事前にアプリのストレージへコピー済み。
// ブロッキング呼び出し - main thread 以外で実行する。
val res = j2534.ptOtaUpdate(devId, file.absolutePath,
object : OtaProgressListener {
override fun onProgress(current: Int, total: Int) { /* プログレスバー */ }
})
if (res.status == 0) {
// ファームウェア書き込み完了、デバイスが再起動:devId は無効、
// 新しい ptOpen で再接続(BLE では約 10 s 待つ)
}
// res.status < 0 - ota_result_t コード(j2534_ota.h 参照)
// ptOtaAbort(devId) はデバイスを再起動せずに更新を中止する
j2534.json の log_level キーで設定:-1 オフ、0 エラー、1 +警告、2 +info、3 +debug、4 +verbose。デフォルトは 3、つまり設定しなければログは完全に書き出されます。-1 では sdlogs フォルダーも .qlog ファイルも作成されず、ディスクへ何も書き込みません。Android ではコードからも設定可能 - ptSetLogLevel(int)。この方法で設定したレベルは設定ファイルより優先されるため、リリースビルドのログを外部から有効化することはできません。
// Android:ptOpen の前に呼び出す
j2534.ptSetLogLevel(-1) // リリースビルド - ログ オフ
j2534.ptSetLogLevel(3) // サポート問い合わせ - 完全なログ
// その他のプラットフォーム:設定フォルダーの j2534.json
// macOS ~/Library/Application Support/Quantex/
// Linux ~/.config/quantex/
// Windows %APPDATA%\Quantex\
{ "log_level": -1, "devices": [] }
修正
PassThruReadVersion と .qlog ヘッダーが 2.0.0.0 を返していました:ビルド番号が Android ビルドへ渡っていませんでした。バージョンは他のプラットフォームと同じ規則で決まります。サポートへの問い合わせ時はこの番号をお知らせください。serial_* シンボル 9 個でアプリのビルドが失敗していました:USB トランスポートは iOS ビルドから除外されていましたが、呼び出しが残っていました。トランスポートをスタブに置き換え - c: 文字列での接続は通常のポートオープンエラーを返します。.qlog ログのデータ切り詰め - メッセージデータは 125 バイトまでしか記録されず、1 回の PassThruReadMsgs または PassThruWriteMsgs で渡されたメッセージ群の記録も固定バッファで制限されていました。メッセージも群全体も完全に記録されます - DTC 一覧などの長い応答で重要です。.qlog ログのフィールド解読 - ライブラリとデバイスが独立した 2 つの実装でログ文字列を生成しており、同じ値の解読が食い違っていました。RxStatus フィールドの TP2.0/TP1.6 接続確立フラグをライブラリは CONNECTION_ESTABLISHED、デバイスは CONN_OK と出力し、IOCTL 名は 22 箇所で異なっていました。プロトコル名、TxFlags と RxStatus のフラグ名、IOCTL とそのパラメーター名は単一の実装で生成されるようになり、同じ通信のアプリログとデバイスログを並べて読めます。J2534 ライブラリ 2.0.0.200 をダウンロード - Windows x86/x64/ARM64(Windows 7 向け別ビルド)、macOS(universal)、Linux(x64、x86、ARM、ARM64)、Android(arm64-v8a、armeabi-v7a、x86、x86_64)、iOS。
新機能
ISO13400_PS(0x8FFD)と HSFZ_PS(0x8FFC)。SAE J2534 標準には含まれない ScanDoc 独自拡張です:Ethernet 経由の診断 - ネットワーク内の車両検出(VIN、論理アドレス)、TCP 接続、routing activation、UDS 交換。テスターアドレスの既定値は 0 - routing activation の前に ISO13400_SOURCE_ADDR を設定してください。設定しないとゲートウェイが拒否します。ECU アドレスは各メッセージで渡されます([TA][SA][UDS])。ISO13400_TARGET_ADDR は Set/GetConfig では設定しません。送信は P2 で直列化されます:未完了の UDS 要求は同時に 1 つ、NRC 7F xx 78 は待機を P2*max(6 秒)まで延長します。新しいチャネルパラメーター ISO13400_P3_DOIP(0x8108)- メッセージ間の待機時間。
uint32_t ch, code = 0;
pt_config_t sa = { ISO13400_SOURCE_ADDR, 0x0E80 };
pt_config_list_t cfg = { 1, &sa };
PassThruConnect(dev, ISO13400_PS, 0, 0, &ch);
PassThruIoctl(ch, SET_CONFIG, &cfg, NULL); /* SA - routing activation の前に設定 */
PassThruIoctl(ch, ISO13400_DISCOVER_VEHICLES, NULL, NULL); /* ECU の IP は自動的に記憶される */
PassThruIoctl(ch, ISO13400_CONNECT_TCP, NULL, NULL);
PassThruIoctl(ch, ISO13400_ACTIVATE_ROUTING, NULL, &code); /* 0x10 = 成功 */
/* 以降は PassThruWriteMsgs / PassThruReadMsgs - 通常の UDS */
0x55(J2534 フレームマーカー)- J2534、それ以外(テキスト AT コマンド)- ELM327。修正
PassThruStartMsgFilter は CAN ID の 4 バイトのみを比較し、指定されたフィルター長を無視していました。標準の要求どおり全長で比較するようになり、フレーム内容による PASS/BLOCK が機能します。
/* 受信キューの TesterPresent 応答(07E8 02 7E ...)を抑制 */
pt_msg_t mask = {0}, pattern = {0};
mask.protocol_id = pattern.protocol_id = CAN;
mask.data_size = pattern.data_size = 6; /* CAN ID 4 バイト + データ 2 バイト */
memcpy(mask.data, "\xFF\xFF\xFF\xFF\xFF\xFF", 6);
memcpy(pattern.data, "\x00\x00\x07\xE8\x02\x7E", 6);
uint32_t fid;
PassThruStartMsgFilter(ch, BLOCK_FILTER, &mask, &pattern, NULL, &fid);
AT SH コマンドが Flow Control を壊し(FC がパディングなし DLC=3 で送信され、ゲートウェイが Consecutive Frames を送らない)、受信フィルターを自身の TX ID で上書きしていました(AT CRA なしの受信が壊れる)。データシートどおり AT SH は送信ヘッダーのみを設定し、受信フィルターは AT CRA/CF/CM のみで制御されます。PassThruStopPeriodicMsg が停止後に余分なフレームを 1 つ送ることがありました。_PS - SET_CONFIG(J1962_PINS) によるピン選択が適用されず、フレームがバスに出ませんでした。修正