I must say, I'm proud of how I have built this program from the beginning. I kept in mind the MVC (Model-View-Controller) design principle and tried to follow it as much as possible. The idea is to keep the model, the representation of the object and data which you are working with, separate from the view which displays this data to the user and forms the layer with which the user interacts. Communication between the two is kept low.
I currently have three classes:
Since most GUI toolkits take control of the program in order to run a main loop, a common question is how the programmer can specify code to run within the main loop. One approach is multithreading. Another is to register an event to fire at certain intervals. In many cases, the event updates the model and view on a regular basis. I learned in the article at the bottom of this post that PyGTK, the graphics library I'm working with, has the ability to do just that:
#Set refresh rate
This registers an event to run every five seconds which calls the update_model_view() method each time. As long as this method returns
True, the event is re-registered for another interval. Just as the method's name implies, the model and view are therefore updated every five seconds. This involves a series of requests to the vehicle for information, processing of the data and updating of the model, and a call to the view to update itself based on the new data. The Vehicle class stores previous data for use in graphing, which is my next task.
I got the interface chip and cable in the mail today and I've been playing with it all morning. It's so cool to be able to talk to my car (in a nerdy kind of way, not a crazy kind of way). The chip (the ELM-327) interfaces with the user by RS-232 serial, but since most computers no longer have such a thing, the product I bought also has on-board RS-232 to USB circuitry. There is a link to the chip's manufacturer and user guide below this post.
The device shows up under Linux as a device file, indicating that the kernel has built-in support for this kind of USB to serial interface. On my system it is identified by the device
/dev/serial/XXXX. After reading parts of the manual and much trial and error, I discovered that a serial connection must be made at 38400 baud with 8 data bits, 1 stop bit, and no parity or flow control. For over an hour I had been trying to connect at 9600 baud and got the typical garbled output.
To request information, you simply have to type a mode number followed by a PID. The chip takes care of a great deal of legwork and returns the information you want. For example, typing "01 05" on my 2006 Pontiac G6 returns the following:
41 05 32
All input and output with this chip is in hexadecimal. The first byte, "41", indicates that this is a response to a mode 01 request. The second byte, "05", is the PID requested. The third byte, "32", is the actual value - the engine's coolant temperature.
Most values returned must be interpreted to be useful. The value "32", for example, is actually the coolant temperature plus 40 in decimal, so decimal 40 must be subtracted after converting "32" to decimal to get the actual coolant temperature. In this case, my coolant temperature is 10 degrees Celsius. Almost every PID has a different encoding, adding the to complexity of this project.
I've made a big decision this week. I've decided to change my project to the other idea in my first post. I will create an ncurses-based program which presents information to the user from a vehicle's onboard computer, such as oil temperature, engine RPMs, fuel usage, etc. This project is made much easier by the fact that the retrieval of this information is standardized by the OBDII (On-Board Diagnostics) protocol which all personal vehicles made after 1996 must support by law.
The OBDII protocol specifies a number of PIDs (parameter IDs) for vehicle systems to support. Each PID identifies a data value related to the vehicle's operation. For example, PID "05" represents the engine's coolant temperature and PID "0A" represents the fuel pressure. The protocol also specifies nine mode numbers which indicate the type of information requested. For example, mode "01" is a request for current data while mode "02" is a request for "freeze-frame" data. Freeze-frames are snapshots of data stored when a trouble code is raised. Mode "03" requests these trouble codes.
I'll need to purchase an "interpreter" which translates slow human input into something that the car's CAN-bus (Controller Area Network bus, more on this later) can use. The interpreter takes commands and builds up frames according to the CAN-bus specification, complete with sender and receiver addresses, checksums, etc, and then returns the information given by the vehicle. This item is only about $14 (see below for link).
Fortunately, I haven't scrapped everything I've done this semester. Since I've learned a great deal more about Python, which wraps all of the C code I'll need for this project, the development of this application will be much more rapid. Python also makes native GUI creation easier with minimal overhead.
The program is now written in Python. This was very easy; considerably easier than writing what I had in C++ the first time. Python has modules (libraries, packages) for just about any task you can imagine. There are modules which integrate with just about any other API imaginable.
I have made some good progress on this project in C++. However, another programming language which I have dismissed for a long time has caught my eye and I am very interested in learning it: Python. Compared to C++, learning Python will be a breeze. It is loosely-typed and much lighter on the syntax but is incredibly versatile and has a great relationship with existing C and C++ libraries. Python can easily wrap C and C++ code which enables it to perform any system calls that C can. It also explains why it is so popular among Linux developers.
Thanks to this epiphany, I have decided to rework the program in Python. The two languages work very well together so this shouldn't cause much trouble at all.
I have decided to start on the Linux info program (aptly named "lininfo"). It will be written in C++ using the ubiquitous ncurses library for terminal control. This will not be terribly difficult but will require brushing up on my C++ skills and learning how to use ncurses.
Several project ideas have come to me since the beginning of the semester. I had been considering something with the cluster but it looks as if it may not be here for quite a while.
One idea is to develop a Linux program which I have always thought would be useful. Windows and Mac OS have always had places to go to get basic system information such as the CPU model/speed, running process information, hard disk size (total/free/used space), networking information, and so on. Some of the major window managers have tools similar to this, such as gnome-system-config, but nothing exists for the main interface of a Linux system: the terminal. My program will display information about a running Linux system on the terminal. Users can then get the basics down at a glance without running a full GUI (X server).
Another idea is to write a different Linux program, one with a similar output (ncurses). This one would ideally run in a Raspberry Pi and interface with a car's onboard diagnostic computer via the OBDII connector. It would display current engine statistics, sensor output, and diagnostic codes if the "check engine" light is on. This would require buying an OBDII to USB cable, which cost about $15. It also would mean finding a small monitor to place in the car temporarily.