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.
Biblioteki dostarczane są w jednym archiwum. Platformy: Windows x86/x64/ARM64 (osobne kompilacje dla Windows 7), macOS (universal), Linux (x64, x86, ARM, ARM64), Android (arm64-v8a, armeabi-v7a, x86, x86_64), iOS (XCFramework). W katalogu docs/ znajduje się dokumentacja SDK: pierwsze kroki, opis API, konfiguracja, obsługa błędów, DoIP, aktualizacja firmware, format logu, Android, iOS.
Pobierz biblioteki J2534 2.0.0.241 - 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), przeglądarki Chrome i Edge 137+ (WebAssembly); w folderze docs/ - dokumentacja SDK (pierwsze kroki, opis API, konfiguracja, obsługa błędów, DoIP, DevHub, aktualizacja firmware, format logu, Android, iOS, przeglądarka). Statyczne archiwa .a są dostarczane tylko dla iOS i serwerowego buildu Linux x64; pozostałe platformy ładują bibliotekę dynamicznie.
Nowości
ConfigWrite po cichu pomija klucz ble_name: nie zwraca błędu, aby aplikacje, które wysyłają wszystkie ustawienia naraz, nadal działały. ConfigRead zwraca nazwę jak wcześniej.PassThruReadVersion przez USB trwa około 6,5 ms zamiast 16. Odpowiedź dłuższą niż 248 bajtów urządzenie wysyła porcjami po 248 bajtów z przerwą 4 ms, dlatego transmisja z urządzenia do komputera przebiega z prędkością około 59 KB/s: odpowiedź o rozmiarze 4 KB zajmuje około 70 ms. Transmisja z komputera do urządzenia nadal odbywa się z prędkością 3 Mbit/s.TCP_NODELAY i odpowiedź wychodzi od razu w całości.Poprawki
PassThruConnect CAN. Urządzenie czasem samo restartowało się około 300 ms po otwarciu kanału CAN. Ponadto wywołanie OtaUpdate po sesji CAN w tym samym PassThruOpen nie rozpoczynało aktualizacji: urządzenie przez 30 s nie odpowiadało na jej rozpoczęcie.PassThruClose. Ponadto w trakcie sesji CAN lub DoIP i po niej urządzenie mogło się zawiesić przy otwieraniu lub zamykaniu portu. Z firmware build 86 i biblioteką 2.0.0.241 po PassThruClose port można bezpiecznie otwierać i zamykać. Zawieszenie jest możliwe tylko wtedy, gdy port zostanie zamknięty w trakcie sesji, przed PassThruClose. W macOS i Linux po PassThruClose port jest wolny dla innego programu, w Windows, tak jak wcześniej, pozostaje zajęty do usunięcia biblioteki z pamięci. Nie otwieraj portu samodzielnie i nie zmieniaj DTR i RTS, dopóki korzysta z niego biblioteka.PassThruWriteMsgs i tak dostawał odpowiedź "przyjęto wszystkie", a wiadomości, które się nie zmieściły, przepadały. Ponadto przy każdej takiej wiadomości urządzeniu ubywało wolnej pamięci i przy gęstym ruchu po kilkudziesięciu sekundach zaczynało ono odrzucać żądania z powodu braku pamięci aż do restartu. Teraz urządzenie czeka na miejsce w kolejce w ramach limitu czasu wywołania i zgłasza, ile wiadomości przyjęło. Jeśli urządzenie nie przyjęło wszystkich wiadomości, biblioteka zwraca ERR_BUFFER_FULL przy zerowym limicie czasu i ERR_TIMEOUT przy niezerowym, a do pNumMsgs zapisuje liczbę przyjętych wiadomości.BUFFER_OVERFLOW w RxStatus.ETHERNET_NDIS. PassThruDisconnect i GET_NDIS_ADAPTER_INFO z numerem kanału zwróconym przez PassThruConnect odpowiadały ERR_INVALID_CHANNEL_ID, a PassThruClose nie zamykał tego kanału. Nieudane rozłączenie zwraca teraz ERR_FAILED, wcześniej zamiast kodu J2534 przychodziła wartość 0xFFFB.P4_MIN = 0 ramki urywały się z TX_FAILED.Nowości
Promise z obiektem, w którym ret zawiera kod J2534, a w pozostałych polach są parametry wyjściowe. Dane o znalezionych pojazdach (ISO13400_GET_VEHICLE_INFO, HSFZ_GET_VEHICLE_INFO) przychodzą jako tablica obiektów z polami vin, logicalAddress, ip i innymi, a nie jako bajty struktur. Urządzenie BLE użytkownik wybiera po nazwie w oknie przeglądarki, a przy pierwszym połączeniu system pyta o PIN. Błędny lub anulowany PIN daje ERR_FAILED i tekst BLE pairing rejected, tak jak w bibliotece natywnej. Oprócz funkcji PassThru dostępne są ConfigRead, ConfigWrite, ConfigReset, ConfigReboot oraz aktualizacja firmware: OtaUpdate przyjmuje plik firmware jako ArrayBuffer i zgłasza postęp, a OtaAbort zatrzymuje trwającą aktualizację i wtedy OtaUpdate zwraca nowy kod OTA_RESULT_ERR_ABORTED (-510). Na serwerze WWW umieszcza się dwa pliki, j2534.js i j2534_web.mjs, a strona musi być otwierana przez HTTPS. Stronę demonstracyjną j2534_demo.html można otworzyć bezpośrednio z dysku. Wymagany jest firmware build 86. Zamknięcie portu USB (releasePort() lub zamknięcie karty) restartuje Nano ET: przy zamykaniu portu sterownik USB przełącza linię DTR, a w Nano ET ta linia steruje resetem urządzenia. Biblioteka natywna zwalnia linie w bezpiecznej kolejności, a przeglądarka nie daje takiej możliwości. Szczegóły w docs/WEB.md.
Przykład
import { loadJ2534 } from './j2534.js';
const ISO15765 = 6;
connectButton.onclick = async () => {
// przeglądarka pokazuje okno wyboru urządzenia tylko w odpowiedzi na działanie użytkownika
const port = await navigator.serial.requestPort({ filters: [{ usbVendorId: 0x0403 }] });
const j2534 = await loadJ2534(port);
// przez BLE zamiast portu przekazuje się urządzenie BLE:
// const device = await navigator.bluetooth.requestDevice({ filters: [{ services: [0xfff0] }] });
// const j2534 = await loadJ2534(device);
const { ret, deviceId } = await j2534.PassThruOpen();
if (ret !== 0) {
const { errorDescription } = await j2534.PassThruGetLastError();
console.error(errorDescription);
return;
}
const { channelId } = await j2534.PassThruConnect(deviceId, ISO15765, 0, 500000);
const { msgs } = await j2534.PassThruReadMsgs(channelId, 10, 100);
// aktualizacja firmware z pliku wybranego przez użytkownika
const fw = await fileInput.files[0].arrayBuffer();
const r = await j2534.OtaUpdate(deviceId, fw, (current, total) => {
progressBar.max = total;
progressBar.value = current;
});
// r.ret: 0 przy powodzeniu, -510 po OtaAbort, pozostałe kody w FIRMWARE_UPDATE.md
};
Poprawki
HSFZ_GET_VEHICLE_INFO zwracał tylko pierwsze 8 bajtów informacji o każdym znalezionym pojeździe. Aplikacja dostawała fragment VIN bez adresu ECU i adresu IP. Teraz każdy rekord hsfz_vehicle_info_t przychodzi w całości, 32 bajty: VIN, adres ECU, MAC i IP. Poprawione we wszystkich bibliotekach natywnych.PassThruWriteMsgs z więcej niż 40 wiadomościami lub więcej niż 5115 bajtami zawieszał urządzenie. Biblioteka wysyłała takie wywołanie jednym poleceniem, a urządzenie takiego polecenia nie przyjmuje. Urządzenie na nie nie odpowiadało i wywołanie czekało pełny limit czasu, a przez LAN/WLAN urządzenie traktowało bajty danych tego polecenia jako kolejne polecenia. Teraz biblioteka dzieli wywołanie na kilka poleceń i każde z nich dostaje pozostałą część limitu czasu wywołania. Wszystkie wiadomości są sprawdzane przed wysłaniem pierwszej. Firmware build 86 odpowiada na takie polecenie ze starszych wersji biblioteki kodem ERR_INVALID_MSG.PassThruReadMsgs z limitem czasu i żądaniem ponad 128 wiadomości był odrzucany w całości, ponieważ urządzenie zwraca najwyżej 128 wiadomości naraz. Teraz wywołanie zwraca do 128 wiadomości, a pozostałe odczytuje następne wywołanie.CLEAR_RX_BUFFER nie czyścił wiadomości, które biblioteka już pobrała z urządzenia, i następne wywołanie PassThruReadMsgs zwracało stare ramki. Teraz czyszczony jest też bufor biblioteki.ERR_DEVICE_NOT_CONNECTED. Deskryptor 0 jest wolny, gdy proces zamknął standardowe wejście, jak zwykle robią to usługi.PassThruReadMsgs przy zamkniętym urządzeniu. Jeśli urządzenie nie było otwarte, funkcja zwracała błąd, ale zostawiała w *pNumMsgs liczbę, o którą prosiła aplikacja. Aplikacja, która sprawdza liczbę odczytanych wiadomości, a nie kod powrotu, przetwarzała tyle pustych wiadomości. Teraz w tym przypadku *pNumMsgs = 0.PassThruGetLastError. Po zerwaniu łączności funkcja zwracała tekst błędu jednego z poprzednich wywołań, na przykład ERR_BUFFER_EMPTY, choć kod powrotu był prawidłowy. Teraz tekst podaje przyczynę: LAN socket closed, BLE not connected lub serial port not open. Dla ERR_BUFFER_OVERFLOW (0x12) zamiast nazwy wyświetlał się Unknown error: 18.Pobierz biblioteki J2534 2.0.0.225
Nowości
ConfigRead, a parę usuwa ConfigWrite. Nie dodano do tego nowych wywołań w bibliotece.
Przykład
char json[2048];
if (ConfigRead(dev, json, sizeof(json)) == STATUS_NOERROR) {
/* w odpowiedzi, obok pozostałych ustawień:
"ble_bonds":[{"name":"WS-07","mac":"A4:C1:38:11:22:33"}] */
}
ConfigWrite(dev, "{\"ble_bond_del\":\"A4:C1:38:11:22:33\"}");
/* działa od razu, ConfigReboot nie jest potrzebny */
Poprawki
reciv ack end single msg timeout SG, a potem reciv ack counter error SG.TX_FAILED, a przywrócić kanał można było tylko przez ponowne połączenie.Nowości
ConfigRead, ConfigWrite, ConfigReboot i ConfigReset (w Windows ordynały @52-@55) były eksportowane już wcześniej, ale nie było ich w dokumentacji i nie dało się z nich skorzystać z zewnątrz. Teraz w docs/API_REFERENCE.md opisano prototypy i zachowanie, a w docs/CONFIGURATION.md podano tabelę kluczy z zakresami, które sprawdza firmware. Urządzenie obsługuje te polecenia przed routingiem J2534, działają więc na każdym transporcie: LAN/WLAN, BLE i USB.
Przykład
char json[2048];
ConfigRead(dev, json, sizeof(json)); /* wszystkie ustawienia jako jeden obiekt JSON */
ConfigWrite(dev, "{\"ble_name\":\"WS-07\"}"); /* zmieniają się tylko przekazane klucze */
ConfigReboot(dev); /* ustawienia działają po restarcie;
device_id traci ważność, otworzyć ponownie po ~10 s */
ptConfigRead, ptConfigWrite, ptConfigReboot i ptConfigReset.
Przykład
external fun ptConfigRead(devId: Int): String? // null przy błędzie
external fun ptConfigWrite(devId: Int, json: String): Int
external fun ptConfigReboot(devId: Int): Int
external fun ptConfigReset(devId: Int): Int
val json = j2534.ptConfigRead(devId) ?: return // przyczyna: ptGetLastError()
j2534.ptConfigWrite(devId, """{"ble_name":"WS-07"}""")
j2534.ptConfigReboot(devId)
PassThruOpen celowo nie sprawdza wersji, żeby nie dokładać wymiany z urządzeniem przy każdym otwarciu: zainstalowany build zwraca PassThruReadVersion, a rozbieżność widać w .qlog w linii firmware build N is older than build 85 required by DLL ….Poprawki
ERR_FAILED, a PassThruGetLastError podaje tekst BLE pairing rejected (wrong PIN or not paired). Kod ERR_FAILED wybrano celowo, bo przy ERR_DEVICE_NOT_CONNECTED aplikacje zwykle nie pobierają tekstu błędu. Działa na wszystkich platformach: Android, macOS, Windows i Linux. Pozostałe awarie BLE nadal dają ERR_DEVICE_NOT_CONNECTED, ale teraz z kodem transportu: wcześniej kod ten drukowano jako numer błędu POSIX i odrzucony zapis wychodził na zewnątrz jako 0x7 - Argument list too long.ptClose przez BLE. Przy zamykaniu połączenia BLE biblioteka zamykała deskryptor pliku 0, choć w trybie BLE nie ma gniazda. Zwykle zamykało to po cichu stdin, ale jeśli fd 0 należał w tym momencie do obiektu JVM, fdsan kończył proces: attempted to close file descriptor 0 … owned by native object. Dlatego awaria występowała nieregularnie.ptClose przez BLE trwało sekundę dłużej. Biblioteka odrzucała odpowiedź urządzenia na zamknięcie, odczekiwała limit czasu odbioru 1 s i zapisywała w logu 0x6E - Connection timed out, jakby urządzenie nie odpowiedziało. Teraz zamknięcie kończy się po odpowiedzi urządzenia. Na macOS, Windows i Linux tego błędu nie było.ptOpen przez BLE, gdy urządzenie nie odpowiedziało na otwarcie. Aplikacja kończyła się z SIGSEGV. Przy innych niepowodzeniach otwarcia (odrzucone parowanie, przekroczony czas połączenia) biblioteka nie zwalniała globalnej referencji JNI do BLEManager, więc przy kolejnych próbach referencje się gromadziły.FAST_INIT. Odpowiedź urządzenia kopiowano do struktury pt_msg_t aplikacji bez sprawdzenia długości: skrócona odpowiedź prowadziła do odczytu niezainicjowanej pamięci, a zawyżona długość w odpowiedzi do zapisu poza strukturę przekazaną przez aplikację. W systemie Android to samo wywołanie wysyłało na magistralę zniekształconą ramkę, a przy niepowodzeniu kończyło aplikację awaryjnie. Poprawiono też kontrolę rozmiaru danych wejściowych: przepuszczała wartości NumOfBytes rzędu 0x20000000.FIVE_BAUD_INIT. Wejście jest ograniczone do jednego bajtu adresu, zgodnie z §11.3.3.3; wcześniej przyjmowany był blok dowolnej długości, a aplikacja przekazująca więcej dostawała kod powodzenia zamiast odmowy..qlog nie był tworzony. Log otwierało tylko PassThruOpen, a wywołanie ptOpen je omija. Dlatego w zewnętrznej aplikacji na Androida katalog sdlogs pozostawał pusty przy każdym poziomie logowania, wpisy trafiały wyłącznie do logcat i nie dało się uzyskać od klienta logu sesji.FIVE_BAUD_INIT i FAST_INIT drukowano tylko > ok: ani adres inicjalizacji, ani odpowiedź sterownika nie trafiały do logu, więc nieudanej inicjalizacji nie dało się z niego zanalizować. Teraz linia zawiera zapytanie i odpowiedź: io 1 FIVE_BAUD_INIT 33 > 8F6F 2850ms.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