© James R. Strickland 2018
James R. StricklandRaspberry Pi for Arduino Usershttps://doi.org/10.1007/978-1-4842-3414-3_4

4. Meet C++

James R. Strickland1 
(1)
Highlands Ranch, Colorado, USA
 

Let’s face it, the C and C++ languages have a bad reputation. Hard to learn, obtuse syntax, lots of ways to mishandle memory; you’ve heard it, I’m sure. You might have heard scuttlebutt that the Arduino sketch language is somehow related to C and C++, but that all the “hard stuff” was taken care of for you by the Arduino desktop application.

The truth is this. Arduino sketches are written in C++. They use the same GNU G++ compiler that Linux uses, albeit configured for 8-bit ATmega CPUs. The Arduino application does handle some things for us, and as we make the leap to C++, we’ll have to learn to do those for ourselves. Don’t worry. I’ll walk you through it. It’s not that complicated.

What the Arduino Package Really Is

So we can understand what we have to do for ourselves now, let’s take a quick look at what Arduino’s been doing for us all this time. We’ll start by looking at what, exactly, the Arduino application is, and what’s in it. To do that, in turn, let’s go ahead and put one on the Raspberry Pi.

Install Arduino on Raspberry Pi

Open the web browser on your Pi and go to http://www.arduino.cc/en/Main/Software . Be patient, especially if you’re on a Pi Zero W. This will take a while. Once you’re there, scroll down to “Download the Arduino IDE” and click on Linux Arm. Time for more patience, while your Pi writes that rather large package to your microSD card.

While you’re waiting, you might be wondering why on Earth I want you to put the Arduino desktop software on your Pi. Fair question. The answer is that way down in Chapter 12, called “The Best of Both Worlds,” we’ll need it. You might also wonder why we’re getting it through the web browser instead of apt-get. Didn’t I just finish saying that apt-get was easier and faster than graphical installers? Well yes, I did say that. There’s one major drawback to apt-get, though, and you might as well find out about it now. The software archives it uses are often behind the times. Nowhere is this more true than the Arduino application. It was ported once, shortly after the Pi was introduced, and hasn’t been updated since. By contrast, the Arduino project itself ported and maintains the ARM version we’re downloading now. All done? Good. You can try just clicking on the downloaded file like you would on a desktop computer, but I don’t recommend it, especially on a Pi Zero W. Instead, crank up the terminal application. (Choose Raspberry menu ➤ Accessories ➤ Terminal, or it’s probably in the top panel of your screen.) Here’s how you do this the old school way. And you’ll get another UNIX/linux command too.

First, cd to the Downloads directory. This is where the Chromium browser puts downloaded files, unless you tell it to put them someplace else. If you do an ls for *.tar.*, you’ll see any file with .tar.whatever as its extension. These are called tarballs today. Once upon a time, in a data center far far away, that file would instead be on a magtape. Google 9 track tape if you’re curious about that.

pi@Pi0W:~$ cd Downloads
pi@Pi0W:~/Downloads$ ls *.tar.*
arduino-1.8.5-linuxarm.tar.xz
pi@Pi0W:~/Downloads$

Anyway, the program we’ll use to expand the archive is called, unsurprisingly, tar, and since you know it had to do with tapes, it’s probably not surprising it stands for Tape Archive. Tar takes a ridiculous number of flags, but here are the ones you’ll most often need. (You can also go to man tar if you forget them. I usually have to for anything but expanding archives.)

To expand an archive, you use tar -xf <<tarball name>. To create a new archive, use tar -cf <<tarball name>> <files or directories to go in the tarball>>. Tar’s one of those strong, silent types. If you want to see what it’s actually doing (because waiting five minutes on a screen where nothing’s happening is boring, if nothing else), pass tar the v flag too.

But we’re looking at a tar.xz file. The xz stands for x-zip. It’s a standard UNIX/Linux data compression tool. The tar file’s been compressed. We could uncompress the tar file and then extract it in two steps, but modern tar is smart and can handle compression automatically. When it sees the xz, or a file extension indicating some other compression routine appended to the end, it will do the right thing automatically. Like this.

pi@Pi0W:~$ cd Downloads
pi@Pi0W:~/Downloads$ tar -xvf arduino-1.8.5*

Here, I’ve used a wildcard to avoid typing out the whole filename. The wildcard matches any file with arduino-1.8.5 at the beginning, in this case arduino-1.8.5-linuxarm.tar.xz.

arduino-1.8.5/
arduino-1.8.5/lib/
arduino-1.8.5/lib/version.txt
arduino-1.8.5/lib/rsyntaxtextarea-2.6.1.jar
arduino-1.8.5/lib/public.gpg.key
arduino-1.8.5/lib/arduino-core.jar
arduino-1.8.5/lib/batik-svg-dom-1.8.jar
arduino-1.8.5/lib/batik-bridge-1.8.jar
arduino-1.8.5/lib/commons-net-3.3.jar

Thousands upon thousands of files later…

arduino-1.8.5/tools/WiFi101/tool/firmwares/19.5.2/
arduino-1.8.5/tools/WiFi101/tool/firmwares/19.5.2/m2m_aio_3a0.bin
arduino-1.8.5/tools/WiFi101/tool/firmwares/19.4.4/
arduino-1.8.5/tools/WiFi101/tool/firmwares/19.4.4/m2m_aio_2b0.bin
arduino-1.8.5/tools/WiFi101/tool/firmwares/19.4.4/m2m_aio_3a0.bin
arduino-1.8.5/tools/howto.txt
pi@Pi0W:~/Downloads$

Next, we need to install the Arduino application. This is easiest from the terminal window too. Just cd into the arduino-1.8.5 (or whatever version you downloaded) directory and type sudo ./install.sh.

pi@Pi0W:~/Downloads/arduino-1.8.5$ sudo ./install.sh
Adding desktop shortcut, menu item and file associations for Arduino IDE...touch: cannot touch '/root/.local/share/applications/mimeapps.list': No such file or directory
/usr/bin/xdg-mime: 803: /usr/bin/xdg-mime: cannot create /root/.local/share/applications/mimeapps.list.new: Directory nonexistent
 done!
pi@Pi0W:~/Downloads/arduino-1.8.5$
Now, if you choose Raspberry menu ➤ Programming ➤ Arduino, the Arduino application will start. Be patient, especially if you’re on a Pi Zero W. It’s slow. Eventually, you’ll see the main window open, as shown in Figure 4-1.
../images/456672_1_En_4_Chapter/456672_1_En_4_Fig1_HTML.jpg
Figure 4-1

Arduino IDE

What you’re looking at here is the Arduino IDE. (It stands for Integrated Development Environment, and has nothing to do with the hard disk standard from the early 1990s. That used to mess me up.) In Figure 4-2, I’ve opened Geany, the IDE we’ll be using on the Pi, beside the Arduino IDE.

IDE

We’ll get into this more in the compiler section, but there are two major steps to compiling a computer program: compiling and linking. Compiling means the raw source code is fed to whatever precompiler is involved, then the compiler. When your code comes out of the compiler, it’s machine code, but it’s not connected to any external libraries you’ve called, nor to any other code you’ve included in it. Hooking all that together and producing a single program that will actually run is the job of the linker.

In the old days, when I learned programming, you wrote code in a text editor and then compiled and linked it by hand. Seriously. The first minicomputer operating system I ever used (Digital Equipment’s Vax VMS) did it that way. If your program consisted of separate parts, you compiled them separately, and it was up to you to make sure all the parts had been compiled before you linked them in. This process was fraught with errors. (Although in school, most of our programs had only one file, so it was less an issue.) If you forgot to compile a module, you could chase your tail for hours trying to fix a bug that you’d already fixed. Allegedly, this, in fact, was how UNIX make came to be. UNIX make was a godsend. Instead of keeping track of what had and had not been compiled, make checked the touch dates (remember touch dates? the date that shows up in ls -l?) of the compiled version of the code against the uncompiled version, and if the uncompiled version (the source code) was later, only then would make compile that code. It saved time and sanity for programmers.

IDEs solve the same problem. Like UNIX make, they keep track of when a given piece of code was last compiled, and whether the source code has been altered since then. You’ve used this, even if you didn’t know it, with the Arduino IDE. If you’ve used a third-party library and dropped it into a separate tab in the IDE, the Arduino IDE is keeping track of whether you’ve compiled that library since the last time it was modified.

The Arduino IDE also does syntax coloring (so you can tell comments from code, for example), they match parentheses for you (a godsend, in and of itself), they can help you keep your code neat by indenting or commenting whole blocks at once, and a dozen other fiddly little things that make programming easier. Again, you’ve probably used these in the Arduino IDE a lot. I certainly did in my previous book about Arduinos.

Compiler

In case you haven’t heard the formal definition a dozen times already in your life, a compiler is a program that translates a higher level language, such as C or C++, into machine code. Like we talked about in the IDE section, compilers usually work in cooperation with linkers, to combine compiled programs into an executable image. Any time you tell the Arduino application to compile? That’s what it’s doing.

In the Linux world, g++ is the default C++ compiler. This tells you nothing, because g++ is a wrapper, in this case around gcc, the GNU project Compiler Collection. (Back in the days when I was building it on a MicroVax II, gcc stood for GNU C Compiler. They changed it as they added more languages.) The usual abbreviation for C++ is cpp, however, so if you type which cpp, you’ll get this:

pi@Pi0W:~$ which cpp
/usr/bin/cpp
pi@Pi0W:~$

If you did an ls -l on that file, you’d discover that it’s a pointer to cpp-6. This calls version 6 and above of GNU cpp. Other distributions of Linux may also have g++ version 5, which is referred to as simply cpp. There’s a lot of redirection, and that when you unwind it all, you’re really calling gcc with some flags. None of which is that important to us. When you call /usr/bin/cpp, it works.

pi@Pi0W:~$ /usr/bin/cpp -v
Using built-in specs.
COLLECT_GCC=/usr/bin/cpp
Target: arm-linux-gnueabihf
Configured with: ../src/configure -v --with-pkgversion='Raspbian 6.3.0-18+rpi1' --with-bugurl=file:///usr/share/doc/gcc-6/README.Bugs --enable-languages=c,ada,c++,java,go,d,fortran,objc,obj-c++ --prefix=/usr --program-suffix=-6 --program-prefix=arm-linux-gnueabihf- --enable-shared --enable-linker-build-id --libexecdir=/usr/lib --without-included-gettext --enable-threads=posix --libdir=/usr/lib --enable-nls --with-sysroot=/ --enable-clocale=gnu --enable-libstdcxx-debug --enable-libstdcxx-time=yes --with-default-libstdcxx-abi=new --enable-gnu-unique-object --disable-libitm --disable-libquadmath --enable-plugin --with-system-zlib --disable-browser-plugin --enable-java-awt=gtk --enable-gtk-cairo --with-java-home=/usr/lib/jvm/java-1.5.0-gcj-6-armhf/jre --enable-java-home --with-jvm-root-dir=/usr/lib/jvm/java-1.5.0-gcj-6-armhf --with-jvm-jar-dir=/usr/lib/jvm-exports/java-1.5.0-gcj-6-armhf --with-arch-directory=arm --with-ecj-jar=/usr/share/java/eclipse-ecj.jar --with-target-system-zlib --enable-objc-gc=auto --enable-multiarch --disable-sjlj-exceptions --with-arch=armv6 --with-fpu=vfp --with-float=hard --enable-checking=release --build=arm-linux-gnueabihf --host=arm-linux-gnueabihf --target=arm-linux-gnueabihf
Thread model: posix
gcc version 6.3.0 20170516 (Raspbian 6.3.0-18+rpi1)
COLLECT_GCC_OPTIONS='-E' '-v' '-march=armv6' '-mfloat-abi=hard' '-mfpu=vfp' '-mtls-dialect=gnu'
 /usr/lib/gcc/arm-linux-gnueabihf/6/cc1 -E -quiet -v -imultilib . -imultiarch arm-linux-gnueabihf - -march=armv6 -mfloat-abi=hard -mfpu=vfp -mtls-dialect=gnu
ignoring nonexistent directory "/usr/local/include/arm-linux-gnueabihf"
ignoring nonexistent directory "/usr/lib/gcc/arm-linux-gnueabihf/6/../../../../arm-linux-gnueabihf/include"
#include "..." search starts here:
#include <...> search starts here:
 /usr/lib/gcc/arm-linux-gnueabihf/6/include
 /usr/local/include
 /usr/lib/gcc/arm-linux-gnueabihf/6/include-fixed
 /usr/include/arm-linux-gnueabihf
 /usr/include
End of search list.

See what I mean?

Anyway. That’s the compiler we’ll be using for our programs in the Pi. It might startle you to know it’s the same compiler used by the Arduino application. Try this. Type cd /home/pi/Downloads/Arduino-1.8.5/hardware/tools/avr/bin. We’ve just jumped into the Arduino application’s directories.

Note

If you plan to use the Arduino application on your Pi for more than experiments, it’s a good idea to move it outside the Downloads directory and re-run install.sh.

Hardware is the directory specific to one type of Arduino. The avr directory is for ATmega AVR Arduinos—the uno, the mega, and all the classic ones. The bin directory is where the binaries are stored for that type of hardware, that is, compiled programs used to produce the compiled program that will run on the ATmega Arduino.

A quick ls shows us that there’s a c++ here.

pi@Pi0W:~/Downloads/arduino-1.8.5/hardware/tools/avr/bin$ ls -l *c++*
-rwxr-xr-x 2 pi pi 637467 Dec  5  2016 avr-c++
-rwxr-xr-x 1 pi pi 586439 Dec  5  2016 avr-c++filt
pi@Pi0W:~/Downloads/arduino-1.8.5/hardware/tools/avr/bin$

If we call that compiler, we can pass it a -v flag to see what version it is. A quick caveat. We have to specify that we want to load avr-gcc from this directory. The bash shell doesn’t assume that’s what you want by default and will search the usual system directories otherwise. This is when the . shortcut becomes the most useful. To do that, precede the file you want to execute with a . to tell bash to “run a program from this directory.” Like this:

pi@Pi0W:~/Downloads/arduino-1.8.5/hardware/tools/avr/bin$ ./avr-c++ -v
Using built-in specs.
Reading specs from /home/pi/Downloads/arduino-1.8.5/hardware/tools/avr/bin/../lib/gcc/avr/4.9.2/device-specs/specs-avr2
COLLECT_GCC=./avr-c++
COLLECT_LTO_WRAPPER=/home/pi/Downloads/arduino-1.8.5/hardware/tools/avr/bin/../libexec/gcc/avr/4.9.2/lto-wrapper
Target: avr
Configured with: ../gcc/configure --enable-fixed-point --enable-languages=c,c++ --prefix=/mnt/jenkins/workspace/avr-gcc/label/cm-raspberrypi2/objdir --enable-long-long --disable-nls --disable-checking --disable-libssp --disable-libada --disable-shared --enable-lto --with-avrlibc=yes --with-dwarf2 --disable-doc --target=avr
Thread model: single
gcc version 4.9.2 (GCC)
pi@Pi0W:~/Downloads/arduino-1.8.5/hardware/tools/avr/bin$

Look familiar? It’s an old version of gcc—4.92 versus 6.3.0—but it’s fundamentally the same compiler. You’ve been writing C/C++ code all along and possibly never realized it.

Libraries

I mentioned that the Arduino application was handling some libraries in the background for you. While we’re poking around in here, let’s look at those too. Use cd to navigate to /home/pi/Downloads/arduino-1.8.5/hardware/arduino/avr/cores/arduino. Once again, we’re looking at just the part of Arduino that’s for the avr/ATmega-based boards. A quick ls gives you quite a list.

pi@Pi0W:~/Downloads/arduino-1.8.5/hardware/arduino/avr/cores/arduino$ ls
abi.cpp              HardwareSerial_private.h  Print.h       WInterrupts.c
Arduino.h            hooks.c                   Server.h      wiring_analog.c
binary.h             IPAddress.cpp             Stream.cpp    wiring.c
CDC.cpp              IPAddress.h               Stream.h      wiring_digital.c
Client.h             main.cpp                  Tone.cpp      wiring_private.h
HardwareSerial0.cpp  new.cpp                   Udp.h         wiring_pulse.c
HardwareSerial1.cpp  new.h                     USBAPI.h      wiring_pulse.S
HardwareSerial2.cpp  PluggableUSB.cpp          USBCore.cpp   wiring_shift.c
HardwareSerial3.cpp  PluggableUSB.h            USBCore.h     WMath.cpp
HardwareSerial.cpp   Printable.h               USBDesc.h     WString.cpp
HardwareSerial.h      Print.cpp                  WCharacter.h  WString.h
pi@Pi0W:~/Downloads/arduino-1.8.5/hardware/arduino/avr/cores/arduino$

All that gets linked with every sketch you write, and any routines you actually call from your sketch are part of the sketch binary that ultimately gets sent to the Arduino. The Arduino app is handling all that in the background. But what about the #includes you sometimes have to do? If you’ve done some spi or i2c programming on the Arduino and had to use an #include statement to add them, like #include <Wire.h>, you might have wondered where that comes from. They’re in there too.

pi@Pi0W:~$ cd /home/pi/Downloads/arduino-1.8.5/hardware/arduino/avr/libraries
pi@Pi0W:~/Downloads/arduino-1.8.5/hardware/arduino/avr/libraries$ ls
EEPROM  HID  SoftwareSerial  SPI  Wire
pi@Pi0W:~/Downloads/arduino-1.8.5/hardware/arduino/avr/libraries$

You get the idea.

Uploader

There’s one other piece of the Arduino puzzle that we have to talk about. We won’t use it when programming the Raspberry Pi, but we will be tinkering with it at some length for the last project in this book, “The Best of Both Worlds,” so this is as good a time to mention it as any. That part is the uploader. For ATmega/AVR-based Arduinos, it’s called AVRDUDE, which stands for AVRDownloaderUploaDEr , according to the website. Like the compiler, it’s another standalone project that has been rolled into the Arduino application. It’s in the same directory as the compiler: /home/pi/Downloads/arduino-1.8.5/hardware/tools/avr/bin.

pi@Pi0W:~/Downloads/arduino-1.8.5$ cd /home/pi/Downloads/arduino-1.8.5/hardware/tools/avr/bin
pi@Pi0W:~/Downloads/arduino-1.8.5/hardware/tools/avr/bin$ ls -l avrdude
-rwxr-xr-x 1 pi pi 449459 Dec 16  2016 avrdude
pi@Pi0W:~/Downloads/arduino-1.8.5/hardware/tools/avr/bin$

AVRDUDE resets the Arduino from whatever it was doing to kick off the bootloader. It signals the bootloader to go into programming mode, then transfers the sketch into the Arduino using the Arduino protocol to verify that the compiled sketch got there in one piece. Then it resets again, and lets the bootloader switch over to sketch mode. At least normally. Our “Best of Both Worlds” project will skip a few of these steps. More on that later.

Meet Geany

In our travels in the Raspberry Pi, we’re going to use the Geany IDE. There are certainly others, but Geany is lightweight, relatively simple to use, and if you decide you like it, odds are you can get it for your desktop computer too.

Geany versus the Arduino IDE

You already have the Arduino application running, right? Go ahead and crank up Geany, (choose Raspberry menu ➤ Programming ➤ Geany), and cut/paste the setup() and loop() functions from the empty Arduino sketch into the window on Geany. Now, in Geany, choose File ➤ Save As and give it the name arduino_skel.cpp. (Some filesystems are touchy about ++ in filenames, so cpp is usually used for the extension.)

Interesting, no? Once you save the file, Geany suddenly colors the syntax. This is because Geany is designed to work with lots of different programming languages, and until we saved the file as a .cpp file, it didn’t know what kind of file we were editing. It does now. Figure 4-2 shows what it looks like. Sadly, it’s in black and white if you’re reading the printed version of this book.
../images/456672_1_En_4_Chapter/456672_1_En_4_Fig2_HTML.jpg
Figure 4-2

Geany with the Arduino Sketch skeleton

Note also that Geany has found the two functions we’ve given it, Loop and Setup, and that they’re listed under Symbols in the left-most column. This is a really, really useful thing. If you click on Loop or Setup in the left-most column, Geany takes your cursor there right now. It would do the same if we had multiple files. Now click on one of the braces. See how it highlights the one that matches that one? It highlights in dark blue by default, so you might have to look closely. It does the same thing with (square) brackets, parentheses, and so on. Good modern editors do this. Heck, even nano, my terminal mode editor of choice, can be configured to do syntax coloring. But Geany also manages your files, just like the Arduino IDE does, only easier.

To add a file in Geany, just choose File ➤ New. A new tab will open. Let’s go ahead and put a function in it that doesn’t do anything, just to practice. As you can see in Figure 4-3, I’ve added a void function called do_nothing. It returns a void variable type (undefined, or nothing), takes no parameters, and has no code. Go ahead and save it to a file called do_nothing.cpp.
../images/456672_1_En_4_Chapter/456672_1_En_4_Fig3_HTML.jpg
Figure 4-3

Do nothing function and donothing.cpp

Here’s where Geany really shines. Instead of having a directory of files that might or might not be associated with arduino_skel. cpp , we can combine them into a project. Choose Project ➤ New, and when it asks if you want to include all the open files (in our case, arduino_skel.cpp and do_nothing.cpp) in the project session, choose yes. It may ask to create a Projects directory (folder.) Go ahead and let it.

What we’ve done is to create metadata for the project that lists all the files in the project. However, Geany has not moved our files to the project directory. We can do that with File ➤ Save_As for each open tab. Make sure to save the files into /home/Pi/projects/arduino_skel to avoid confusion later. When we go to create new files, however, Geany will use the project’s directory as the default.

But wait, as the commercial goes, there’s more. Go back to the arduino_skel.cpp tab, and at the very top add this: #include "do_nothing.cpp". Because it’s included in this project, Geany knows where that file is, so if you press Compile (we’ll cover compiling shortly), it will give the compiler the right path to do_nothing.cpp. More still. If you click on the right-facing arrow in the Symbols column at the left of the Geany window, shown in Figure 4-4, Geany will tell you exactly where all the files in this project are, and the heading on that column will change to Documents.
../images/456672_1_En_4_Chapter/456672_1_En_4_Fig4_HTML.jpg
Figure 4-4

Geany in Documents mode

I admit. I’ve been a holdout for the tools of the 80s and 90s—make and text editors—but now that I am used to using the Arduino IDE with Arduino projects and have used Geany (for this book, in fact), I’m sold. Hopefully you are too.

Configuring Geany

Out of the box, as it came with the Raspbian distribution, Geany works pretty well. There are a few issues though. The big one is that while it can compile and build software (they’re different, I’ll get to that shortly), it can neither run Lint (cppcheck) to check our C++ syntax, nor can it execute (run) whatever we built. Let’s fix those problems.

Install Lint (cppcheck)

We won’t be using Lint (aka cppcheck) to check our C++ syntax in this book. If you want it, you can fix this problem by typing this:

pi@Pi0W:~$ sudo apt-get install cppcheck
Reading package lists... Done
Building dependency tree
Reading state information... Done
The following NEW packages will be installed:
  cppcheck

Packages get installed…

Processing triggers for man-db (2.7.6.1-2) ...
pi@Pi0W:~$

Basically Geany couldn’t make Lint work because the program it was calling, cppcheck, wasn’t installed.

Set Up Execute

The execute problem is a bit stranger, and really should be taken care of in the distribution itself. In fact, by the time you read this, it might have been. Feel free to skip ahead to where we actually try to use the Execute button and come back here if it fails.

Hello again. Didn’t work? Okay. To make it brief, Geany should be able to run a program we’ve just built, but as of the August 8th, 2017 version of Raspbian I have, it can’t. The terminal window starts, but it hangs. By default, Geany is calling the terminal through the alternatives system. This, in turn, wraps around default applications, like the terminal program, so that if you were to change terminal programs, you don’t have to go to Geany and any of dozens of other programs using that terminal and change the terminal call in them. That’s great, except that the alternatives wrapper doesn’t take the parameters Geany is trying to send it. Bug in the wrapper? Bug in Geany? Bug in LXterminal, the Pi’s default terminal program? I don’t really know.

We can fix it in Geany’s preferences. Choose Edit ➤ Preferences and select the Tools tab in the window that comes up. It should look like Figure 4-5.
../images/456672_1_En_4_Chapter/456672_1_En_4_Fig5_HTML.jpg
Figure 4-5

Geany Preferences window

The Terminal line is what we’re after. Yours almost certainly looks different from mine. (Mine’s already fixed.) Replace what’s in terminal with /usr/bin/lxterminal -e /bin/sh %c and save the configuration file. But let’s stop and look at the fix a moment.

That /usr/bin/lxterminal part looks like a call to a program, doesn’t it? You’re right. That file, lxterminal, is the real name of the Terminal program we’ve been using right along. If you’re reading this more than a few years after 2017, it’s possible that’s changed. Here’s how you tell for sure.

pi@Pi0W:~$ update-alternatives --list x-terminal-emulator
/usr/bin/lxterminal
pi@Pi0W:~$

The update-alternatives command works on any Debian-derived system, and it lists what program, of the many options, is being used for a specific function on that Linux installation. In this case, the x-terminal-emulator is the terminal emulator we’ve selected to run on this Pi.

We’re calling lxterminal directly with /usr/bin/lxterminal. Passing lxterminal the -e flag means “execute this program.” We then pass it /bin/sh, which is a shell. Once upon a time, sh was a separate, small, lightweight shell called the Bourne shell . If you do an ls -l on /bin/sh, you’ll see it’s just a symbolic link to our old friend bash, which stands for Bourne Again SHell. It’s an improved, open source version of sh. In Linux, they’re usually the same thing.

Anyway, the %c is a variable filled in by Geany with the name of the program we’d like to run. So why, you might ask (as I did), not have lxterminal call the file directly? By having lxterminal call /bin/sh first, we get all the environment variables we’re used to setting. Environment variables are how bash keeps track of a great many things, most importantly (right now) our current directory. We can then pass just the filename of the compiled program to sh, which runs it in the terminal window. Well. Kind of. Geany wraps our compiled program in a script that gives us more information when it runs.

That’s a lot of Linux poking we just did, and a pretty dense explanation of it on my part. We covered all these concepts back in Chapter 3, “Survival Linux,” so if you need to look back at them and review, go ahead. That’s why that chapter is there.

By the by, if you’re wondering, “Does this mean if I do change terminal applications, Geany won’t be able to run programs again?” Good catch. Maybe. It depends on whether you uninstall lxterminal. As long as /bin/lxterminal is there, it will work. If it’s not there, execute won’t work.

Build versus Compile

Okay. Now that we have Geany working right, lets test the building, compiling, and execution functions. We’ll use the arduino_skel project for that, but we’ll have to add a couple of things to it.

Right now, the arduino_skel.cpp file looks like this:

#include "do_nothing.cpp"
void setup() {
  // put your setup code here, to run once:
do_nothing();
}
void loop() {
  // put your main code here, to run repeatedly:
}

This isn’t a complete program. Just a couple of functions. The truth is, every Arduino sketch you write is that: code in a couple of functions. In the background, the Arduino IDE adds what we’re about to add by hand. Add the following function at the bottom of the arduino_skel file.

int main(){
    setup();
    while(true){
        loop();
    }
}

Your finely tuned Arduino habits should tell you instantly that main is a function, returning an integer. It calls setup, without passing it any parameters, and then it loops forever, calling loop over and over again. This may not be the exact code the Arduino uses, but it does what the Arduino code does. Run setup once, run loop forever.

Go ahead and choose Build ➤ Compile. That compiles the file we’ve been working on, in this case arduino_skel.cpp. You can run Lint on it too, if you like. But here’s the catch. Compile only compiles the one file shown. It only compiles arduino_skel.cpp. It does not compile do_nothing.cpp, and it does not link anything together.

Choosing Build ➤ Build will tell Geany to compile all the files in the project, as needed, and link them together in a finished image, which is an executable program. Go ahead and build the project. I don’t recommend executing it. It doesn’t do anything, and it loops infinitely at the end, so you’ll just have to close the terminal window anyway.

Executing Programs

Let’s modify the arduino_skel project to at least produce something we can see, and so it doesn’t loop infinitely. Then we can execute it and verify that it, and all our tools, work.

Right now, arduino_skell.cpp looks like this:

#include "do_nothing.cpp"
void setup() {
  // put your setup code here, to run once:
do_nothing();
}
void loop() {
  // put your main code here, to run repeatedly:
}
int main(){
    setup();
    while(true){
        loop();
    }
}

The first thing we want to do is have it print something in the terminal window. To do this, we need to pull in a library called iostream. You can bet the Arduino IDE does something like it for you, so that serial.print() works. We’ll do it by hand.

At the top, where we added #include "do_nothing.cpp", we’ll include the library. The syntax is a little different. Instead of quote marks, we’ll use greater-than/less-than marks. This tells the precompiler that handles the includes to use the system library instead of looking for it in our directory. It looks like this: #include <iostream.h>.

Next, we need to fix the infinite loop. Let’s change it to a for loop. You’ve probably done these a thousand times in sketches. Edit main() so that it looks like this:

int main(){
    setup();
    for(int c=0;c<5;c++){
        loop();
    }
}

Now let’s put some code in the loop function, for old time’s sake. We’ll use a function called cout, which we included in iostream. I won’t explain what all it does right now, because we’ll get into that in the “Write Your First C++ Program” section. It does more or less what serial.print does.

void loop() {
  // put your main code here, to run repeatedly:
std::cout<<"Sketches are really C++!!!"<<std::endl
}

Now choose Build ➤ Build. The compiler will compile both arduino_skell.cpp and do_nothing.cpp . The linker will go out and find the precompiled library called iostream and link that in, and it will produce the finished image, called arduino_skell, and put it in ~/projects/arduino_skell/arduino_skell. If you do an ls -l on that file, you’ll see that Geany even set it as executable. So let’s execute it.

You should get a new window that looks like Figure 4-6. Normally I won’t do screenshots of output windows. Putting the output in as text is much easier to read, but this once it seemed appropriate.
../images/456672_1_En_4_Chapter/456672_1_En_4_Fig6_HTML.jpg
Figure 4-6

The Output window

Write Your First C++ Program

So you’ve already written your very first C++ program, but we left the Arduino training wheels on for that one. To be honest, maintaining them by hand from here on out will be more work than they’re worth. So let’s go ahead and do a program without them, the C/C++ way.

The C++ Way

Full disclosure. I’m not a C++ expert by any stretch of the imagination. The techniques I’m going to tell you are more “use C++isms, especially objects, when they make sense” rather than pedantically pure C++ structure. Computers don’t care about pedantry. If the program works, in many cases, that’s all that’s required. If you’re doing security, aerospace, medical, or other places where any bug might be a major issue, you’re probably reading the wrong book, and you might want to read the Raspberry Pi foundation’s notice that Pis aren’t for that. If you happen to be a C++ expert, all I can say is you know more than I do about it. These programs work (I’ve tested them). That’s all I can promise.

The Preprocessor

I’ve mentioned the preprocessor in passing, but it’s time I give you the heads up on what exactly the preprocessor does. The preprocessor, as the name suggests, is a program that reads your C++ source code (the human readable stuff we’re going to write) before compilation takes place. It’s best thought of as an interpreted programming language to make C++ programming easier. We’ve already used it.

Expanding #include

The C/C++ preprocessor interpreted the #include directives we put in arduino_skel.cpp. It hit that directive, went out and got the do_nothing.cpp file, and copied that code into a file along with arduino_skell.cpp, before the whole business got sent to the C++ compiler. That’s the most common job for the preprocessor.

Macro Expansion

Preprocessor macros are extraordinarily useful. They’re also extremely common in the microcontroller world (like Arduino), because they take no memory at runtime. None. A variable can get pretty heavy, memory-wise, when you’re dealing with only 4KB of memory, so having constants in that kind of environment is a waste. I used them a ton in my previous book, Junk Box Arduino, to substitute for Arduino constants with ambiguous names, to substitute for binary bit patterns, and so forth. Here’s an example.

#define Control_Port portb
#define Control_DDR ddrb
#define pi 3.14

If you’ve done any Arduino port programming, you know that those port names change depending on what model of Arduino you’re on. By abstracting them in a macro, it meant that if you moved my code to say, an Arduino Mega, you just had to change portb or ddrb, instead of modifying the whole program. That’s how macros are expanded. The first term is the macro, the second is its value. So we’re defining Control_Port and telling the preprocessor to substitute portb every time it sees Control_Port, ddrb for every Control_DDR, and 3.14 for every pi. Macros can do a lot more than that. They can take parameters and do math and string operations on them. The C/C++ precompiler is, itself, a fairly complete programming language.

In a contest called “Obfuscated C,” the story goes, a programmer wrote an entire sieve of Eratosthenes in precompiler macros, and the only C code was the code that printed out the list of prime numbers that was the result. If memory serves, he won the brand new “Best Abuse of the Preprocessor” award. Once compiled, of course, his program would have taken no time to run, since the prime numbers were already generated. It would have taken a long time to compile though. I don’t use preprocessor functions in this book. They’re tricky and hard to read, and they’re well documented online.

Conditional Compilation

C and C++ are funny animals. You can sometimes find yourself in a corner where you have to #include something twice. In arduino_skel.cpp, the function setup() calls the function do_nothing(). Suppose do_nothing() calls a third function that is also called by main in arduino_skel. Function order can get very fussy, and at times with complex programs, it’s possible to get stuck in a situation where there’s no right answer when a function can be defined. The C/C++ solution to this conundrum is the function prototype. We’ll get to those in later chapters, but the short version is, it provides a placeholder definition for a function to be formally defined later. These, in turn, are often stored in .h files and included at compile time.

Here’s where conditional compilation matters. You often break out those function definitions in separate files, but put the skeletons together in the same file. Your compiler will complain if you include the header file twice. Here’s how the preprocessor fixes that for you. In your program file and in all the function definition files, you can put this.

#ifndef header_included
    #define header_included
    #include "header.h"
#endif

What’s happening here? Well, #ifndef is “if not defined.” If the macro header_included is not defined, it means that the header file has not been included. The next lines are what happen if header_included is not defined. We define it, and then we include the header file.

The last line ends the #ifndef statement. This bit of preprocessor code will #include the header file only if it hasn’t already been loaded. When the precompiler goes to roll this particular file into the one big file it will feed to the compiler, if header_included is already defined, it won’t run the #include "header.h". I’ve intended the ifdef code here like we would in C++ and C, but it’s often not written that way.

But you can do more with conditional compilation. To get back to the code we talked about in the “Macro Expansion” section, let’s say I knew my Arduino sketch was going to be run on more than one type of Arduino. I could put something like this in:

#ifdef Cestino        //We're using a Cestino, a type of Arduino-derived board.
#define Control_Port portb
#define Control_DDR ddrb
#elif Mega            //Else if we're using an Arduino Mega 2560
#define Control_Port porte
#define Control_DDR ddre
#endif                //end of the if.

You’re not limited to putting #ifdefs before the C++ code, either. If you have a function that is specific to one processor but not another, you can #ifdef that function out based on what processor you’re using.

We won’t use #ifdef much, if at all, but it’s a useful thing.

Object-Oriented Programming

You can program a long time in Arduino and not touch object-oriented programming. I’ve found objects useful from time to time, so I’m going to dive right on in and give you a quick overview of the subject.

There are four major parts to the object-oriented puzzle that you really have to understand, and they’re easy to get muddy on. They go by different names and have slightly different rules in different languages, but these are the C++ names.

Objects

An object is a way to put data and code in a single entity. It’s like if the toolkit in your car (I’m dating myself again, aren’t I?) had literally all the tools you’d ever need to work on the car, and only that car. Every other kind of car has its own tools, and even if my car is the same as your car, each of our cars has its own toolbox, and we can’t use each other’s.

Attributes

In non-object-oriented programming, attributes are what we’d call variables. They’re where the data in an object is stored. Here’s one of the big differences. You know how a function can have variables that the rest of the program can’t see (local variables)? An object can have private attributes like that. An object can also have public attributes that, if you have an object, you can change with code outside the object.

Methods

Methods are the object-oriented equivalent to functions, except they’re contained inside the object. Like attributes, they can be public or private. Because a method is part of the object, whether it’s public or private, it can access private attributes and (other) private methods. So to use the car analogy again, if I have a public method called lug_wrench and a private attribute called lugs (the studs and nuts that hold the wheels on), I can’t touch lugs because I am not part of the car and its tools, and lugs is private. However, I can call lug_wrench. It’s public. Because lug_wrench is part of the car and its tools, it can access lugs.

To extend the analogy to its limit without getting silly, if I have a private method called cheater_bar (a long piece of heavy pipe you put over the handle of a wrench to increase your leverage), once again, I can’t touch either lugs or cheater_bar because I am not part of the car or its tools. But if lug_wrench can call cheater_bar, I can call lug_wrench, it can call cheater_bar and access lugs, because it is part of the car and its tools.

The car and its tools are one object. I am code outside the object. Cheater_bar is a private method, and lugs is a private attribute. Lug_wrench is a public method. See?

Classes

So now that you’ve got a grasp of what an object is, and what it’s made of, the next obvious question is, “how do you make them?”

There are two steps. Bear this in mind. It’s one of the things that confused me about C++ for a long time. Two steps. The first is to define what we want the object to be. That definition is called a class.

A class defines the attributes and methods of the object and gives them their names. For the previous example, it might look like this:

class car_and_tools {
    private:
    int lugs=100;          //An integer attribute that stores how tight//the lugs are. Initialized to 100.
    void cheater_bar(){    //A private method to deal with very tight lugs
        //code goes in here
    }   //end of cheater_bar
    public:
    void lug_wrench(){    //A public method for accessing lugs.
        //code goes in here too
    } //end of lug_wrench
}; //End of class.

Lugs and the cheater_bar function are private, but lug_wrench is public. It’s important, so I’ll repeat it. A class is not an object. Nothing is actually created by a class. If I put this code in arduino_skel. cpp , it will compile, but it won’t do anything. If I tried to call lug_wrench(), I’d get an error.

Let There Be Objects

When you turn a class into an object, it’s exactly the same as creating a variable. Same idea, same syntax.

car_and_tools My_VW;

This declares an object called My_VW of the type car_and_tools.

Now an object exists. Let’s create another one.

car_and_tools My_Wifes_Subaru;

Done. If I want to use the lug_wrench() method of My_VW, I can call it like this:

My_VW.lug_wrench();

I can’t do anything to My_Wifes_Subaru calling methods on My_VW. My_Wifes_Subaru has its own lug wrench, and I’d call it like this.

My_Wifes_Subaru.lug_wrench();

I can’t touch the lugs attribute of either object because they’re defined in the class as private. I can’t touch the cheater_bar() method in either object because they’re defined in the class as private. I know, I’m repeating myself, but these are the fundamentals of object-oriented programming. Do they make sense now?

Good. Enough lecture. Let’s go write a program.

TicTac

The first program we’re going to write in C++ really has nothing to do with Raspberry Pi-specific programming. It runs just as well on my Mac as it did on the Raspberry Pi I wrote it on. (I used Pi3plus, if you wondered. It’s faster.) We’re going to write a tic-tac-toe program. In the interest of keeping it really simple, we’re not even going to write an opponent. We’ll make it a two player game. (A good opponent would involve some game theory. A quick and easy opponent would always win. Tic-Tac-Toe is not a very good game.)

Planning

Maybe it’s my age, that I grew up in the days of pencil and paper, and that I was about 10 when I first got my hands on a computer, but I’ve found that when I plan a program on paper, it works better. Laziness forces me to keep things simple. You don’t have to use pencil and paper, but it’s a good idea to plan the program, especially when it comes to the objects and data structures in it. Prior preparation prevents poor performance, or so they say.

Rules

The rules of tic-tac-toe are pretty simple. You and your opponent take turns placing Xs and Os on the board until one or the other (or more often neither) of you gets three in a row horizontally, vertically, or diagonally. (Yeah, the Elle King song is running through my head now too. Sorry.) So the program needs to represent the board in data. It needs to be able to tell if someone won. And it needs a way for players to put their data in. If that sounds like there’s an object involved, you’ve got a good ear.

Objects

There’s only one object we need in this program. It’s called the_board, of the class board. Go ahead and write that down. We need a class called board.

class board{
};
Attributes

The board class needs to store all the moves in the game. To make it easy to picture how all this code works, we’ll represent those moves as a two-dimensional array of chars. (Single characters.) Yes, a boolean would use less memory. Don’t worry about it. You’re programming a Raspberry Pi now. Your Pi has at least 256MB of RAM. The fact that we’re using nine bytes of RAM to store data we could fit in nine bits doesn’t matter. We’ll call it board_data.

No code outside the board object needs to talk to board_data, so we’ll make it private. So write that down in the board class.

class board{
    private:
        char board_data[3][3];
};
Methods

The board class needs to be able to see if anyone has won. While that method needs to be accessed from the outside, it’s going to be a huge monster of a method. Let’s break it down further.

If you think about it, you can check all the possible victory conditions with three types of checks. A check across, a check vertically, and a check diagonally. So let’s create methods to do those things. No code outside the board object needs to access these smaller methods, so we’ll make them private. We’ll fill the actual code in later.

class board{
    private:
    char board_data[3][3];
    bool check_across(){
    }
    bool check_vert(){
    }
    bool check_diag(){
    }
};

We’ll need a public method so that code outside an object of the board class can see if the board is in a winning state. But by now, there’s something that should have you screaming at me. The board_data array is not initialized. Anywhere. That is a great way to get pseudo-random results, and that’s not what we’re looking for, so we need to create two public methods: one to initialize the array, and one to check to see if a player has won.

Actually we need more methods than that. We need a method to display the board on the terminal window. We also need a way for players to make their moves. Okay. Let’s write all those down too.

Actually wait.

The only time we’re going to call the method that initializes the board_data array is when the object is first instantiated. It’d be nice if C++ could just call that for us, wouldn’t it? It can. If you name a public method the same thing as the class name, it’s called the constructor, and C++ will call it when the object is created. As the name might suggest, there is also a destructor, if you need one. It’s also a public method and it’s the class name again, only with a tilde (~) in front of it. Like this:

class board{
    public:
    board(){
    //code goes here
    }
    ~board(){
    //code would go here too.
    }
}; //end of the board class

C++ actually has a default constructor and destructor, so if you don’t have to do anything special for one or the other, you don’t need to include one. We need a constructor to initialize board_ data , but the default destructor is just fine. So let’s write that down too.

class board{
    private:
    char board_data[3][3];
    bool check_across(){
    }
    bool check_vert(int col, char player){
    }
    bool check_diag(){
    }
    public:
    board(){
    }
    void display(){
    }
    bool win_check(){
    }
    void player_move(){
    }
}; //end of board class.

It’s more complicated than a sketch, but not much more complicated. You may have written sketches with objects already. If so, you’re ahead of the game. If not, and you’re looking at the class and wondering how much worse this is going to get, the answer is not much. Most of the complexity is right here in the skeleton. Each of those methods is straightforward code. You’ve done functions harder than these if you’ve done much Arduino programming. And with all the heavy lifting done in objects of the board class, main() is pretty simple too, as you’ll see.

So let’s get coding.

Coding

I’m not going to walk you through writing each of these functions. As I said, they’re not complicated at all. I’m going to throw the code at you, annotate it in spots above and beyond my already lengthy comments, and figure you’ve done this enough to follow along.

Note

Do comment your code, even if you’re the only person who will ever see it. You might have to try to understand it again a few years down the road, and future you will thank present you for it.

The Class

Here’s the actual board class, in all its glory, comments intact.

class board{
    private:
    /* Private variable: board_data
    * -----------------------------------------------
    * What it is:
    * -------------
    * a two dimensional array of characters.
    *
    * What it's for:
    * -------------
    * stores all the X or O values. Represents the board.
    * -----------------------------------------------
    */
    char board_data[3][3];
    /* Private method: check_across
    * ----------------------------
    * Parameters: int row, char player
    * Returns: a boolean value (true or false)
    *
    * How it works:
    * -------------
    * given a row and a player, start at the 0th
    * column in that row and traverse that row of the array
    * to the 2nd position. If any of those chars are NOT
    * equal to player, return false, otherwise return true.
    * -----------------------------------------------
    */
    bool check_across(int row, char player){
        for (int c=0;c<=2;c++){
            if (board_data[row][c]!=player) return (false);
        }
        return(true);
    }
    /* Private method: check_vert
    * ----------------------------
    * Parameters: int col, char player
    * Returns: a boolean value (true or false)
    *
    * How it works:
    * -------------
    * Given a column and a player, start at the 0th
    * row in that column and traverse that column vertically
    * to the 2nd position. If any of those chars are NOT
    * equal to player, return false, otherwise return true.
    * -----------------------------------------------
    */
    bool check_vert(int col, char player){
        for (int c=0;c<=2;c++){
            if (board_data[c][col]!=player) return(false);
        }
        return(true);
    }
    /* Private method: check_diag
    * ----------------------------
    * Parameters: bool up, char player
    * Returns: a boolean value (true or false)
    *
    * How it works:
    * -------------
    * If up is false
    *     Loop on c.
    *         Using the value of c as both row and column,
    *         check each value in the board_data array at
    *         that position (c,c). If it's not equal to player,
    *         return false. If c goes past 2, return true.
    *
    * Otherwise (up is true) -
    *     Initialize d as an int with the value 2
    *         Loop on c from 0 to 2
    *         if the char in board data at row d, column c is
    *         not equal to player, return false. otherwise
    *         decrement d and repeat. The c variable will be
    *         incremented automatically by the for loop.
    *     If c goes past 2, return true.
    * -----------------------------------------------
    */
    bool check_diag(bool up,char player){
        if (!up){
            for (int c=0;c<=2;c++){
                if (board_data[c][c]!=player) return(false);
            }
        }else{
            int d=2;
            for (int c=0;c<=2;c++){
                if (board_data[d][c]!=player) return(false);
                d--;
            }
        }
        return(true);
    };
    public:
    /* Public method: board
    * ----------------------------
    * Parameters: none.
    * Returns: nothing.
    *
    * How it works:
    * -------------
    * This method is the class constructor. It's called when
    * an instance of the "board" class is created.
    * The functionality is classic stuff: a pair of nested loops.
    * The outer for loop loops on c. This will be the row.
    *     The inner for loop loops on d.
    *         Set board_data at the addresses c and d to the empty character.
    *     increment d
    *     When d gets bigger than 2 increment c.
    * When c gets bigger than 2, exit.
    * -----------------------------------------------
    */
    board(){
        for (int c=0;c<=2;c++){ //outer loop
            for (int d=0;d<=2;d++){//inner loop
                board_data[c][d]=(char)0; //set the element of the array
            }//end of inner loop
        }//end of outer loop
    }

We just declared the constructor. You noticed, right?

    /* Public method: display
    * ----------------------------
    * Parameters: none.
    * Returns: nothing.
    *
    * How it works:
    * -------------
    * This method is all about pretty-printing the board_data
    * array. First, we print the column number line.
    * After that, it's a classic nested for loop to traverse
    * the board_data array by rows.
    *
    * Of note: while this method is public (can be called by
    * private entities), because it is part of the board class,
    * it can access board's private variables. It could call
    * board's private methods too, but does not.
    *
    * Loop on c
    *     Every time the c loop increments, we're at a new
    *     row, so  print the row's coordinate value
    *     Loop on d.
    *     If board_data at row c, column d is empty
    *     (which will make the value logically false),
    *     print three blank spaces. Otherwise print
    *     board_data at row c column d, with a blank
    *     space on each side. If d (the column) is less
    *     than 2, print a pipe character(|). This forms the
    *     vertical lines in the tic-tac-toe board. Increment
    *     d. When the d loop gets past 2 and exits, print
    *     an endl. This ends the line so we start at the
    *     left margin for the next line. If c is less than 2,
    *     print the horizontal line for the crosshatch.
    *     Increment c. When the c loop exits, we've gone
    *     through all the elements in the board_data
    *     array. Print an endl to give some whitespace.
    * -----------------------------------------------
    */
    void display(){
        std::cout<<"   (0) (1) (2)"<<std::endl; //column numbers
        for(int c=0;c<=2;c++){
            std::cout<<"("<<c<<")"; //row number
            for (int d=0;d<=2;d++){
                if (!board_data[c][d]){
                    std::cout<<"   ";
                }else{
                    std::cout<<" "<<board_data[c][d]<<" ";
                }
                if (d<2) std::cout<<"|";
            }//end of d loop (columns)
            std::cout<<std::endl;
            if (c<2) std::cout<<"   --- --- ---"<<std::endl;
        }//end of c loop (rows)
        std::cout<<std::endl;
    }//end of method.
    /* Public method: win_check
    * ----------------------------
    * Parameters: player, a char.
    * Returns: a boolean (true or false).
    * What it does:
    * -------------
    * Tic-Tac-Toe is a simple game. There are only 8 win
    * conditions, so we'll just check them all. I'm playing
    * more boolean games here. In boolean, only false plus
    * false is false, so any true returned by any of the checks
    * will be preserved.
    * Of note: While this method is public (can be called by
    * outside entities), because it is part of the board class,
    * it can call board's private methods. It could access
    * private variables too, but it doesn't.
    *
    * How it works:
    * -------------
    * Set the boolean "won" to false.
    * Loop on c.
    *     Add whatever check_across on row c returns.
    *     Add whatever check_vert on column c returns.
    * Increment c.
    * When loop c exits, check both diagonals (top left to
    * bottom right and bottom left to top right) and add their
    * results to won. Return won. If any of the win conditions
    * has occurred, it will be true.
    * -----------------------------------------------
    */
    bool win_check(char player){
        bool won=false;
        for (int c=0;c<=2;c++){
            won+=check_across(c,player);
            won+=check_vert(c,player);
        }//end of the c loop
        won+=check_diag(false,player);
        won+=check_diag(true,player);
        if (won) std::cout<<"Player "<<player<<" Won."<<std::endl;
        return(won);
    }//end of the win_check method
    /* Public method: player_move
    * ----------------------------
    * Parameters: player (a char)
    * Returns: a boolean (true or false).
    *
    * What it does:
    * -------------
    * The player_move method does two things. Given a
    * player name, it asks the player for a row and a column
    * for that player's move. It then checks the move to
    * make sure it's not out of range (no values greater than
    * 2) and that the box the player chose is not already taken.
    * Of note: while this method is public (can be called by
    * private entities), because it is part of the board class,
    * it can access board's private variables. It could call
    * board's private methods too, but does not.
    *
    * How it works:
    * -------------
    * Set a boolean called "Valid" to false.
    * Set integers "row" and "column" to zero
    * Loop on valid not being true,
    *     Ask the player to enter coordinates.
    *     Input (cin) the row and the column
    *     If the element of board_data at row and col is empty
          //and//
    *  if row is less than 3 //and// if column is less than 3:
    *         thank the user, set the value in board_data,
    *         and set valid to true.
    *     Otherwise tell the user that the coordinates they
    *     gave were  invalid.
    * Go back to the beginning of the valid loop.
    * If valid is true, exit from the method.
    * -----------------------------------------------
    */
    void player_move(char player){
        bool valid=false;
        int row=0,col=0;
         std::cout<<"Player "<<player<<", it's your move."<<std::endl;
        std::cout<<"Enter Coordinates"<<std::endl;
        while (!valid){
            std::cout<<"Row: ";
            std::cin>>row;
            std::cout<<"Column: ";
            std::cin>>col;

I use boolean logic a lot. It’s very important to differentiate between a binary and (&) and a logical and (&&). A binary and (&) takes two binary values and returns a third. If you pass it a char, that’s eight bits. Say, 0b00000001 and 0b00000011. If you and those two values together, you get 0b00000001. Only the leading 1 is true in both values. The point is, binary ands don’t work at all when you pass them a boolean variable (true or false). For that you need a boolean, or logical, and (&&). If it sounds like I chased my tail for some time writing this program because I forgot that, I did.

By the by: 0bxxxx is notation for a binary literal, just as 0x precedes hexadecimal literals. It’s part of the C++ standard as of 2014, and was part of GNU C++ long before that. If you’re also coding for the Arduino, I strongly recommend against using their B prefix for binary values. It only works with values up to eight bits. 0b always works.

if ((board_data[row][col]==(char)0) && (row<3) && (col<3)){
                std::cout<<"Thank You."<<std::endl;
                board_data[row][col]=player;
                valid=true;
            }else{
                std::cout<<"Invalid Coordinates. Please try again."<<std::endl;
            } //end of if
        } //end of while valid is not true loop
    } //end of method
}; //end of the board class

Just in case you didn’t already know, // is an alternative notation for comments. Multiline comments are surrounded with /* and */.

Main

So with most of the game taken care of in the board object class, what’s left for main to do? Not a whole lot, and that’s fine. The ideal main() doesn’t do a lot of heavy lifting. The idea is that somehow objects in code might be reusable without a lot of custom code to make them go in main(). How realistic that is, I don’t honestly know, but that’s the ideal.

Our main needs to do three things, really. It needs to instantiate a board class object, display the board, then loop back and forth between players, display the board and getting moves until someone wins.

And that’s exactly what it does.

Note that main must return an integer variable. This tells Linux whether or not there were errors during the program’s run.

int main(){
    bool we_have_a_winner=false; //has anyone won?
    char player="X"; //what player is playing?
    board the_board; //instantiate the object the_board
    while(!we_have_a_winner){ //loop on we_have_a_winner being false
        the_board.display(); //display the board
        the_board.player_move(player); //have the player move
        we_have_a_winner=the_board.win_check(player); //see if they won
        if (player=='X'){ //if player X was playing
            player='O'; //set player to O
        }else{
            player='X'; //otherwise set player to X
        }//end of the if
    }//end of the loop
    the_board.display(); //display the final board
    return 0; //return zero, telling Linux that there were no errors
}
Cout Is Not Serial.print

It’s tempting to use std:: cout just the same as we used serial.print in Arduino. They are not the same thing. Because this is C++, cout and cin are objects. The commands we’re actually issuing are << (the stream insertion operator) and >> (the stream extraction operator). They are formatted input and output operators, and they’re smart enough (barely) to recognize what type of variable or attribute they’re being asked to put data into or get data out of. The problem is, the stream may have other stuff in it. For cout , this is seldom a problem. For cin , it can make quite a mess, because anything left in the stream will be read the next time cin is accessed. In later programs we’ll get into more serious input protection, when we need it. For tictac.cpp, just bear in mind that if you feed it bad input values, it will go into an infinite loop and give you an error message. By default, C++ and its ancestor C are horrible at handling user input in general, but especially character strings. I guarantee you that you’ll miss the Arduino string class long before we’re done. We’ll use a better mechanism as we get into later chapters.

Compiling

Go ahead and build the tictac.cpp file, whether you type it in by hand or load it from the example code available for this book. Remember, build, not just compile. We want iostream linked in.

Running

When you click Execute, a new terminal window should pop up, and this is what should be in it.

   (0) (1) (2)
(0)   |   |
   --- --- ---
(1)   |   |
   --- --- ---
(2)   |   |
Player X, it's your move.
Enter Coordinates
Row:

Remember when we told Geany what to do explicitly to execute a program? This is the result. Go ahead and play the game through.

   (0) (1) (2)
(0)   |   |
   --- --- ---
(1)   |   |
   --- --- ---
(2)   |   |
Player X, it's your move.
Enter Coordinates
Row: 1
Column: 1
Thank You.
   (0) (1) (2)
(0)   |   |
   --- --- ---
(1)   | X |
   --- --- ---
(2)   |   |
Player O, it's your move.
Enter Coordinates
Row: 0
Column: 0
Thank You.
   (0) (1) (2)
(0) O |   |
   --- --- ---
(1)   | X |
   --- --- ---
(2)   |   |
Player X, it's your move.
Enter Coordinates
Row: 2
Column: 1
Thank You.
   (0) (1) (2)
(0) O |   |
   --- --- ---
(1)   | X |
   --- --- ---
(2)   | X |
Player O, it's your move.
Enter Coordinates
Row: 1
Column: 0
Thank You.
   (0) (1) (2)
(0) O |   |
   --- --- ---
(1) O | X |
   --- --- ---
(2)   | X |
Player X, it's your move.
Enter Coordinates
Row: 0
Column: 1
Thank You.
Player X Won.
   (0) (1) (2)
(0) O | X |
   --- --- ---
(1) O | X |
   --- --- ---
(2)   | X |
------------------
(program exited with code: 0)
Press return to continue

See the line that says (program executed with code: 0)? That’s the script Geany generates to run our program talking. That 0 is what main returns. If you run tictac.cpp from a terminal window directly, like this—~/projects/tictac/tictac—you won’t get that. If you run it in its own terminal, like this—lxterminal -e ~/projects/tictac/tictac or lxterminal -e ./tictac if you’re in the project directory already—you’ll notice that when the game ends, the terminal window closes immediately.

Congratulations. You’ve written a C++ program, with nothing Arduino-related involved.

The Code

Here’s the complete source code for tictac.cpp, including all my comments and the usual GNU copyleft boilerplate. Geany will insert that for you, if you choose File ➤ New ➤ New (with template) ➤ main.cxx when you create the file, instead of the usual File ➤ New.

/*
 * tictac.cxx
 *
 * Copyright 2017 Jim Strickland
 *
 * Standard GNU boilerplate:
 * This program is free software; you can redistribute it
 * and/or modify it under the terms of the GNU General Public
 * License as published by the Free Software Foundation;
 * either version 2 of the License, or (at your option) any later version.
 * This program is distributed in the hope that it will be
 * useful, but WITHOUT ANY WARRANTY; without even the
 * implied warranty of MERCHANTABILITY or FITNESS FOR A
 * PARTICULAR PURPOSE. See the GNU General Public
 * License for more details.
 * You should have received a copy of the GNU General Public
 * License along with this program; if not, write to the Free
 * Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 * Boston, MA 02110-1301, USA.
 *
 */
/* tictac
 * version 1.0
 * language: c++
 * This program exists solely to demonstrate basic C++ programming concepts,
 * like objects, classes, and methods. It is two player, so there is no
 * programmed opponent (game theory would be too much).
*/
/* Iostream gives us cin and cout, among other things we
 * won't be using. These functions let us talk to the terminal.
 * It also defines the std:: namespace. Note that every time
 * we call cin or cout we have to tell C++ what namespace
 * those functions are in. There are ways around that, but for
 * this first program we'll go ahead and do it explicitly.
 * Also, I forgot about the workaround.
 */
#include <iostream>
/* Class Declaration
 * ------------------------------------------------
 *
 * Private methods:
 * ------------------------------------------------
 * check_across - checks a horizontal line for wins.
 * check_vert - checks a vertical line for wins.
 * check_diag - checks a diagonal line for wins.
 * ------------------------------------------------
 *
 * Public Methods:
 * ------------------------------------------------
 * board - constructor. Sets all chars in board_data to empty.
 * win_check - checks to see if the player given has won.
 * player_move - interacts with the player to get coordinates and call wincheck
 * -------------------------------------------------
 * There's no custom destructor. When we'd destruct the
 * object, the program is terminating anyway.
 * -------------------------------------------------*/
class board{
    private:
    /* Private variable: board_data
    * -----------------------------------------------
    * What it is:
    * -------------
    * a two dimensional array of characters.
    *
    * What it's for:
    * -------------
    * stores all the X or O values. Represents the board.
    * -----------------------------------------------
    */
    char board_data[3][3];
    /* Private method: check_across
    * ----------------------------
    * Parameters: int row, char player
    * Returns: a boolean value (true or false)
    *
    * How it works:
    * -------------
    * given a row and a player, start at the 0th
    * column in that row and traverse that row of the array
    * to the 2nd position. If any of those chars are NOT
    * equal to player, return false, otherwise return true.
    * -----------------------------------------------
    */
    bool check_across(int row, char player){
        for (int c=0;c<=2;c++){
            if (board_data[row][c]!=player) return (false);
        }
        return(true);
    }
    /* Private method: check_vert
    * ----------------------------
    * Parameters: int col, char player
    * Returns: a boolean value (true or false)
    *
    * How it works:
    * -------------
    * Given a column and a player, start at the 0th
    * row in that column and traverse that column vertically
    * to the 2nd position. If any of those chars are NOT
    * equal to player, return false, otherwise return true.
    * -----------------------------------------------
    */
    bool check_vert(int col, char player){
        for (int c=0;c<=2;c++){
            if (board_data[c][col]!=player) return(false);
        }
        return(true);
    }
    /* Private method: check_diag
    * ----------------------------
    * Parameters: bool up, char player
    * Returns: a boolean value (true or false)
    *
    * How it works:
    * -------------
    * If up is false
    *     Loop on c.
    *         Using the value of c as both row and column,
    *         check each value in the board_data array at
    *         that position (c,c). If it's not equal to player,
    *     return false. If c goes past 2, return true.
    *
    * Otherwise (up is true) -
    *     Initialize d as an int with the value 2
    *     Loop on c from 0 to 2
    *         if the char in board data at row d, column c is
    *         not equal to player, return false. otherwise
    *         decrement d and repeat. The c variable will be
    *         incremented automatically by the for loop.
    *     If c goes past 2, return true.
    * -----------------------------------------------
    */
    bool check_diag(bool up,char player){
        if (!up){
            for (int c=0;c<=2;c++){
                if (board_data[c][c]!=player) return(false);
            }
        }else{
            int d=2;
            for (int c=0;c<=2;c++){
                if (board_data[d][c]!=player) return(false);
                d--;
            }
        }
        return(true);
    };
    public:
    /* Public method: board
    * ----------------------------
    * Parameters: none.
    * Returns: nothing.
    *
    * How it works:
    * -------------
    * This method is the class constructor. It's called when
    * an instance of the "board" class is created.
    * The functionality is classic stuff: a pair of nested loops.
    * The outer for loop loops on c. This will be the row.
    *     The inner for loop loops on d.
    *         Set board_data at the addresses c and d to
    *         the empty character.
    *     increment d
    *     When d gets bigger than 2 increment c.
    * When c gets bigger than 2, exit.
    * -----------------------------------------------
    */
    board(){
        for (int c=0;c<=2;c++){ //outer loop
            for (int d=0;d<=2;d++){//inner loop
                board_data[c][d]=(char)0; //set the element of the array
            }//end of inner loop
        }//end of outer loop
    }
    /* Public method: display
    * ----------------------------
    * Parameters: none.
    * Returns: nothing.
    *
    * How it works:
    * -------------
    * This method is all about pretty-printing the board_data
    * array. First, we print the column number line.
    * After that, it's a classic nested for loop to traverse the
    * board_data array by rows.
    *
    * Of note: while this method is public (can be called by
    * private entities), because it is part of the board class,
    * it can access board's private variables. It could call
    * board's private methods too, but does not.
    *
    * Loop on c
    *     Every time the c loop increments, we're at a new
    *     row, so print the row's coordinate value
    *     Loop on d.
    *         If board_data at row c, column d is empty
    *         (which will make the value logically false),
    *         print three blank spaces. Otherwise print
    *         board_data at row c column d, with a blank
    *         space on each side.
    *         if d (the column) is less than 2, print a pipe
    *         character(|). This forms the vertical lines in the
    *         tic-tac-toe board. Increment d.
    *     When the d loop gets past 2 and exits, print an
    *     endl. This ends the line so we start at the left
    *     margin for the next line. if c is less than 2, print
    *     the horizontal line for the crosshatch. Increment c.
    * When the c loop exits, we've gone through all the
    * elements in the board_data array. Print an endl to give
    * some whitespace.
    * -----------------------------------------------
    */
    void display(){
        std::cout<<"   (0) (1) (2)"<<std::endl; //column numbers
        for(int c=0;c<=2;c++){
            std::cout<<"("<<c<<")"; //row number
            for (int d=0;d<=2;d++){
                if (!board_data[c][d]){
                    std::cout<<"   ";
                }else{
                    std::cout<<" "<<board_data[c][d]<<" ";
                }
                if (d<2) std::cout<<"|";
            }//end of d loop (columns)
            std::cout<<std::endl;
            if (c<2) std::cout<<"   --- --- ---"<<std::endl;
        }//end of c loop (rows)
        std::cout<<std::endl;
    }//end of method.
    /* Public method: win_check
    * ----------------------------
    * Parameters: player, a char.
    * Returns: a boolean (true or false).
    * What it does:
    * -------------
    * Tic-Tac-Toe is a simple game. There are only 8 win
    * conditions, so we'll just check them all. I'm playing
    * more boolean games here. In boolean, only false plus
    * false is false, so any true returned by any of the checks
    * will be preserved.
    * Of note: While this method is public (can be called by
    * outside (entities), because it is part of the board class,
    * it can call board's private methods. It could access
    * private variables too, but it doesn't.
    *
    * How it works:
    * -------------
    * Set the boolean "won" to false.
    * Loop on c.
    *     Add whatever check_across on row c returns.
    *     Add whatever check_vert on column c returns.
    * Increment c.
    * When loop c exits, check both diagonals (top left to
    * bottom right and bottom left to top right) and add their
    * results to won. Return won. If any of the win conditions
    * has occurred, it will be true.
    * -----------------------------------------------
    */
    bool win_check(char player){
        bool won=false;
        for (int c=0;c<=2;c++){
            won+=check_across(c,player);
            won+=check_vert(c,player);
        }//end of the c loop
        won+=check_diag(false,player);
        won+=check_diag(true,player);
        if (won) std::cout<<"Player "<<player<<" Won."<<std::endl;
        return(won);
    }//end of the win_check method
    /* Public method: player_move
    * ----------------------------
    * Parameters: player (a char)
    * Returns: a boolean (true or false).
    *
    * What it does:
    * -------------
    * The player_move method does two things. Given a
    * player name, it asks the player for a row and a column
    * for that player's move. It then checks the move to make
    * sure it's not out of range (no values greater than 2) and
    * that the box the player chose is not already taken.
    *
    * Of note: while this method is public (can be called by
    * private entities), because it is part of the board class,
    * it can access board's private variables. It could call
    * board's private methods too, but does not.
    *
    * How it works:
    * -------------
    * Set a boolean called "Valid" to false.
    * Set integers "row" and "column" to zero
    * Loop on valid not being true,
    *     Ask the player to enter coordinates.
    *     Input (cin) the row and the column
    *     If the element of board_data at row and col is
    *  empty //and//. If row is less than 3 //and// if column is
    *         less than 3: thank the user, set the value in
    *         board_data, and set valid to true.
    *     Otherwise tell the user that the coordinates they
    *     gave were invalid.
    * Go back to the beginning of the valid loop.
    * If valid is true, exit from the method.
    * -----------------------------------------------
    */
    void player_move(char player){
        bool valid=false;
        int row=0,col=0;
         std::cout<<"Player "<<player<<", it's your move."<<std::endl;
        std::cout<<"Enter Coordinates"<<std::endl;
        while (!valid){
            std::cout<<"Row: ";
            std::cin>>row;
            std::cout<<"Column: ";
            std::cin>>col; // &&
            if ((board_data[row][col]==(char)0) && (row<3) && (col<3)){
                std::cout<<"Thank You."<<std::endl;
                board_data[row][col]=player;
                valid=true;
            }else{
                std::cout<<"Invalid Coordinates. Please try again."<<std::endl;
            } //end of if
        } //end of while valid is not true loop
    } //end of method
}; //end of the board class
/* main function
 * ----------------------------
 * Parameters: nothing
 * Returns: an integer (C++ requires this)
 *
 * How it works:
 * -------------
 * Create the boolean "we_have_a_winner" and set it false
 * Create the char "player" and set it to X. (X always starts)
 * Instantiate an object of the board class (above) called
 * the_board
 * Loop on we_have_a_winner being false
 *     Call the "display" method on the_board.
 *     Call the "player_move" method on the_board, and tell it which player.
 *     Call the "win_check" method on the_board for the player.
 *     If we've been dealing with the X player, set the
 *     variable player to O. Otherwise it must be O, so set it to X.
 * End of the while we_have_a_winner is false loop, which means someone won.
 * Display the final board.
 * Exit, returning zero to tell Linux there were no errors.
 * -----------------------------------------------
 */
int main(){
    bool we_have_a_winner=false; //has anyone won?
    char player="X"; //what player is playing?
    board the_board; //instantiate the object the_board
    while(!we_have_a_winner){ //loop on we_have_a_winner being false
        the_board.display(); //display the board
        the_board.player_move(player); //have the player move
        we_have_a_winner=the_board.win_check(player); //see if they won
        if (player=='X'){ //if player X was playing
            player='O';   //set player to O
        }else{
            player='X'; //otherwise set player to X
        }//end of the if
    }//end of the loop
    the_board.display(); //display the final board
    return 0; //return zero, telling Linux that there were no errors
}//end of the program.

Conclusion

The Arduino software is made up of the Arduino IDE, the GNU C++ compiler for AVR, Wiring, the standard interface for the various AVR flavors’ built-in hardware, and the AVRDUDE uploader for transferring compiled code to the Arduino. For the Pi, we’ll use the Geany IDE, which is quite similar to Arduino’s, and GNU C++ for ARM Linux (it comes with Raspbian). We can run the code directly on the Pi where we wrote it. We’ll use WiringPi in place of Wiring, and we’ll cover that in depth in Chapter 5.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.222.193.207