Quickie: Linux on the STM32F429 Discovery

For a while now, I’ve wanted to run Linux on an STM32F4, ever since I was working on CAPE.

I knew about running Linux on the Discovery Boards that had an LCD Screen, but never bothered to pick one up until recently.

I saw on eLinux that they had instructions, so I tried to follow them, but I really had trouble understanding them. Luckily, they have a quickstart but it needs some tweaks. I’ve provided a patch for the device tree overlay for the stm32f429 discovery and if you clone from my repo then it should work. As of writing, I’ve only tested it on my Ubuntu system, so I’ll need to fix it to work on OpenSuSE.

stflash does have some issues with libraries, you’ll see something like it complaining about it missing libusb.so.0 or some other. If you search your system, then you’ll see it exists, but it is in some unusual place, so I just softlinked in a lot of places. I’ll probably need to submit a patch to stflash to fix those since it’s kind of annoying.

But anyway, just clone the repo and execute quickstart.sh and you should be pretty much good. It’ll take care of itself for the most part. Reach out to me if there are issues and I’ll see what I can do. I did make a copy of the initramfs which you can find here in case it gets removed from elinux. I’ll probably eventually fork the other repos mentioned in the script just for safety.

If you do want a good understanding of what’s going on at a lower level, then this video gives a lot of great information and I encourage you to watch it regardless if you’re using quickstart or not:

Posted in Engineering | Tagged , , | Leave a comment

Setting up and installing Jenkins on OpenSuSE

By The Jenkins project (http://jenkins-ci.org/)

So this is going to be a relatively simple setup for how I set up and installed Jenkins on my server (jenkins.ceneblock.com) and how I have it integrated with github.

Jenkins is a build system that I use daily at my current job and at previous ones. It isn’t without flaws, but it has proven to be useful for finding bugs. It can be set up to not only build, but to run test suites, packaging, and all sorts of stuff that makes life really easy for end users.

I’m currently working on a hardware project and I want to write some APIs that abstract a lot of the lower level stuff for me, so that’s why I want to get Jenkins set up whenever I do a push on my repos.

First things first, we need to get the repo, enable it, and install Jenkins:


zypper addrepo -f https://pkg.jenkins.io/opensuse-stable/ jenkins
zypper in jenkins

Next, go ahead and start up Jenkins and set it to start on boot:


systemctl enable jenkins
systemctl start jenkins

When I tried this, I got the following errors in /var/log/jenkins.rc:


Sep 09, 2020 8:15:49 PM Main verifyJavaVersion
SEVERE: Running with Java class version 59 which is not in the list of supported versions: [52, 55]. Run with the --enable-future-java flag to enable such behavior. See https://jenkins.io/redirect/java-support/
java.lang.UnsupportedClassVersionError: 59.0
at Main.verifyJavaVersion(Main.java:174)
at Main.main(Main.java:142)

Jenkins requires Java versions [8, 11] but you are running with Java 15 from /usr/lib64/jvm/java-15-openjdk-15
java.lang.UnsupportedClassVersionError: 59.0
at Main.verifyJavaVersion(Main.java:174)
at Main.main(Main.java:142)

So let’s take a look at the link provided.

Java 8 runtime environments, both 32-bit and 64-bit versions are supported

Since Jenkins 2.164 and 2.164.1 [1], Java 11 runtime environments are supported

Running Jenkins with Java 11 is documented here

There are some precautions to take when upgrading from Java 8 to Java 11 in Jenkins, please follow these guidelines.

Older versions of Java are not supported

Java 9 and Java 10 are not supported

Java 12 is not supported

So I’m using too new of a version of Java…😬

Now I see why they recommend running it in Docker.

Okay, so let’s install an older version of Java and hope things don’t catch on fire.

zypper se openjdk
Loading repository data...
Reading installed packages...

S | Name                             | Summary                            | Type
--+----------------------------------+------------------------------------+--------
  | java-11-openjdk                  | OpenJDK 11 Runtime Environment     | package
  | java-11-openjdk-accessibility    | OpenJDK 11 accessibility connector | package
  | java-11-openjdk-demo             | OpenJDK 11 Demos                   | package
  | java-11-openjdk-devel            | OpenJDK 11 Development Environment | package
i | java-11-openjdk-headless         | OpenJDK 11 Runtime Environment     | package
  | java-11-openjdk-javadoc          | OpenJDK 11 API Documentation       | package
  | java-11-openjdk-jmods            | JMods for OpenJDK 11               | package
  | java-11-openjdk-src              | OpenJDK 11 Source Bundle           | package
  | java-14-openjdk                  | OpenJDK 14 Runtime Environment     | package
  | java-14-openjdk-accessibility    | OpenJDK 14 accessibility connector | package
  | java-14-openjdk-demo             | OpenJDK 14 Demos                   | package
  | java-14-openjdk-devel            | OpenJDK 14 Development Environment | package
  | java-14-openjdk-headless         | OpenJDK 14 Runtime Environment     | package
  | java-14-openjdk-javadoc          | OpenJDK 14 API Documentation       | package
  | java-14-openjdk-jmods            | JMods for OpenJDK 14               | package
  | java-14-openjdk-src              | OpenJDK 14 Source Bundle           | package
i | java-15-openjdk                  | OpenJDK 15 Runtime Environment     | package
  | java-15-openjdk-accessibility    | OpenJDK 15 accessibility connector | package
  | java-15-openjdk-demo             | OpenJDK 15 Demos                   | package
i | java-15-openjdk-devel            | OpenJDK 15 Development Environment | package
i | java-15-openjdk-headless         | OpenJDK 15 Runtime Environment     | package
  | java-15-openjdk-javadoc          | OpenJDK 15 API Documentation       | package
  | java-15-openjdk-jmods            | JMods for OpenJDK 15               | package
  | java-15-openjdk-src              | OpenJDK 15 Source Bundle           | package
  | java-1_8_0-openjdk               | OpenJDK 8 Runtime Environment      | package
  | java-1_8_0-openjdk-accessibility | OpenJDK 8 accessibility connector  | package
  | java-1_8_0-openjdk-demo          | OpenJDK 8 Demos                    | package
  | java-1_8_0-openjdk-devel         | OpenJDK 8 Development Environment  | package
  | java-1_8_0-openjdk-headless      | OpenJDK 8 Runtime Environment      | package
  | java-1_8_0-openjdk-javadoc       | OpenJDK 8 API Documentation        | package
  | java-1_8_0-openjdk-src           | OpenJDK 8 Source Bundle            | package

And install it:

zypper in java-11-openjdk java-11-openjdk-devel

Note: I am installing the corresponding devel as I found that that was part of some issues I had.

Now we can restart Jenkins, but if you’re still having trouble, then you may need to run update-alternatives --all and manually select what version of java to use.

You may see something like the following:

There are 3 choices for the alternative java (providing /usr/bin/java).

  Selection    Path                                       Priority   Status
------------------------------------------------------------
  0            /usr/lib64/jvm/jre-11-openjdk/bin/java      2105      auto mode
* 1            /usr/lib64/jvm/jre-1.8.0-openjdk/bin/java   1805      manual mode
  2            /usr/lib64/jvm/jre-11-openjdk/bin/java      2105      manual mode
  3            /usr/lib64/jvm/jre-15-openjdk/bin/java      0         manual mode

Press  to keep the current choice[*], or type selection number: 
There are 2 choices for the alternative javac (providing /usr/bin/javac).

  Selection    Path                                         Priority   Status
------------------------------------------------------------
* 0            /usr/lib64/jvm/java-1.8.0-openjdk/bin/javac   1805      auto mode
  1            /usr/lib64/jvm/java-1.8.0-openjdk/bin/javac   1805      manual mode
  2            /usr/lib64/jvm/java-15-openjdk/bin/javac      0         manual mode

Press  to keep the current choice[*], or type selection number: 
There is only one alternative in link group java_sdk_15 (providing /usr/lib64/jvm/java-15): /usr/lib64/jvm/java-15-openjdk
Nothing to configure.
There is only one alternative in link group java_sdk_1.8.0 (providing /usr/lib64/jvm/java-1.8.0): /usr/lib64/jvm/java-1.8.0-openjdk
Nothing to configure.
There are 2 choices for the alternative java_sdk_openjdk (providing /usr/lib64/jvm/java-openjdk).

  Selection    Path                               Priority   Status
------------------------------------------------------------
* 0            /usr/lib64/jvm/java-1.8.0-openjdk   1805      auto mode
  1            /usr/lib64/jvm/java-1.8.0-openjdk   1805      manual mode
  2            /usr/lib64/jvm/java-15-openjdk      0         manual mode

Despite this and a reboot, it still wanted to run Java 15, so I wound up editing /etc/sysconfig/jenkins:

With Jenkins up and running, we’ll need to log into it.

By default it lives at http://localhost:8080

So first you’ll be presented to enter in an admin password followed by asking if you want to install the suggested plugins.

We’ll go ahead and do the defaults and let those install. In particular, it should automatically install GitHub which is what we’ll want.

Once that’s finished, it’ll prompt you to set up an administrator account.

You’ll then be prompted to set a URL, this should be some forward facing URL so in my case https://jenkins.ceneblock.com

First thing we’ll do is create a non-admin user:

  • Manage Jenkins
    • Manage Users
      • Create User
        • Enter the credentials.

Now Jenkins does have the ability to auth off of /etc/shadow or LDAP through:

  • Manage Jenkins
    • Configure Global Security

Authing off of /etc/shadow is probably not a good idea, but LDAP with Kerberos isn’t that bad; although you’ll want to put some sort of restraint to prevent a script kiddie from getting usernames and passwords.

There are a few ways to set up a Jenkins Project and the absolute easiest is through “Blue Ocean”; however, this is a set of plugins not installed by default.

So as our admin user:

Manage Jenkins

  • Manage Plugins
    • Avilable
      • Search for Blue Ocean
      • There will be a lot of options, but you want the one that just says “Blue Ocean”
      • Select the Checkbox
      • Select “Download Now and Install After Restart”
    • At the bottom of the new page, select “Restart Jenkins when installation is complete and no jobs are running”

This will install and restart Jenkins, but if you look at what all is being installed, you’ll notice it supports a lot of Atlassian products… :/

For me, I wound up getting kicked out while it was installing and it seemed liked things were stuck, so after refreshing and logging in as an admin, I noticed on the left hand side there was a Blue Ocean icon.

Clicking on “Open Blue Ocean” I was brought to a page to create my first pipeline.

For the sake of simplicity, we’ll use an old repo that builds a simple webserver that I wrote a few years back.

  • Select Github
  • It’ll ask you for an auth token. Click the link to generate one (I named mine Jenkins)
  • Paste it
  • Select what organization this is for (aka your user name).
  • You’ll then be presented with all of your repos. For my sake, I’m going to choose an old webserver I wrote a few years back.
  • Select Create Pipeline

It’ll take you to the pipeline editor.

It’s very basic and the first thing you’ll do is click on the “+” icon in the middle of the page.

You’ll want to name this stage (init, in this case), and then select “Add Step”. Search for “Print Message” and then type in “Hello World” (without quotes).

Select Save.

You’ll then be presented with what is essentially a commit dialogue. Put in an optional message and create an optional branch (I did and named it jenkins), and then select “Save and Run”

With this completed, we can see our “Hello World” message. It’s very simple.

If we go back to the Blue Ocean main page (http://localhost:8080/blue), then we can create some additional steps.

Select the project, then select branches.

Mouse over towards the star and select the pencil icon.

This will bring us back to our pipeline editor.

Let’s change the init stage to something more useful for my particular project.

  • Select the init stage
    • On the right hand side, select “Print Message”
      • Select the three dots at the top and delete the step.
    • Select Add Step
      • Select “Shell Script”
        • Type in “sh ./autogen.sh”
        • Select the Back Arrow next to where it says “Shell Script”
    • Select Add Step
      • Select “Shell Script”
        • Type in “./configure”
        • Select the Back Arrow (again) next to where it says “Shell Script”

Cool, so now our project will create all the necessiary files and configure itself, but we still haven’t built.

Select the plus icon in the main editor to the right of “init”. We’ll name this stage “build”

We’re going to repeat the same steps that we did by calling a shell script, except this time we’re just going to run “make”.

Like before, go ahead and click “save”, put in your commit message if you want then you can watch the project being built.

That is the basics of Jenkins to get yourself started.

You’ll notice that in your repo, that it’ll automatically create a pull request and state which commits passed and which failed.

As a note, if you are going to fork my repo, then delete the Jenkinsfile from your instance so it isn’t automatically picked up when you import the repo and you can go through the steps yourself.

I’ll try to remember to do an update so when I do a push it’ll kick off a new build, but this is enough to get you started.

Posted in Computer Science | Tagged , , | Leave a comment

Easy68k is down

It looks like the Easy68k main page is down. 🙁

I recently downloaded the program to help with learning Motorola 68000 assembly (although I think there is a bug in it), but it seems the site is down.

Here is a copy of the program until their site is back up.

Posted in Computer Science | Tagged , , | Leave a comment

Just a small update, while most of my content has been geared towards beginners and as such, I’ve used the Arduino for showing code, I think I’m going to move towards using pure AVR C instead.

I’ll try to link this page or some sort of tutorial page for converting between the two somewhere, but I think it’ll be better for me in the long run.

I still use the Arduino IDE for throwing something together really quickly, but a catch 22 is that it obscures a lot of the lower level work which if we want to be good Computer Engineers, we need exposure to.

I have used following the following book:

    Title: Make: AVR Programming
    Author(s): Elliot Williams
    Release date: February 2014
    Publisher(s): Make: Community
    ISBN: 9781449355784

It’s really easy to read and use. Here is the associated git hub to it: https://github.com/hexagon5un/AVR-Programming and my fork https://github.com/ceneblock/AVR-Programming

Luckily I come from a C background so learning AVR C hasn’t been that hard.

Posted on by ceneblock | Leave a comment

Quickie: Problems with the PIUART

All rights reserved to LadaAda

It’s been a while since I’ve done a quickie, but I wanted to put this out there before I forget it.

Now, I openly admit that I found this by searching for a while and am basically going to copy and paste the answer; however, I’m going to add some additional information so that when Google (or some other search engine) crawls across my website it’ll be easier for others to find this page and they won’t have to spend so much time searching.

So I got the Adafruit PiUART from Microcenter, just to pick it up and I thought it looked cute as it fit just perfectly on the Pi itself (unlike using a “traditional” USB to Serial converter).

So I followed the directions listed here, which basically show how to enable a serial console using `raspi-config`; however, when plugging it in, I got this in `dmesg`:

[121428.924972] usb 2-1.3: new full-speed USB device number 6 using xhci_hcd
[121429.033381] usb 2-1.3: New USB device found, idVendor=10c4, idProduct=ea60, bcdDevice= 1.00
[121429.033386] usb 2-1.3: New USB device strings: Mfr=1, Product=2, SerialNumber=3
[121429.033390] usb 2-1.3: Product: CP2104 USB to UART Bridge Controller
[121429.033392] usb 2-1.3: Manufacturer: Silicon Labs
[121429.033395] usb 2-1.3: SerialNumber: 01A0FEC4
[121429.640723] usbcore: registered new interface driver cp210x
[121429.640737] usbserial: USB Serial support registered for cp210x
[121429.640791] cp210x 2-1.3:1.0: cp210x converter detected
[121429.645560] usb 2-1.3: cp210x converter now attached to ttyUSB2
[121429.768218] usb 2-1.3: usbfs: interface 0 claimed by cp210x while 'brltty' sets config #1
[121429.769908] cp210x ttyUSB2: cp210x converter now disconnected from ttyUSB2
[121429.770030] cp210x 2-1.3:1.0: device disconnected
[121430.260637] input: BRLTTY 6.0 Linux Screen Driver Keyboard as /devices/virtual/input/input19
[121770.452594] usb 2-1.3: USB disconnect, device number 6
[121772.725940] usb 2-1.3: new full-speed USB device number 7 using xhci_hcd
[121772.838333] usb 2-1.3: New USB device found, idVendor=10c4, idProduct=ea60, bcdDevice= 1.00
[121772.838339] usb 2-1.3: New USB device strings: Mfr=1, Product=2, SerialNumber=3
[121772.838342] usb 2-1.3: Product: CP2104 USB to UART Bridge Controller
[121772.838344] usb 2-1.3: Manufacturer: Silicon Labs
[121772.838347] usb 2-1.3: SerialNumber: 01A0FEC4
[121772.841427] cp210x 2-1.3:1.0: cp210x converter detected
[121772.846646] usb 2-1.3: cp210x converter now attached to ttyUSB2
[121773.460377] usb 2-1.3: usbfs: interface 0 claimed by cp210x while 'brltty' sets config #1
[121773.461454] cp210x ttyUSB2: cp210x converter now disconnected from ttyUSB2
[121773.461551] cp210x 2-1.3:1.0: device disconnected
[121773.955520] input: BRLTTY 6.0 Linux Screen Driver Keyboard as /devices/virtual/input/input20

So as we can see, it starts to register the device as /dev/ttyUSB2, but then `brltty` takes over and says “thanks, but I’ll take it from here” and when I try to connect to it, the device is no longer there.

First off, what is brltty? Well it’s the Braille tty daemon, simply put. I didn’t put too much stock into trying to figuring it out; however, I knew that was the problem.

Adafruit’s directions doesn’t give any troubleshooting advice. My first guess was to try and search currently running daemons using systemctl and stop the daemons. I tried that, but systemctl wouldn’t let me stop them…something about them being a prereq to something (IIRC). So with that not working I had to search until I came across an OpenSuSE Forum post.

Solution

Basically, I was able to solve it by just removing brltty. Now if you need Braille support, then this obviously won’t work for you, but I’m (relatively) able-bodied, so I had no problems just chucking it.

su
zypper rm brltty brltty-driver-at-spi2 brltty-driver-brlapi brltty-driver-espeak brltty-driver-speech-dispatcher brltty-driver-xwindow brltty-lang

Now, for me it said there was some errors and to check with `zypper ps`, so I did and I shut down all of the brltty instances:


zypper ps
systemctl stop brltty@

After doing that, unplugging and replugging the device back in, I was successfully able to connect using picocom (my preferred serial terminal emulator). The baud speed is 11500, but you can get that from the Adafruit docs.

Now, I’m using it on a Pi0W, so using a serial console doesn’t make too much sense, since I can just ssh over Wi-Fi, but that’s a different story. 🙂

Posted in Computer Science, Engineering | Tagged , , , | Leave a comment

Introduction To Apache Portable Runtime (APR) for C++

So this is going to be an introduction to working with apr using c++ for command line argument processing.

This assumes that you have some basic knowledge of C++. If you want to just jump into it, then click here I also put all of my code on GitHub if you really want to just see how to do it quickly.

Introduction

Let’s jump into it with an example C++ program:

#include <iostream>
using namespace std;

int main(int argc, char *argv[])
{
  cout << "Hello World\n";
}

Now, this should be a very simple program to understand. We simply print "Hello World" to the screen.

I'm sure you're familiar with adding the int argc and char *argv[] in your main implementation. You probably know that argc stands for the total amount of command line arguments (including the program name). Likewise, argv is a two dimensional array containing the corresponding values.

Let's go ahead and print those:

#include <iostream>
using namespace std;

int main(int argc; char *argv[])
{
  for(int x = 0; x < argc; x++)
  {
    cout << argv[x] << endl;
  }
}

Now if we compile and run our program, like so, we should see output as follows:

./a.out 1 2 3 4 5
./a.out
1
2
3
4
5

Of course, you could use some if statements to parse and handle your command line options, but that is complex and hard.

Let's use a library! Now, if you're on Linux, or some other OS that has POSIX libraries, then you have getopt.h.

This is an older tool, but it's super useful. Let's say that we have a program that needs the following:

  1. -h -- will display help info
  2. -v -- will display version info
  3. -n VALUE -- will take in a name and requires a value
  4. -o [VALUE] -- will take in a file name and is optional

Let's write the code first and break it down:

#include <unistd.h>
#include <iostream>
#include <string>

#define VERSION_INFO "0.0.1"

using namespace std;

void show_help(char *prog_name)
{
  cout << prog_name << endl;
  cout << "-h\tDisplay this help message and exit\n";
  cout << "-v\tDisplay version info and exit\n";
  cout << "-o[VALUE]\tAn output file\n";
  cout << "-n VALUE\tA name\n"; 
  exit(EXIT_SUCCESS);
}

void show_version()
{
  cout << VERSION_INFO << endl;
  exit(EXIT_SUCCESS);
}

int main(int argc, char *argv[])
{
 char opt;
 
 bool have_o = false, have_n = false;
 string o_value, n_value;

 while ((opt = getopt(argc, argv, "hvn:o::")) != -1)
 {
     switch (opt) 
     {
       case 'h':
         show_help(argv[0]);
         break;
       case 'v':
         show_version();
         break;
       case 'o':
         have_o = true;
         if(optarg)
         {
           o_value = optarg;
         }
         break;
       case 'n':
         if(optarg)
         {
           have_n = true;
           n_value = optarg;
         }
         else
         {
           cerr << "No argument for -n!";
           exit(EXIT_FAILURE);
         }
         break;
     }
 }

 if(have_o)
 {
   cout << "O's value " << o_value << endl;
 }
 if(have_n)
 {
   cout << "N's value " << n_value << endl;
 }
 return EXIT_SUCCESS;
}

Let's run it!

./a.out -h
./a.out
-h	Display this help message and exit
-v	Display version info and exit
-o[VALUE]	An output file
-n VALUE	A name
./a.out -v
0.0.1
./a.out -n ceneblock
N's value ceneblock
./a.out -o
O's value 
./a.out -ofile
O's value file

Okay, so we can see that it works! Let's look at the most important part of the code:

 char opt;
 
 bool have_o = false, have_n = false;
 string o_value, n_value;

 while ((opt = getopt(argc, argv, "hvn:o::")) != -1)

getopt() takes in int argc, char **argv, and char *optstring.

It's the optstring that's important. It's a sequence of characters that for each letter, opt is set accordingly.

You'll also see that the n has a : after it. This means that there is a required argument. See what happens if you run the program without it!

After that, you'll see o has two : after it. This means that it's optional.

This is fine and great, but what if you want to write your program and have it compile on Windows or an OS without POSIX? Well, you could port POSIX (use Cygwin or MinGW for Windows) to your OS or you could use Apache's Portable Runtime!

Installing

I'm on OpenSuSE Linux and it came installed by default, but for other distro's searching for apr-devel .

For Windows, here is Apache's guide.

I'm going to assume that you can figure out how to install apr and link it. This is article is mostly to show how easy it is to code.

API

Here is the API. Now just giving it to you wouldn't be too helpful, but it's important to know where to get info.

If we click on any of the functions or data types, then we can see more info about them. Let's take a look at apr_status_t apr_getopt (apr_getopt_t *os, const char *opts, char *option_ch, const char **option_arg)

We can see that we need to provide an apr_getopt_t. Well, what exactly is that?

From that link we can see it is:

Structure to store command line argument information.

Luckily, we don't need to fill this out manually, but we do need it to have valid data, from that link, we need to call:

apr_status_t apr_getopt_init(apr_getopt_t **os, apr_pool_t *cont, int argc,const char argv)

Now here, the apt_getopt_t is going to be our return type. So we'll want to declare it:

apt_getopt_t *opt;

Next what is this apt_pool_t? Well, it's a fundamental data type for apr. You can read about related functions from that link, but really, we need to do the following:

apr_status_t rv; ///the return value datatype.
apr_pool_t *pool;
apr_pool_create(&pool, NULL);

And just like that, we've created a new memory pool. Don't worry too much about it.

Something about APR is that it needs a special function call before we do anything. This call is apr_status_t apr_initialize(void).

So right after the bracket in main, let's call it (don't worry, I'll summarize with final code at the end).

int main(int argc, char *argv[])
{
  apt_initialize();

Likewise, we need to call a special terminator before quitting:

 apr_terminate();
 return EXIT_SUCCESS;
}

Okay, now that is over, let's jump back to apr_getopt_init, the next options are obvious, argc and argv.

So at this point, we've doing our initalization, memory pool allocation, and getopt_t initalization. Now we can get to our actual apt_getopt call.

If we look at it, it is actually very similar to our POSIX getopt:

opts A string of characters that are acceptable options to the program. Characters followed by ":" are required to have an option associated

So let's copy our POSIX optstring in and see what happens!

Here is our entire code:

#include <apr_general.h>
#include <apr_getopt.h>
#include <iostream>
#include <string>

#define VERSION_INFO "0.0.1"

using namespace std;

void show_help(char *prog_name)
{
  cout << prog_name << endl;
  cout << "-h\tDisplay this help message and exit\n";
  cout << "-v\tDisplay version info and exit\n";
  cout << "-o[VALUE]\tAn output file\n";
  cout << "-n VALUE\tA name\n"; 
  exit(EXIT_SUCCESS);
}

void show_version()
{
  cout << VERSION_INFO << endl;
  exit(EXIT_SUCCESS);
}

int main(int argc, char *argv[])
{
    apr_initialize();

    apr_status_t rv;
    apr_getopt_t *opt;
    apr_pool_t *pool;
   
    char optch;
    const char *optarg;
 
    bool have_o = false, have_n = false;
    string o_value, n_value;
 
    rv = apr_pool_create(&pool, NULL);
    if(rv != APR_SUCCESS)
    {
      cerr << "Error in apr_pool_create\n";
    }

    rv = apr_getopt_init(&opt, pool, argc, argv);
    if(rv != APR_SUCCESS)
    {
      cerr << "Error in apt_getopt_init\n";
    }

    while ((rv = apr_getopt(opt, "hvn:o::", &optch, &optarg)) == APR_SUCCESS) 
    {
     switch (optch) {
       case 'h':
         show_help(argv[0]);
         break;
       case 'v':
         show_version();
         break;
       case 'o':
         have_o = true;
         if(optarg)
         {
           o_value = optarg;
         }
         break;
       case 'n':
         if(optarg)
         {
           have_n = true;
           n_value = optarg;
         }
         else
         {
           cerr << "No argument for -n!";
           exit(EXIT_FAILURE);
         }
         break;
      }
    }
    if (rv != APR_EOF) {
        printf("bad options\n");
    }

    if(have_o)
   {
     cout << "O's value " << o_value << endl;
   }
   if(have_n)
   {
     cout << "N's value " << n_value << endl;
   }

    apr_terminate();
    return EXIT_SUCCESS;
}

Now how in the world do we compile this? To be honest, I don't know! However, there is a helper program to help us out!

apr-1-config 
Usage: apr-1-config [OPTION]

Known values for OPTION are:
  --prefix[=DIR]    change prefix to DIR
  --bindir          print location where binaries are installed
  --includedir      print location where headers are installed
  --cc              print C compiler name
  --cpp             print C preprocessor name and any required options
  --cflags          print C compiler flags
  --cppflags        print C preprocessor flags
  --includes        print include information
  --ldflags         print linker flags
  --libs            print additional libraries to link against
  --srcdir          print APR source directory
  --installbuilddir print APR build helper directory
  --link-ld         print link switch(es) for linking to APR
  --link-libtool    print the libtool inputs for linking to APR
  --shlib-path-var  print the name of the shared library path env var
  --apr-la-file     print the path to the .la file, if available
  --apr-so-ext      print the extensions of shared objects on this platform
  --apr-lib-target  print the libtool target information
  --apr-libtool     print the path to APR's libtool
  --version         print the APR's version as a dotted triple
  --help            print this help

When linking with libtool, an application should do something like:
  APR_LIBS="`apr-1-config --link-libtool --libs`"
or when linking directly:
  APR_LIBS="`apr-1-config --link-ld --libs`"

An application should use the results of --cflags, --cppflags, --includes,
and --ldflags in their build process.

As it ays at the bottom, we need:

  • --cppflags
  • --include
  • --ldflags

For me, the results are as follows:

apr-1-config --cppflags --includes --ldflags
 -DLINUX -D_REENTRANT -D_GNU_SOURCE -I/usr/include/apr-1

So I'll compile with those options:

g++ apr.cpp -DLINUX -D_REENTRANT -D_GNU_SOURCE -I/usr/include/apr-1

Now, let's test it like we did before:

./a.out -h
./a.out
-h	Display this help message and exit
-v	Display version info and exit
-o[VALUE]	An output file
-n VALUE	A name
./a.out -v
0.0.1
./a.out -n ceneblock
N's value ceneblock
./a.out -ofile
O's value file
./a.out -o
a.out: option requires an argument -- o
bad options

Uh oh! Despite our o::, we aren't able to have our optional argument like our original requirements are!

Is apr not a good solution?

Well....no. apr is a good solution, it's that I lied to you earlier. the o:: is actually a GNU extension. If we really want optional arguments, then we'll need to use getopt_long.

That, for right now, is a story for another day. This should be enough to at least get you started with apr. 😉

All code and a makefile is here

Posted in Computer Science | Tagged , , , , , , | Leave a comment

Driving a 7-segment Display with a Shift Register (74HC595)

I had a post a while back about driving a 7-segment display with an Arduino. Well, as you may recall, that took a lot of pins, 8 in fact.

What if we could reduce that by 3? What if we could only use 3?

Well, let’s introduce the shift register. This is a device which can take serial I\O and convert it into parallel.

It has two clocks on it one that reads in data and the other that shifts it out.

We have an output enable, data in, and data clear line as well.

First things first, let’s look at the datasheet.

Here is the pinout:

  • QA — QH are the outputs. In our analogy, think of having a birds eye view of our entire assembly line. We can see if there are products at any location at the same time.
  • SR — this is our input. So this is what we would place next on the assembly line.
  • OE’ — This is to say if we want to view our output on QA — QH. Two things, one is the bar (or as I’ve typed a tick or prime mark), this means logical NOT. So if you do want to view the output, then you set OE to LOW, and when you don’t, you set it to HIGH.
  • SRCLR’ — Likewise, with this tick mark, when we set this pin to low, the entire register gets cleared. All values are set back to 0. In our assembly line, this would be like flipping the entire table over.

Here is a timing diagram:

This is VERY important as it tells us what’s going on.

Let’s explain this before we get too far.

The easiest is the Output Enable (OE). As you can see, when OE’ is HIGH, the output lines (QA — QH) are in an unknown state.

Likewise, we can see the output lines go to LOW when SRCLR’ is HIGH.

Since QA — QH are outputs are low, we won’t worry about them too much, we just need to observe them along the diagram.

As we can see, the SRCLK goes up and down and the RCLK goes down and up in opposite directions. We’ll go further into that later on, but for right now, just notice that that are out of phase meaning that they do not line up. In this case, they are 180° out of phase.

Now let’s look at our SER line and our SRCLK. Notice that When SER is high and when SRCLK is high, then the QA goes high! Likewise, when SER is low.

To better understand this, take a look at Table 1. You can see arrows pointing up and down. These represent the clock phases, a raising edge and a falling edge depending on which way the arrow is pointing.

Let’s build a circuit finally!

Here is our circuit, now it looks complicated, but as we can see, it takes up less pins on the Arduino.

Here is our code:


#define SER 2
#define OE 3
#define RCLK 4
#define SRCLK 5
#define SRCLR 6

void setup() {
// put your setup code here, to run once:

pinMode(SER, OUTPUT);
pinMode(OE, OUTPUT);
pinMode(RCLK, OUTPUT);
pinMode(SRCLK, OUTPUT);
pinMode(SRCLR, OUTPUT);

//Clear everything first:
digitalWrite(SRCLR, LOW);
digitalWrite(SRCLR, HIGH);

//Turn off the output
digitalWrite(OE, HIGH);

//Now, since we're using a common annode 7-segment,
//everything will be reversed, so a LOW will mean a
//segment is on.

//DP off
digitalWrite(SER, HIGH);
digitalWrite(SRCLK, LOW);
digitalWrite(SRCLK, HIGH);

//Shift to the output register
digitalWrite(RCLK, LOW);
digitalWrite(RCLK, HIGH);

//G on
digitalWrite(SER, LOW);
digitalWrite(SRCLK, LOW);
digitalWrite(SRCLK, HIGH);

//Shift to the output register
digitalWrite(RCLK, LOW);
digitalWrite(RCLK, HIGH);

//F on
digitalWrite(SER, LOW);
digitalWrite(SRCLK, LOW);
digitalWrite(SRCLK, HIGH);

//Shift to the output register
digitalWrite(RCLK, LOW);
digitalWrite(RCLK, HIGH);

//E off
digitalWrite(SER, HIGH);
digitalWrite(SRCLK, LOW);
digitalWrite(SRCLK, HIGH);

//Shift to the output register
digitalWrite(RCLK, LOW);
digitalWrite(RCLK, HIGH);

//D off
digitalWrite(SER, HIGH);
digitalWrite(SRCLK, LOW);
digitalWrite(SRCLK, HIGH);

//Shift to the output register
digitalWrite(RCLK, LOW);
digitalWrite(RCLK, HIGH);

//C On
digitalWrite(SER, LOW);
digitalWrite(SRCLK, LOW);
digitalWrite(SRCLK, HIGH);

//Shift to the output register
digitalWrite(RCLK, LOW);
digitalWrite(RCLK, HIGH);

//B On
digitalWrite(SER, LOW);
digitalWrite(SRCLK, LOW);
digitalWrite(SRCLK, HIGH);

//Shift to the output register
digitalWrite(RCLK, LOW);
digitalWrite(RCLK, HIGH);

//A Off
digitalWrite(SER, HIGH);
digitalWrite(SRCLK, LOW);
digitalWrite(SRCLK, HIGH);

//Shift to the output register
digitalWrite(RCLK, LOW);
digitalWrite(RCLK, HIGH);

digitalWrite(OE, LOW);

}

void loop() {
// put your main code here, to run repeatedly:

}

If you build, compile, and run this, then you’ll see the number 4 is displayed.

If you look, the first bit of data is our decimal point (DP), and we shift data to the left so that our last data out is our A segment. Now, go ahead and modify this so that we only have one DP on and everything else is off. Now, add an additional SRCLK and RCLK increment. You’ll see that all the segments are off! This process of data movement, where the first piece of data in becomes the first piece of data out (First In First Out\FIFO) is called a queue. Now, for international readers, you’re already familiar with this term, but for my fellow Americans, this is a line. The first person in line is the first person leaves.

You can now play with this to create a 0 — 9 counter. As a hint though, you’ll want to put a delay(####) where #### is a number (1000 = 1 second) so you can watch the number increment.

That’s all for now.

Posted in Engineering | Tagged , , , , | Leave a comment

2019/02/03 Updates!

It’s been a while and boy does the new WordPress layout stinks (v5). It looks like it was designed for mobile interfaces…

Anyway, there are some weird things going on with the site, as some of you may have noticed weird timeouts. If I have time, I’ll look into those.

I do have a lot of stuff going on and I’ll hopefully have a new post somewhat soon. I have some pics from NYC to post as well as a tech project. Here is a sneak peek.

Posted in Announcements | Leave a comment

Reading analog values over I2C

So I’m back again with another I2C device made by NXP. My last one did I2C to SPI, but we’re here to do ADC.

Now, if you’re the average Arduino user, then you have 6 ADC ports on your Uno, so why would you need any more? Well, you probably don’t, but if you’re using an ESP8266, then the onboard ADC is kinda garbage as it only tolerates values up to 1V. For some devices, this may not work as they require or output values greater than that.

I’ll be using the NXP PCF8951. A quick search looks like it can be purchased in DIP form, but I’m using a SO-16 (SMD). From the datasheet, we have the following pinouts:

If you’re familiar with any I2C device, then a lot of these pins should look familiar:

  • The A0-A2 lines are to determine the address (it starts at 0x48 – 0x4F for Arduino).
  • Vss goes to GND and Vdd to +5v.
  • SDA goes to the SDA pin on the Arduino, and likewise for SCL.

For this example, we’re going bring all of the address lines to GND. Vref is pulled to Vdd, but this isn’t needed for this example as this will be ADC, but that’d be your max output value when converting a digital value to analog. The same goes for AGND, except this will be the corresponding GND (useful if you’re using this with a separate and unrelated GND).

EXT and OSC relates to using an oscillator. The datasheet says:

8.6 Oscillator
An on-chip oscillator generates the clock signal required for the A/D conversion cycle and for refreshing the auto-zeroed buffer amplifier. When using this oscillator the EXT pin must be connected to VSS. The oscillator frequency is available at the OSC pin. If the EXT pin is connected to VDD, the oscillator output OSC is switched to a high-impedance state allowing to feed an external clock signal to OSC.

For what we’re doing, we’ll just set EXT to low.

We’ll put two pull-up resistors on the SDA and SCL lines (as per usual). We’ll tie our non-used analog lines to GND (A1-A3).

Finally, for our actual device, we’ll connect our Analog Out to A0. In my case I’m using a cheap moisture meter (FC-28, for those playing alone at home), but you can use whatever you want. I’ve left it purposefully ambiguous in the circuit diagram.

Speaking of witch, if you have everything set up correctly, your breadboard should look like this:

Time to code!

I’m going to assume that you have the prerequisite libraries and such and don’t need an explanation on them. I’ll include that stuff in my code, but I won’t go in depth.

If we look at Figure 18 in the datasheet…hold on, I can’t harp on it how much you NEED to read the datasheet! Take my examples and use them to learn how to read the datasheet.

Anyway, if we look at Figure 18, we can figure out what commands we need to read from different values (or write them):

Since we just want to read from A0 on the chip, we’ll write 0x00 to the device from our Arduino. If you want to do A1, then you’d send 0x01, and so on. Now if all four of your analog ports have devices you want to read from, you can use the auto-increment flag and send 0x05 and read multiple times.

Anyway, here is the code as promised. It’s extremely short. As you run this, you’ll notice your max values might seem strange. For the answer why, you can easily find that in the datasheet. 😉


#include "Wire.h"
#define PCF8591 0x48

void setup()
{
Wire.begin();
Serial.begin(9600);
}

void loop()
{
int value = 0
Wire.beginTransmission(PCF8591);
Wire.write(0x00);
Wire.endTransmission();
Wire.requestFrom(PCF8591, 1);

value=Wire.read();

Serial.print(value);
Serial.println();

}

Posted in Engineering | Tagged , , , , | Leave a comment

TV Time! On the go! Part 1

Not too long ago, YouTube recommended this video to me about hacking a Sony Watchman:

I thought that was pretty neat and wondered what I could do with one, so I was able to pick one up for like $20, but if I just redid the experiment shown, then that would be boring and we may run out of those in the future. So instead, I purchased a Citizen Compact Pocket B&W LCD TV 06-TA (Which apparently cost $88!).

As we open this, we’ll see a TV tuner in there that we’ll want to remove. It is 10 pins and a pain in the butt to remove. I’ve highlighted the pins that connect to the tuner.

Now, with that removed, we can start looking at the good stuff! As mentioned in the above video, we have a MS1348FP on our board. Now, I didn’t go yanking it away, but I did experiment as shown below:

Now that we know this is the chip, we can remove it and (ab)use the datasheet and it’s pins for a composite out.

However, after removing it and hooking everything up, I found that composite video out isn’t quite right and has sync issues, so I’m going to have to come back with a follow up. 🙁

Posted in Engineering | Tagged , , , , | Leave a comment