Pour le développement de votre propre logiciel de diagnostic, les adaptateurs ScanDoc prennent en charge deux protocoles d'échange de données : J2534 PassThru et ELM327. L'ensemble des protocoles pris en charge dépend du modèle de l'adaptateur - choisissez celui qui convient le mieux à votre tâche.
Spécification et description des fonctions J2534 ›
Spécification et description des commandes ELM327 ›
L'interface ELM327 est disponible dans l'adaptateur Nano ET. Les autres adaptateurs ScanDoc utilisent le protocole J2534 PassThru.
Changements dans la DLL J2534, ELM327 et le firmware des adaptateurs ScanDoc concernant l'intégration : nouvelles fonctions, protocoles et paramètres - avec des exemples d'utilisation.
Télécharger les bibliothèques J2534 2.0.0.213 - Windows x86/x64/ARM64 (builds séparés pour Windows 7), macOS (universal), Linux (x64, x86, ARM, ARM64), Android (arm64-v8a, armeabi-v7a, x86, x86_64), iOS (XCFramework) ; le dossier docs/ contient la documentation du SDK (prise en main, référence de l'API, configuration, gestion des erreurs, DoIP, mise à jour du firmware, format du journal, Android, iOS). Les archives statiques .a ne sont fournies que pour iOS et le build serveur Linux x64 ; les autres plateformes chargent la bibliothèque dynamiquement.
Corrections
CAN_PS, ISO15765_PS, J1939_PS et réglage des broches sur les canaux _PS - la connexion de ces trois protocoles était refusée par l'appareil ; ils fonctionnent désormais comme TP2_0_PS et ISO9141_PS. Le réglage des broches a été mis en conformité avec J2534-2 sur trois points :
PassThruConnect sur les broches par défaut, alors qu'un canal _PS doit rester muet jusqu'à SET_CONFIG(J1962_PINS). Le canal n'entre désormais sur le bus qu'après le réglage des broches.SET_CONFIG(J1962_PINS) répété basculait un canal actif sur d'autres contacts en pleine session. Selon la norme, les broches se règlent une seule fois par canal : un appel répété renvoie ERR_CHANNEL_IN_USE, d'autres broches ne sont possibles qu'après PassThruDisconnect.ERR_PIN_NOT_SUPPORTED.uint32_t ch;
pt_config_t pins = { J1962_PINS, 0x0000060EU }; /* broches 6 et 14 */
pt_config_list_t cfg = { 1, &pins };
PassThruConnect(dev, ISO15765_PS, 0, 500000, &ch);
/* le canal n'est pas encore sur le bus */
if (PassThruIoctl(ch, SET_CONFIG, &cfg, NULL) != STATUS_NOERROR) {
/* ERR_PIN_NOT_SUPPORTED - cette combinaison n'existe pas dans le câblage de l'appareil */
}
/* seulement maintenant PassThruWriteMsgs / PassThruReadMsgs ;
un SET_CONFIG(J1962_PINS) répété - ERR_CHANNEL_IN_USE */
PassThruWriteMsgs renvoyait un succès, PassThruReadMsgs restait vide et l'indicateur CONNECTION_LOST n'était jamais levé. La programmation d'un calculateur via TP2.0 a été vérifiée sur banc.REQUEST_CONNECTION échoué : une dizaine de tentatives vers un calculateur muet occupait tous les emplacements de filtres et rendait le canal muet ; TEARDOWN_CONNECTION sur TP1_6_PS était refusé - impossible de fermer la connexion côté application ; TP2.0 n'acceptait pas une connexion établie par le calculateur et ne transmettait pas à l'application les trames reçues hors connexion (§19.3.1 J2534-2).PassThruReadMsgs. La connexion est ici point à point, l'adresse du testeur est enregistrée lors du routing activation, il n'y a rien à filtrer : le canal transmet chaque message à l'application et PassThruStartMsgFilter répond ERR_NOT_SUPPORTED. Une défaillance du pilote CAN redémarrait l'appareil en pleine session DoIP. Le watchdog de la tâche de réception passe de 5 à 30 s - l'établissement d'une connexion DoIP prend légitimement jusqu'à 20 s.PassThruConnect suivant recevait un débordement de file dès le premier message. Les protocoles de base CAN et ISO15765 partaient vers l'autre contrôleur CAN et n'atteignaient pas le bus. La lecture de la file de réception ne se rétablissait pas après une entrée corrompue - l'indicateur était vérifié incorrectement dans tous les protocoles basés sur CAN.GET_NDIS_ADAPTER_INFO - des données non initialisées étaient renvoyées sous STATUS_NOERROR. La réponse contient désormais l'identifiant de l'adaptateur, le MAC, l'adresse IPv4 sous laquelle le calculateur voit l'appareil et l'état de la ligne d'activation ; sur un appareil sans Ethernet - ERR_NOT_SUPPORTED.GET_PROTOCOL_INFO - ne répondait que pour une partie des protocoles et dans un mauvais format. Il fonctionne désormais sur tout canal ouvert : résolution de l'horodatage (1 µs), parité prise en charge, bits de données UART. Un paramètre auquel l'appareil ne peut pas répondre est marqué dans le champ supported, l'appel lui-même renvoie STATUS_NOERROR.PassThruDisconnect - l'accès à une tâche de canal déjà terminée corrompait la mémoire de l'appareil.Nouveautés
libj2534.xcframework contient des tranches pour l'appareil (arm64) et le simulateur (arm64/x86_64), version minimale iOS 12.0. Chaque tranche embarque les en-têtes j2534.h et j2534_ota.h, une module map (Swift import J2534, CoreBluetooth lié automatiquement) et un privacy manifest. Les prototypes de l'API Pass-Thru sont déclarés dans j2534.h lui-même - sur toutes les plateformes. mbedTLS est compilé dans la bibliothèque, aucune dépendance externe. Configuration Xcode : Embed = Do Not Embed (bibliothèque statique), -lc++ dans Other Linker Flags, les clés NSBluetoothAlwaysUsageDescription (BLE) et NSLocalNetworkUsageDescription (WLAN) dans Info.plist - sans elles, iOS termine l'application au premier accès au transport.
import J2534
var deviceId: UInt32 = 0
// PassThruOpen attend un char* mutable - passer une copie de la chaîne
var cstr = Array("ScanDoc;b:N4999".utf8CString) // BLE par préfixe de nom
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)
}
/* les ID de protocoles et d'IOCTL sont des macros avec transtypage, non importées en Swift :
utiliser les nombres, let CAN: UInt32 = 5, let ISO15765: UInt32 = 6 */
ptOtaUpdate(devId, firmwarePath, callback) et ptOtaAbort(devId) sont ajoutés à la couche JNI ; auparavant OtaUpdate/OtaAbort n'étaient accessibles que via l'API C. La progression est transmise dans onProgress(current, total) - blocs, numérotés à partir de 1.
// update.bin a été copié au préalable dans le stockage de l'application.
// L'appel est bloquant - à exécuter hors du main thread.
val res = j2534.ptOtaUpdate(devId, file.absolutePath,
object : OtaProgressListener {
override fun onProgress(current: Int, total: Int) { /* barre de progression */ }
})
if (res.status == 0) {
// firmware écrit, l'appareil redémarre : devId n'est plus valide,
// reconnexion par un nouveau ptOpen (en BLE - attendre ~10 s)
}
// res.status < 0 - code ota_result_t (voir j2534_ota.h)
// ptOtaAbort(devId) interrompt la mise à jour sans redémarrer l'appareil
log_level dans j2534.json : -1 désactivé, 0 erreurs, 1 +avertissements, 2 +info, 3 +debug, 4 +verbose ; la valeur par défaut est 3, c'est-à-dire que sans configuration le journal est écrit en entier. Au niveau -1, ni le dossier sdlogs ni le fichier .qlog ne sont créés, rien n'est écrit sur le disque. Sur Android, le niveau se règle aussi depuis le code - ptSetLogLevel(int) ; un niveau ainsi fixé a priorité sur le fichier de configuration, si bien qu'en build release le journal ne peut pas être activé de l'extérieur.
// Android : appeler avant ptOpen
j2534.ptSetLogLevel(-1) // build release - journal désactivé
j2534.ptSetLogLevel(3) // demande au support - journal complet
// Autres plateformes : j2534.json dans le dossier de configuration
// macOS ~/Library/Application Support/Quantex/
// Linux ~/.config/quantex/
// Windows %APPDATA%\Quantex\
{ "log_level": -1, "devices": [] }
Corrections
PassThruReadVersion et l'en-tête .qlog renvoyaient 2.0.0.0 : le numéro de build n'était pas transmis au build Android. La version est désormais déterminée selon la même règle que sur les autres plateformes ; c'est ce numéro qu'il faut indiquer lors d'une demande au support.serial_* non résolus : le transport USB est exclu du build iOS, mais les appels subsistaient. Le transport est remplacé par un stub - une connexion par chaîne c: renvoie une erreur normale d'ouverture de port..qlog - les données d'un message n'étaient écrites que jusqu'à 125 octets, et l'enregistrement d'un groupe de messages passé en un seul appel PassThruReadMsgs ou PassThruWriteMsgs était limité par un tampon fixe. Le message et le groupe entier sont désormais écrits en totalité - important pour les réponses longues, par exemple une liste de DTC..qlog - la bibliothèque et l'appareil produisaient le texte du journal avec deux implémentations indépendantes, et le décodage des mêmes valeurs différait. L'indicateur de connexion établie TP2.0 et TP1.6 dans le champ RxStatus était imprimé CONNECTION_ESTABLISHED par la bibliothèque et CONN_OK par l'appareil ; les noms d'IOCTL différaient à 22 endroits. Les noms des protocoles, des indicateurs TxFlags et RxStatus, des IOCTL et de leurs paramètres proviennent désormais d'une seule implémentation, de sorte que le journal de l'application et celui de l'appareil pour un même échange se lisent côte à côte.Télécharger les bibliothèques J2534 2.0.0.200 - Windows x86/x64/ARM64 (builds séparés pour Windows 7), macOS (universal), Linux (x64, x86, ARM, ARM64), Android (arm64-v8a, armeabi-v7a, x86, x86_64), iOS.
Nouveautés
ISO13400_PS (0x8FFD) et HSFZ_PS (0x8FFC). Ils ne font pas partie du standard SAE J2534 - c'est une extension propriétaire ScanDoc : diagnostic par Ethernet - découverte des véhicules sur le réseau (VIN, adresse logique), connexion TCP, routing activation, échange UDS. L'adresse du testeur vaut 0 par défaut - définissez ISO13400_SOURCE_ADDR avant le routing activation, sinon la passerelle refusera ; l'adresse de l'ECU est transmise dans chaque message ([TA][SA][UDS]), ISO13400_TARGET_ADDR ne se définit pas via Set/GetConfig. L'émission est sérialisée selon P2 : une seule requête UDS en cours à la fois, le NRC 7F xx 78 prolonge l'attente jusqu'à P2*max (6 s). Nouveau paramètre de canal ISO13400_P3_DOIP (0x8108) - pause entre les messages.
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 - avant le routing activation */
PassThruIoctl(ch, ISO13400_DISCOVER_VEHICLES, NULL, NULL); /* l'IP de l'ECU est mémorisée automatiquement */
PassThruIoctl(ch, ISO13400_CONNECT_TCP, NULL, NULL);
PassThruIoctl(ch, ISO13400_ACTIVATE_ROUTING, NULL, &code); /* 0x10 = succès */
/* ensuite PassThruWriteMsgs / PassThruReadMsgs - UDS classique */
0x55 (marqueur de trame J2534) - J2534, tout autre octet (commande AT texte) - ELM327.Corrections
PassThruStartMsgFilter ne comparait que les 4 octets du CAN ID, en ignorant la longueur de filtre indiquée. La trame est désormais comparée sur toute la longueur, comme l'exige le standard : PASS/BLOCK selon le contenu de la trame fonctionnent.
/* Supprimer les réponses TesterPresent (07E8 02 7E ...) de la file de réception */
pt_msg_t mask = {0}, pattern = {0};
mask.protocol_id = pattern.protocol_id = CAN;
mask.data_size = pattern.data_size = 6; /* 4 octets CAN ID + 2 octets de données */
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 sur un canal CAN actif cassait le Flow Control (le FC partait sans padding, DLC=3 - la passerelle n'envoyait pas de Consecutive Frames) et écrasait le filtre de réception avec son propre TX ID (la réception sans AT CRA était cassée). Selon la datasheet, AT SH ne définit que l'en-tête d'émission - le filtre de réception n'est plus contrôlé que par AT CRA/CF/CM.PassThruStopPeriodicMsg pouvait envoyer une trame supplémentaire après l'arrêt._PS - la sélection des broches via SET_CONFIG(J1962_PINS) n'était pas appliquée, les trames n'atteignaient pas le bus.Corrections