Safe or Glitch-Free Clock Gating

August 10th, 2008 by lane

Following is an example of a way to perform glitch-free clock gating. The clock is stalled in the high state one clock cycle after gate is asserted high. It is safe as long as the delay through the register is less than a half clock cycle.


OpenVPN setup on Centos 5.2

August 10th, 2008 by lane

OpenVPN is a very capable SSL-based VPN client/server software package. It has great documentation at
OpenVPN Howto Documents.

  • To install on CentOS, I grab the rpms from the EPEL repo. EPEL stands for Extra Packages for Enterprise Linux. They are Fedora packages repackaged for Redhat Enterprise. The project homepage and documentation is at http://fedoraproject.org/wiki/EPEL. There is also a package list at that site.
    To install the EPEL yum repo, run the following command:

    sudo rpm -ihv http://download.fedora.redhat.com/pub/epel/5/x86_64/epel-release-5-2.noarch.rpm 

    Change the architecture and version appropriately for your machine.

  • Install OpenVPN with the following command:
    yum install openvpn
  • For now I will setup OpenVPN to route rather than bridge. Later I will likely bridge two remote networks.
  • Generate the Master Certificate Authority. Copy the templates files into place:
    sudo cp -r /usr/share/openvpn/easy-rsa/2.0 /etc/openvpn/certs

    Now cd into /etc/openvpn/certs and edit the var file. The only thing I changed was the last five lines containing the location information. Now run the following commands

    sudo su
    . ./vars
    ./clean-all
    ./build-ca
    

    Note that you want to be root when running these commands because the vars script alters your environment, and they will get lost if you are using sudo on each command individually.

  • Generate certificate & key for server.
    ./build-key-server server_name

    I left challenge password empty and answered yes to signing and committing the certificate.

  • Generate client certificates
    ./build-key client1
  • Build Diffie Hellman data
    ./build-dh
  • You can now drop root permissions and setup the server configuration file
    sudo cp /usr/share/doc/openvpn-2.1/sample-config-files/server.conf /etc/openvpn

    Edit it to your liking. I did not change much except to add paths appropriately to the certificate and dh files.

  • Install OpenVPN on the client.
    yum install openvon

    . In my case this a Fedora 9 machine.

  • sudo cp /usr/share/doc/openvpn-2.1/sample-config-files/client.conf /etc/openvpn/

    and edit it to your liking.

  • Copy the keys from the server to the client and start it up
  • For routing so that I run the following
    echo 1 > /proc/sys/net/ipv4/ip_forward

    on the server so that machines on the same subnet as the server can talk to the clients. Likewise, I add the following static route to the default gateway (which is my wireless router):

    Destination LAN IP:  	  10.8.0.0
    		Subnet Mask: 	255.255.255.0
    		Gateway: 	192.168.35.2
    

    where gateway is the IP of the vpn server.

LVM Example

July 28th, 2008 by lane

I always look at the MythTV documentation for a short, quick LVM reference

I have a large 2TB RAID 5 device that I want to split into two partitions. LVM gives that ability. Here are the steps I followed:

  • Create the physical group
    sudo pvcreate /dev/md0
  • Create the volume to include the whole physical group.
    vgcreate bigdisk /dev/md0
  • Then use lvcreate as follows:
    sudo lvcreate --name mm --size 1TB bigdisk
    sudo lvcreate --name home -l 214789 bigdisk

Example Software RAID 5 Setup in Linux

July 28th, 2008 by lane

I have three identical 1TB hard drives that I want to configure in a RAID 5 configuration to give me 2 TB. A good resource is RAID Quick HOWTO. Here are the steps I took:

  • Create partitions on the desired devices to have a type of 0xFD (linux raid autodetect). I created a single 1TB partition on each drive using fdisk.
  • Create the raid device using mdadm command
     sudo mdadm --create --verbose --level=5 --raid-devices=3 /dev/md0 /dev/sda1 /dev/sdc1 /dev/sdd1
  • The output for me looks like this:

    mdadm: layout defaults to left-symmetric
    mdadm: chunk size defaults to 64K
    mdadm: /dev/sdc1 appears to be part of a raid array:
        level=raid5 devices=2 ctime=Mon Jul 28 09:09:11 2008
    mdadm: /dev/sdd1 appears to be part of a raid array:
        level=raid5 devices=2 ctime=Mon Jul 28 09:09:11 2008
    mdadm: size set to 976759936K
    Continue creating array? y
    mdadm: array /dev/md0 started.
    
  • Take a look in the /proc/mdstat file to see how things went. For me, it looks like
    this

    $ cat /proc/mdstat
    Personalities : [raid6] [raid5] [raid4]
    md0 : active raid5 sdd1[3] sdc1[1] sda1[0]
          1953519872 blocks level 5, 64k chunk, algorithm 2 [3/2] [UU_]
          [>....................]  recovery =  0.0% (55552/976759936) finish=1171.1min speed=13888K/sec
    
    unused devices: 
    
  • Create the /etc/mdadm.conf file.
    mdadm --detail --scan --verbose > /etc/mdadm.conf
    
  • Setup mdadm to monitor the array and send an email if anything fails. I add the following line to my /etc/rc.local file:
    /sbin/mdadm --monitor -t -f -d 3600 -y --scan -m lane@brooks.nu
    

    The -t option causes a test message to be sent when the command is first run. This lets you verify the notification path. The -f puts the process in the background. -d 3600 puts the polling rate at once every hour. -y causes events to get logged to the syslog.

    You will get a DegradedArray array when you first setup the raid and it is doing the initial build of the array (which can take some time if you have big disks). This is to be expected as the array is not finished building.

  • Done. Now format the /dev/md0 and start using it. You can check /proc/mdstat at any time to see the state of your devices. It will tell if one has failed.

Gray Coding

July 25th, 2008 by lane

The schematic for gray coding and back to binary is shown in the figure below.

Below are two verilog functions to implement this logic. They are made functions for ease of instancing.

   function [ADDR_WIDTH-1:0] bin2gray;
      input [ADDR_WIDTH-1:0] x;
      begin
         bin2gray = x ^ (x>>1);
      end
   endfunction

   function [ADDR_WIDTH-1:0] gray2bin;
      input [ADDR_WIDTH-1:0] x;
      integer                i;
      begin
         gray2bin[ADDR_WIDTH-1] = x[ADDR_WIDTH-1];
         for(i=ADDR_WIDTH-2; i>=0; i=i-1) begin
            gray2bin[i] =  gray2bin[i+1] ^ x[i];
         end
      end
   endfunction

Following is a simple module for testing these functions:

module graytest
   (input clk,
    input resetn
    );
   parameter ADDR_WIDTH=3;

   reg [ADDR_WIDTH-1:0] count;

   wire [ADDR_WIDTH-1:0] gcount = bin2gray(count);
   wire [ADDR_WIDTH-1:0] bcount = gray2bin(gcount);

   always @ (posedge clk or negedge resetn) begin
      if(~resetn) begin
	 count <= 0;
      end else begin
	 $display("0b%b -> 0b%b -> 0b%b", count, gcount, bcount);
	 count <= count + 1;
      end
   end

   function [ADDR_WIDTH-1:0] bin2gray;
      input [ADDR_WIDTH-1:0] x;
      begin
         bin2gray = x ^ (x>>1);
      end
   endfunction

   function [ADDR_WIDTH-1:0] gray2bin;
      input [ADDR_WIDTH-1:0] x;
      integer                i;
      begin
         gray2bin[ADDR_WIDTH-1] = x[ADDR_WIDTH-1];
         for(i=ADDR_WIDTH-2; i>=0; i=i-1) begin
            gray2bin[i] =  gray2bin[i+1] ^ x[i];
         end
      end
   endfunction
endmodule

When I run this simulation (using verilator), I get the following output:

0b000 -> 0b000 -> 0b000
0b001 -> 0b001 -> 0b001
0b010 -> 0b011 -> 0b010
0b011 -> 0b010 -> 0b011
0b100 -> 0b110 -> 0b100
0b101 -> 0b111 -> 0b101
0b110 -> 0b101 -> 0b110
0b111 -> 0b100 -> 0b111

The left-most column is a 3 bit number from a binary counter. The middle column is the gray encoded value of this counter, and the right column is the gray2bin output. This verifies that it works. Here is a picture of the simulation results:

Dynamic method creation in python

June 26th, 2008 by lane

I recently wrote some python bindings for a third party, closed source shared library. This library was a USB communication API to a board made by Opal Kelly. I was writing a multi threaded python application for video streaming. The video stream went through the shared library on a worker thread. The GUI thread, however, also had access to the shared library giving the user the ability to change settings while the thread was running. The shared library was not thread safe, however, the global interpreter lock kept things safe. I found the global interpreter lock when trying to figure out why the video stream through this shared library was so slow and choppy. The reason was that the streaming thread would not context switch while waiting on I/O. After adding the Py_BEGIN_ALLOW_THREADS and Py_END_ALLOW_THREADS macros around my I/O calls, my video stream started behaving nicely, but now I had a thread safety issue because the GUI thread could now access the shared library while the capture thread was waiting on I/O.

To solve this, I wanted to wrap the python bindings in a class that would use a mutex to lock access to every function in the shared library. I did not want to have individually wrap each function call either. So I used the __getattribute__ function to globally wrap each function like this:

class FrontPanelThreadSafe(ok.FrontPanel):
    """This class wraps up the ok.FrontPanel to make it thread safe by
    creating a lock that must be acquired before any function call in
    the base class can be called."""

    def __init__(self):
        ok.FrontPanel.__init__(self)
        self.lock = threading.Lock()

    def __getattribute__(self, key):
        """This function does all the magic.  All function calls to
        this object go through this method.  This method passes them
        on to the base class after it acquires the lock to make the
        access to the opal kelly board atomic."""
        if(key == "lock"):
            return object.__getattribute__(self, key)
        else:
            def func(*args, **kw):
                try:
                    self.lock.acquire()
                    return ok.FrontPanel.__getattribute__(self, key)(*args, **kw)
                finally:
                    self.lock.release()
            return func

Fortunately, right now the base class does not have any attributes–just methods. If it had attributes, then I would need to add a condition to distinguish the two.

Elan USBscope50 on Fedora 8

June 3rd, 2008 by lane

I have wanted a USB scope for quite some time now, and even considered designing my own. Well the other day I set out to find one with linux support and found one made by Elan Digital Systems. While $400 is way too expensive for such a device, it is much cheaper than a stand alone option, so I decided to try it out. It is a bit strange that it does not come with a probe, so I ordered a probe separately from Digikey. I need two channel support, but appearantly the Linux software does not yet support multiple channels, so I just bought one channel for now to evaluate it.

The installation procedure that I used is below. Overall the installation process was fine. They do not provide udev rules and say to run the program as root. This is bad. Follow my rules to avoid this. The java application is listed as Beta, and it is missing quite a bit of functionality. So much so that I booted my laptop into windows to try their windows version. It is a lot more complete and usabe.

Installation Instructions

Fedora 8 kernel has the Elan device support, so it is not necessary to recompile the kernel. I plugged it in and the red LED came on without any changes.

  • First setup the udev rules so that you do not need to be root to access the Elan device. The following udev rules placed in a file called /etc/udev/rules.d/60-elan.rules directory worked for me
    # give all ttyUSB devices rw permission to all
    KERNEL=="ttyUSB*", MODE="0666"
    

    Run udevcontrol reload_rules as root after adding the rules.

  • Now plug the elan device in, run lsusb (part of the usbutils package) and see the addition of the Elan scope with this line:

    Bus 002 Device 002: ID 10c4:f001 Cygnal Integrated Products, Inc.
  • Look to ensure that /proc/bus/usb/devices contains the following listing:
    T:  Bus=02 Lev=01 Prnt=01 Port=07 Cnt=01 Dev#=  2 Spd=12  MxCh= 0
    D:  Ver= 1.10 Cls=00(>ifc ) Sub=00 Prot=00 MxPS=64 #Cfgs=  1
    P:  Vendor=10c4 ProdID=f001 Rev= 1.06
    S:  Manufacturer=Silicon Labs
    S:  Product=USBscope50
    S:  SerialNumber=K58159-002
    C:* #Ifs= 1 Cfg#= 1 Atr=80 MxPwr=200mA
    I:* If#= 0 Alt= 0 #EPs= 2 Cls=ff(vend.) Sub=00 Prot=00 Driver=cp2101
    E:  Ad=81(I) Atr=02(Bulk) MxPS=  64 Ivl=0ms
    E:  Ad=01(O) Atr=02(Bulk) MxPS=  64 Ivl=0ms
    
  • And look at /var/log/messages for a similar message:

    May 29 10:42:18 XXXX kernel: usb 2-8: new full speed USB device using ohci_hcd and address 2
    May 29 10:42:18 XXXX kernel: usb 2-8: configuration #1 chosen from 1 choice
    May 29 10:42:18 XXXX kernel: cp2101 2-8:1.0: cp2101 converter detected
    May 29 10:42:18 XXXX kernel: usb 2-8: reset full speed USB device using ohci_hcd and address 2
    May 29 10:42:18 XXXX kernel: usb 2-8: cp2101 converter now attached to ttyUSB0
    
  • Check the permissions of the device using ls -al /dev/ttyUSB0. This will verify that your udev rules are working.
    crw-rw-rw- 1 root uucp 188, 0 2008-05-29 11:03 /dev/ttyUSB0
    
  • Now install the Elan software. I ran the following commands to download and install
    wget http://www.elandigitalsystems.co.uk/support/usbtmfaq/usbscope50/usbscope50_java_beta_linux_setup.zip
    mkdir usbscope50
    cd usbscope50
    unzip ../usbscope50_java_beta_linux_setup.zip
    sudo cp USBscope50Drvr.so /usr/lib
    
  • Try running the software (while in the same directory)
    java -jar USBscope50_Software.jar
    
  • On a 32 bit machine, I initially got this error:
    Exception in thread "main" java.lang.NoClassDefFoundError: de.javasoft.plaf.synthetica.SyntheticaLookAndFeel
       at java.lang.Class.initializeClass(libgcj.so.8rh)
       at java.lang.Class.initializeClass(libgcj.so.8rh)
       at usbscope50software.USBFamily_Main.main(USBFamily_Main.java:304)
    Caused by: java.lang.ClassNotFoundException: sun.swing.DefaultLookup not found in gnu.gcj.runtime.SystemClassLoader{urls=[file:USBscope50_Software.jar], parent=gnu.gcj.runtime.ExtensionClassLoader{urls=[], parent=null}}
       at java.net.URLClassLoader.findClass(libgcj.so.8rh)
       at gnu.gcj.runtime.SystemClassLoader.findClass(libgcj.so.8rh)
       at java.lang.ClassLoader.loadClass(libgcj.so.8rh)
       at java.lang.ClassLoader.loadClass(libgcj.so.8rh)
       at java.lang.Class.initializeClass(libgcj.so.8rh)
       ...2 more
    

    So I installed the icedtea version of java with the following command:

    yum install java-1.7.0-icedtea

    Then the application at least launched, but the signal was a constant flat line zero. So I installed Sun’s JRE, and then things started working.

  • On a 64 bit machine I got this error:
    Exception in thread "main" java.lang.UnsatisfiedLinkError: /usr/lib/USBscope50Drvr.so: /usr/lib/USBscope50Drvr.so: wrong ELF class: ELFCLASS32 (Possible cause: architecture word width mismatch)
            at java.lang.ClassLoader$NativeLibrary.load(Native Method)
            at java.lang.ClassLoader.loadLibrary0(ClassLoader.java:1769)
            at java.lang.ClassLoader.loadLibrary(ClassLoader.java:1665)
            at java.lang.Runtime.load0(Runtime.java:788)
            at java.lang.System.load(System.java:1042)
            at usbscope50software.LoadDataArray.(LoadDataArray.java:600)
            at usbscope50software.USBscope50_Main.(USBscope50_Main.java:145)
            at usbscope50software.USBFamily_Main.(USBFamily_Main.java:108)
            at usbscope50software.USBFamily_Main.main(USBFamily_Main.java:310)
    

    It seems Elan needs a 64 bit release of their shared library.

linux gpib on Fedora 5 with swig’d python bindings - National Instraments USB HS card

April 6th, 2008 by lane
  • Download linux-gpib version 3.2.10 from http://linux-gpib.sourceforge.net
  • Build the linux-gpib software
    ./configure --disable-guile-binding --disable-perl-binding --disable-php-binding  --disable-python-binding --disable-tcl-binding --prefix=/usr
    make
    sudo make install
  • Created a file /etc/udev/rules.d/60-gpib.rules with the following contents
    BUS=="usb", SYSFS{idVendor}=="3923", MODE="0666", RUN+="/usr/sbin/gpib_config"
    KERNEL="gpib[0-9]*", MODE="0666"

    I found that the kernel was oops’ing with these udev lines, so I commented out the first line that runs gpib_config and then manually run gpib_config. My guess is that the device needs some time to come on-line and that a delay is necessary. I am not sure how to force udev to wait though.

  • Reload the udev rules
    sudo udevcontrol reload_rules
  • Create /etc/gpib.conf as follows:
    interface {
    	minor = 0
    	board_type = "ni_usb_b"
    	name = "usb"
    	pad = 0
    	sad = 0
    	timeout = T3s
    	master = yes
    }
  • From the manual

    Unlike the USB-B, the USB-HS does not require a firmware upload to become functional after being
    plugged in. The linux-gpib tarball contains hotplug scripts which will automatically run gpib_config
    after the device is plugged in.

  • Unpack this tar file in the languages subdirectory swig’d linux gpib.
  • cd into the py_swig directory. run make and make install
  • Now you can import gpib in python
  • Here is some examples of how to use it
    import gpib
    
    class hp34401A:
        def __init__(self, addr, minor=0, timeout=11):
            self.ud = gpib.ibdev(minor, addr, 0, timeout, 1, 0)
            if(self.ud < 0):
                raise RuntimeError("Error creating hp8656B")
    
        def meas(self):
            gpib.ibWrt(self.ud, "RST*");
            gpib.ibWrt(self.ud, "MEAS:VOLT:DC?");
            status, data = gpib.ibRd(self.ud);
            if(gpib.ThreadIberr()):
                raise Exception("Read error: status = 0x%x" % status)
            else:
                print data[:gpib.ThreadIbcnt()]
                return float(data[:gpib.ThreadIbcnt()])
    
    class hp8656B:
        def __init__(self, addr, minor=0, timeout=11):
            self.ud = gpib.ibdev(minor, addr, 0, timeout, 1, 0)
            if(self.ud < 0):
                raise RuntimeError("Error creating hp8656B")
    
        def setFreq(self, freq):
    
            # 9 digits max
            gpib.ibWrt(self.ud, "FR"+str(freq)+"MZ")
    
        def setAmpl(self, ampl):
            # 9 digits max
            gpib.ibWrt(self.ud, "AP"+str(ampl)+"VL")
    
    class hp8644B:
        def __init__(self, addr, minor=0, timeout=11):
            self.ud = gpib.ibdev(minor, addr, 0, timeout, 1, 0)
            if(self.ud < 0):
                raise RuntimeError("Error creating hp8656B")
    
        def setFreq(self, freq):
    
            # 9 digits max
            gpib.ibWrt(self.ud, "FR"+str(freq)+"MZ")
    
        def setAmpl(self, ampl):
            # 9 digits max
            gpib.ibWrt(self.ud, "AP"+str(ampl)+"VL")
    
    if __name__ == "__main__":
    
        hp = hp34401A(12)

exim rewrite subject based on spam

March 26th, 2008 by lane

Here is how I got exim to rewrite the Subject header after spamassassin marks a message as spam.

I have an spam ACL in my /etc/exim/exim.conf as follows:

  warn    spam       = spam/defer_ok
          add_header = X-Spam-Flag: YES

This will add the X-Spam-Flag: YES header to the email, but I also want to append *** SPAM *** to the Subject :. The way I got this working was to use a filter. Before the begin ACL section of the /etc/exim/exim.conf file, I added the following line:

system_filter = /etc/exim/spam.filter

Then I created a /etc/exim/spam.filter file with the following contents:

if $header_X-Spam-Flag: contains "YES" then
headers add "Old-Subject: $h_subject:"
headers remove "Subject"
headers add "Subject: *** SPAM *** $h_old-subject"
headers remove "Old-Subject"
endif

cyrus imap folder seen state problems

March 26th, 2008 by lane

I had a user with a problem where squirrelmail would not let him click on his INBOX. In thunderbird he would mark all the messages in his INBOX as read, but that would not stick so that the next time he logged in they would all be marked unread again. I looked in the /var/logs/maillog log file and found these messages:

Mar 26 23:21:12 imaps[30634]: DBERROR: skiplist recovery /var/lib/imap/user/b/buser.seen: ADD at 2FC0 exists
Mar 26 23:21:12 imaps[30634]: DBERROR: opening /var/lib/imap/user/b/buser.seen: cyrusdb error
Mar 26 23:21:12 imaps[30634]: Could not open seen state for buser (System I/O error)

Without stopping the cyrus-imap server, I cd’d into the directory above, deleted the buser.seen file, and everything started working again.