Friday, January 01, 2016

Getting Q-logic 2532/2562 (qla2xxx) and Linux-IO SCSI Target Working On RedHat/CentOS 6.7

Having oodles of enterprise shit at work makes me a bit spoiled, so it's nice to have some sliver of that at home. So one of the things I've wanted to do for some time now is have as-real-as-possible-to-me fibre channel SAN to work with at home but do it as minimalistic as possible.

However, a few things that won't be happening:
  1. Not buying and/or firing up any sort of rack-mount entry/mid/enterprise storage array at my place
  2. Making my eletric bill any more hefty from the amount of shit already running in my little datacenter close
  3. Have my wife draft up divorce papers for increasing the amount of space I'm already taking up with my stuff
A few things that are essential requirements (for me) for this:
  1. Reusing whatever hardware I have at my place and not buying anything of significant real expense
  2. Keep a small footprint (e.g. contained a mini-ATX case at most)
  3. Operational and managable on top of a full OS installation of CentOS/RHEL 6.x
So, the compromise to all of this is a cheap, Brocade fibre channel switch and using Linux-IO SCSI target package.

If you did any sort of high-level googling, you'd see that are successful and documented examples of this here, here and here with newer Linux distro's using Linux Kernel 3.x and Linux-IO 3.x packages.

Reason For Doing This

The reason I am doing this:
  • Because I need something to do on my 2015 holiday break from work
  • I stubbornly still run RHEL/CentOS 6.x distros because of my ever loving HATE of 'system-d'
  • RHEL/CentOS 6.x uses a stable but relic 2.6.x kernel --- which Q-Logic HBA fibre channel target mode is not merged into (obviously)
  • Even with a support Linux kernel that has Q-Logic HBA fibre channel support (3.x+), the Linux-IO packages for RHEL/CentOS 6.x (fcoe-target-utils) still won't work and you have to re-build those so it picks up the support in configFS under sysfs.  Since the tools are written in python, without digging into any code in 'targetcli' or 'rtslib', I'm leaning towards 'rtslib' being the outdated piece of fcoe-target-utils.
  • I'm sure one could have tracked and gathered a bunch of patches to see if it's possible to merge the tcm_qla2xxx + sysfs changes into the stock CentOS 6.7 (2.6.32-573.el6.x86_64) but it's just easier to re-compile the whole thing.

What Else this is useful for

There seems to be a lot of buzz off other people's blog posts about even folks using RHEL/CentOS 7.x not being able to get qla2xxx working.  Again, I lean on either parsing in 'targetcli' or 'rtslib' as a complete wild ass guess being the issue, since tcm_qla2xxx module is already pre-compiled and availbale with the stock kernels.

My advice would be just skip down to the latest-and-greatest Linux-IO compilation builds to get yourself going.

Install Needed Packages

Depending on how you baseline your RHEL/CentoOS 6.x installs, you'll definitely want to install these packages via 'yum' (and possibly more).  I'll order these by the groups of things you'll need the packages for just so it makes sense as far as what is depended for what.

For Linux kernel compiling:

$ yum install gcc ncurses-devel kernel-devel lsscsi patch git -y

For Linux-IO configshell, rtslib and targetcli latest rebuild:

$ yum install python-devel epydoc python-pyparsing python-configobj python-prettytable -y

Extra RPMs you will have to hand-install and can easily find on for Linux-IO rebuild:

Build Linux 3.x Kernel (3.18.25)

This is a pretty clean-cut set of step(s) to get the kernel rebuilt and do the bare minimum tweak of enabling the build of the Q-logic TCM_QLA2XXX fabric module for Qlogic 2xxx series target mode HBAs:

Download and Unpack Linux Kernel Source

First step is to download and unpack the Linux kernel source:

$ wget --no-check-certificate
$ tar zxvf linux-3.18.25.tar.xz

Copy Existing Kernel Configuration and Configure Kernel Build

Next is to copy over our latest stock kernel configuration for our CentOS as a starting configuration point so, if you want, you can build at a minimum what you have configured in your big, bloated distro kernel plus whatever you are going to enable.  Do note, there are numerous changes between 2.6 and any 3.x or 4.x kernel, so again, I'm not advocating this, but for the sake of 'getting shit done via blog directions', it'll do.

Let's change directory into the kernel source and run our ncurses text-based kernel configuration menu:

$ \cp /boot/config-2.6.32-573.el6.x86_64 /path/to/linux-3.18.25/.config
$ cd linux-3.18.25
$ make menuconfig

You'll want to, at a minimum, navigate to the following menu tree to enable Q-logic TCM_QLA2XXX fabric module for Qlogic 2xxx series target mode HBAs:

   -> Device Drivers                        
     -> SCSI device support           
       -> SCSI low-level drivers (SCSI_LOWLEVEL [=y])
         -> QLogic QLA2XXX Fibre Channel Support (SCSI_QLA_FC [=m])
          -> [m] TCM_QLA2XXX fabric module for Qlogic 2xxx series target mode HBAs

You can toggle on module (e.g. m) build by using your space-bar.  Then exit out of the menu's and save the configuration.

If you're super leery if you did the right thing or not, run this:

$ cat linux-3.18.25/.config | grep -q "CONFIG_TCM_QLA2XXX=m" && echo "enabled" || echo "not enabled"

...if you see 'not enabled' echo'd on the screen, you didn't get it enabled.  So you can either hand-edit that configuration line into '.config' or go back through ncurses menuconfig and re-enable it.  Either or will work.

Once your configuration is saved, we can build the linux kernel.

Build the Kernel and Modules

To build the kernel and it's accompanied modules, simply type:

$ make -j4 bzImage modules

...then go get some coffee.  If you compile with all the CentOS configured extra modules and add-in's you had with your stock os kernel, you're looking at just under one hour for a multi-threading build above.

Also, you'll definitely want to adjust '-j <n>' to your tastes; this runs automake with <n> threads.  Try to, at a minimum, make <n> equal to the number of cores you have on your system you are building on.

Install and Boot Into 3.x Kernel

After your kernel and modules build (successfully, I hope), it's time to install the kernel and the modules onto your system.  The linux kernel build strap scripts have come a LONG ways over the years and they work pretty flawelessly.

Add 'qla2xxx' target mode parameter for kernel module

This is an important step so prior to using the kernel build strap scripts for installing the kernel modules and invoking 'dracut', will automagically grab these options and incorporate them into your ramdisk (e.g. initrd).

Run the following command(s) to add the target mode enable options for the qla2xx fibre channel module:

$ echo "options qla2xxx qlini_mode=\"disabled\"" >> /etc/modprobe.d/qla2xxx.conf

Install Kernel, Modules and config

To install the kernel modules, do the following:

$ make modules_install

To install the kernel, do the following:

$ make install

This isn't a necessary step, but for the sake of making our custom kernel 'look and feel' the same, let's copy over the configuration as well to the /boot directory:

$ cp linux-3.18.25/.config /boot/config-3.18.25

Double-check the GRUB2 entries in '/etc/grub.conf' as well.  If you're super paranoid, you may also want to look at the contents of your in ramdisk (e.g. initrd) to make sure you got the 'qla2xxx' and 'tcm_qla2xxx' modules in there.

Reboot into New Kernel

Let's reboot your system:

$ init 6

We are going to assume you're going to leave your existing, distro-built kernel as 'default' and you'll manually select the 3.18.25 kernel from your GRUB menu.

If you don't and want to boot into this from the get-go without any intervention (e.g. maybe you're running a headless box like I am OR you're cocky as shit), just edit '/etc/grub.conf' and change the following line back to:

default=0 the bootloader defaults to the first-most kernel entry, which the linux kernel build strap scripts will put your new kernel at the top of the available kernels-to-boot list.

Do whatever you want to do.

Verify Kernel Installation

To do a quick kernel installation verification, obviously having the system back and booted is a probably the top indicator.

Next, let's verify the kernel we are booted into is, in fact, the one we built (sounds funny, but I have shot myself in the foot MANY times by overlooking that and skipping a few steps doing this by-the-cuff):

$ uname -r

Next, lets verify that our Q-logic module(s) can be loaded (assuming the card isn't plugged into any SAN fabric or have any existing storage attached/zoned to it).  You should see similar when running 'dmesg':

$ dmesg | grep -i qla
qla2xxx [0000:00:00.0]-0005: : QLogic Fibre Channel HBA Driver:
qla2xxx [0000:02:00.0]-001d: : Found an ISP2532 irq 16 iobase 0xffffc90004afe000.
qla2xxx 0000:02:00.0: irq 26 for MSI/MSI-X
qla2xxx 0000:02:00.0: irq 27 for MSI/MSI-X
scsi host10: qla2xxx
qla2xxx [0000:02:00.0]-00fb:10: QLogic QLE2560 - PCI-Express Single Channel 8Gb Fibre Channel HBA.
qla2xxx [0000:02:00.0]-00fc:10: ISP2532: PCIe (5.0GT/s x8) @ 0000:02:00.0 hdma+ host#=10 fw=7.03.00 (90d5).

Lastly, lets load the target SCSI module we added and make sure that loads:

$ modprobe tcm_qla2xxx

Build the Latest Linux-IO Packages

Below are to-the-points steps to rebuild the latest and greatest Linux-IO packages you'll need since even after having the new kernel that supports Q-logic 256x target support, the current relic 'targetcli' package set still won't work.

Make sure 'fcoe-target-utils is Uninstalled

Before we go any further, let's make sure anything related to the stock distro 'fcoe-target-utils' is uninstalled and NOT on our system:

$ yum remove fcoe-target-utils python-rtslib python-configshell -y

Build and Install Configshell

To build and install the latest/greatest configshell, do the following command(s):

$ git clone
$ cd configshell
$ make rpm
$ cd dist
$ rpm -ivh python-configshell-1.6.1~g020d540-1.el6.noarch.rpm

Build and Install RTSLib

To build and install the latest/greatest RTSLib, do the following command(s):

$ git clone
$ cd configshell
$ make rpm
$ cd dist
$ rpm -ivh python-rtslib-3.0.pre4.9~g6fd0bbf-1.el6.noarch.rpm

Build and Install TargetCLI

To build and install the latest/greatest TargetCLI, do the following command(s):

$ git clone
$ cd configshell
$ make rpm
$ cd dist
$ rpm -ivh targetcli-3.0.pre4.5~ga125182-1.el6.noarch.rpm

Verify 'targetcli' is working

Lastly, a simple verification and what will look different from using the 'fcoe-target-util' package targetcli command is the actual qla2xxx target config being loaded so you can set up your block storage backstores for export.  You'll also notice in the output of targetcli it references the rtslib build version we just build and installed via RPM, too:

$ targetcli
targetcli 3.0.pre4.5~ga125182 (rtslib 3.0.pre4.9~g6fd0bbf)
Copyright (c) 2011-2014 by Datera, Inc.
All rights reserved.

/> qla2xxx/ info
Fabric module name: qla2xxx
ConfigFS path: /sys/kernel/config/target/qla2xxx
Allowed WWNs list (free type): 21:00:00:24:xx:xx:xx:xx
Fabric module specfile: /var/target/fabric/qla2xxx.spec
Fabric module features: acls
Corresponding kernel module: tcm_qla2xxx
/> ls
o- / ............................................................................................................. [...]
  o- backstores .................................................................................................. [...]
  | o- fileio ....................................................................................... [0 Storage Object]
  | o- iblock ....................................................................................... [0 Storage Object]
  | o- pscsi ........................................................................................ [0 Storage Object]
  | o- rd_mcp ....................................................................................... [0 Storage Object]
  o- loopback .............................................................................................. [0 Targets]
  o- qla2xxx ............................................................................................... [0 Targets]
That's it (in a big nutshell)! You should now be able to continue on setting up your block storage to front as a backstore from your newly set up fibre channel target.

Monday, August 31, 2015

Adding 'Hack' monospace font functionality into Spyder IDE in Fedora Core 21

As of late, a lot of the code I have been hacking out for just about anything has been straight, 100% Python.  With that, I've also ditched 'vi' + plugins and have grown extremely comfortable (and probably complacent?) using Spyder IDE GUI.  I never wanted to be GUI dependent (again) but I am, so whatever.  I deal with it.

But, recently, I saw a post on touting the coolness of Hack, an open-source monospace font marketed towards the code slingers of the world.

I undoubtedly get tired of using of the defacto DejaVu and Liberation monospace fonts and decided to give this a shot.  And quite honestly, even though it's subtle, I really like it.

Characters of note:  I don't notice the lowercase-L vs. the numeral 1 as much as I do the zero vs. uppercase-O and lowercase-I curvature.

Font sizes:  I think my favorite font size is 9px or 11px (11px especially if I've been staring at my monitor for more than 4 hour straight with contacts in to boot!)

The overall font character scheme also seems a bit more compressed as well, which is nice so I 'feel' like I'm getting more width real-estate.  Case in point:  take it for what it's worth.

Even though this is a less traditional and definitely 'non-distro' way to add an overall font to your OS, I think it gives most people the flexibility enough to give it a shot themselves with as minimal overhead as possible, especially if you want it 'long-term' and want to put it in the same place as your other distro fonts via package management without creating a distro package for it.

Here's how to make the 'Hack' monospace font accessible in Spyder IDE under Fedora (or any other RHEL based OS for that matter).

If you really want to get technical and overview-ish, I guess this would be a good way to hack-and-slash 'any' font you want to Spyder, monospace or not.

Download and Unzip 'Hack' Font from SourceFoundary

Go to Hack's SourceFoundary site and download the True-Type font .zip archive.

Once you have downloaded the 'Hack' fonts, simply unzip them wherever you want:

$ cd /path/to/hack/fonts/
$ unzip
  inflating: Hack-Bold.ttf           
  inflating: Hack-BoldOblique.ttf    
  inflating: Hack-Regular.ttf        
  inflating: Hack-RegularOblique.ttf

Add 'Hack' font into to your OS

Adding the Hack monospace font (this way) is pretty trivial.  The key point here is to know the top-level path where your Linux distro stashes it's fonts.  For a font like this that I really want to use long-term, I think this is a better solution than putting it in ~/.fonts/  or equivalent. I'm also going to assume you have proper privileges to do all these command(s) or know how to obtain it (e.g. NOT prefacing the sudo command to obvious root-level stuff)
  • Create a new directory for the 'Hack' font in your Linux distro's top-level system font path
  • $ mkdir /usr/share/fonts/hack
  • Copy fonts over
  • $ cp -a /path/to/hack/fonts/Hack-*.ttf /usr/share/fonts/hack/
  • Make sure permissions + ownership are sane on your font directory and fonts
  • $ chown -R root:root /usr/share/fonts/hack && chmod 755 /usr/share/fonts/hack
Changes to Spyder IDE

I'm using Spyder IDE v2.2.4, so YMMV if you're using another version.  I didn't go scout all this out, but it's pretty self-explanatory.

Spyder IDE has a default, hard-coded list of approve and available monospace fonts that are defacto standards.  All you have to do is alter the list data structure defining the list of monospace fonts in spyderlib.

To do this, you'll want to look for the following line of code in /usr/lib/python2.7/site-packages/spyderlib/ module:

MONOSPACE = ['Monospace', 'DejaVu Sans Mono', 'Consolas', 'Monaco',
                'Bitstream Vera Sans Mono', 'Andale Mono', 'Liberation Mono',
                'Courier New', 'Courier', 'monospace', 'Fixed', 'Terminal']

...and add in the 'Hack' fonts into the MONOSPACE list structure so it looks something like this:

MONOSPACE = ['Monospace', 'DejaVu Sans Mono', 'Consolas', 'Monaco',
               'Bitstream Vera Sans Mono', 'Andale Mono', 'Liberation Mono',
               'Courier New', 'Courier', 'monospace', 'Fixed', 'Terminal',
               'Hack-Regular', 'Hack-RegularOblique.ttf', 'Hack-Bold.ttf',

NOTE:  There are several '' modules in Spyder IDE, so if you're really confused at this point, just do a case-insensitive recursive grep (e.g.  grep -i -R "MONOSPACE" /path/to/spyderide/site-package/install) and find the right one to edit.

Restart Spyder IDE and Choose 'Hack' as your Font

If you still have Spyder IDE running, close it and re-open it.

Then on Sypder's top menu bar, you'll want to navigate to 'Tools > Preferences', then select the 'Editor' option on the left-hand side.  Now, if you select the 'font' drop-down menu, you should see 'Hack' available for your choosing:

You can now click 'Apply' and watch all those wonderful tabs of 'code' change over to using 'Hack'.

If you also want your Python console in Spyder to use this font as well, just select 'Console' and change it there, too.

Before-and-After of Hack vs. DejaVu Sans

Here's a couple of quick screenshots put in extra-large to show the differences of Hack vs. DejaVu Sans out-of-the-box Spyder IDE font:

DejaVu Sans - Normal - 9px

Hack - Normal - 9px

Now as much as I'd want to package this into an RPM for my own sake in case some update comes about, that would just be more work than it's worth.


Wednesday, October 09, 2013

United States Government Furlough - Day 1 through 9

One thing about being a government contractor is that, well, you guessed it:  You're susceptible to consequences of the indecisiveness on "Capital Hill" and shear inability of elected Congress members and our President to get their shit together on the tax payer's dime.  In other words:  A U.S. Government shutdown.

I do have to say, at first, it was kind of interesting-yet-cool to be told that you can't come to work until an undetermined day in future, but you're not fired, laid off and you still retain employment.  Anyone in the mid-west or east coast can kind of relate it to getting a 'snow' day from the public school system; it was 'cute' and 'cool' for the first few days, but after that, it starts to wear on you really quick after the reality replaces the shock value --- things like 'homework' aren't going to go away and in the end your school system principal is going to more than likely extend the school remaining school days and/or classes to make up all that 'lost' time.  If you get too many days off, it could cut right into your summer and lengthen your school year clear into June.  Case in point:  It may seem free-and-fun, but it you will ultimately have to make up that time to a certain extent no matter anyway.

As most of us government contractors sit around, burning up their sick time and vacation, hoping for an end date for all of this, at least for me, it's been a good time for self-reflection.  As with most situations that are totally out of your control yet affect you, you really have to shrug it off and stay motivated.  No matter how positive you are about any of this, reality of life is just that:  reality.  My bills, mortgage, groceries, family, kids, expenses, holidays aren't getting a life 'pause' button, and there's only so much you can float before you have to start making some 'big' decisions --- apply for new job?  Leave-without-pay?  Start hitting the savings account?  Get unemployment check?  Find side work?  

I have chosen to not beat myself up about this too much.  I certainly haven't sat on my ass and been pouting --- So this is what I've been up to:

Day 1 (10/1/2013):
 - Came home at 10:30am, said "eff you world"
 - Started up the grill and made myself one HELL of a burger:  Bacon Chedder Burger + Fried egg + Thick Applewood Bacon + Sharp Chedder and Pepperjack cheese
 - Poured myself a Black-and-Tan
 - Laid out in my hammock for a few hours and enjoyed the cool, Fall day
 - Volleyball practice with the 6th grade girls.

Day 2 (10/2/2013):
  - Winterized lawn and put in tree feeder stakes
  - Had lunch with some of my 'furlough' friends from work at Qdoba mexican restaurant

Day 3 (10/3/2013):
 - Changed the oil in the snow blower to get ready for winter
 - Put some of the kids bikes/scooters away
 - Played 'Gyruss' and tried to beat my wife's high score.  Unsuccessful.
 - Had 6th grade volleyball practice and had a heck of a good time watching the girls put together a pre and post game motivational cheer.  Good stuff.  

Day 4 (10/4/2013):
 - Played guitar --- working on a few new tunes I'm acoustic-ifying (pretty sure that isn't a word, but now it is).  Still need to break out the electric, it's been WAY too many months.  
 - Went out with one of my good buddies to Old Chicago --  had wings, pizza, artichoke dip and beers.  Didn't get the shitty waitress we always dread, so it was a good night.

Day 5 (10/5/2013):
 - Played against Sioux Valley in 6th grade Volleyball.  The girls did fantastic, took it down to the 3rd set and pulled out a win.  Very excited and very proud of them as a team.  It's been great coaching them.
 - Stayed at home, picked up the house and did a shitload of dishes.  
 - Hung out with my mom before she she flies out to AZ.

Day 6 (10/6/2013):
 - NFL Football all day.  (This is a repeating event every Sunday --- don't expect much more).  Thank you Peyton Manning yet again (see FFB plug below) 
 - Pulled out a win in a FFB league and lost in another.  Still maintaining a good league ranking of 4th and 2nd.
 - Helped my daughter make a blue whale sculpture for school out of home-made play-dough that we oven baked to harden up.

Day 7 (10/7/2013):
 - Got some more of my 'carpentry skills' on; cut-down and shrunk a kitchen cabinet down by 1/2" in width to fit between a neighbors newly purchased and slightly oversized refrigerator and stove.
 - Played some more guitar --- still rocking the acoustic for some reason.
 - Watched Monday Night Football:  the Atlanta Falcons, yet again, fail to beat someone this year and take a loss to the Jets.  Julio Jones re-breaks his foot.  Might not even get a wildcard into the playoffs.  What's my motivation when even my football team is playing like shit?  Talk about a life crutch being kicked out from under you.

Day 8 (10/8/2013):
 - Played 'Gyruss' and tried to beat my wife's high score.  Still unsuccessful.  Damnit.
 - Started working again on my Python project to automate some OS-level package builds I do at work --- well that it, when I can work.  Regardless of where that effort will be put to use, it's still a challenging coding endeavor.
 - Set up some Halloween/Fall decorations, pumpkins and shit outside.  Looks pretty good.  Still have my Pac-man pumpkin lightup to get set up.
 - Made some home-made pizza on the pizza stone.  The dough turned out awesome.  It was a good eating night for sure.

Day 9 (10/9/2013):
 - Played guitar --- worked on an acoustic solo bit along with the rhythm to Black Label Society - Stillborn.  It's coming together well, but I'm no Zakk Wylde.  Still need to get the damn electric out (LAZY)
 - Picked up a Banana Bread Beer by some company from the local spirits place.  Not too bad --- certainly not something I'd have more than one-in-a-row of.
 - Went over to one of my 'furlough' friend's house, and re-created the bacon cheddar egg-bacon burger from Day 1.  Plus added a jalapeno brat to the plate.  Holy shit.  Very good.
 - Thought I would play 'mechanic' and replace my EGR valve in my truck.  That was a train wreck when my truck started to idle like shit, produce some vacuum issue and stall.  Fixed it, all is right with the universe again.
 - Played 'Gyruss' and tried to beat my wife's high score.  Fail again.  I will concur and shit all over that high score soon.
 - More coding on the remote-build-service project (Python project)
 - Swept some silica sand on the patio to fill in any cracks or musing from bastard ants before winter. 

Sunday, January 20, 2013

1PPS Support with GPIO For Raspberry Pi in Fedora 17 Remix

One of my projects as of the last 5 months (although slow going) is making a full-out stratum-1 time server appliance out of the Raspberry Pi.  I'm going to be using an EM408 GPS module + generating my own 1PPS signal with an AVR attiny84 microcontroller inputting into GPIO on the Pi, and if i have enough GPIO left, will be driving a 16x4 LCD parallel output-only display for fun as well.

When it comes to just using the Raspberry Pi as a NTP stratum-1 server, there's quite a few documented artifacts out there on the internets already being done, most notably from David Taylor's excellent documentation on his website.  

It's worthy to note that most, if not all, Raspberry Pi Linux distribution spins DO NOT come with CONFIG_PPS or CONFIG_PPS_CLIENT_GPIO compiled into the kernel or as modules.  

I'm not totally down with the amount of hackery floating around to insert dirty modules into the kernel.  Ya, it works.  Yes, if you have  CONFIG_MODVERSIONS set, then you should be able to install modules not compiled with your kernel into it.  However, I'm rolling with Fedora 17 remix and option isn't compiled in with the stock kernel.  So either way, I had to result to building my own RPMs for this.  

If you're interested in getting 1PPS supprt on the Raspberry Pi via GPIO (like I and many other time enthusiasts are), then here's some steps to get you in the right direction.  Below are some options you have:

Download 1PPS Packaged RPM for Fedora 17 Remix

Here's a link to my binary RPM package for 1PPS, which includes support for:
  • PPS Support (CONFIG_PPS=m)
  • PPS Source using GPIO pin (CONFIG_PPS_CLIENT_GPIO=m)

NOTE:  Yes, I am using the FC 18 source rpm, but they will install on FC 17.  I have tested.

Build your own Kernel + RPMs

There's quite a few step(s) I'll omit since it's clearly beyond the scope of this blog post, but here's a quick and dirty run-down on how to do it on an RPM-based Linux distribution:

1)  Build yourself a soft-float ARM cross compiler (at least for Fedora 17 remix) using crosstool-ng

2)  Set up your RPM build environment using `rpmdev-setuptree`

3)  Download the raspberry-pi-kernel source RPM from here

4)  Patch the kernel config ( in SOURCES folder) and .spec file (in SPECS folder) using `patch` with my patches that are posted on the Fedora Remix as an 'enhancement' option:

5)  Rebuild kernel package + sub-packages with:  

# rpmbuild -bb --clean --target=armv5tel raspberrypi-kernel.spec

6)  Copy 'at least' the kernel-pps RPM package to you RPi and install with:

# rpm -ivh raspberrypi-kernel-pps-3.2.27-1.20120926git9245b4c.rpfr18.armv5tel.rpm

7)  On the RPi, run:

# modprobe pps-gpio

     ...then verify the module loaded correctly with:

# dmesg

     ...and look for some output like:
[ 1404.141098] pps_core: LinuxPPS API ver. 1 registered
[ 1404.141123] pps_core: Software ver. 5.3.6 - Copyright 2005-2007 Rodolfo Giometti 

Do note that applying my patches in step #4 will also apply some of my other .spec file changes that change the way the kernel image is built and installed on the FC remix distro.  Do take a look at the changes and don't apply blindly if you can help it.  This only matters if you plan to install my kernel RPM.


Saturday, January 05, 2013

Calculating NMEA sentence checksums with Python

Another feature I wanted to add to my NTP/GPS project I'm doing with my Raspberry Pi is to validate the NMEA sentences I'm reading in by checksum'ing the NMEA sentence and comparing it with the XOR checksum provided from the GPS receiver.

This is especially important if you plan on writing an application that is reading $GPGGA, $GPGLL or $GPRMC sentences for timekeeping purposes and want to validate the sentence you read for time is legit or not.

Background on NMEA Checksums

After reading some documentation on NMEA sentence types and, more importantly, about checksums, the process is actually quite easy and can be coded up fairly easily.

Here's the main blurb from the NMEA documentation about the checksum and how to calculate it:
Programs that read the data should only use the commas to determine the field boundaries and not depend on column positions. There is a provision for a checksum at the end of each sentence which may or may not be checked by the unit that reads the data. The checksum field consists of a '*' and two hex digits representing an 8 bit exclusive OR of all characters between, but not including, the '$' and '*'. A checksum is required on some sentences.
Not so hard, right? We need to exclusive OR (XOR) all of the characters (INCLUDING the commas) between the '$' and the '*'. 

Let's do it!

NMEA Sentence Breakdown

Here's a NMEA sentence example that I will use to show the XOR process on:


The color breakdown is:

            Black: Two positional characters in the NMEA sentence we need to read our characters 
                      from between
            Green:  Characters we need to XOR
            Blue:  The calculated checksum we need to compare our calculated checksum against

Bitwise XOR on NMEA Sentences

As the documentation states, we need to exclusive OR (XOR) all of the characters (INCLUDING the commas) between the '$' and the '*'.

The process is quite simple: We want to take each character and XOR it with the previous XOR'd output from the last character. The very last character that is XOR'd will be the final checksum value that you'd then compare with the checksum value.

If you're a bit fuzzy on on XOR, the bitwise operator in most programming languages is ' ^ ' and the rules are as follows:

  • 1 ^ 1 = 0
  • 1 ^ 0 = 1
  • 0 ^ 1 = 1
  • 0 ^ 0 = 0

One thing to note, when you start of XOR'ing, you'll want to compare your first character with zero (e.g. 0, 0xFF, 0b0, etc.) so on the next character iteration (which would be the 2nd character in the NMEA string) will XOR against the binary value of the first character.  Why is this so?  If you look at the XOR rules above, we only need one bit 'on' (or '1') on to bit-flip-it and keep it 'on' (or '1').  So if we XOR against '0', we get our original value back.

Let's use our example sentence above to go through a handful of binary XOR iterations of what we'll be accomplishing in code:

0b0000000     0
0b1000111     G
0b1000111     XOR output
0b1010000     P
0b0010111     XOR output
0b1000111     G
0b1010000     XOR output
0b1000111     G
0b0010111     XOR output
0b1000001     A
0b1010110     XOR output
0b0101100     ,
0b1111010     XOR output
0b0110001     1
0b1001011     XOR output


0b1010000     XOR output
0b0110000     0
0b1100000     XOR output
0b0110000     0
0b1010000     XOR output
0b0110000     0
0b1100000     Our checksum (96 decimal, 0x60 HEX)

As you can see, we ended up with '0x60' which is the same as our example sentence above of '*60'. So we were able to validate this NMEA sentence!

NMEA Checksum Python Code

Now that we got the explanation out of the way, let's look at the code.  It's really simple:
def chksum_nmea(sentence):
    # This is a string, will need to convert it to hex for 
    # proper comparsion below
    cksum = sentence[len(sentence) - 2:]
    # String slicing: Grabs all the characters 
    # between '$' and '*' and nukes any lingering
    # newline or CRLF
    chksumdata = re.sub("(\n|\r\n)","", sentence[sentence.find("$")+1:sentence.find("*")])
    # Initializing our first XOR value
    csum = 0 
    # For each char in chksumdata, XOR against the previous 
    # XOR'd char.  The final XOR of the last char will be our 
    # checksum to verify against the checksum we sliced off 
    # the NMEA sentence
    for c in chksumdata:
       # XOR'ing value of csum against the next char in line
       # and storing the new XOR value in csum
       csum ^= ord(c)
    # Do we have a validated sentence?
    if hex(csum) == hex(int(cksum, 16)):
       return True

    return False

There you have it!

Parsing NMEA sentences from GPS with Python + PySerial

I've had a need to parse some NMEA output on my Raspberry Pi for a project I'm working on. In essence, it is pretty trivial to read from a serial port and parse ASCII data in any programming language, but to build some resiliency and efficiency in need to be handled with some care.

I happen to interfacing with an EM-408 GPS module with my Raspberry Pi off the GPIO Rx/Tx USART GPIO pins.

If you need a quick reference for NMEA sentence standard, go here.

Working with PySerial

Below is a quick and dirty code sample to interface with a USART/serial interface. The biggest thing to take into consideration is the 'timeout' option when creating your serial.Serial() object.

From my trial and error process, specifying timeout=0 (e.g. no blocking at all), while makes some sense in a GPS NMEA sentence polling application to return immediately and keep reading output, it causes serious amounts of CPU overhead (almost 100% utilization).

Eliminating the timeout altogether (wait forever) isn't a great idea either because your code will endlessly block/wait for output from the GPS module; not good if the module ever dies/power loss/etc.

Setting a gracious timeout of 5-10 seconds (e.g. timeout=5 or timeout=10) seems to help out as well and end up being the best of both worlds.

Here's a snipit of my class for the EM-408:

import serial 

class EM408GPS:
    def __init__(self, serialport, baudratespeed):

        self.gpsdevice = serial.Serial(port=serialport, baudrate=baudratespeed, timeout=5)

    def init(self):
        if self.isOpen():
            return True
        return False

    def open(self):
    def isOpen(self):
        return self.gpsdevice.isOpen()

That rough class sketch should be a perfect class wrapper to get you going with interfacing with a GPS via serial port or USART pins on the Pi.

Reading data with PySerial: Buffer or Newline?

This was the most interesting piece so far with. PySerial has a handful of methods for reading data that I tested with:

  • read(): This method reads the size of bytes from serial port input buffer.
  • readline(): This method reads serial port data down until a "\n" (newline) character is observed, then returns back a string.

    To be clever and witty, you'd generally want to use something like readline() since each NMEA sentence that it output to the serial port is terminated with a CRLF, right? I mean, why the hell wouldn't you? The answer is wrong the second you notice the very high CPU utilization happening when reading data.

    The good thing is this isn't a new problem, as it's a documented quite extensively on stack overflow amongst other places.

    The better way I found to attack this CPU utilization problem, is to take advantage of another method that PySerial offers:

  • inWaiting(): Return the number of bytes currently in the input buffer.

    ...and used this in combination with reading just '1' byte with read() then read whatever is left in PySerial's input buffer, then return for me to parse.

    Here's my class method called 'readBuffer()' partly solves this issue:

    def readBuffer(self):
                data =
                n = self.gpsdevice.inWaiting()
                if n:
                    data = data +
                return data
            except Exception, e:
                print "Big time read error, what happened: ", e

    The next part to deal with is now that we are reading everything out of the input buffer, our NMEA sentences aren't exactly in sentence order anymore.

    Now we have to leverage a bit of coding to properly find the start and end of a NMEA sentence. It's not too bad of an effort since we know a NMEA sentence starts with a '$' and ends with 'CRLF'. The key point is to find the CRLF in your read data buffer, then ensure to use the right end of that CRLF split (which is the start and some data of your other NMEA sentence) as the new start of the data buffer to construct the next line until you find the next CRLF, and so on...

    Here's the code snipit from my main() area that shows the initialization of the GPS and the read out of the NMEA sentences from my readBuffer() method:

    import re
    def main():
        device = EM408GPS("/dev/ttyAMA0", 4800)
        newdata = ""
        line = ""
        while device.isOpen():
             # If we have new data from the data CRLF split, then 
             # it's the start + data of our next NMEA sentence.  
             # Have it be the start of the new line
             if newdata: 
                 line = newdata
                 newdata = ""
             # Read from the input buffer and append it to our line 
             # being constructed
             line = line + device.readBuffer()
             # Look for  \x0d\x0a or \r\n at the end of the line (CRLF) 
             # after each input buffer read so we can find the end of our 
             # line being constructed
             if"\r\n", line):
                 # Since we found a CRLF, split it out
                 data, newdata = line.split("\r\n")
                 print "----" + str( + "----"
                 print data
                 # Reset our line constructer variable
                 line = ""

    Below is graphed output from 'vmstat' on the Raspberry Pi (in 2 second intervals) showing the performance benefit from using readBuffer() approach with read() + inWaiting() vs. using PySerial's readline():