MERG Article - Object Oriented Programming
For the last half year or so I've been writing a regular article for the MERG Journal covering what I'm currently upto. I'm doing this mainly because my current big project allows me to dip into several areas typically of interest to MERG members. I'll be posting the articles (slightly edited) after they're printed. Typically the delay (between writing and posting here) will be a few months, so if you want to stay more upto date and get the deleted parts then join MERG.
As I sit here waiting for the spring journal to drop through the door, I can't help but think what to write for the next part of this “on my workbench” type series. Well what I've been doing lately fits quite well with the recent articles on using Visual Basic so I'll describe that but first a bit of an introduction to object oriented programming. For the sake of readability anything between a “ and a ” is a class name.
Object Oriented Programming
I'm going to share with you a paraphrased description of object oriented programming (OOP) that was told to me during an introductory programming course. “In object oriented programming you design a class which tells the computer what the object does, what properties it has etc. (Like the design for a car). Before you can use it though you have to make an instance of that class, (Like building a car from the design). This approach allows you to make several cars, whilst only having to give the instructions for one.”
This may not seem interesting until you start to look at things like inheritance. With a full object oriented programming language (which VB 6 is not) you can make a class called “vehicle” which can deal with such things as moving it around without crashing. You can then have another class “bus” which inherits from “vehicle” and all you have to do is add code to draw the bus on the screen. Not too useful until you decide to add cars, well we can now create a class “car” which also inherits from “vehicle”. Not only have we saved ourselves from having to rewrite code for shared actions like moving but if we discover that we made a mistake (we're all human after all) then we only have to fix it in one place, rather then remembering to fix it in several. It also has the advantage of allowing someone to build a “motor bike” class without having to know anything about how “vehicle” works – abstraction in action.
My Objects (so far)
So how am I using this in my software? So far I can only talk about the process of making a train move (points and signals are to be done soon) but by having a number of objects which work together I can achieve some quite useful effects when it comes to making my life easier. On the logic that a picture says a thousand words (and I don't want to add that editing burden to our editor) have a look at fig. 1. I've simplified it from a design diagram to show only what's relevant to this description.
Starting at the right (the class which connects to the railway) I've got a “Controller” class, by making this an interface (in VB speak, abstract class in normal OOP) I can have several controllers which each share the same method of being used. At the moment (see next section) this is a SPROG but by creating another class I could use any other control system and as long as it also uses the “Controller” interface they become interchangeable within my program (well at least for the job being described).
The “Controller” has a number of locos associated with it, in the case of the SPROG whenever its queue of new messages is empty it simply loops through these sending out ‘refresher packets’ in case any got missed by the decoder.
The “Loco” class mainly serves the purpose of remembering things like current speed, thus allowing a loco to move from one cab to another and allowing the new cab to get this information.
The “CabLinker” class is the interesting one, it creates a sort of communication system between the loco and things which want to control it. This could be an ‘autodriver’ for full computer controlled driving or some form of human interface.
Currently on my test project a human cab, AWS, TPWS and DRA controls all use it. Using this setup it becomes trivial to ‘plug in’ some other control in the future (such as an ATP). A strange side effect of this is that two sets of human cabs attached to the same “CabLinker” object will mirror each other's actions – changing the speed on one causes the slider on the other to reflect the new speed etc. Switching on a function on one causes it to switch on on the other.
So how does it work? Let's look at a simple example, changing speed:
- The user moves the speed slider to a new position
- The human interface asks the “CabLinker”'s “Loco” to change speed
- The “Loco” tells its controller to change speed then tells the “CabLinker” that the speed has changed
- The “CabLinker” raises a ‘Speed Changed’ event
- The Human interface responds to the ‘Speed Changed’ event by displaying the new speed.
My SPROG Control
The majority of my hobby time lately has been spent writing a “Controller” and “Programmer” interface which is used by a “SPROG” control, allowing it to run in either; Command Station, Programmer or Rolling Road modes.
Having read through the manual for the SPROG, I set about writing the code to convert my way of saying “change this loco's speed to 14/128 Forward” to the SPROG's way of saying “output a packet to set loco 1234's speed to 14 forward in 128 speed step mode”. A side effect of this is that I've ended up with a “DCCPacketGenerator” class which will generate the required DCC Packet for a requested operation. (A really good part of OOP is that this could be used elsewhere with ease). My control contains an MSComm control to allow it to talk to the virtual serial port in the SPROG and two timer controls. The first of these triggers every 5 seconds and if we're connected to a SPROG requests its current status (getting such things as the supply voltage and track current). The second one triggers every 20 milliseconds (so 50 times a second), when in command station mode and causes either the next message in the queue or (if the queue is empty) a refresher message to be sent.
Although a DCC packet (depending on size) lasts 5 milliseconds the timer control is only accurate to 15 milliseconds – a case of programming to the lowest denominator. 20 was chosen as it gives a round number of packets per second.
Assuming I just have to send these refresher packets and I have 10 locos being updated then each one will receive 5 packets a second.
I did hit one big snag when trying to communicate this fast though – I had about a 80% error rate from the SPROG, when this only dropped to about 50% sending 1 packet per second which told me it wasn't a speed issue. Turns out I hadn't read the manual properly, I was finishing my commands with a carriage return character followed by a new line character, whereas the SPROG requires only a carriage return – the new line at the start of the next command was causing confusion. Having fixed this I got down to a 0% error rate when sending packets as quickly as I could. Just goes to show the value of rereading the manual when things don't quite work.
- DCC – Digital Command Control. A method of independently controlling several locos on electrically the same track. Provides both power and instructions using only the 2 rails.
- Packet – A formatted chunk of data.
- SPROG – A DCC programmer which can also be used as a low power (up to just under an amp) command station.
- AWS – Automatic Warning System. On the prototype warns a driver of a restrictive signal and applies the brakes unless cancelled.
- TPWS – Train Protection and Warning System. Essentially a more modern version of AWS. Applies the brakes if a driver approaches a signal/buffer too fast or passes a signal at danger.
- DRA – Drivers Reminder Appliance. A device which when activated by the driver prevents traction from being applied until cancelled. Required to be applied at when stopping at a station. Supposed to remind the driver to check the signal before moving.
- ATP – Automatic Train Protection.
- OOP – Object Oriented programming.