Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adapter cable types supported on Linux-like OSes #35

Open
mvglasow opened this issue Mar 12, 2023 · 10 comments
Open

Adapter cable types supported on Linux-like OSes #35

mvglasow opened this issue Mar 12, 2023 · 10 comments

Comments

@mvglasow
Copy link

According to the documentation, on Windows the cable needs to present a COM port and is addressed as such, whereas on Unix-like OSes (Linux and Mac) only FTDI adapters are supported (as far as I understand), which are addressed by the adapter ID.

Looking at the source code, I am getting a different picture: the string submitted on the command line is matched against a regex to determine if it is an alphanumeric string of exactly 8 characters. If so, it is a valid FTDI adapter ID and treated as such, i.e. kw1281test will open an FTDI interface with the given ID. Anything else is treated as a serial port.

Therefore, e.g. COM3 would cause kw1281test to open a serial port with that name, which is what happens on Windows.

However, /dev/ttyUSB0 would also be treated as a standard serial port. Would I be able to make use of that on Linux/MacOS if my adapter presents itself as a serial port, by specifying its filesystem path, and thus be able to use any adapter that the OS sees as a serial port?

If so, then CH340-based adapters should work on Linux – I have successfully used a USB to RS232 adapter based on the CH340 for serial console access on Linux (Ubuntu 18.04, 20.04 an 22.04 – the latter required a modification because of a Braille terminal using the same USB ID as my adapter, preventing it from being recognized as a serial port). In that case, the documentation should be amended to include that any adapter that creates a /dev/tty* node should work on Linux.

PS: I have taken the risk and just ordered a USB KKL cable – no idea what chipset it uses, but I will report back on my Linux experience once it arrives.

@gmenounos
Copy link
Owner

The reason that only FTDI adapters are supported under Linux is that the kw1281 protocol wakes up a module in the car by sending the address of the module at 5 baud and then waiting to receive an acknowledgement at 9600 or 10400 baud. 5 baud is not supported by most serial APIs and even when supported, switching from 5 baud to a higher baud rate often takes too much time reprogram the UART chip timing, which results in missing the acknowledgement. To work around that problem, kw1281test simulates the 5 baud wakeup by sending a break or clearing a break on the serial line for 200ms per bit. This works fine on Windows but the Linux/macOS serial port API does not support sending a break signal for a specific amount of time:

https://linux.die.net/man/4/tty_ioctl

"Sending a break

TCSBRK

int arg
Equivalent to tcsendbreak(fd, arg).
If the terminal is using asynchronous serial data transmission, and arg is zero, then send a break (a stream of zero bits) for between 0.25 and 0.5 seconds. If the terminal is not using asynchronous serial data transmission, then either a break is sent, or the function returns without doing anything. When arg is nonzero, nobody knows what will happen.
(SVr4, UnixWare, Solaris, Linux treat tcsendbreak(fd,arg) with nonzero arg like tcdrain(fd). SunOS treats arg as a multiplier, and sends a stream of bits arg times as long as done for zero arg. DG/UX and AIX treat arg (when nonzero) as a time interval measured in milliseconds. HP-UX ignores arg.)"

At least that's my experience when I tried to get kw1281test working under macOS and Linux using a regular serial port. The FTDI Linux/macOS driver supports more precise timing of the break signal. Of course if your experience is different and you successfully get it to work with a CH340 cable, please let me know.

@mvglasow
Copy link
Author

Thanks for the clarification. Great there are people like you who have both car and IT knowledge – FOSS car diagnostics tends to be a niche because most FOSS devs don’t seem to have cars, and most DIY car mechanics seem to shun computers.

Anyways, I have little experience with that kind of low-level bit banging. Having (re-)read the part on KW1281 initialization at https://www.blafusel.de/obd/obd2_kw1281.html, a few approaches came to my mind:

  • Is the set/clear break method how other tools (VAS1551, VCDS) solve the baud rate switch as well? Although VCDS only supports Windows, it uses the same cables and would face the same challenges. Do these tools use timed breaks, or do they approach this differently?
  • Have you tried asking around sites like Stack Overflow or Unix Stack Exchange if others have encountered and solved this problem?
  • Would it be possible to simulate a fraction of the current baud rate not by sending and clearing a break but by repeating the same bit multiple times? Start/stop bits would get in the way (the actual communication is 8n1, hence no parity bit) – how do the remote ends deal with “impurities” several orders of magnitude shorter than the duration of a bit? Are they ignored or would they be taken as an indication of an ongoing data transmission at a higher baud rate?
  • Assuming the serial driver supports the low baud rate, we start at 5bps and then switch: As I understand the description by Hex Microsystems (linked from blafusel.de), the PC acknowledges each byte of the ECU’s response with its complement (save for the three bytes preceding the first block, of which only the last byte is acknowledged), and responds to each block with an ACK block. What would happen if the PC fails to acknowledge the start of the transmission?
    • Will the ECU retransmit it? (Which is why I imagine this whole acknowledgement business is there in the first place.) In that case the adapter could take a little longer for the baud rate switch and wait for the retransmission.
    • Or will the ECU simply stop talking until the PC sends something – say, a NACK block? Then we could listen for the ECU response, and if none arrives in a certain timeframe (or we get garbage that doesn’t start with a sync byte), ask the ECU to repeat the transmission.
    • Or will the ECU close the connection and stop communicating with the PC altogether until it is woken up again? In that case this approach won’t work.

@accept
Copy link

accept commented Mar 14, 2023

@mvglasow
Sorry for interrupting. I am Japanese and not fluent in English so I am using DeepL translation.
I apologize if I didn't make myself understood or if I sounded rude.

It would be very much appreciated if you could get it working on CH340, so I don't mean to put a damper on that.
I know this is advice in a different direction, but if you want to be sure of getting a KKL cable using FT232RL, there is a way to combine an RS232 KKL cable with FT232RL.

RS232 KKL Interface
https://www.ecufix.com/shop/index.php?main_page=product_info&products_id=181
https://aliexpress.com/item/1005001464817648.html

USB to RS232 with FT232
https://www.amazon.com/DSD-Tech-SH-RS232A-adaptador-5-9/dp/B07MYYCMJT
https://www.amazon.com/DSD-TECH-SH-U20A-Adapter-FT232RL/dp/B083TFL4KS/

I am operating with the above ECUFix cable and SH-RS232A combination and have confirmed in the past that it also works with FT232BM and a cable using an external EEPROM.
We have run it with Windows 10 and Raspberry Pi (built by myself for 64bit Bullseye), and it works fine because we were able to get SKC of Polo 9N3 with Windows, and get SKC and read/rewrite cluster EEPROM with Golf mk4 on Raspberry Pi.
I think this is the most reliable method, although the cables are longer and the appearance is a bit ugly.

So, I hope that the operation with CH340 will be successful.
Sincerely yours

@mvglasow
Copy link
Author

@accept Thanks, getting a serial KKL cable and separate USB-serial adapter really sounds like an option. Fortunately, I got my cable these days and it is FTDI.

Nonetheless, having to disable USB-serial kernel modules or messing with USB device identification is not particularly nice. So, if the regular serial driver stack were supported on Linux, that would be a huge plus.

@mvglasow
Copy link
Author

Back on topic: I have had a chance to look at another tool, buried in the source code of AndrOBD and to my knowledge never published as a tool in its own right – however the author claims to have used it successfully.

It is written in Java and relies on the RXTX library for serial communication, which ultimately translates into calls to the serial API.

Said tool sends the bits of the slow-init sequence by turning break on or off, then sleeping for 200 ms before sending the next bit. As I understand the manpages on Ubuntu 22.04, this should translate into calls to tty_ioctl with TIOCSBRK and TIOCCBRK. (Still working on getting it to build, then I can report on success.)

Alternatively, tty_ioctl also has TCSBRKP:

So-called "POSIX version" of TCSBRK. It treats nonzero arg as a time interval measured in deciseconds, and does nothing when the driver does not support breaks.

Calling that with an arg value of 2 should have the desired effect.

@gmenounos
Copy link
Owner

Thanks for doing the research on this. I'm pretty sure I tried this a year or two ago and discovered that macOS would not allow precise timing of TIOCSBRK/TIOCCBRK (I have a logic analyzer so I can see the timing of what shows up on the k-line when I run kw1281test). When I get some free time I'll try again and see if I get better results.

@gmenounos
Copy link
Owner

Back on topic: I have had a chance to look at another tool, buried in the source code of AndrOBD and to my knowledge never published as a tool in its own right – however the author claims to have used it successfully.

I think AndrOBD may not be that useful for examples of how to implement the 5-baud wakeup. AndrOBD relies on an ELM327 adapter, which has built-in 5-baud initialization. If you discover otherwise, please let me know and point me at the relevant source code.

@gmenounos
Copy link
Owner

Alternatively, tty_ioctl also has TCSBRKP:

So-called "POSIX version" of TCSBRK. It treats nonzero arg as a time interval measured in deciseconds, and does nothing when the driver does not support breaks.

Calling that with an arg value of 2 should have the desired effect.

That does seem to be implemented in the Linux source code, so I'll see if I can implement it:

https://github.com/torvalds/linux/blob/master/drivers/tty/tty_io.c

	case TCSBRKP:	/* support for POSIX tcsendbreak() */
		return send_break(tty, arg ? arg*100 : 250);

@mvglasow
Copy link
Author

I think AndrOBD may not be that useful for examples of how to implement the 5-baud wakeup. AndrOBD relies on an ELM327 adapter, which has built-in 5-baud initialization. If you discover otherwise, please let me know and point me at the relevant source code.

AndrOBD proper relies on the ELM327 and therefore does not need any of the baud-switching tricks. However, it is built on top of a JRE application the author built a few years earlier, which is intended for use with a dumb USB or serial KKL cable and has support for both OBD-II and KW1281. Some parts of the source code were reused in AndrOBD; the app itself can be found in the library dir. The code is no longer 100% complete and requires a few fixes to build properly, but the author claims to have used it successfully to diagnose his old car with it. The code I am referring to is not used in AndrOBD. It is located here: https://github.com/fr3ts0n/AndrOBD/blob/master/library/src/main/java/com/fr3ts0n/prot/gui/KLHandler.java#L233

@ofauchon
Copy link

New LinuxInterface may solve the problem.
See PR #73 . Thx

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants