Step 4: Adding the Pin Class

Read time: 8 minutes (2162 words)

Let’s start off with our project by building the lowly pin. We need a way to attach wires to parts, and just pointing a wire to a part will not do. We need to know what wire we are working with, and there will be several wires connected to each part.

A Pin is part of a component, and it is a place to attach a wire. It is also a convenient place to record the value of a signal, either one arriving at a part from an attached wire, or one leaving a part, headed out on another attached wire. The Pin object does not do much. In fact, it does nothing at all. It just sits there holding a value until some other gadget wants that value. Both wires and components can write to the pin, or read from the pin.

Signal Values

Computers know nothing about “data types”. To the machine every signal moving is just a pile of binary bits. For our current project, the most bits we will want to move at one time is 16, which happens to be the size of an address in this machine. The best C++ data type to use for this kind of signal is a uint16_t (unsigned 16-bit integer). This data type is defined in the cstdint header.

Pin Class Specification

Let’s add the attributes and methods needed for our Pins.

Note

Although we are calling this gadget a “pin” it is really a set of pins, over which a multi-bit signal can move all at once (in parallel). The “wire” we attach to a pin will be moving all of the required bits as well. The proper term for that “wire” is a “bus” (it carries a bunch of bits!)

Here is the new header for the Pin class:

include/Pin.h
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// Copyright 2018 Roie R. Black
#pragma once

#include <cstdint>
#include <string>

class Pin {
 public:
     // constructor
    explicit Pin(std::string n);

    // accessors
    uint16_t get_val(void);
    std::string get_name(void);

    // mutators
    void set_val(uint16_t v);

 private:
    std::string name;
    uint16_t val;
};

Testing the Pin Class

Testing this class is pretty easy. All we need to add to our test set is code that sets a pin value and reads it back. The test code is pretty simple.

tests/test_pin.cpp
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
// Copyright 2018 ROie R. Black
#include <catch.hpp>
#include "Pin.h"

const std::string name = "basic";

TEST_CASE( "test pin constructor", "pin" ){
    Pin pin(name);
    REQUIRE(pin.get_name() == name);
    REQUIRE(pin.get_val() == 42);
}

TEST_CASE( "test_pin set/get methods", "pin" ) {
    Pin pin(name);
    // new pins have a value of 42
    REQUIRE(pin.get_val() == 42);
    pin.set_val(1234);
    REQUIRE(pin.get_val() == 1234);
}

Pin Implementation

The code required to make this test pass is all the code we need for this class.

lib/Pin.cpp
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// Copyright 2018 Roie R. Black
#include "Pin.h"

// constructor
Pin::Pin(std::string n) {
    name = n;
    val = 42;
}

// mutators
void Pin::set_val(uint16_t v) {
    val = v;
}


// accessors
uint16_t Pin::get_val(void) {
    return val;
}

std::string Pin::get_name(void) {
    return name;
}

At this point, you should run your tests again, and verify that the new Pin class functions properly!

The more of this testing you do, the more satisfying it becomes. I like it when my code is working properly! I can worry about something else, not this code!

Note

As the code gets more complex, so will the tests. Testing cannot fix all of your problems in programming, but it sure can limit where you spend you time to the really tough parts of your code!