Monday, January 12, 2015

Makefiles Made Easy

The bane of computer programming is the Makefile. As soon as there are more than one source file and a library, a Makefile becomes essential and generating one can be painful.  The Makefile syntax reminds me of a sendmail configuration file, which looks like someone banged his head on a keyboard.

# This rule ensures that all local mail is delivered using the 
# smtp transport, everything else will go via the smart host. 
R$* < @ $* .$m. > $* $#smtp $@ $2.$m. $: $1 < @ $2.$m. > $3 dnl

Obvious, yeah...

Same as with sendmail, you should never edit a Makefile manually.  It is a total waste of time.  There are nice and simple utilities to do it for you!

GCC -MM

If you have a very simple project, then gcc can generate the Makefile for you:
$ gcc -MM *.c > Makefile
$ make

Error: cc1plus

If you get the following or similar error regarding cc1plus, then the solution is not at all obvious:
gcc: error trying to exec 'cc1plus': execvp: No such file or directory

The problem is that while gcc is installed, g++ is missing:
# yum install gcc-c++

Also see the previous post for details on installing gcc.

CMake

If your project is more complex, then cmake can generate the Makefile for you, but you need to give it a few instructions in the file CMakeLists.txt.  First install cmake and related tools:
# yum install cmake*

Now create the file CMakeLists.txt and tell it which are the output, source and libraries:
project(FlashProject)
cmake_minimum_required(VERSION 2.8.12.2)
add_executable(flasher flasher.c)
find_library(FTDI ftdi)
target_link_libraries(flasher ${FTDI})

Note that gcc assumes that library file names start with lib and end with .so, therefore only specify the base ftdi or whatever, not libftdi.so.

The first time you run cmake, you need to specify the compiler:
$ CXX=gcc
$ export CXX

After that, run cmake to generate the makefile complete with all the obscure, head banging, gobbledygook lines:
$ cmake .
-- Configuring done
-- Generating done
-- Build files have been written to: /home/herman/sw/ftdi


Now you should have a very detailed almost 200 line Makefile and can compile your project with:
$ make

La voila!


Serial Port I/O

Until about 20 years ago, most desktop and portable computers had serial and parallel ports built in.  Those ports were great for controlling and testing home brew gadgets.  Modern machines are blessed/cursed with USB ports, which are just getting more and more complex.

The result is that if you want to do anything at all in your Underground Lab or Rooftop Radio Shack, you need an Arduino,  a Raspberry or a Beaglebone embedded computer.

However, every respectable engineer has two or three FTDI USB to RS232 serial adaptors lying in a drawer (to control his Raspberry or Beaglebone).  These adaptors are great, since they effectively insulate your target system from your expensive computer, therefore whatever goes wrong on the far end, is unlikely to fry your machine and they are delightfully hackable.

I prefer the dongles made by SerialComm.  They are cheap and both RS232 and RS422/485 are available.

You can also get ones from Sparkfun that are even more hackable, or you can crack the case and remove the line driver chip from a regular off the shelf one if you are desperate for TTL I/O lines.

The secret Open Sauce is the libftdi project, which is available for Linux and Mac systems. Documentation and examples are here.  The online files are the latest and greatest.  Therefore it may be best to work with the header file on your machine which is /usr/include/ftdi.h since your installed version of the library may be older and some functions may be deprecated or missing.

Simple Bitbanging with libftdi

Here is a tiny little C program for an older version of libftdi, that will toggle the Tx, DTR and CTS lines on a USB RS232 adaptor.  Note that you have to run it as root (or join some or other USB group), otherwise the USB device will not open.

/* File flasher.c */
/* libftdi API Example LED Flasher */

#include <stdio.h>
#include <ftdi.h>

/* RS232 DE9 pins */
#define DCD 0x40 /* 1 in */
#define RX  0x02 /* 2 in */
#define TX  0x01 /* 3 out */
#define DTR 0x10 /* 4 out */
#define DSR 0x20 /* 6 in */
#define RTS 0x04 /* 7 out */
#define CTS 0x08 /* 8 in */
#define RI  0x80 /* 9 in */
/* 5 GND */


int main()
{
    unsigned char data = 0;
    unsigned char pins = TX | DTR | RTS;
    struct ftdi_context context;

    /* Initialize libftdi */
    ftdi_init(&context);

    /* Open FTDI dongle using FT232RL vendor & product IDs */
    if(ftdi_usb_open(&context, 0x0403, 0x6001) < 0) 

    {
        puts("ERROR: ftdi_usb_open()");
        return 1;
    }

    /* Set bitbang mode on the RS232 output pins */
    ftdi_enable_bitbang(&context, pins);

    /* Forever */
    for(;;) 

    {
        data ^= pins;
        ftdi_write_data(&context, &data, 1);
        sleep(1);
    }
}


Improved Bitbanging with libftdi

Here is a more advanced program with proper error checking.  Note that you have to run it as root (or join some or other USB group), otherwise the USB device will not open.

/* File flasher.c */
/* libftdi.so API Example LED Flasher */
/* Copyright reserved Herman Oosthuysen, 2015 */
/* License: GPL version 2 or later */
/* Use at your own peril */

#include <stdio.h>
#include <stdlib.h>
#include <ftdi.h>

/* RS232 DE9 pins */
#define DCD 0x40 /* 1 in */
#define RX  0x02 /* 2 in */
#define TX  0x01 /* 3 out */
#define DTR 0x10 /* 4 out */
#define DSR 0x20 /* 6 in */
#define RTS 0x04 /* 7 out */
#define CTS 0x08 /* 8 in */
#define RI  0x80 /* 9 in */
/* 5 GND */


int main()
{
    int i;
    int ret;
    unsigned char data = 0;
    unsigned char outputs = TX | DTR | RTS;
    struct ftdi_context *ftdi;

    /* Initialize libftdi */
    printf("FTDI Initialize\n");
    ftdi = ftdi_new();
    if (ftdi == NULL)
    {
        fprintf(stderr, "ERROR: ftdi_new()\n");
        return EXIT_FAILURE;
    }

    ret = ftdi_init(ftdi);
    if (ret < 0)
    {
        fprintf(stderr, "ERROR: ftdi_init() = %d\n", ret);
        ftdi_free(ftdi);
        return EXIT_FAILURE;
    }

    /* Open FTDI dongle using FT232RL vendor & product IDs */
    /* Plug the device in and run 'dmesg' to see these codes */
    printf("FTDI USB Open\n");
    ret = ftdi_usb_open(ftdi, 0x0403, 0x6001);
    if (ret < 0)
    {
        fprintf(stderr, "ERROR: ftdi_usb_open() = %d\n", ret);
        ftdi_free(ftdi);
        return EXIT_FAILURE;
    }

    /* Set bitbang mode on the RS232 output pins */
    /* pins: Output = 1, Input = 0 */
    printf("FTDI set Bitbang Mode\n");
    ret = ftdi_set_bitmode(ftdi, outputs, BITMODE_BITBANG);
    if (ret < 0)
    {
        fprintf(stderr, "ERROR: ftdi_set_bitmode() = %d\n", ret);
        ftdi_free(ftdi);
        return EXIT_FAILURE;
    }

    /* Flash for a little while */

    /* Note: Use ftdi_read_pins() to read data directly */
    printf("FTDI Flashing...\n");
    for(i = 0; i < 10; i++)
    {
        printf("%d\r", i);
        data ^= outputs;
        ret = ftdi_write_data(ftdi, &data, sizeof(data));
        if (ret < 0)
        {
            ftdi_free(ftdi);
            fprintf(stderr, "ERROR: ftdi_write_data() = %d\n", ret);
            return EXIT_FAILURE;
        }
        usleep(500000);
    }

    /* Done */
    printf("\nDone\n");
    ret = ftdi_usb_close(ftdi);
    if (ret)
    {
        ftdi_free(ftdi);
        fprintf(stderr, "ERROR: ftdi_usb_close() = %d\n", ret);
        return EXIT_FAILURE;
    }

    ftdi_free(ftdi);
    return EXIT_SUCCESS;
}


CBUS Discretes

In addition to the 8 lines used for RS232, there are 4 more, which are used to control the LEDs and RS485 drivers.  These lines can be controlled in a similar fashion using BITMODE_CBUS.  It is not clear whether one can interleave the two bitbashing modes in order to control all 12 lines at the same time and whether the lines will glitch if one does. See this example.

I also read that one can use the CBUS bitbashing concurrently with the normal serial mode, to provide a UART plus 4 discretes, but I have not tried it.

Compile and Test

Assuming that your Linux machine is configured properly with GCC, compile it thus:
$ gcc -o flasher flasher.c -lftdi
$ chmod 754 flasher

Now stick a LED with a 1k resistor in series onto the RS232 adaptor Tx and Gnd pins to see how it works and run it:
$ ./flasher

Install and Configuration of libftdi

If you don't have a GCC and libftdi configured system yet, then assuming that you have Fedora Linux:
$ su -
# yum update

# yum install kernel-headers

# yum groupinstall "Development Tools" "Development Libraries"
# yum install libftdi libftdi-devel

Now you can control the world!

Cmake

Also see the next post on Makefiles.

Thursday, January 8, 2015

Ecrasez l'infâme

A moment of silence please, in a world gone mad.

$ make bzImage
$ echo Not war.

Tuesday, January 6, 2015

MGL V6R ATC VHF Radio Control Protocol in Bash

The MGL V6R and V10, ATC VHF radios have a binary protocol (described in the V10 manual), in addition to the ubiquitous Garmin SL40 protocol.

The Emergency/Setup channel is 121.5 MHz.  Don't use it for testing...

In this example, I used the Bash let operator to do the calculations and printf is treated as a built-in function - TIMTOWTDI.

Here is a Bash script that attempts to compute the frequency message:

#! /bin/bash
echo MGL V6R ATC VHF Radio Protocol
echo

STX="02"        # Message header
DLE="05"        # Message header
CC="00"            # Active Frequency message ID = 00H, Standby Frequency message ID = 01H
KHZ="000000"    # Frequency in Kilohertz, decimal string (6 digits)
KHZH="000000"    # Frequency in Kilohertz, hexadecimal string (3 bytes)       
KHZ0="00"        # Frequency in Kilohertz, B0, LSB first
KHZ1="00"        # Frequency in Kilohertz, B1
KHZ2="00"        # Frequency in Kilohertz, B2, MSB last
SUM="00"        # XOR checksum from CC to last data byte, then XOR with 55H to invert some bits

if [ -n "$1" ]; then
KHZ=$1
echo "Frequency = $KHZ kHz Decimal"
echo

echo "Set serial port USB0 to 9600N81"
stty -F /dev/ttyUSB0 raw
stty -F /dev/ttyUSB0 9600
echo

echo "Compute frequency in hexadecimal"
printf -v KHZH "%06x" "$KHZ"
echo "Frequency MSB first = $KHZH Hex"

KHZ0=$(echo "$KHZH" | cut -c 5-6)
KHZ1=$(echo "$KHZH" | cut -c 3-4)
KHZ2=$(echo "$KHZH" | cut -c 1-2)
echo "Frequency LSB first = $KHZ0$KHZ1$KHZ2 Hex"
echo

# Bash by default handles numbers as decimal ASCII strings.
# A number starting with a zero is considered to be octal.
# A number starting with 0x is considered to be hexadecimal.
# The final modulo 256 reduces the answer to one byte
# and the printf makes it hexadecimal.
echo "Compute byte wide XOR checksum"
let "SUM=$CC ^ $KHZ0 ^ $KHZ1 ^ $KHZ2"
let "SUM ^= 0x55"
let "SUM %= 256"
printf -v SUM "%02x" "$SUM"
echo "SUM = $SUM"
echo

# The format string "\x" tells echo to output each variable as an
# 8 bit binary value to the serial port,
# and not as two ASCII characters.
echo "Frequency message = $STX $DLE $CC $KHZ0 $KHZ1 $KHZ2 $SUM"
echo -en "\x$STX\x$DLE\x$CC\x$KHZ0\x$KHZ1\x$KHZ2\x$SUM" > /dev/ttyUSB0
echo

echo "La Voila!"
exit 1

fi
echo Example: mglfreq 123450
exit 0


Please note that I don't know whether this is completely correct yet.  There is always some uncertainty with interpreting an ICD and I may have something wrong still and MGL Avionics sent me the V6R protocol doc after I wrote the above based on the V10 document.

By implementing this in a Bash script, any problems can be fixed easily and one will probably only need to rearrange some variables in the final echo statements to make it work.

Use at your own peril though...



Monday, January 5, 2015

Garmin SL40 ATC VHF Radio Serial Protocol in Bash

The Garmin SL30 and SL40 protocols are used by most aircraft and marine VHF radios.  These radios are very simple AM devices and basically one only needs to set the frequency.

The Emergency/Setup channel is 121.5 MHz.  Don't use it for testing...

Here is a Bash script that will compute a SL40 frequency message complete with its arithmetic checksum, using the bc calculator:

#! /bin/bash
echo Garmin SL40 ATC Radio Protocol
echo

# Set Active Frequency Message
HDR='$PMRRC'    # Header
IDH='0'        # ID
IDL='0'       
MHZ='119'    # 118 to 136 MHz
KHZ='100'    # multiples of 25 kHz
MOD='N'        # N=normal

SUM=0    # Arithmetic Checksum
MD=0    # MHZ scaled to ASCII decimal value
MA=""    # MHZ in ASCII character
KD=0    # KHZ scaled to ASCII decimal value
KA=""    # KHZ in ASCII character
MODD="" # MOD in ASCII decimal value
IDHD="" # ID high ASCII decimal value
IDLD="" # ID low ASCII decimal value
SUMH="" # Checksum as two digit Hex


# Example: "Set ATC radio to 119.100 MHz Normal"
# '$PMRRC00G4N29\r\n'

if [ -n "$1" ]; then
MHZ=$(echo "$1" | cut -d "." -f 1)   
KHZ=$(echo "$1" | cut -d "." -f 2)
echo "Frequency=$MHZ.$KHZ"
echo

echo "Set serial port USB0 to 9600N81"
stty -F /dev/ttyUSB0 raw
stty -F /dev/ttyUSB0 9600
echo

echo Calculate frequency characters
MD=$(echo "$MHZ - 48" | bc)
MA=$(printf \\$(printf "%o" $MD))
KD=$(echo "$KHZ - 48" | bc)
KA=$(printf \\$(printf "%o" $KD))
echo m=$MA
echo k=$KA
echo

echo Calculate checksum
IDHD=$(printf "%d" "'$IDH")
IDLD=$(printf "%d" "'$IDL")
MODD=$(printf "%d" "'$MOD")
SUM=$(echo "$IDHD + $IDLD + $MD + $KD + $MODD" | bc)
SUM=$(echo "$SUM % 256" | bc)
SUMH=$(printf "%02x" "$SUM")
echo SUMH=$SUMH
echo

echo "Frequency Message = $HDR$IDH$IDL$MA$KA$MOD$SUMH"
echo "$HDR$IDH$IDL$MA$KA$MOD$SUMH" > /dev/ttyUSB0
echo

echo "La Voila!"
exit 1

fi
echo Example: atcfreq 123.450
exit 0


The above script will take 119.100 MHz and output the message '$PMRRC00G4N29' to the screen and to the serial port.


Why on earth do I use Bash for this?  Because I'm a masochist and love to fight the Bash automatic type conversions...  

All Linux/UNIX machines have Bash (and Windows has Cygwin), therefore this is an easy way to debug and test any and all black boxes in a lab setting.

Modify at your peril!

Tuesday, December 30, 2014

Stalling Aircraft

Modern passenger planes cruise at very high altitude and very close to their stall speed, flying on a knife edge, in order to minimise fuel consumption.  The problem is that when a plane encounters turbulent air due to a storm or a side wind, it can stall unexpectedly, while still traveling at high speed.

It appears to me, that in the relentless pursuit of lower drag and lower fuel consumption, the designers have compromised aircraft stability and safety. 

The situation now, that a passenger plane can stall at 30,000 feet and then fall out of the sky, with the total loss of aircraft, crew and passengers, unable to recover despite the best efforts of an experienced flight crew, because the plane was designed to save every last drop of fuel, is inexcusable.

Aircraft designers should always put stability and safety first and should not be driven by marketing only.

Tuesday, December 23, 2014

FreeCAD

I've been playing with FreeCAD for a few hours, since I need to make little Nylon brackets and things at Shapeways.

The program is absolutely amazing for its price - Zero Dollars - which is a nice way to say that there are a few hiccups, but once one knows how to avoid the hiccups, then it works perfectly... :)

To aid with error checking of CAD files before uploading them to Shapeways, also install the free Meshlab.  Note that uploading a file to Shapeways takes a while, because they also do a conversion and error check, so be patient.  If you checked it with Meshlab, then it should work.


I made the above widget by drawing four cubes, resizing them and subtracting  three from the other, then subtracting four cylinders for the mounting holes and finally applying fillets to the edges.  That's all there is to it.  Made out of Nylon, it makes a strong base for a little step motor.

In general, I would say that FreeCAD is almost as good as Solidworks.   It is certainly good for hobby use and it may even be good enough in a small business for simple things.

The nice thing about FreeCAD, is that it is cross platform and it works exactly the same way on Windows, Linux and Mac - it even has the same bugs too...

Here are a few pointers on FreeCAD version 0.14:

The smallest features that Shapeways can produce is about 1 mm.  Widgets may also be somewhat uneven and may require sanding/polishing, but the resulting whatchammacallits are generally fine for prototype and hobby use as is.

If you keep the thickness at 1 mm, then the cost is about 50c per 10 square cm for the cheapest Nylon.

The only CAD export format that works consistently and which is supported by Shapeways, is VRML.  Other CAD export formats such as STP may cause position/add/subtract of shapes to get lost and the mesh export format such as STL or OBJ may be full of triangular holes, so then the resulting oddity won't be usable.  To save a model in VRML, Click Part Workbench, Edit, Select All, Ctrl-E, then type filename.vrml, Save.  (Weird bug: VRML is not actually an option in the File Save drop down when you click Part, Export, but it should be there with many other formats when you press Ctrl-E, otherwise just type it).

I wanted to make an old fashioned Radio Ham handheld/standing Microphone/Speaker/PTT gadget, that looks like it was stamped out of brass, circa 1920 or so.  Here is the base:



Note that there is a weird bug with vrml export.  If it won't work, first export the file as .brp and then export it as .vrml.  I had to try several times to get this revolved object to export successfully as a vrml file. Don't ask me why, but it eventually worked.

It is also recommended to check the final file with Meshlab before sending it to Shapeways.  If the file is full of holes, or if the Shapeways uploader complain about the file being unusable, read the VRML file into Meshlab and then export it to STL and try uploading it again.

If you make a drawing using the 3D add/subtract method in the Part Workbench, then the whole hoosammawatzit seems to remain fully constrained all by itself.  This is a wonderful way to make a little wazzisname consisting of rectangular shapes and cylindrical holes very quickly and is the drafting method that I can recommend.  Follow this tutorial: http://www.freecadweb.org/wiki/index.php?title=Basic_modeling_tutorial

If you make a watchammacallit using the 2D drawing and extrusion process in the Part Design WorkBench, then you have to keep an eye on the constraints box and ensure that every single line or shape is fully constrained before moving on to the next line or shape.  It is almost impossible to fix missing constraints later, but you may be able to find a loose end by clicking and dragging lines with the mouse - if it moves, then it isn't fully constrained.

The best way to draw a fully constrained line in the Part Design Workbench, is to draw the line close to where you want it to be, but not exactly.  Then click the end point and the point where you want it to be and apply a constraint (a dot 'coincident', or 'fix point to object' or some such), to make the line end point jump to the right spot.  You typically need to apply two to three constraints to get it exactly where it should be.  Watch the Constraints box on the left.

Here is the Speaker front and the tiny little hole at the top is for the Mic (The backside looks similar but without the rose of holes):



So now I can put my $20 of amplifier electronics inside a seemingly century old custom plastic enclosure costing $100 - ouch.  It is not a cheap hobby...

When making plastic/metal nurgles, it is important that you fillet/chamfer the edges.  Stress build up at edges can cause a plastic mcgafter to crack and metal thingammajigs may cut your fingers if you don't.  The fillet tool is a little unreliable, so save oftenDo this step last.

Sometimes (not very often!) FreeCAD exits, or the drawing disappears from view, leaving you rubbing your eyes and reaching for your mug of coffee in frustration.  The only solution is to restart it and get yet more coffee.  It is therefore important to save your work regularly and use an incrementing number for simple version control (filename-1, filename-2), so that you can go back to the last thingammabob that worked.

La voila!