With the GPS module done, I was feeling confident about my experience so far with PyQt, so I went on the tackle the CAN bus input portion of the application.
But first, a little background on CAN bus. CAN bus (Controller Area Network Bus) is a simple 2 wire electrical and protocol specification commonly used in vehicles. I believe it's the bus behind higher level protocols like ODB used for vehicle diagnostics, but I haven't looked into that aspect. My new motorcycle has a CAN bus and I expect other, more modern motorcycles do too. It's been around in cars for a while. The ECU in a vehicle uses the bus to communicate with other components and systems within the vehicle like the ABS system, and the dashboard indicators, for example. Communication takes the form of messages. In simple terms, each message has a numeric ID and 0 to 8 bytes of data. The numeric ID is either 11 bits for "standard" IDs, or 29 bits for "extended" IDs. Simple enough, but what those message IDs mean and how data is packed into those 8 bytes is completely at the discretion of the vehicle maker. This poses some problems. More on that a little further down.
There are two pieces to CAN bus input: the first needs to show a list of all the messages read from the bus and the second needs to allow the user to configure an input based on one of those messages.
Here's the first part:
This window shows any messages received on the CAN bus, sorted by message ID, and the data bytes that came with the message. This display is in real time and is constantly changing when receiving data at a high rate. I read that the CAN bus on my motorcycle puts out about 1000 messages per second. For what it's worth, you can see a pause button in the window above which allows you to pause/play the display. Handy if you need a moment to digest what you're seeing.
Back to decoding those CAN messages. In order to decode the messages on the bus, you need to either get information about message IDs and data packing from the vehicle maker (or someone else who knows), or figure it out yourself. I've made some meager attempts at begging others for those things for my motorcycle with no success, so I assume I'll have to figure it out myself.
To that end, I've built a user interface in the application that I hope will assist me in that task. Here it is:
This dialog required writing the custom widget that you see on the right (the big grid thing). When you enter a message ID that matches any of the IDs from the previous window, this dialog starts breaking down the data bytes in the message and displaying them in the widget, all in real time. As you tweak the settings on the left, or click and drag on the right, a decoded value is display in the lower left.
The idea behind these two windows is, while the device is hooked up to the vehicle, do things with the vehicle, like rev the engine, press the brakes, etc., and see which message IDs respond in a sensible way, then target those IDs and try to discern how the corresponding values are encoded in the message data. Once you can decode something useful, you can give it a name and use it elsewhere in the application.
If that sounds like a pain in the ass, you're right, it is. But I haven't figured out a better way to do it. If I ever make this a commercial product, I imagine I'll integrate an online database where users can submit their decodings for their make/model vehicle and other users can download them right into the software. I imagine with enough users, that kind of data sharing will ease the suffering for some.
If anyone has any other suggestions about how to do this, I'm all ears.