loehnertj / bsbgateway

Read and write data on a BSB (Boiler System Bus).
GNU General Public License v3.0
15 stars 13 forks source link

improve collision detection #29

Open ptesarik opened 5 months ago

ptesarik commented 5 months ago

Upfront, I know that many people have successfully operated a BSB adapter which does not even have a "bus-in-use" bit, relying on CRC checking and accepting occasional command timeouts. I want to do better.

I have built my board with collision detection, not just bus-in-use. My adapter compares the requested TX level with the actual line level. If they don't match, its sets a collision bit (hardware flip-flop), which immediately turns off the transmitter. I have wired this collision bit to CTS and a flip-flop reset to RTS. Now, it's nice that I can configure expect_cts_state in bsbgateway, but after a collision, the collision bit must be reset by asserting RTS momentarily. I have added a setRTS(True) / setRTS(False) sequence to the wait loop in SerialSource._write_delayed().

However, there is still a race condition. Another device may start transmitting on the bus after a successful CTS check but before the bsbgateway UART starts transmitting In fact, this is why my hardware forcibly turns off the TX optocoupler when a collision is detected. As soon as a character is deposited in the UART shift register, it's too late to stop the transmission in software... My board reports the collision via CTS in this case, so after doing serial_port.write(), I can do serial_port.flush() and check CTS state once again. Of course, this is also racy, because a collision may happen between finishing the write and re-checking CTS, but in that case the same message is transmitted twice, which is not an issue AFAICS.

I can add a config option and code to support this configuration, if there's a chance such code would be accepted.

loehnertj commented 5 months ago

This is an interesting solution. I also think that proper collision handling can only be done in hardware, since delays in the driver layer are uncontrollable.

Still, I would tend to not merging it, since as I understand this is specific to your own board. If anybody else uses this kind of design, we can of course talk :-) Also you can easily publish it by forking here on github.

On a sidenote, for my board I am (ab)using RTS+DTR as power supply (see https://github.com/loehnertj/bsbgateway/blob/master/doc/broetje_interface.sch.svg.png) - which is why those pins are set in SerialSource.run. Thus there would at least need to be a config option to switch this behavior.