I’ve been working on a project to decode pinball bus signals to figure out the current state of the lights on the machine.
Why I am doing that is still shrouded in mystery, but I’m to the point where I have the hardware ready to hook together for prototyping purposes. At this point, I would generally start writing code, but this is a bit more sophisticated than what I usually build – I have shift registers to read through serial, some decoding logic to write, and I need to detect whether a light is on, off, or flashing.
So, taking a page from my day job, I decided to write the code using TDD. One of the advantages at TDD is that it’s good at making progress if you aren’t quite sure what you need; you start building things that you need, and pretty soon you’re done.
Since I knew that I needed to be able to read serial data out of a the shift registers and convert it into bytes, I started writing a SerialToByte converter. And, I decided to write it in my fastest TDD language – C#. My plan is to write the code – using as few non-C++ features as possible – get it all working, and then convert it to C++ code for the Arduino.
Once I had that, I decided to write the class that would talk with the 74HC595 shift register. Conceptually, the operation that I need to do is fairly simple:
- When new data is available (how will I know this?)
- Flip the shift register from parallel to serial mode (it’s just setting a pin to low).
- Read a bit
- Clock to the next bit
- repeat until 8 bits are read
- Flip the shift register back to serial mode
There is a problem, however; to talk to the shift register I need to send electrical signals to the hardware, which is something I can’t do until I’m writing code on the arduino and choosing pin assignments. Or can I?
The situation – dealing with external dependencies – is a common problem when using TDD, and there’s a great pattern to deal with it, which is described at length in my post: Port/Adapter/Simulator. Instead of building code that talks directly to the hardware, I can define an abstraction on top of the serial register. I’ll build a simulator that I can use for test purposes, and then a real version when I move the code to the arduino.
Here’s the abstraction (aka “port”):
interface IShiftRegister
{
byte GetBit();
void SetParallelMode(byte parallelMode);
void SetSerialClock(byte serialClock);
}
To test the code that uses this abstraction, I built a simulator (using TDD), along with a full set of unit tests for the simulator:
public class ShiftRegisterSimulator : IShiftRegister
{
public void SimulateParallelLoad(byte value) {}
public byte GetBit() {}
public void SetSerialClock(byte serialClock) {…}
public void SetParallelMode(byte parallelMode) {…}
}
The simulator implements the 3 methods in the port, and also one additional method to put values into the shift register. I also write a DataStrobeSimulator that lets me simulate an interrupt, and then I can write a test for the BusDataConverter class:
[Test]
public void when_strobe_with_a_medium_value__it_has_the_correct_value()
{
DataStrobeSimulator dataStrobe = new DataStrobeSimulator();
ShiftRegisterSimulator shiftRegister = new ShiftRegisterSimulator();
BusDataConverter busDataConverter =
new BusDataConverter(dataStrobe, shiftRegister);
shiftRegister.SetParallelMode(1);
shiftRegister.SimulateParallelLoad(179);
dataStrobe.SimulateStrobe();
Assert.AreEqual(179, busDataConverter.GetValue());
}
This test sets up the shift register simulator with a value, simulates the strobe, and then verifies that the BusDataConverter correctly reads the data from the shift register.
So far, this approach has worked well; I’m confident that the code is pretty close to what I will need.