Archives For May 2016

I am easily seduced by the new. I read about how wonderful something is, and I fall like a sack of potatoes for the sales pitch. In this case I fell for both Go’s and Rust’s sales pitch, without completely thinking things through, like how I would transition complex software already written in one language (C++) into equivalents in either Go or Rust. I also too easily bought into the “better, faster, safer” code argument for both Go and Rust.

I’ve had some time to try out both languages and various Raspberry Pi device frameworks, some of them written in Go, another written in Javascript, and at least one written in C/C++. It turns out that the C/C++ framework, WiringPi, is the most complete, and the one that works best for me. The Javascript framework is a very close second. In spite of some intense personal research into Go and Rust, I’m still a better C++ programmer (or at least, I understand it best) than I am in either Go or Rust. All of this combines to lead me one inevitable decision: write my code in C++ with what works best right now. And if I want “better, faster, safer” software then (re-) learn best C++ coding practices and use them diligently. And not just C++ specific best practices, but good old fashioned common sense best software engineering practices. If there’s one thing I’ve learned over time, it’s that no language will save you from a poor design: above all, KISS.

With that in mind, here’s the latest GPIO manipulation application source.

#include <wiringPi.h>

#include <boost/algorithm/string.hpp>
#include <boost/tokenizer.hpp>

#include <iostream>
#include <fstream>
#include <sstream>

struct glyph {
    unsigned int GPIOpindata = 0;
    int delayInMillis = 0;
};

std::vector<glyph> glyphs;

bool loadBlinkData(std::string const fileName) {
    std::ifstream inFile(fileName);
    glyphs.clear();

    if (not inFile.is_open()) {
        std::cout << "Could not open " << fileName << std::endl;
        return false;
    }

    std::cout << "Using " << fileName << std::endl;
    std::string inLine;

    while (std::getline(inFile, inLine)) {
        boost::trim(inLine);
        if (not inLine.length() or inLine[0] == '#') {
            continue;
        }

        boost::tokenizer<> tokens(inLine);
        glyph g;

        for(auto &&token: tokens) {
            if (token.find("x") != std::string::npos or 
                token.find("X") != std::string::npos) {
                g.GPIOpindata = std::stoul(token, nullptr, 16);
            }
            else {
                g.delayInMillis = std::stoi(token);
            }
        }

        glyphs.push_back(g);
    }

    inFile.close();
    return true;
}

std::string defaultDataFile("blinkdata.csv");

int main (int argc, char *argv[]) {
    // Check to see if we passed another file on the command line.
    // If so, use it instead of the default.
    //
    if (argc > 1) {
        defaultDataFile = argv[1];
    }

    // Look to see if we can open and parse the file.
    // If not, stop.
    //
    if (not loadBlinkData(defaultDataFile)) {
        return 1;
    }

    // The input file was opened and parsed.
    // Now go to work.
    //
    wiringPiSetup();

    pinMode(0, OUTPUT);
    pinMode(1, OUTPUT);
    pinMode(2, OUTPUT);
    pinMode(3, OUTPUT);

    for (int i = 0; i < 5; ++i) { 
        for (auto &&g : glyphs) { 
            // Just a series of shifts and ANDs to create the bit necessary 
            // write out to the GPIO pin. 
            // 
            digitalWrite(0, g.GPIOpindata & 0x1);
            digitalWrite(1, (g.GPIOpindata >> 1 ) & 0x1 );
            digitalWrite(2, (g.GPIOpindata >> 2 ) & 0x1 );
            digitalWrite(3, (g.GPIOpindata >> 3 ) & 0x1 );

            delay(g.delayInMillis);
        }
    }

    // Turn everything off.
    //
    digitalWrite(0, LOW);
    digitalWrite(1, LOW);
    digitalWrite(2, LOW);
    digitalWrite(3, LOW);

    return 0;
}

Little improvements abound in this re-write.

  • Idiomatic C++11 is used as much as possible to avoid older C++ hacks (see the use of std::stoul at line 41 to convert the hex data string, for example) and cleaner reading code (see the for loops at lines 38 and 83, for example).
  • I use the One True Brace Style (1TBS) throughout, which frankly is just a variation of K&R brace style (the opening brace is on the same line as code). 1TBS helps these tired old eyes read code more easily. It also helps to minimize errors like Apple’s SSL/TLS “goto fail” bug.
  • More descriptive variable names are used throughout, and variables are declared close to where they’re first needed. Scope actually means something.
  • Rudimentary error checking now takes place, with quick exits that minimize resource usage on various failures. For example, the input data file is checked to see if it can be opened and parsed before any I/O devices are initialized.
  • I performed a static code check with cppcheck to make sure I haven’t missed anything like improperly uninitialized variables.
  • The code is compiled with ‘-Wall’ to get all warnings, and all warnings are treated as errors; they’re corrected.
  • Write the namespace (std:: and boost::) in front of elements explicitly, rather than use the lazy way of declaring a namespace globally with “using namespace namespace” at the top of source. I know exactly what comes ¬†from where, which is quite useful when I revisit code six months after writing it.

It’s barely 100 lines long, but it’s an opportunity to get back into good C++ coding habits and to stay there than go off with a new, and unknown-to-me language.

daytona pig stand

May 29, 2016


We’re having lunch with my oldest daughter and her boyfriend (soon-to-be-husband next year) at the Daytona Pig Stand off I-95 near Ormand. It’s not every BBQ place that has a converted eighteen wheeler tanker truck used for catering. But hey, whatever helps. Besides we’re eating in the main building where it’s air conditioned.



Yes, rusting metal chickens stand guard out front. The food has arrived, time to eat…

gingersnaps report

May 29, 2016

Second cat post, this time about the Florida Gingersnaps. The real reason for the vet visit where I met little Victoria was to have the Gingersnaps weighed and their claws trimmed. At nearly eight months of age, Luke (in front above) now weighs 10 pounds, while Beau (in back) weighs a more svelte 9.4 pounds. Considering how Luke looks like a mirror image of his mom Sunshine, and how Sunshine was a thirteen pound adult, I can see how Luke would follow his mom not just in looks but in overall size and weight.

They’re still quite loving and playful, and when resting like they are above, they still like to cuddle together. After eight months I assume the two will keep up the cuddling behavior for as long as they’re living together, which I hope is many years to come. They both still allow me to pick them up in my arms and gently rub their stomachs until they purr like motorboats. My wife says it was Lucy who looked down from heaven and picked them out, and I believe that as they purr just like she did; loud and continuous. I’d sit here and gush quite a bit more but it’s the Memorial weekend and I’m already tasked to do other things. Perhaps later this weekend.

victoria

May 29, 2016

You can’t have a bunch of dry-as-toast posts about programming the Raspberry Pi in C++, no matter how exciting I think the RPi is, without posting about some cats. So here is the first of two cat posts.

This first post is about little Victoria, who is just four weeks old at this point in time. She was adopted by my vet’s office when she was brought in by another client. At that time little Victory was about five days old, her eyes still closed. She’d been found by that client’s Labrador Retriever, who’d soft-mouth carried the little kitten to the Lab’s person. Since being brought in the staff have been looking after her, bottle feeding her until she’s old enough to switch off to more solid food. In the mean time the staff bring Victoria out to mix, however briefly, with those True Cat Persons. Since the vet staff knows what a soft touch I am with cats, they let me hold her briefly in her blanket after she’d been fed. Because of all the human attention Victoria is extremely socialized and loves to look up and purr.

In about four weeks Victoria is going to need a forever home. If you’re interested let me know in the comments.


This is my third GPIO application, written in C++ with support from the Boost libraries. My purpose was to strip out the hard-coded LED manipulation pattern so that I could, in effect, “program” how the LEDs would light up, and for how long. I wrote it in comma-separated-value layout, so that it could be edited in either a regular editor or even in a spreadsheet. I’ve done this in the past with other applications because, whether you like it or not, spreadsheets (saved out as CSV) is how an awful lot of people organize information. This is again about approachability, this time with data. Before I present the source, let me present the file we can read now.

# This is an example blink data file
# These are comments that can be added to the 
# data file.
#
# Values are simple: a hex value with the bit pattern
# to turn on or off an LED (1 = on, 0 = off) followed
# by a delay in milliseconds.
#
# For example: 0x5,50
# 0x5 has the bit pattern 0101, meaning LED 0 is on,
# LED 1 is off, LED 2 is on, and LED 3 is off
# The wait is 50 milliseconds.
#
      
0x0,50
0x1,50
0x3,50
0x7,50
0xf,50
0xe,50
0xc,50
0x8,50
0x0,50
0x8,50
0xc,50
0xe,50
0xf,50
0x7,50
0x3,50
0x1,50

The data are the same hard-coded values that were in the earlier C-based application, including the delay in milliseconds. You can add comments to the data file, as many as you want, anywhere, as long as the comments are on their on line. The comment character, a ‘#’, has to be the first character in the string, although you can have spaces in front of the ‘#’. Blank lines are also considered comments.

Here is the source to the more elaborate blink application.

#include <wiringPi.h>

#include <boost/algorithm/string.hpp>
#include <boost/tokenizer.hpp>

#include <iostream>
#include <fstream>
#include <sstream>

// The data structure and collection into which
// we'll place our LED data and millisecond delays.

struct glyph {
    unsigned int data = 0;  // LED data
    int delay = 0;          // in milliseconds
};

std::vector<glyph> glyphs;

void loadBlinkData(std::string fileName) {
    std::ifstream inFile;
    std::string inLine;
    inFile.open(fileName);
    glyphs.clear();

    while (std::getline(inFile, inLine)) {
        boost::trim(inLine);

        // Skip comments and empty lines.
        //
        if (not inLine.length() || inLine[0] == '#') {
            continue;
        }

        // It's not a comment or empty line, so tokenize the lines
        // using the comma that separates the values.
        //
        boost::tokenizer<> tokens(inLine);
        glyph g;
        std::stringstream ss;

        for(auto &&token: tokens) {
            if (token.find("x") != std::string::npos or
                token.find("X") != std::string::npos) {
                ss << std::hex << token;
                ss >> g.data;
            }
            else {
                g.delay = std::stoi(token);
            }
        }

        glyphs.push_back(g);
    }

    inFile.close();
}

int main () {
    wiringPiSetup();

    pinMode(0, OUTPUT);
    pinMode(1, OUTPUT);
    pinMode(2, OUTPUT);
    pinMode(3, OUTPUT);

    loadBlinkData("blinkdata.csv");

    for (int i = 0; i < 5; ++i) {
        for (auto &&g : glyphs) {
            // Just a series of shifts and ANDs
            // to create the bit necessary to
            // write out to the GPIO pin.
            //
            digitalWrite(0, g.data & 0x1);
            digitalWrite(1, (g.data >> 1 ) & 0x1 );
            digitalWrite(2, (g.data >> 2 ) & 0x1 );
            digitalWrite(3, (g.data >> 3 ) & 0x1 );

            delay(g.delay);
        }
    }

    // Turn everything off.
    //
    digitalWrite(0, LOW);
    digitalWrite(1, LOW);
    digitalWrite(2, LOW);
    digitalWrite(3, LOW);

    return 0 ;
}

The big change is he addition of the loadBlinkData(…) function in place of the hard coded blink data in the prior application. This is where I switched from C to C++ to take advantage of some of C++’s and Boost’s features to both parse the text file as well as store up the parsed results. The main functionality has changed very little.

The datafile name is hard-coded as “blinkdata.csv”. I could have gotten more elaborate and written code to handle command-line input, but I was more interested in writing the parser. Perhaps later.

I am of a very mixed mind about the use of C++. I could have written the parser in a more straight-forward manner with Go’s built-in string package. Instead I had to go rummaging around Boost’s library (and install it) to keep the code down to a readable minimum. The for-each construct was nice to use, allowing me to hide explicit iterator declarations and concentrate on the collection and its individual elements. I also used the C++11 auto keyword and rvalue references (‘&&’), which simplified for-loop coding in significant ways. So C++ has evolved in some very useful ways. But really, the depths I go to to write code on such an itty-bitty machine in C++.

I decided to use C++ because the promise of the Go GPIO frameworks haven’t turned out to work for me. That’s not because of any limitation in the foundational languages. Arch Linux ARM for ARMv7 has native Go v1.6.2 packages, and using yaourt, I installed Rust 1.8 and Cargo. For Python, I have both versions 2.7.11 and 3.5.1. GCC comes out-of-the-box at version 6.1.1, meaning it has full support for C++11. Boost, via pacman, is at version 1.60.0. So I have all the necessary, native, up-to-date language tools that any software folk could want, running natively on my Raspberry Pi 3. When used for other non-trivial applications they seem to work just fine. It’s when I try to mix in libraries and frameworks that I run into issues, except, it would appear, for Wiring Pi’s libraries. And, of course, for node.js and onoff, using Javascript.

I know I wrote earlier about how I’d “permanently” moved to Raspbian. Well, after a bit of a hiatus away from the Raspberry Pi, I decided to go back and give Arch Linux for ARM another whirl. This time I haven’t had any issues, which may be due to my better understanding of how to use Arch, and possibly, just possibly, better quality in the Arch Linux ARM distribution itself. So I’m a happy Arch user again.

And before I forget, here’s the makefile I now use to build this thing. I hate makefiles, which is why I so wanted to use Go’s build or Rust’s cargo system. Anyway…

CC = g++
LDFLAGS = -lwiringPi
CPPFLAGS = -Wall

TARGET = blinks

all: $(TARGET)

clean: $(TARGET); rm $(TARGET)

$(TARGET): $(TARGET).c; \
$(CC) $(LDFLAGS) $(CPPFLAGS) -o $(TARGET) $(TARGET).c