Προδιαγραφή J2534 και αναφορά λειτουργιών ›
Προδιαγραφή ELM327 και αναφορά εντολών ›
Η διεπαφή ELM327 είναι διαθέσιμη στο Nano ET. Οι υπόλοιποι προσαρμογείς ScanDoc χρησιμοποιούν το πρωτόκολλο J2534 PassThru.
Αλλαγές στο J2534 DLL, στο ELM327 και στο υλικολογισμικό των προσαρμογέων ScanDoc που αφορούν την ενσωμάτωση: νέες λειτουργίες, πρωτόκολλα και παράμετροι - με παραδείγματα χρήσης.
Λήψη βιβλιοθηκών J2534 2.0.0.213 - Windows x86/x64/ARM64 (ξεχωριστά builds για 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 και για το server build Linux x64· οι υπόλοιπες πλατφόρμες φορτώνουν τη βιβλιοθήκη δυναμικά.
Διορθώσεις
CAN_PS, ISO15765_PS, J1939_PS και ρύθμιση ακίδων στα κανάλια _PS - η σύνδεση αυτών των τριών πρωτοκόλλων απορριπτόταν από τη συσκευή· τώρα λειτουργούν όπως τα TP2_0_PS και ISO9141_PS. Η ρύθμιση ακίδων ευθυγραμμίστηκε με το J2534-2 σε τρία σημεία:
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 δεν εμφανιζόταν ποτέ. Ο προγραμματισμός ECU μέσω TP2.0 επιβεβαιώθηκε στον πάγκο δοκιμών.REQUEST_CONNECTION: δέκα περίπου προσπάθειες προς σιωπηλό ECU κατανάλωναν όλες τις θέσεις φίλτρων και σίγαζαν το κανάλι· το TEARDOWN_CONNECTION στο TP1_6_PS απορριπτόταν - η σύνδεση δεν μπορούσε να κλείσει από την εφαρμογή· το TP2.0 δεν δεχόταν σύνδεση που ξεκινούσε το ECU και δεν παρέδιδε στην εφαρμογή πλαίσια εκτός σύνδεσης (§19.3.1 J2534-2).PassThruReadMsgs. Η σύνδεση εδώ είναι σημείο προς σημείο, η διεύθυνση του tester καταχωρείται στο routing activation, δεν υπάρχει τίποτα να φιλτραριστεί: το κανάλι παραδίδει κάθε μήνυμα στην εφαρμογή και το PassThruStartMsgFilter απαντά ERR_NOT_SUPPORTED. Σφάλμα στον οδηγό CAN επανεκκινούσε τη συσκευή στη μέση συνεδρίας DoIP. Το watchdog της εργασίας λήψης αυξήθηκε από 5 σε 30 s - η εγκαθίδρυση σύνδεσης DoIP διαρκεί κανονικά έως 20 s.PassThruConnect έπαιρνε υπερχείλιση ουράς από το πρώτο μήνυμα. Τα βασικά CAN και ISO15765 πήγαιναν στον άλλο ελεγκτή CAN και δεν έφταναν στον δίαυλο. Η ανάγνωση της ουράς λήψης δεν επανερχόταν μετά από κατεστραμμένη εγγραφή - η ένδειξη ελεγχόταν λανθασμένα σε όλα τα πρωτόκολλα που βασίζονται σε CAN.GET_NDIS_ADAPTER_INFO - υπό STATUS_NOERROR επιστρέφονταν μη αρχικοποιημένα δεδομένα. Τώρα έρχονται το αναγνωριστικό του προσαρμογέα, η MAC, η διεύθυνση IPv4 με την οποία το ECU βλέπει τη συσκευή και η κατάσταση της γραμμής ενεργοποίησης· σε συσκευή χωρίς Ethernet - ERR_NOT_SUPPORTED.GET_PROTOCOL_INFO - απαντούσε μόνο για μέρος των πρωτοκόλλων και σε λάθος μορφή. Τώρα λειτουργεί σε κάθε ανοιχτό κανάλι: ανάλυση χρονοσφραγίδας (1 µs), υποστηριζόμενη ισοτιμία, bits δεδομένων UART. Παράμετρος στην οποία η συσκευή δεν μπορεί να απαντήσει επισημαίνεται στο πεδίο supported, ενώ η ίδια η κλήση επιστρέφει STATUS_NOERROR.PassThruDisconnect - η πρόσβαση σε ήδη τερματισμένη εργασία καναλιού κατέστρεφε τη μνήμη της συσκευής.Νέα
libj2534.xcframework περιέχει slices για συσκευή (arm64) και προσομοιωτή (arm64/x86_64), ελάχιστη έκδοση iOS 12.0. Κάθε slice φέρει τις κεφαλίδες j2534.h και j2534_ota.h, module map (Swift import J2534, αυτόματη σύνδεση CoreBluetooth) και privacy manifest. Τα πρωτότυπα του Pass-Thru API δηλώνονται στο ίδιο το j2534.h - σε όλες τις πλατφόρμες. Το mbedTLS είναι ενσωματωμένο, δεν υπάρχουν εξωτερικές εξαρτήσεις. Ρύθμιση στο Xcode: Embed = Do Not Embed (η βιβλιοθήκη είναι στατική), -lc++ στα Other Linker Flags, τα κλειδιά NSBluetoothAlwaysUsageDescription (BLE) και NSLocalNetworkUsageDescription (WLAN) στο Info.plist - χωρίς αυτά το 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)
}
/* τα ID πρωτοκόλλων και IOCTL είναι μακροεντολές με μετατροπή τύπου, δεν εισάγονται στη 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) διακόπτει την ενημέρωση χωρίς επανεκκίνηση της συσκευής
log_level στο j2534.json: -1 απενεργοποιημένη, 0 σφάλματα, 1 +προειδοποιήσεις, 2 +info, 3 +debug, 4 +verbose· προεπιλογή 3, δηλαδή χωρίς ρύθμιση η καταγραφή γράφεται πλήρως. Στο επίπεδο -1 δεν δημιουργούνται ούτε ο φάκελος sdlogs ούτε το αρχείο .qlog, τίποτα δεν γράφεται στον δίσκο. Στο Android το επίπεδο ορίζεται και από τον κώδικα - ptSetLogLevel(int)· επίπεδο που ορίστηκε έτσι υπερισχύει του αρχείου διαμόρφωσης, οπότε σε release build η καταγραφή δεν μπορεί να ενεργοποιηθεί απ' έξω.
// Android: κλήση πριν το ptOpen
j2534.ptSetLogLevel(-1) // release build - καταγραφή απενεργοποιημένη
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: ο αριθμός build δεν περνούσε στο build Android. Η έκδοση προσδιορίζεται τώρα με τον ίδιο κανόνα όπως στις άλλες πλατφόρμες· αυτός ο αριθμός αναφέρεται στα αιτήματα υποστήριξης.serial_*: η μεταφορά USB εξαιρείται από το build iOS, αλλά οι κλήσεις προς αυτήν παρέμεναν. Η μεταφορά αντικαταστάθηκε από stub - σύνδεση με συμβολοσειρά c: επιστρέφει κανονικό σφάλμα ανοίγματος θύρας..qlog - τα δεδομένα μηνύματος γράφονταν μόνο έως 125 bytes και η εγγραφή ομάδας μηνυμάτων από μία κλήση PassThruReadMsgs ή PassThruWriteMsgs περιοριζόταν από σταθερή προσωρινή μνήμη. Το μήνυμα και ολόκληρη η ομάδα γράφονται τώρα πλήρως - σημαντικό για μακριές απαντήσεις, π.χ. λίστα DTC..qlog - η βιβλιοθήκη και η συσκευή παρήγαγαν το κείμενο καταγραφής με δύο ανεξάρτητες υλοποιήσεις και η αποκωδικοποίηση των ίδιων τιμών διέφερε. Την ένδειξη εγκατεστημένης σύνδεσης TP2.0 και TP1.6 στο πεδίο RxStatus η βιβλιοθήκη τύπωνε ως CONNECTION_ESTABLISHED, η συσκευή ως CONN_OK· τα ονόματα IOCTL διέφεραν σε 22 σημεία. Τα ονόματα πρωτοκόλλων, ενδείξεων TxFlags και RxStatus, IOCTL και των παραμέτρων τους παράγονται τώρα από μία υλοποίηση, ώστε η καταγραφή της εφαρμογής και της συσκευής για την ίδια ανταλλαγή να διαβάζονται δίπλα-δίπλα.Λήψη βιβλιοθηκών J2534 2.0.0.200 - Windows x86/x64/ARM64 (ξεχωριστά builds για 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. Η διεύθυνση tester είναι προεπιλεγμένα 0 - ορίστε το ISO13400_SOURCE_ADDR πριν από το routing activation, αλλιώς η πύλη θα αρνηθεί· η διεύθυνση του ECU μεταδίδεται σε κάθε μήνυμα ([TA][SA][UDS]), το ISO13400_TARGET_ADDR δεν ορίζεται μέσω Set/GetConfig. Η αποστολή σειριοποιείται με P2: ένα εκκρεμές αίτημα UDS κάθε φορά, το NRC 7F xx 78 παρατείνει την αναμονή έως P2*max (6 s). Νέα παράμετρος καναλιού 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); /* η IP του ECU απομνημονεύεται αυτόματα */
PassThruIoctl(ch, ISO13400_CONNECT_TCP, NULL, NULL);
PassThruIoctl(ch, ISO13400_ACTIVATE_ROUTING, NULL, &code); /* 0x10 = επιτυχία */
/* έπειτα PassThruWriteMsgs / PassThruReadMsgs - κανονικό UDS */
0x55 (δείκτης πλαισίου J2534) - J2534, οτιδήποτε άλλο (εντολή AT σε κείμενο) - ELM327.Διορθώσεις
PassThruStartMsgFilter συνέκρινε μόνο τα 4 bytes του CAN ID, αγνοώντας το δηλωμένο μήκος φίλτρου. Πλέον το πλαίσιο συγκρίνεται σε όλο το μήκος, όπως απαιτεί το πρότυπο: τα 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; /* 4 bytes CAN ID + 2 bytes δεδομένων */
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 σε ενεργό κανάλι CAN χαλούσε το Flow Control (το FC έφευγε χωρίς padding, DLC=3 - η πύλη δεν έστελνε Consecutive Frames) και αντικαθιστούσε το φίλτρο λήψης με το δικό της TX ID (η λήψη χωρίς AT CRA χαλούσε). Σύμφωνα με το datasheet, το AT SH ορίζει μόνο την κεφαλίδα αποστολής - το φίλτρο λήψης ελέγχεται πλέον μόνο από τα AT CRA/CF/CM.PassThruStopPeriodicMsg μπορούσε να στείλει ένα επιπλέον πλαίσιο μετά τη διακοπή._PS - η επιλογή ακίδων μέσω SET_CONFIG(J1962_PINS) δεν εφαρμοζόταν, τα πλαίσια δεν έφταναν στον δίαυλο.Διορθώσεις