Προδιαγραφή J2534 και αναφορά λειτουργιών ›
Προδιαγραφή ELM327 και αναφορά εντολών ›
Η διεπαφή ELM327 είναι διαθέσιμη στο Nano ET. Οι υπόλοιποι προσαρμογείς ScanDoc χρησιμοποιούν το πρωτόκολλο J2534 PassThru.
Αλλαγές στο J2534 DLL, στο ELM327 και στο υλικολογισμικό των προσαρμογέων ScanDoc που αφορούν την ενσωμάτωση: νέες λειτουργίες, πρωτόκολλα και παράμετροι - με παραδείγματα χρήσης.
Οι βιβλιοθήκες διατίθενται σε ένα αρχείο. Πλατφόρμες: Windows x86/x64/ARM64 (ξεχωριστά build για 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.
Λήψη βιβλιοθηκών J2534 2.0.0.241 - Windows x86/x64/ARM64 (ξεχωριστά builds για Windows 7), macOS (universal), Linux (x64, x86, ARM, ARM64), Android (arm64-v8a, armeabi-v7a, x86, x86_64), iOS (XCFramework), προγράμματα περιήγησης Chrome και Edge 137+ (WebAssembly)· στον φάκελο docs/ βρίσκεται η τεκμηρίωση του SDK (ξεκίνημα, αναφορά API, διαμόρφωση, χειρισμός σφαλμάτων, DoIP, DevHub, ενημέρωση υλικολογισμικού, μορφή αρχείου καταγραφής, Android, iOS, πρόγραμμα περιήγησης). Στατικά αρχεία .a παρέχονται μόνο για iOS και για το server build Linux x64· οι υπόλοιπες πλατφόρμες φορτώνουν τη βιβλιοθήκη δυναμικά.
Νέα
ConfigWrite παραλείπει σιωπηλά το κλειδί ble_name: δεν επιστρέφει σφάλμα, ώστε να συνεχίσουν να λειτουργούν οι εφαρμογές που στέλνουν όλες τις ρυθμίσεις μαζί. Η ConfigRead επιστρέφει το όνομα όπως πριν.PassThruReadVersion μέσω USB διαρκεί περίπου 6,5 ms αντί για 16. Απάντηση μεγαλύτερη από 248 byte η συσκευή τη στέλνει σε τμήματα των 248 byte με παύση 4 ms, οπότε η μεταφορά από τη συσκευή στον υπολογιστή γίνεται με ταχύτητα περίπου 59 KB/s: απάντηση 4 KB χρειάζεται περίπου 70 ms. Η μεταφορά από τον υπολογιστή στη συσκευή γίνεται όπως πριν με 3 Mbit/s.TCP_NODELAY και η απάντηση φεύγει ολόκληρη αμέσως.Διορθώσεις
PassThruConnect CAN. Η συσκευή κάποιες φορές επανεκκινούσε μόνη της περίπου 300 ms μετά το άνοιγμα καναλιού CAN. Επιπλέον, η OtaUpdate μετά από συνεδρία CAN μέσα στο ίδιο PassThruOpen δεν ξεκινούσε την ενημέρωση: η συσκευή δεν απαντούσε στην έναρξή της για 30 s.PassThruClose. Επιπλέον, κατά τη διάρκεια συνεδρίας CAN ή DoIP και μετά από αυτήν, η συσκευή μπορούσε να κολλήσει κατά το άνοιγμα ή το κλείσιμο της θύρας. Με υλικολογισμικό build 86 και βιβλιοθήκη 2.0.0.241 η θύρα μπορεί να ανοίγει και να κλείνει με ασφάλεια μετά την PassThruClose. Κόλλημα είναι δυνατό μόνο αν η θύρα κλείσει κατά τη διάρκεια συνεδρίας, πριν από την PassThruClose. Σε macOS και Linux η θύρα είναι ελεύθερη για άλλο πρόγραμμα μετά την PassThruClose· στα Windows παραμένει κατειλημμένη μέχρι την αποφόρτωση της βιβλιοθήκης, όπως και πριν. Μην ανοίγετε τη θύρα μόνοι σας και μην αλλάζετε τις DTR και RTS όσο τη χρησιμοποιεί η βιβλιοθήκη.PassThruWriteMsgs λάμβανε παρ' όλα αυτά την απάντηση "έγιναν όλα δεκτά", ενώ τα μηνύματα που δεν χωρούσαν χάνονταν. Επιπλέον, σε κάθε τέτοιο μήνυμα η συσκευή έχανε μνήμη και, υπό πυκνή ροή, μετά από μερικές δεκάδες δευτερόλεπτα άρχιζε να απαντά με άρνηση λόγω έλλειψης μνήμης μέχρι την επανεκκίνηση. Τώρα η συσκευή περιμένει να ελευθερωθεί θέση στην ουρά μέσα στον χρόνο λήξης της κλήσης και αναφέρει πόσα μηνύματα δέχτηκε. Αν δεν έγιναν δεκτά όλα, η βιβλιοθήκη επιστρέφει ERR_BUFFER_FULL με μηδενικό χρόνο λήξης και ERR_TIMEOUT με μη μηδενικό, και γράφει στο pNumMsgs τον αριθμό των μηνυμάτων που έγιναν δεκτά.BUFFER_OVERFLOW στο RxStatus.ETHERNET_NDIS. Οι PassThruDisconnect και GET_NDIS_ADAPTER_INFO με τον αριθμό καναλιού που επέστρεψε η PassThruConnect απαντούσαν ERR_INVALID_CHANNEL_ID, ενώ η PassThruClose δεν έκλεινε αυτό το κανάλι. Η αποτυχία αποσύνδεσης επιστρέφεται τώρα ως ERR_FAILED· πριν, αντί για κωδικό J2534 ερχόταν 0xFFFB.P4_MIN = 0 τα πλαίσια διακόπτονταν με TX_FAILED.Νέα
Promise με αντικείμενο, στο οποίο το ret περιέχει τον κωδικό J2534 και τα υπόλοιπα πεδία φέρουν τις παραμέτρους εξόδου. Οι πληροφορίες για τα οχήματα που βρέθηκαν (ISO13400_GET_VEHICLE_INFO, HSFZ_GET_VEHICLE_INFO) έρχονται ως πίνακας αντικειμένων με τα πεδία vin, logicalAddress, ip και άλλα, και όχι ως byte δομών. Τη συσκευή BLE ο χρήστης την επιλέγει από το όνομα στο παράθυρο του προγράμματος περιήγησης, και στην πρώτη σύνδεση το σύστημα ζητά το PIN. Λανθασμένο ή ακυρωμένο PIN δίνει ERR_FAILED και το κείμενο BLE pairing rejected, όπως στην εγγενή βιβλιοθήκη. Εκτός από τις συναρτήσεις PassThru είναι διαθέσιμες οι ConfigRead, ConfigWrite, ConfigReset, ConfigReboot και η ενημέρωση υλικολογισμικού: η OtaUpdate δέχεται το αρχείο υλικολογισμικού ως ArrayBuffer και αναφέρει την πρόοδο, ενώ η OtaAbort σταματά μια ενημέρωση σε εξέλιξη, οπότε η OtaUpdate επιστρέφει τον νέο κωδικό OTA_RESULT_ERR_ABORTED (-510). Στον ιστότοπο ανεβαίνουν δύο αρχεία, τα j2534.js και j2534_web.mjs, και η σελίδα πρέπει να ανοίγει μέσω HTTPS. Η σελίδα επίδειξης j2534_demo.html ανοίγει απευθείας από τον δίσκο. Απαιτείται υλικολογισμικό build 86. Το κλείσιμο της θύρας USB (releasePort() ή κλείσιμο της καρτέλας) προκαλεί επανεκκίνηση του Nano ET: κατά το κλείσιμο της θύρας το πρόγραμμα οδήγησης USB αλλάζει την κατάσταση της γραμμής DTR, και στο Nano ET αυτή η γραμμή ελέγχει την επαναφορά της συσκευής. Η εγγενής βιβλιοθήκη απελευθερώνει τις γραμμές με ασφαλή σειρά, ενώ το πρόγραμμα περιήγησης δεν το επιτρέπει. Λεπτομέρειες στο docs/WEB.md.
Παράδειγμα
import { loadJ2534 } from './j2534.js';
const ISO15765 = 6;
connectButton.onclick = async () => {
// το πρόγραμμα περιήγησης εμφανίζει το παράθυρο επιλογής συσκευής μόνο ως απόκριση σε ενέργεια του χρήστη
const port = await navigator.serial.requestPort({ filters: [{ usbVendorId: 0x0403 }] });
const j2534 = await loadJ2534(port);
// μέσω BLE περνάμε συσκευή 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);
// ενημέρωση υλικολογισμικού από αρχείο που επέλεξε ο χρήστης
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 σε επιτυχία, -510 μετά από OtaAbort, οι άλλοι κωδικοί στο FIRMWARE_UPDATE.md
};
Διορθώσεις
HSFZ_GET_VEHICLE_INFO επέστρεφε μόνο τα πρώτα 8 byte των πληροφοριών για κάθε όχημα που βρέθηκε. Η εφαρμογή λάμβανε ένα κομμάτι του VIN χωρίς τη διεύθυνση ECU και τη διεύθυνση IP. Τώρα κάθε εγγραφή hsfz_vehicle_info_t έρχεται ολόκληρη, 32 byte: VIN, διεύθυνση ECU, MAC και IP. Διορθώθηκε σε όλες τις εγγενείς βιβλιοθήκες.PassThruWriteMsgs με περισσότερα από 40 μηνύματα ή όγκο πάνω από 5115 byte κολλούσε τη συσκευή. Η βιβλιοθήκη έστελνε μια τέτοια κλήση ως μία εντολή, την οποία η συσκευή δεν δέχεται. Η συσκευή δεν απαντούσε σε αυτήν και η κλήση περίμενε ολόκληρο τον χρόνο λήξης, ενώ μέσω LAN/WLAN η συσκευή ερμήνευε τα byte δεδομένων αυτής της εντολής ως επόμενες εντολές. Τώρα η βιβλιοθήκη χωρίζει την κλήση σε περισσότερες εντολές και κάθε εντολή παίρνει τον υπόλοιπο χρόνο λήξης της κλήσης. Όλα τα μηνύματα ελέγχονται πριν σταλεί το πρώτο. Το υλικολογισμικό build 86 απαντά σε μια τέτοια εντολή από παλαιότερες εκδόσεις της βιβλιοθήκης με ERR_INVALID_MSG.PassThruReadMsgs με χρόνο λήξης και αίτημα για περισσότερα από 128 μηνύματα απορριπτόταν ολόκληρη, επειδή η συσκευή δίνει το πολύ 128 μηνύματα κάθε φορά. Τώρα η κλήση επιστρέφει έως 128 μηνύματα και τα υπόλοιπα διαβάζονται με την επόμενη κλήση.CLEAR_RX_BUFFER δεν καθάριζε τα μηνύματα που η βιβλιοθήκη είχε ήδη πάρει από τη συσκευή, και η επόμενη PassThruReadMsgs επέστρεφε παλιά πλαίσια. Τώρα καθαρίζεται και η προσωρινή μνήμη της βιβλιοθήκης.ERR_DEVICE_NOT_CONNECTED. Ο περιγραφέας 0 είναι ελεύθερος όταν η διεργασία έχει κλείσει την τυπική είσοδο, όπως συνήθως κάνουν οι υπηρεσίες.PassThruReadMsgs με κλειστή συσκευή. Αν η συσκευή δεν ήταν ανοιχτή, η συνάρτηση επέστρεφε σφάλμα, αλλά άφηνε στο *pNumMsgs τον αριθμό που είχε ζητήσει η εφαρμογή. Μια εφαρμογή που ελέγχει τον αριθμό των μηνυμάτων που διαβάστηκαν και όχι τον κωδικό επιστροφής επεξεργαζόταν ισάριθμα κενά μηνύματα. Τώρα σε αυτή την περίπτωση *pNumMsgs = 0.PassThruGetLastError. Μετά από απώλεια σύνδεσης η συνάρτηση επέστρεφε το κείμενο σφάλματος μιας από τις προηγούμενες κλήσεις, για παράδειγμα ERR_BUFFER_EMPTY, αν και ο κωδικός επιστροφής ήταν σωστός. Τώρα το κείμενο ονομάζει την αιτία: LAN socket closed, BLE not connected ή serial port not open. Για το ERR_BUFFER_OVERFLOW (0x12) εμφανιζόταν Unknown error: 18 αντί για το όνομα.Λήψη βιβλιοθηκών J2534 2.0.0.225
Νέα
ConfigRead και τη ζεύξη διαγράφει η ConfigWrite. Δεν προστέθηκαν νέες κλήσεις στη βιβλιοθήκη γι' αυτό.
Παράδειγμα
char json[2048];
if (ConfigRead(dev, json, sizeof(json)) == STATUS_NOERROR) {
/* στην απάντηση, μαζί με τις υπόλοιπες ρυθμίσεις:
"ble_bonds":[{"name":"WS-07","mac":"A4:C1:38:11:22:33"}] */
}
ConfigWrite(dev, "{\"ble_bond_del\":\"A4:C1:38:11:22:33\"}");
/* ισχύει αμέσως, δεν χρειάζεται ConfigReboot */
Διορθώσεις
reciv ack end single msg timeout SG και κατόπιν reciv ack counter error SG.TX_FAILED και μόνο η επανασύνδεση του καναλιού το επανέφερε.Νέα
ConfigRead, ConfigWrite, ConfigReboot και ConfigReset (στα Windows ordinals @52-@55) εξάγονταν και πριν, όμως δεν υπήρχαν στην τεκμηρίωση και δεν μπορούσε κανείς να τις χρησιμοποιήσει από έξω. Τώρα στο docs/API_REFERENCE.md περιγράφονται τα πρωτότυπα και η συμπεριφορά, ενώ στο docs/CONFIGURATION.md δίνεται ο πίνακας των κλειδιών με τα εύρη που ελέγχει το υλικολογισμικό. Η συσκευή επεξεργάζεται αυτές τις εντολές πριν από τη δρομολόγηση J2534, επομένως λειτουργούν σε κάθε μεταφορά: LAN/WLAN, BLE και USB.
Παράδειγμα
char json[2048];
ConfigRead(dev, json, sizeof(json)); /* όλες οι ρυθμίσεις ως ένα αντικείμενο JSON */
ConfigWrite(dev, "{\"ble_name\":\"WS-07\"}"); /* αλλάζουν μόνο τα κλειδιά που δόθηκαν */
ConfigReboot(dev); /* οι ρυθμίσεις ισχύουν μετά την επανεκκίνηση·
το device_id παύει να ισχύει, άνοιγμα ξανά μετά ~10 s */
ptConfigRead, ptConfigWrite, ptConfigReboot και ptConfigReset.
Παράδειγμα
external fun ptConfigRead(devId: Int): String? // null σε σφάλμα
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 // αιτία: ptGetLastError()
j2534.ptConfigWrite(devId, """{"ble_name":"WS-07"}""")
j2534.ptConfigReboot(devId)
PassThruOpen σκόπιμα δεν ελέγχει την έκδοση, ώστε να μην προστίθεται επικοινωνία με τη συσκευή σε κάθε άνοιγμα: το εγκατεστημένο build το επιστρέφει η PassThruReadVersion, ενώ η απόκλιση φαίνεται στο .qlog στη γραμμή firmware build N is older than build 85 required by DLL ….Διορθώσεις
ERR_FAILED και η PassThruGetLastError δίνει το κείμενο BLE pairing rejected (wrong PIN or not paired). Ο κωδικός ERR_FAILED επιλέχθηκε σκόπιμα, επειδή στο ERR_DEVICE_NOT_CONNECTED οι εφαρμογές συνήθως δεν ζητούν το κείμενο του σφάλματος. Ισχύει σε όλες τις πλατφόρμες: Android, macOS, Windows και Linux. Οι υπόλοιπες αστοχίες BLE εξακολουθούν να δίνουν ERR_DEVICE_NOT_CONNECTED, τώρα όμως με τον κωδικό της μεταφοράς: παλαιότερα ο κωδικός αυτός τυπωνόταν ως αριθμός σφάλματος POSIX και η απόρριψη εγγραφής έβγαινε ως 0x7 - Argument list too long.ptClose μέσω BLE. Κατά το κλείσιμο σύνδεσης BLE η βιβλιοθήκη έκλεινε τον περιγραφέα αρχείου 0, παρότι σε λειτουργία BLE δεν υπάρχει socket. Συνήθως έτσι έκλεινε σιωπηλά το stdin, αν όμως εκείνη τη στιγμή το fd 0 ανήκε σε αντικείμενο της JVM, το fdsan τερμάτιζε τη διεργασία: attempted to close file descriptor 0 … owned by native object. Γι' αυτό η κατάρρευση ήταν ακανόνιστη.ptClose μέσω BLE διαρκούσε ένα δευτερόλεπτο παραπάνω. Η βιβλιοθήκη απέρριπτε την απάντηση της συσκευής στο κλείσιμο, περίμενε τον χρόνο λήξης λήψης 1 s και έγραφε στην καταγραφή 0x6E - Connection timed out, σαν να μην είχε απαντήσει η συσκευή. Πλέον το κλείσιμο ολοκληρώνεται με την απάντηση της συσκευής. Σε macOS, Windows και Linux το σφάλμα αυτό δεν υπήρχε.ptOpen μέσω BLE, όταν η συσκευή δεν απαντούσε στο άνοιγμα. Η εφαρμογή τερματιζόταν με SIGSEGV. Σε άλλες αποτυχίες ανοίγματος (απόρριψη ζεύξης, λήξη χρόνου σύνδεσης) η βιβλιοθήκη δεν αποδέσμευε την καθολική αναφορά JNI στον BLEManager, και με τις επαναλαμβανόμενες προσπάθειες οι αναφορές συσσωρεύονταν.FAST_INIT. Η απάντηση της συσκευής αντιγραφόταν στη δομή pt_msg_t της εφαρμογής χωρίς έλεγχο μήκους: κοντύτερη απάντηση οδηγούσε σε ανάγνωση μη αρχικοποιημένης μνήμης, ενώ υπερβολικό μήκος στην απάντηση σε εγγραφή έξω από τη δομή που έδωσε η εφαρμογή. Στο Android η ίδια κλήση έστελνε αλλοιωμένο πλαίσιο στον δίαυλο και σε αστοχία τερμάτιζε βίαια την εφαρμογή. Διορθώθηκε και ο έλεγχος του μεγέθους εισόδου: δεχόταν τιμές NumOfBytes της τάξης του 0x20000000.FIVE_BAUD_INIT. Η είσοδος περιορίζεται σε ένα byte διεύθυνσης, όπως απαιτεί το §11.3.3.3· προηγουμένως γινόταν δεκτό μπλοκ οποιουδήποτε μήκους και η εφαρμογή που έστελνε περισσότερα έπαιρνε κωδικό επιτυχίας αντί για απόρριψη..qlog. Την καταγραφή άνοιγε μόνο η PassThruOpen, ενώ η κλήση ptOpen την παρακάμπτει. Έτσι σε εφαρμογή Android τρίτου ο φάκελος sdlogs έμενε άδειος σε κάθε επίπεδο καταγραφής, οι εγγραφές πήγαιναν μόνο στο logcat και δεν ήταν δυνατό να ληφθεί καταγραφή συνεδρίας από τον πελάτη.FIVE_BAUD_INIT και FAST_INIT τυπωνόταν μόνο > ok: ούτε η διεύθυνση αρχικοποίησης ούτε η απάντηση του εγκεφάλου έφταναν στην καταγραφή και μια αποτυχημένη αρχικοποίηση δεν μπορούσε να αναλυθεί από αυτήν. Τώρα η γραμμή περιέχει και το αίτημα και την απάντηση: io 1 FIVE_BAUD_INIT 33 > 8F6F 2850ms.Λήψη βιβλιοθηκών 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) δεν εφαρμοζόταν, τα πλαίσια δεν έφταναν στον δίαυλο.Διορθώσεις