Specyfikacja i opis funkcji J2534 ›
Specyfikacja i opis komend ELM327 ›
Interfejs ELM327 jest dostępny w adapterze Nano ET. Pozostałe adaptery ScanDoc używają protokołu J2534 PassThru.
Zmiany w J2534 DLL, ELM327 i firmware adapterów ScanDoc dotyczące integracji: nowe funkcje, protokoły i parametry - z przykładami użycia.
Pobierz biblioteki J2534 2.0.0.213 - Windows x86/x64/ARM64 (osobne buildy dla Windows 7), macOS (universal), Linux (x64, x86, ARM, ARM64), Android (arm64-v8a, armeabi-v7a, x86, x86_64), iOS (XCFramework); w folderze docs/ - dokumentacja SDK (pierwsze kroki, opis API, konfiguracja, obsługa błędów, DoIP, aktualizacja firmware, format logu, Android, iOS). Statyczne archiwa .a są dostarczane tylko dla iOS i serwerowego buildu Linux x64; pozostałe platformy ładują bibliotekę dynamicznie.
Poprawki
CAN_PS, ISO15765_PS, J1939_PS i ustawianie pinów na kanałach _PS - przy podłączaniu tych trzech protokołów urządzenie odpowiadało odmową; teraz działają na równi z TP2_0_PS i ISO9141_PS. Ustawianie pinów dostosowano do J2534-2 w trzech punktach:
PassThruConnect na pinach domyślnych, choć kanał _PS musi milczeć do SET_CONFIG(J1962_PINS). Teraz kanał wychodzi na magistralę dopiero po ustawieniu pinów.SET_CONFIG(J1962_PINS) przełączało aktywny kanał na inne styki w trakcie sesji. Według standardu piny ustawia się na kanał raz: powtórne wywołanie zwraca ERR_CHANNEL_IN_USE, inne piny - dopiero po PassThruDisconnect.ERR_PIN_NOT_SUPPORTED.uint32_t ch;
pt_config_t pins = { J1962_PINS, 0x0000060EU }; /* piny 6 i 14 */
pt_config_list_t cfg = { 1, &pins };
PassThruConnect(dev, ISO15765_PS, 0, 500000, &ch);
/* kanał jeszcze nie jest na magistrali */
if (PassThruIoctl(ch, SET_CONFIG, &cfg, NULL) != STATUS_NOERROR) {
/* ERR_PIN_NOT_SUPPORTED - takiej kombinacji nie ma w okablowaniu urządzenia */
}
/* dopiero teraz PassThruWriteMsgs / PassThruReadMsgs;
powtórne SET_CONFIG(J1962_PINS) - ERR_CHANNEL_IN_USE */
PassThruWriteMsgs zwracał sukces, PassThruReadMsgs - pusto, a flaga CONNECTION_LOST nie była ustawiana. Programowanie sterownika przez TP2.0 sprawdzono na stanowisku.REQUEST_CONNECTION: kilkanaście prób do milczącego sterownika zajmowało wszystkie sloty filtrów i wyciszało kanał; TEARDOWN_CONNECTION na TP1_6_PS odpowiadał odmową - nie dało się zamknąć połączenia od strony aplikacji; TP2.0 nie przyjmował połączenia nawiązanego przez sterownik i nie przekazywał aplikacji ramek odebranych poza połączeniem (§19.3.1 J2534-2).PassThruReadMsgs. Połączenie jest tu punkt-punkt, adres testera jest zarejestrowany przy routing activation, nie ma czego odfiltrowywać: kanał przekazuje aplikacji wszystkie komunikaty, a PassThruStartMsgFilter odpowiada ERR_NOT_SUPPORTED. Awaria w sterowniku CAN restartowała urządzenie w trakcie sesji DoIP. Watchdog zadania odbiorczego podniesiono z 5 do 30 s - nawiązanie połączenia DoIP zajmuje regulaminowo do 20 s.PassThruConnect dostawał przepełnienie kolejki już przy pierwszym komunikacie. Bazowe CAN i ISO15765 trafiały na inny kontroler CAN i nie docierały do magistrali. Odczyt kolejki odbiorczej nie odzyskiwał sprawności po uszkodzonym wpisie - flaga była sprawdzana błędnie we wszystkich protokołach opartych na CAN.GET_NDIS_ADAPTER_INFO - pod kodem STATUS_NOERROR zwracane były niezainicjalizowane dane. Teraz przychodzi identyfikator adaptera, MAC, adres IPv4, pod którym sterownik widzi urządzenie, oraz stan linii aktywacji; na urządzeniu bez Ethernetu - ERR_NOT_SUPPORTED.GET_PROTOCOL_INFO - odpowiadał nie za wszystkie protokoły i w złym formacie. Teraz działa na każdym otwartym kanale: rozdzielczość znacznika czasu (1 µs), obsługiwana parzystość, liczba bitów danych UART. Parametr, na który urządzenie nie może odpowiedzieć, jest oznaczany w polu supported, a samo wywołanie zwraca STATUS_NOERROR.PassThruDisconnect - odwołanie do już zakończonego zadania kanału uszkadzało pamięć urządzenia.Nowości
libj2534.xcframework zawiera slice'y dla urządzenia (arm64) i symulatora (arm64/x86_64), minimalna wersja iOS 12.0. Każdy slice ma nagłówki j2534.h i j2534_ota.h, module map (Swift import J2534, CoreBluetooth linkowany automatycznie) oraz privacy manifest. Prototypy Pass-Thru API są zadeklarowane w samym j2534.h - na wszystkich platformach. mbedTLS jest wkompilowany, brak zależności zewnętrznych. Konfiguracja w Xcode: Embed = Do Not Embed (biblioteka statyczna), -lc++ w Other Linker Flags, klucze NSBluetoothAlwaysUsageDescription (BLE) i NSLocalNetworkUsageDescription (WLAN) w Info.plist - bez nich iOS zamyka aplikację przy pierwszym użyciu transportu.
import J2534
var deviceId: UInt32 = 0
// PassThruOpen przyjmuje mutable char* - przekazujemy kopię łańcucha
var cstr = Array("ScanDoc;b:N4999".utf8CString) // BLE po prefiksie nazwy
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)
}
/* ID protokołów i IOCTL to makra z rzutowaniem, nie importują się do Swifta:
podawaj liczbą, let CAN: UInt32 = 5, let ISO15765: UInt32 = 6 */
ptOtaUpdate(devId, firmwarePath, callback) i ptOtaAbort(devId); wcześniej OtaUpdate/OtaAbort były dostępne tylko przez C API. Postęp jest przekazywany w onProgress(current, total) - bloki, numeracja od jedynki.
// update.bin został wcześniej skopiowany do pamięci aplikacji.
// Wywołanie blokujące - wykonywać poza main thread.
val res = j2534.ptOtaUpdate(devId, file.absolutePath,
object : OtaProgressListener {
override fun onProgress(current: Int, total: Int) { /* pasek postępu */ }
})
if (res.status == 0) {
// firmware zapisany, urządzenie się restartuje: devId jest nieważny,
// połączenie odtwarza nowy ptOpen (przez BLE - odczekać ~10 s)
}
// res.status < 0 - kod ota_result_t (zob. j2534_ota.h)
// ptOtaAbort(devId) przerywa aktualizację bez restartu urządzenia
log_level w j2534.json: -1 wyłączone, 0 błędy, 1 +ostrzeżenia, 2 +info, 3 +debug, 4 +verbose; domyślnie 3, czyli bez konfiguracji log jest zapisywany w całości. Na poziomie -1 folder sdlogs ani plik .qlog nie są tworzone, nic nie trafia na dysk. Na Androidzie poziom można ustawić także z kodu - ptSetLogLevel(int); tak ustawiony poziom ma pierwszeństwo przed plikiem konfiguracji, więc w buildzie release logu nie da się włączyć z zewnątrz.
// Android: wywołać przed ptOpen
j2534.ptSetLogLevel(-1) // build release - log wyłączony
j2534.ptSetLogLevel(3) // zgłoszenie do wsparcia - pełny log
// Pozostałe platformy: j2534.json w folderze konfiguracji
// macOS ~/Library/Application Support/Quantex/
// Linux ~/.config/quantex/
// Windows %APPDATA%\Quantex\
{ "log_level": -1, "devices": [] }
Poprawki
PassThruReadVersion i nagłówek .qlog zwracały 2.0.0.0: numer buildu nie był przekazywany do buildu Android. Wersja jest teraz wyznaczana tą samą regułą co na pozostałych platformach; ten numer podaje się przy zgłoszeniu do wsparcia.serial_*: transport USB jest wyłączony z buildu iOS, a wywołania do niego pozostały. Transport zastąpiono zaślepką - połączenie łańcuchem c: zwraca zwykły błąd otwarcia portu..qlog - dane komunikatu zapisywano najwyżej do 125 bajtów, a zapis grupy komunikatów przekazanych jednym wywołaniem PassThruReadMsgs lub PassThruWriteMsgs ograniczał stały bufor. Komunikat i cała grupa są teraz zapisywane w całości - to ważne dla długich odpowiedzi, np. listy DTC..qlog - biblioteka i urządzenie tworzyły tekst logu dwiema niezależnymi implementacjami i dekodowanie tych samych wartości się różniło. Flagę nawiązanego połączenia TP2.0 i TP1.6 w polu RxStatus biblioteka drukowała jako CONNECTION_ESTABLISHED, urządzenie - jako CONN_OK; nazwy IOCTL różniły się w 22 miejscach. Nazwy protokołów, flag TxFlags i RxStatus, IOCTL i ich parametrów pochodzą teraz z jednej implementacji, więc log aplikacji i log urządzenia z tej samej wymiany czyta się obok siebie.Pobierz biblioteki J2534 2.0.0.200 - Windows x86/x64/ARM64 (osobne buildy dla Windows 7), macOS (universal), Linux (x64, x86, ARM, ARM64), Android (arm64-v8a, armeabi-v7a, x86, x86_64), iOS.
Nowości
ISO13400_PS (0x8FFD) i HSFZ_PS (0x8FFC). Nie wchodzą w skład standardu SAE J2534 - to własne rozszerzenie ScanDoc: diagnostyka przez Ethernet - wykrywanie pojazdów w sieci (VIN, adres logiczny), połączenie TCP, routing activation, wymiana UDS. Adres testera domyślnie wynosi 0 - ustaw ISO13400_SOURCE_ADDR przed routing activation, inaczej brama odmówi; adres ECU jest przekazywany w każdej wiadomości ([TA][SA][UDS]), ISO13400_TARGET_ADDR nie jest ustawiany przez Set/GetConfig. Wysyłanie jest serializowane wg P2: jedno otwarte żądanie UDS naraz, NRC 7F xx 78 wydłuża oczekiwanie do P2*max (6 s). Nowy parametr kanału ISO13400_P3_DOIP (0x8108) - pauza między wiadomościami.
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 - przed routing activation */
PassThruIoctl(ch, ISO13400_DISCOVER_VEHICLES, NULL, NULL); /* IP ECU zapamiętywane automatycznie */
PassThruIoctl(ch, ISO13400_CONNECT_TCP, NULL, NULL);
PassThruIoctl(ch, ISO13400_ACTIVATE_ROUTING, NULL, &code); /* 0x10 = sukces */
/* dalej PassThruWriteMsgs / PassThruReadMsgs - zwykłe UDS */
0x55 (znacznik ramki J2534) - J2534, każdy inny (tekstowa komenda AT) - ELM327.Poprawki
PassThruStartMsgFilter porównywał tylko 4 bajty CAN ID, ignorując zadaną długość filtra. Teraz ramka jest porównywana na całej długości, jak wymaga standard: PASS/BLOCK po zawartości ramki działają.
/* Wytłumienie odpowiedzi TesterPresent (07E8 02 7E ...) w kolejce odbiorczej */
pt_msg_t mask = {0}, pattern = {0};
mask.protocol_id = pattern.protocol_id = CAN;
mask.data_size = pattern.data_size = 6; /* 4 bajty CAN ID + 2 bajty danych */
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 przy aktywnym kanale CAN psuła Flow Control (FC wychodził bez paddingu, DLC=3 - brama nie wysyłała Consecutive Frames) i nadpisywała filtr odbiorczy własnym TX ID (odbiór bez AT CRA przestawał działać). Zgodnie z datasheetem AT SH ustawia tylko nagłówek nadawania - filtrem odbiorczym sterują teraz wyłącznie AT CRA/CF/CM.PassThruStopPeriodicMsg mógł wysłać dodatkową ramkę po zatrzymaniu._PS - wybór pinów przez SET_CONFIG(J1962_PINS) nie był stosowany, ramki nie trafiały na magistralę.Poprawki